From 774471d39cb5f6499e8a2f74f61a79aa36108656 Mon Sep 17 00:00:00 2001 From: SennayT Date: Thu, 14 May 2026 10:00:57 +0300 Subject: [PATCH 01/38] add freight api and web to workspace --- pnpm-workspace.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index c78606724..448988a79 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,4 +1,6 @@ packages: + - "apps/edr-freight-api" + - "apps/edr-freight-web/*" - "apps/edr-passenger-api" - "apps/edr-passenger-web/*" - "packages/*" From d590f485055b022c7295ffed4284556bc9ed21a0 Mon Sep 17 00:00:00 2001 From: SennayT Date: Thu, 14 May 2026 10:01:09 +0300 Subject: [PATCH 02/38] comment out test property --- apps/edr-passenger-web/backoffice/vite.config.ts | 8 ++++---- apps/edr-passenger-web/portal/vite.config.ts | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/edr-passenger-web/backoffice/vite.config.ts b/apps/edr-passenger-web/backoffice/vite.config.ts index eddf5190a..157a94445 100644 --- a/apps/edr-passenger-web/backoffice/vite.config.ts +++ b/apps/edr-passenger-web/backoffice/vite.config.ts @@ -7,8 +7,8 @@ export default defineConfig({ port: 5184, host: "0.0.0.0", }, - test: { - environment: "jsdom", - globals: true, - }, + // test: { + // environment: "jsdom", + // globals: true, + // }, }); diff --git a/apps/edr-passenger-web/portal/vite.config.ts b/apps/edr-passenger-web/portal/vite.config.ts index 5a40a5f32..324a8dfa7 100644 --- a/apps/edr-passenger-web/portal/vite.config.ts +++ b/apps/edr-passenger-web/portal/vite.config.ts @@ -7,8 +7,8 @@ export default defineConfig({ port: 5174, host: "0.0.0.0", }, - test: { - environment: "jsdom", - globals: true, - }, + // test: { + // environment: "jsdom", + // globals: true, + // }, }); From 4bdcefe8e06f31fa3a25a3f7ad31c3f294f1acac Mon Sep 17 00:00:00 2001 From: SennayT Date: Thu, 14 May 2026 10:01:25 +0300 Subject: [PATCH 03/38] generate prisma client before building --- apps/edr-passenger-api/package.json | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/edr-passenger-api/package.json b/apps/edr-passenger-api/package.json index 87d0b4bbf..aa3f34d64 100644 --- a/apps/edr-passenger-api/package.json +++ b/apps/edr-passenger-api/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "dev": "nest start --watch", - "build": "nest build", + "build": "prisma generate && nest build", "start": "node dist/main.js", "start:prod": "node dist/main.js", "lint": "eslint src", @@ -61,11 +61,19 @@ "typescript": "^5.3.3" }, "jest": { - "moduleFileExtensions": ["js", "json", "ts"], + "moduleFileExtensions": [ + "js", + "json", + "ts" + ], "rootDir": "src", "testRegex": ".*\\.spec\\.ts$", - "transform": { "^.+\\.(t|j)s$": "ts-jest" }, - "collectCoverageFrom": ["**/*.(t|j)s"], + "transform": { + "^.+\\.(t|j)s$": "ts-jest" + }, + "collectCoverageFrom": [ + "**/*.(t|j)s" + ], "coverageDirectory": "../coverage", "testEnvironment": "node" } From c3f0219eea1bb09accef4108e3bf68791a3507f6 Mon Sep 17 00:00:00 2001 From: SennayT Date: Thu, 14 May 2026 11:43:49 +0300 Subject: [PATCH 04/38] fix docker issues on edr --- .dockerignore | 7 + .npmrc | 2 + Dockerfile | 78 + apps/edr-freight-api/Dockerfile | 4 +- package.json | 2 +- pnpm-lock.yaml | 2618 ++++++++++++++++++------------- pnpm-workspace.yaml | 14 + 7 files changed, 1591 insertions(+), 1134 deletions(-) create mode 100644 .dockerignore create mode 100644 .npmrc create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..122332251 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +**/node_modules +**/dist +**/.github +**/.vscode +**/.git +**/.env +.env diff --git a/.npmrc b/.npmrc new file mode 100644 index 000000000..063d75376 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +@tria-plc:registry=https://npm.pkg.github.com +//npm.pkg.github.com/:_authToken=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 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..086b5d751 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,78 @@ +FROM node:24.15.0-alpine AS base +RUN corepack enable && corepack prepare pnpm@latest-11 --activate +WORKDIR /app + +FROM base AS deps + +COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./ + +COPY apps/edr-freight-api/package.json ./apps/edr-freight-api/ +COPY apps/edr-passenger-api/package.json ./apps/edr-passenger-api/ + +COPY apps/edr-freight-web/backoffice/package.json ./apps/edr-freight-web/backoffice/ +COPY apps/edr-freight-web/portal/package.json ./apps/edr-freight-web/portal/ + +COPY apps/edr-passenger-web/backoffice/package.json ./apps/edr-passenger-web/backoffice/ +COPY apps/edr-passenger-web/portal/package.json ./apps/edr-passenger-web/portal/ + + +COPY packages/api-common/package.json packages/api-common/ + +COPY packages/config/eslint-config/package.json packages/config/eslint-config/ +COPY packages/config/prettier-config/package.json packages/config/prettier-config/ +COPY packages/config/tsconfig/package.json packages/config/tsconfig/ + +COPY packages/types/package.json packages/types/ +COPY packages/ui-common/package.json packages/ui-common/ + +RUN --mount=type=cache,id=pnpm,target=/pnpm/store\ + --mount=type=secret,id=npmrc,target=./.npmrc \ + pnpm install --frozen-lockfile +FROM deps AS build +COPY . . +# ENV CI=true + +RUN pnpm run build +RUN find . -name "main.js" + +FROM base AS freight-api +# RUN corepack enable && corepack prepare pnpm@9.12.0 --activate +WORKDIR /app/apps/edr-freight-api +ENV NODE_ENV=production + +COPY --from=deps /app/node_modules ./../../node_modules +COPY --from=deps /app/apps/edr-freight-api/node_modules ./node_modules +COPY --from=build /app/apps/edr-freight-api/dist ./dist +COPY --from=build /app/apps/edr-freight-api/package.json ./package.json +COPY --from=build /app/packages ./../../packages + +EXPOSE 3001 +CMD ["node", "dist/main.js"] + + +FROM base AS passenger-api +# RUN corepack enable && corepack prepare pnpm@9.12.0 --activate +WORKDIR /app/apps/edr-passenger-api +ENV NODE_ENV=production + +COPY --from=deps /app/node_modules ./../../node_modules +COPY --from=deps /app/apps/edr-passenger-api/node_modules ./node_modules +COPY --from=build /app/apps/edr-passenger-api/dist ./dist +COPY --from=build /app/apps/edr-passenger-api/package.json ./package.json +COPY --from=build /app/packages ./../../packages + +EXPOSE 3001 +CMD ["node", "dist/main.js"] + + + +FROM nginx:1.27-alpine AS freight-web-portal +COPY --from=build /app/apps/edr-freight-web/portal/dist /usr/share/nginx/html +EXPOSE 5173 +CMD ["nginx", "-g", "daemon off;"] + + +FROM nginx:1.27-alpine AS freight-web-backoffice +COPY --from=build /app/apps/edr-freight-web/backoffice/dist /usr/share/nginx/html +EXPOSE 5173 +CMD ["nginx", "-g", "daemon off;"] diff --git a/apps/edr-freight-api/Dockerfile b/apps/edr-freight-api/Dockerfile index 1f4ac2e60..7755900f4 100644 --- a/apps/edr-freight-api/Dockerfile +++ b/apps/edr-freight-api/Dockerfile @@ -6,7 +6,9 @@ FROM base AS deps COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./ COPY apps/edr-freight-api/package.json ./apps/edr-freight-api/ COPY packages ./packages -RUN pnpm install --frozen-lockfile --filter @edr/freight-api... +RUN --mount=type=cache,id=pnpm,target=/pnpm/store\ + --mount=type=secret,id=npmrc,target=./.npmrc \ + pnpm install --frozen-lockfile --filter @edr/freight-api... FROM deps AS build COPY apps/edr-freight-api ./apps/edr-freight-api diff --git a/package.json b/package.json index 0c3b26cb8..5800955ef 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "prettier --write" ] }, - "packageManager": "pnpm@9.12.0", + "packageManager": "pnpm@11.1.1+sha512.d1fdf5f73c617b64fa1a56a81c3c8dfe0e966e33a6010aa256b517ae77be21d93e05affc0de1a83b0e4f29d569f68b446ae8f068cd7247c0bb3df0fb4d7bdf9a", "engines": { "node": ">=20" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bf0d892f0..d9f429ae8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,12 +4,6 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false -overrides: - date-fns: ^3.6.0 - pdfjs-dist: ^3.11.174 - react: 18.3.1 - react-dom: 18.3.1 - importers: .: @@ -67,10 +61,10 @@ importers: version: 11.0.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))) '@tria-plc/api-common': specifier: ^0.1.0 - version: 0.1.4(dlk6rffkpcjlebt3tne6hjqwx4) + version: 0.1.4(42b11c4715772d7b83dab2dbc0ea2324) '@tria-plc/iamapi-common': specifier: ^0.1.0 - version: 0.1.6(nhzmwbpvzw5m5dv4mcbu7ilapi) + version: 0.1.6(7eaf302065296f503c6ce1ae1c9ee51c) class-transformer: specifier: ^0.5.1 version: 0.5.1 @@ -152,7 +146,7 @@ importers: version: 5.100.10(react@18.3.1) '@tria-plc/iamui-common': specifier: 1.0.3 - version: 1.0.3(iv2eyyfavqphryq7oznx6tfwre) + version: 1.0.3(b753628ac65312d9adb4ccd0069fe702) axios: specifier: ^1.7.7 version: 1.16.0 @@ -160,10 +154,10 @@ importers: specifier: ^2.1.1 version: 2.1.1 react: - specifier: 18.3.1 + specifier: ^18.3.1 version: 18.3.1 react-dom: - specifier: 18.3.1 + specifier: ^18.3.1 version: 18.3.1(react@18.3.1) react-router-dom: specifier: ^6.27.0 @@ -192,7 +186,7 @@ importers: version: 10.5.0(postcss@8.5.14) jsdom: specifier: ^25.0.1 - version: 25.0.1(canvas@2.11.2) + version: 25.0.1 postcss: specifier: ^8.4.47 version: 8.5.14 @@ -207,7 +201,7 @@ importers: version: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1) vitest: specifier: ^2.1.2 - version: 2.1.9(@types/node@24.12.4)(jsdom@25.0.1(canvas@2.11.2))(lightningcss@1.32.0)(terser@5.47.1) + version: 2.1.9(@types/node@24.12.4)(jsdom@25.0.1)(lightningcss@1.32.0)(terser@5.47.1) apps/edr-freight-web/portal: dependencies: @@ -222,7 +216,7 @@ importers: version: 5.100.10(react@18.3.1) '@tria-plc/iamui-common': specifier: 1.0.3 - version: 1.0.3(iv2eyyfavqphryq7oznx6tfwre) + version: 1.0.3(9c106f46deace9660b1e6a7145f91ebf) axios: specifier: ^1.7.7 version: 1.16.0 @@ -230,10 +224,10 @@ importers: specifier: ^2.1.1 version: 2.1.1 react: - specifier: 18.3.1 + specifier: ^18.3.1 version: 18.3.1 react-dom: - specifier: 18.3.1 + specifier: ^18.3.1 version: 18.3.1(react@18.3.1) react-router-dom: specifier: ^6.27.0 @@ -262,7 +256,7 @@ importers: version: 10.5.0(postcss@8.5.14) jsdom: specifier: ^25.0.1 - version: 25.0.1(canvas@2.11.2) + version: 25.0.1 postcss: specifier: ^8.4.47 version: 8.5.14 @@ -277,7 +271,7 @@ importers: version: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1) vitest: specifier: ^2.1.2 - version: 2.1.9(@types/node@24.12.4)(jsdom@25.0.1(canvas@2.11.2))(lightningcss@1.32.0)(terser@5.47.1) + version: 2.1.9(@types/node@24.12.4)(jsdom@25.0.1)(lightningcss@1.32.0)(terser@5.47.1) apps/edr-passenger-api: dependencies: @@ -415,10 +409,10 @@ importers: specifier: ^2.1.1 version: 2.1.1 react: - specifier: 18.3.1 + specifier: ^18.3.1 version: 18.3.1 react-dom: - specifier: 18.3.1 + specifier: ^18.3.1 version: 18.3.1(react@18.3.1) react-router-dom: specifier: ^6.27.0 @@ -447,7 +441,7 @@ importers: version: 10.5.0(postcss@8.5.14) jsdom: specifier: ^25.0.1 - version: 25.0.1(canvas@2.11.2) + version: 25.0.1 postcss: specifier: ^8.4.47 version: 8.5.14 @@ -462,7 +456,7 @@ importers: version: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1) vitest: specifier: ^2.1.2 - version: 2.1.9(@types/node@24.12.4)(jsdom@25.0.1(canvas@2.11.2))(lightningcss@1.32.0)(terser@5.47.1) + version: 2.1.9(@types/node@24.12.4)(jsdom@25.0.1)(lightningcss@1.32.0)(terser@5.47.1) apps/edr-passenger-web/portal: dependencies: @@ -482,10 +476,10 @@ importers: specifier: ^2.1.1 version: 2.1.1 react: - specifier: 18.3.1 + specifier: ^18.3.1 version: 18.3.1 react-dom: - specifier: 18.3.1 + specifier: ^18.3.1 version: 18.3.1(react@18.3.1) react-router-dom: specifier: ^6.27.0 @@ -514,7 +508,7 @@ importers: version: 10.5.0(postcss@8.5.14) jsdom: specifier: ^25.0.1 - version: 25.0.1(canvas@2.11.2) + version: 25.0.1 postcss: specifier: ^8.4.47 version: 8.5.14 @@ -529,7 +523,7 @@ importers: version: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1) vitest: specifier: ^2.1.2 - version: 2.1.9(@types/node@24.12.4)(jsdom@25.0.1(canvas@2.11.2))(lightningcss@1.32.0)(terser@5.47.1) + version: 2.1.9(@types/node@24.12.4)(jsdom@25.0.1)(lightningcss@1.32.0)(terser@5.47.1) packages/api-common: dependencies: @@ -630,10 +624,10 @@ importers: specifier: ^18.3.0 version: 18.3.7(@types/react@18.3.28) react: - specifier: 18.3.1 + specifier: ^18.3.1 version: 18.3.1 react-dom: - specifier: 18.3.1 + specifier: ^18.3.1 version: 18.3.1(react@18.3.1) typescript: specifier: ^5.5.4 @@ -666,8 +660,8 @@ packages: '@ark-ui/react@5.36.2': resolution: {integrity: sha512-2lrZ7+Qtlj7hGx4qU2jZkE892JNrkULg/fUxqUuqmQfv9UGAXhdcw1Hr3N+zBgMDVz3aqip0Qa4v0Mox09MMvg==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=18.0.0' + react-dom: '>=18.0.0' '@asamuzakjp/css-color@3.2.0': resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} @@ -860,8 +854,8 @@ packages: resolution: {integrity: sha512-qzfRNLwxKjxx2IXjBj6uz1nYI+pKsq6uwHxO619+hx1OzNNuwLIjEHJxnDfBzoynO7sPCBlubMwFWb1e1PrXzw==} peerDependencies: '@emotion/react': '>=11' - react: 18.3.1 - react-dom: 18.3.1 + react: '>=18' + react-dom: '>=18' '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} @@ -990,7 +984,7 @@ packages: resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: '>=16.8.0' peerDependenciesMeta: '@types/react': optional: true @@ -1006,7 +1000,7 @@ packages: peerDependencies: '@emotion/react': ^11.0.0-rc.0 '@types/react': '*' - react: 18.3.1 + react: '>=16.8.0' peerDependenciesMeta: '@types/react': optional: true @@ -1017,7 +1011,7 @@ packages: '@emotion/use-insertion-effect-with-fallbacks@1.2.0': resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==} peerDependencies: - react: 18.3.1 + react: '>=16.8.0' '@emotion/utils@1.4.2': resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==} @@ -1200,14 +1194,14 @@ packages: '@floating-ui/react-dom@2.1.8': resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@floating-ui/react@0.27.19': resolution: {integrity: sha512-31B8h5mm8YxotlE7/AU/PhNAl8eWxAmjL/v2QOxroDNkTFLk3Uu82u63N3b6TXa4EGJeeZLVcd/9AlNlVqzeog==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=17.0.0' + react-dom: '>=17.0.0' '@floating-ui/utils@0.2.11': resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} @@ -1491,7 +1485,7 @@ packages: '@lottiefiles/react-lottie-player@3.6.0': resolution: {integrity: sha512-WK5TriLJT93VF3w4IjSVyveiedraZCnDhKzCPhpbeLgQeMi6zufxa3dXNc4HmAFRXq+LULPAy+Idv1rAfkReMA==} peerDependencies: - react: 18.3.1 + react: 16 - 19 '@lukeed/csprng@1.1.0': resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} @@ -1501,8 +1495,8 @@ packages: resolution: {integrity: sha512-9tph1lTVogKPjTx02eUxDUOdXacPzK62UuSqb4TdGliI54/Xgxftq0Dfqu6XuhCxn9J5MDJaNiLDvL/1KRkYqA==} peerDependencies: '@mantine/hooks': 8.3.18 - react: 18.3.1 - react-dom: 18.3.1 + react: ^18.x || ^19.x + react-dom: ^18.x || ^19.x '@mantine/dates@8.3.18': resolution: {integrity: sha512-FHx5teJOhupI0gO2o5evtVYQEdqOjayOkLRhEQfB5Nc5DvcysfPfmNILGkc1Nrp9ZQeQWKLT9qr+CkcCXwHOaw==} @@ -1510,13 +1504,13 @@ packages: '@mantine/core': 8.3.18 '@mantine/hooks': 8.3.18 dayjs: '>=1.0.0' - react: 18.3.1 - react-dom: 18.3.1 + react: ^18.x || ^19.x + react-dom: ^18.x || ^19.x '@mantine/hooks@8.3.18': resolution: {integrity: sha512-QoWr9+S8gg5050TQ06aTSxtlpGjYOpIllRbjYYXlRvZeTsUqiTbVfvQROLexu4rEaK+yy9Wwriwl9PMRgbLqPw==} peerDependencies: - react: 18.3.1 + react: ^18.x || ^19.x '@mapbox/node-pre-gyp@1.0.11': resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==} @@ -1534,8 +1528,8 @@ packages: deprecated: This package has been replaced by @base-ui/react peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 - react: 18.3.1 - react-dom: 18.3.1 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@types/react': optional: true @@ -1549,7 +1543,7 @@ packages: peerDependencies: '@mui/material': ^5.0.0 '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 - react: 18.3.1 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@types/react': optional: true @@ -1561,8 +1555,8 @@ packages: '@emotion/react': ^11.5.0 '@emotion/styled': ^11.3.0 '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 - react: 18.3.1 - react-dom: 18.3.1 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@emotion/react': optional: true @@ -1576,7 +1570,7 @@ packages: engines: {node: '>=12.0.0'} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 - react: 18.3.1 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@types/react': optional: true @@ -1587,7 +1581,7 @@ packages: peerDependencies: '@emotion/react': ^11.4.1 '@emotion/styled': ^11.3.0 - react: 18.3.1 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@emotion/react': optional: true @@ -1601,7 +1595,7 @@ packages: '@emotion/react': ^11.5.0 '@emotion/styled': ^11.3.0 '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 - react: 18.3.1 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@emotion/react': optional: true @@ -1623,7 +1617,7 @@ packages: engines: {node: '>=12.0.0'} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 - react: 18.3.1 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@types/react': optional: true @@ -1633,7 +1627,7 @@ packages: engines: {node: '>=14.0.0'} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 - react: 18.3.1 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@types/react': optional: true @@ -1646,15 +1640,15 @@ packages: '@emotion/styled': ^11.8.1 '@mui/material': ^5.8.6 '@mui/system': ^5.8.0 - date-fns: ^3.6.0 + date-fns: ^2.25.0 || ^3.2.0 date-fns-jalali: ^2.13.0-0 dayjs: ^1.10.7 luxon: ^3.0.2 moment: ^2.29.4 moment-hijri: ^2.1.2 moment-jalaali: ^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0 - react: 18.3.1 - react-dom: 18.3.1 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 peerDependenciesMeta: '@emotion/react': optional: true @@ -1675,6 +1669,81 @@ packages: moment-jalaali: optional: true + '@napi-rs/canvas-android-arm64@0.1.100': + resolution: {integrity: sha512-hjhCKhntPv9+t4ckHymdx0phYNcVW+GKQR6Lzw2zE+pOVjOplSmtx9nNNknTjbEDLcuLZqA1y8ufKg1XfgftzQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@napi-rs/canvas-darwin-arm64@0.1.100': + resolution: {integrity: sha512-2PcswRaC7Ly645DGt88///zuFDhJxJYdKAs1uU3mfk1atYkXufgcgLfBpk6Tm12nCQBaNt1wpybuPZ4qOhTo8A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@napi-rs/canvas-darwin-x64@0.1.100': + resolution: {integrity: sha512-ePNZtj7pNIva/siZMg+HmbeozkIjqUIYdoymH8HaA3qK7LfzFN4WMBM8G6HQ9ZC+H3+Dnn5pqtiXpgLykaPOhw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@napi-rs/canvas-linux-arm-gnueabihf@0.1.100': + resolution: {integrity: sha512-d5cDB48oWFGU8/XPhUOFAlySgb/VAu7D+s8fi55K1Pcfg8aPplHWqMgibhVLU8ky7Pyg/fuiVLz4Nf3JrSTuUA==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@napi-rs/canvas-linux-arm64-gnu@0.1.100': + resolution: {integrity: sha512-rDxgxRu69RvDlX/bh9o22DxLsGr8EqsNgotL9+RwQE1S0b0cqeatqsw6aW45mukm0B42DIAaAacKaYQ8cqS1nw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@napi-rs/canvas-linux-arm64-musl@0.1.100': + resolution: {integrity: sha512-K3mDW66N+xT2/V439u1alFANiBUjdEx2gLiNYnCmUsva5jZMxWTjafBYwTzYK+EMFMHrUoabuU+T1BIP5CgbYQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@napi-rs/canvas-linux-riscv64-gnu@0.1.100': + resolution: {integrity: sha512-mooqUBTIsccZpnoQC4NgrC1v6C1vof39etLNMnBwCY+p0gajWJvAHLGQ6g/gGyS5YrpDW+GefSN4+Cvcr08UWw==} + engines: {node: '>= 10'} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@napi-rs/canvas-linux-x64-gnu@0.1.100': + resolution: {integrity: sha512-1eCvkDCazm7FFhsT7DfGOdSaHgZVK3bt/dSBl5EWHOWmnz+I7j8tPseJqqD81NF+MH21jKUK4wQSDjN0mdhnTg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@napi-rs/canvas-linux-x64-musl@0.1.100': + resolution: {integrity: sha512-20arT6lnI19S68qNlii73TSEDbECNgzMz2EpldC1V3mZFuRkeujXkcebRk0LRJe9SEUAooYiLokfMViY8IX7yA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@napi-rs/canvas-win32-arm64-msvc@0.1.100': + resolution: {integrity: sha512-DZFFT1wIAg37LJw37yhMRFfjATd3vTQzjZ1Yki8u2vhO6Hi5VE6BVaGQ1aaDu7xb4iMErz+9EOwjpS7xcxFeBw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@napi-rs/canvas-win32-x64-msvc@0.1.100': + resolution: {integrity: sha512-MyT1j3mHC2+Lu4pBi9mKyMJhtP6U7k7EldY7sj/uS5gJA65gTXt8MefJQXLJo5d/vZbuWmfxzkEUNc/urV3pHA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@napi-rs/canvas@0.1.100': + resolution: {integrity: sha512-xglYA6q3XO5P3BNJYxVZ1IV7DLVjp1Py6nwag88YntrS+3vKHyYcMqXVS4ZztJmwz2uGvz1FWhI/4LgbR5uQDA==} + engines: {node: '>= 10'} + '@nestjs/axios@4.0.1': resolution: {integrity: sha512-68pFJgu+/AZbWkGu65Z3r55bTsCPlgyKaV4BSG8yUAD72q1PPuyVRgUwFv6BxdnibTUHlyxm06FmYWNC+bjN7A==} peerDependencies: @@ -1934,8 +2003,8 @@ packages: '@onlyoffice/document-editor-react@2.1.1': resolution: {integrity: sha512-b0SnFPmT+OEyJons18PPHpwtFABVCI4nr3gPtAAImar1PhN9tNc9703Yo5KPYsHhIgVq+FqHSWgunI9GJnKa5w==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.9.0 || ^17 || ^18 || ^19 + react-dom: ^16.9.0 || ^17 || ^18 || ^19 '@pandacss/is-valid-prop@1.11.1': resolution: {integrity: sha512-tvfThJmSw88Lgk5qVYzVckZ2FY8T376mGvP1cWUC5SR58AYm82ZKEFciDbGOQKcyN70rF9qqJBB5JVWgJo3JmA==} @@ -1989,8 +2058,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2002,8 +2071,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2015,8 +2084,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2028,8 +2097,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2041,8 +2110,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2054,8 +2123,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2067,8 +2136,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2079,7 +2148,7 @@ packages: resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2089,8 +2158,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2101,7 +2170,7 @@ packages: resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2110,7 +2179,7 @@ packages: resolution: {integrity: sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2120,8 +2189,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2132,7 +2201,7 @@ packages: resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2142,8 +2211,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2155,8 +2224,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2167,7 +2236,7 @@ packages: resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2177,8 +2246,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2190,8 +2259,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2202,7 +2271,7 @@ packages: resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2212,8 +2281,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2225,8 +2294,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2238,8 +2307,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2251,8 +2320,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2264,8 +2333,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2277,8 +2346,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2290,8 +2359,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2303,8 +2372,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2316,8 +2385,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2329,8 +2398,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2342,8 +2411,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2355,8 +2424,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2368,8 +2437,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2381,8 +2450,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2394,8 +2463,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2407,8 +2476,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2419,7 +2488,7 @@ packages: resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2428,7 +2497,7 @@ packages: resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2438,8 +2507,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2451,8 +2520,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2464,8 +2533,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2477,8 +2546,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2490,8 +2559,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2503,8 +2572,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2515,7 +2584,7 @@ packages: resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2524,7 +2593,7 @@ packages: resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2533,7 +2602,7 @@ packages: resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2542,7 +2611,7 @@ packages: resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2551,7 +2620,7 @@ packages: resolution: {integrity: sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2560,7 +2629,7 @@ packages: resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2569,7 +2638,7 @@ packages: resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2578,7 +2647,7 @@ packages: resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2587,7 +2656,7 @@ packages: resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2597,8 +2666,8 @@ packages: peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -2611,111 +2680,111 @@ packages: '@react-pdf-viewer/attachment@3.12.0': resolution: {integrity: sha512-mhwrYJSIpCvHdERpLUotqhMgSjhtF+BTY1Yb9Fnzpcq3gLZP+Twp5Rynq21tCrVdDizPaVY7SKu400GkgdMfZw==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@react-pdf-viewer/bookmark@3.12.0': resolution: {integrity: sha512-i7nEit8vIFMAES8RFGwprZ9cXOOZb9ZStPW6E6yuObJEXcvBj/ctsbBJGZxqUZOGklM0JoB7sjHyxAriHfe92A==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@react-pdf-viewer/core@3.12.0': resolution: {integrity: sha512-8MsdlQJ4jaw3GT+zpCHS33nwnvzpY0ED6DEahZg9WngG++A5RMhk8LSlxdHelwaFFHFiXBjmOaj2Kpxh50VQRg==} peerDependencies: - pdfjs-dist: ^3.11.174 - react: 18.3.1 - react-dom: 18.3.1 + pdfjs-dist: ^2.16.105 || ^3.0.279 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@react-pdf-viewer/default-layout@3.12.0': resolution: {integrity: sha512-K2fS4+TJynHxxCBFuIDiFuAw3nqOh4bkBgtVZ/2pGvnFn9lLg46YGLMnTXCQqtyZzzXYh696jmlFViun3is4pA==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@react-pdf-viewer/full-screen@3.12.0': resolution: {integrity: sha512-hQouJ26QUaRBCXNMU1aI1zpJn4l4PJRvlHhuE2dZYtLl37ycjl7vBCQYZW1FwnuxMWztZsY47R43DKaZORg0pg==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@react-pdf-viewer/get-file@3.12.0': resolution: {integrity: sha512-Uhq45n2RWlZ7Ec/BtBJ0WQESRciaYIltveDXHNdWvXgFdOS8XsvB+mnTh/wzm7Cfl9hpPyzfeezifdU9AkQgQg==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@react-pdf-viewer/open@3.12.0': resolution: {integrity: sha512-vhiDEYsiQLxvZkIKT9VPYHZ1BOnv46x9eCEmRWxO1DJ8fa/GRDTA9ivXmq/ap0dGEJs6t+epleCkCEfllLR/Yw==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@react-pdf-viewer/page-navigation@3.12.0': resolution: {integrity: sha512-tVEJ48Dd5kajV1nKkrPWijglJRNBiKBTyYDKVexhiRdTHUP1f6QQXiSyDgCUb0IGSZeJzOJb1h7ApKHe8OTtuw==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@react-pdf-viewer/print@3.12.0': resolution: {integrity: sha512-xJn76CgbU/M2iNaN7wLHTg+sdOekkRMfCakFLwPrE+SR7qD6NUF4vQQKJBSVCCK5bUijzb6cWfKGfo8VA72o4Q==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@react-pdf-viewer/properties@3.12.0': resolution: {integrity: sha512-dYTCHtVwFNkpDo7QxL2qk/8zAKndLwdD1FFxBftl6jIlQbtvNdxkFfkv1HcQING9Ic+7DBryOiD7W0ze4IERYg==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@react-pdf-viewer/rotate@3.12.0': resolution: {integrity: sha512-yaxaMYPChvNOjR8+AxRmj0kvojyJKPq4XHEcIB2lJJgBY1Zra3mliDUP3Nlb4yV8BS9+yBqWn9U9mtnopQD+tw==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@react-pdf-viewer/scroll-mode@3.12.0': resolution: {integrity: sha512-okII7Xqhl6cMvl1izdEvlXNJ+vJVq/qdg53hJIDYVgBCWskLk/cpjUg/ZonBxseG9lIDP3w2VO1McT8Gn11OAg==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@react-pdf-viewer/search@3.12.0': resolution: {integrity: sha512-jAkLpis49fsDDY/HrbUZIOIhzF5vynONQNA4INQKI38r/MjveblrkNv7qbr9j5lQ/WFic5+gD1e+Mtpf1/7DiA==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@react-pdf-viewer/selection-mode@3.12.0': resolution: {integrity: sha512-yysWEu2aCtBvzSgbhgI9kT5cq2hf0FU6Z+3B7MMXz14Kxyc3y18wUqxtgbvpFEfWF0bNUUq16JtWRljtxvZ83w==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@react-pdf-viewer/theme@3.12.0': resolution: {integrity: sha512-cdBi+wR1VOZ6URCcO9plmAZQu4ZGFcd7HJdBe7VIFiGyrvl9I/Of74ONLycnDImSuONt8D3uNjPBLieeaShVeg==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@react-pdf-viewer/thumbnail@3.12.0': resolution: {integrity: sha512-Vc8j3bO6wumWZV4o6pAbktPWKDSC9tQAzOCJ3cof541u4i44C11ccYC4W9aNcsMMUSO3bNwAGWtP8OFthV5akQ==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@react-pdf-viewer/toolbar@3.12.0': resolution: {integrity: sha512-qACTU3qXHgtNK8J+T13EWio+0liilj86SJ87BdapqXynhl720OKPlSKOQqskUGqg3oTUJAhrse9XG6SFdHJx+g==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@react-pdf-viewer/zoom@3.12.0': resolution: {integrity: sha512-V0GUTyPM77+LzhoKX+T3XI10/HfGdqRTbgeP7ID60FCzcwu6kXWqJn5tzabjDKLTlFv8mJmn0aa/ppkIU97nfA==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=16.8.0' + react-dom: '>=16.8.0' '@react-pdf/fns@3.1.3': resolution: {integrity: sha512-0I7pApDr1/RLAKbizuLy/IHTEa93LSPy/bEwYniboC3Xqnp6Od8xFJKbKEzGw2wh/5zKFFwl00g4t9RwgIMc3w==} @@ -2738,7 +2807,7 @@ packages: '@react-pdf/reconciler@2.0.0': resolution: {integrity: sha512-7zaPRujpbHSmCpIrZ+b9HSTJHthcVZzX0Wx7RzvQGsGBUbHP4p6s5itXrAIOuQuPvDepoHGNOvf6xUuMVvdoyw==} peerDependencies: - react: 18.3.1 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 '@react-pdf/render@4.5.1': resolution: {integrity: sha512-IW/N4HWJWtioBXCf7n02IR24VJJ8gbdS3jGypf+vW/rSErEx3/URRzh9UK6Ma8Fpog9+T/W6GE2NHJ5AAKHhVA==} @@ -2746,7 +2815,7 @@ packages: '@react-pdf/renderer@4.5.1': resolution: {integrity: sha512-5r1VQrE6FRLXX5wWUxwZzM24E2BJMo6g8AQWuS8WyPs9ugu5yMnb2g8/RpPYka/Z6J+RUEWc32wty2NoUJF42Q==} peerDependencies: - react: 18.3.1 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 '@react-pdf/stylesheet@6.2.1': resolution: {integrity: sha512-2+UEk+7e+z8baaWi2l5kPLWmwtJeOI+T5wW9GGeN3iDH7vd3kbTqOpN1yt9mmfNVZFxQsnDHpznFb5v5UF983A==} @@ -2763,7 +2832,7 @@ packages: '@reduxjs/toolkit@2.11.2': resolution: {integrity: sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==} peerDependencies: - react: 18.3.1 + react: ^16.9.0 || ^17.0.0 || ^18 || ^19 react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 peerDependenciesMeta: react: @@ -2812,66 +2881,79 @@ packages: resolution: {integrity: sha512-DV6fJoxEYWJOvaZIsok7KrYl0tPvga5OZ2yvKHNNYyk/2roMLqQAbGhr78EQ5YhHpnhLKJD3S1WFusAkmUuV5g==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.60.3': resolution: {integrity: sha512-mQKoJAzvuOs6F+TZybQO4GOTSMUu7v0WdxEk24krQ/uUxXoPTtHjuaUuPmFhtBcM4K0ons8nrE3JyhTuCFtT/w==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.60.3': resolution: {integrity: sha512-Whjj2qoiJ6+OOJMGptTYazaJvjOJm+iKHpXQM1P3LzGjt7Ff++Tp7nH4N8J/BUA7R9IHfDyx4DJIflifwnbmIA==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.60.3': resolution: {integrity: sha512-4YTNHKqGng5+yiZt3mg77nmyuCfmNfX4fPmyUapBcIk+BdwSwmCWGXOUxhXbBEkFHtoN5boLj/5NON+u5QC9tg==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.60.3': resolution: {integrity: sha512-SU3kNlhkpI4UqlUc2VXPGK9o886ZsSeGfMAX2ba2b8DKmMXq4AL7KUrkSWVbb7koVqx41Yczx6dx5PNargIrEA==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-loong64-musl@4.60.3': resolution: {integrity: sha512-6lDLl5h4TXpB1mTf2rQWnAk/LcXrx9vBfu/DT5TIPhvMhRWaZ5MxkIc8u4lJAmBo6klTe1ywXIUHFjylW505sg==} cpu: [loong64] os: [linux] + libc: [musl] '@rollup/rollup-linux-ppc64-gnu@4.60.3': resolution: {integrity: sha512-BMo8bOw8evlup/8G+cj5xWtPyp93xPdyoSN16Zy90Q2QZ0ZYRhCt6ZJSwbrRzG9HApFabjwj2p25TUPDWrhzqQ==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-musl@4.60.3': resolution: {integrity: sha512-E0L8X1dZN1/Rph+5VPF6Xj2G7JJvMACVXtamTJIDrVI44Y3K+G8gQaMEAavbqCGTa16InptiVrX6eM6pmJ+7qA==} cpu: [ppc64] os: [linux] + libc: [musl] '@rollup/rollup-linux-riscv64-gnu@4.60.3': resolution: {integrity: sha512-oZJ/WHaVfHUiRAtmTAeo3DcevNsVvH8mbvodjZy7D5QKvCefO371SiKRpxoDcCxB3PTRTLayWBkvmDQKTcX/sw==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.60.3': resolution: {integrity: sha512-Dhbyh7j9FybM3YaTgaHmVALwA8AkUwTPccyCQ79TG9AJUsMQqgN1DDEZNr4+QUfwiWvLDumW5vdwzoeUF+TNxQ==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.60.3': resolution: {integrity: sha512-cJd1X5XhHHlltkaypz1UcWLA8AcoIi1aWhsvaWDskD1oz2eKCypnqvTQ8ykMNI0RSmm7NkTdSqSSD7zM0xa6Ig==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.60.3': resolution: {integrity: sha512-DAZDBHQfG2oQuhY7mc6I3/qB4LU2fQCjRvxbDwd/Jdvb9fypP4IJ4qmtu6lNjes6B531AI8cg1aKC2di97bUxA==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.60.3': resolution: {integrity: sha512-cRxsE8c13mZOh3vP+wLDxpQBRrOHDIGOWyDL93Sy0Ga8y515fBcC2pjUfFwUe5T7tqvTvWbCpg1URM/AXdWIXA==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openbsd-x64@4.60.3': resolution: {integrity: sha512-QaWcIgRxqEdQdhJqW4DJctsH6HCmo5vHxY0krHSX4jMtOqfzC+dqDGuHM87bu4H8JBeibWx7jFz+h6/4C8wA5Q==} @@ -2952,7 +3034,7 @@ packages: '@tabler/icons-react@3.44.0': resolution: {integrity: sha512-8+rvzBbVm/1Z3sG3x7GUNAaxIKxwgz8xaMhRs23nrCnMTKRFAhEC+82zAIFeAA0seXdrAGX5HFCkaLpGK2rVHg==} peerDependencies: - react: 18.3.1 + react: '>= 16' '@tabler/icons@3.44.0': resolution: {integrity: sha512-Wn0AOZG9sg0L+bjfMqq4eNhC6pQjIrk94LvvWYNYkY8KH8wC3YILRzQlrnVJc4FUeMxH/AK97QsYCX35H3LndA==} @@ -2995,24 +3077,28 @@ packages: engines: {node: '>= 20'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.3.0': resolution: {integrity: sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.3.0': resolution: {integrity: sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==} engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.3.0': resolution: {integrity: sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==} engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.3.0': resolution: {integrity: sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==} @@ -3057,19 +3143,19 @@ packages: resolution: {integrity: sha512-zes0+o9ef5rAZXJ9f/SeaLs2nufJaeVkZkl/Or9NGrWVF41kL9Od9ED9nCwtQlgiF2VGtrzhEw5AU/igAO+aAg==} peerDependencies: '@tanstack/react-query': ^5.100.10 - react: 18.3.1 + react: ^18 || ^19 '@tanstack/react-query@5.100.10': resolution: {integrity: sha512-FLaZf2RCrA/Zgp4aiu5tG3TyasTRO7aZ99skxQpr3Hg/zXOhu6yq5FZCYQ/tRaJtM9ylnoK8tFK7PolXQadv6Q==} peerDependencies: - react: 18.3.1 + react: ^18 || ^19 '@tanstack/react-table@8.21.3': resolution: {integrity: sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==} engines: {node: '>=12'} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=16.8' + react-dom: '>=16.8' '@tanstack/table-core@8.21.3': resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==} @@ -3078,8 +3164,8 @@ packages: '@tinymce/tinymce-react@6.3.0': resolution: {integrity: sha512-E++xnn0XzDzpKr40jno2Kj7umfAE6XfINZULEBBeNjTMvbACWzA6CjiR6V8eTDc9yVmdVhIPqVzV4PqD5TZ/4g==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: ^19.0.0 || ^18.0.0 || ^17.0.1 || ^16.7.0 + react-dom: ^19.0.0 || ^18.0.0 || ^17.0.1 || ^16.7.0 tinymce: ^8.0.0 || ^7.0.0 || ^6.0.0 || ^5.5.1 peerDependenciesMeta: tinymce: @@ -3253,8 +3339,8 @@ packages: '@tiptap/pm': 3.23.1 '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 '@types/react-dom': ^17.0.0 || ^18.0.0 || ^19.0.0 - react: 18.3.1 - react-dom: 18.3.1 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 '@tiptap/starter-kit@3.23.1': resolution: {integrity: sha512-CURePHQagBaZIDJrHH3of4Nmi0VYGpZ6yBlkdFxFHBxY9aeG2/h5kn+oHo8GbzkSFsRV+9olzRgDTOULVgs8pQ==} @@ -3868,8 +3954,8 @@ packages: '@zag-js/react@1.40.0': resolution: {integrity: sha512-2TFS1HYABYGc0lurC+4WEXvKkpxsVv6vKm+t8QAL7wfoeZnw6HDQWLc91kINp89vln+A2kwCfYqIq8HSm+9EeA==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=18.0.0' + react-dom: '>=18.0.0' '@zag-js/rect-utils@1.40.0': resolution: {integrity: sha512-ikgLuE4rLlACm4mGLp6Ga8sJA44uFwohA1nVmb95sQ+VIyx2naf91CEF7SMrZVEwFKHaHpxdKVQSZLRjJqO/dw==} @@ -4700,10 +4786,6 @@ packages: caniuse-lite@1.0.30001792: resolution: {integrity: sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==} - canvas@2.11.2: - resolution: {integrity: sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==} - engines: {node: '>=6'} - canvg@3.0.11: resolution: {integrity: sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==} engines: {node: '>=10.0.0'} @@ -4847,8 +4929,8 @@ packages: cmdk@1.1.1: resolution: {integrity: sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: ^18 || ^19 || ^19.0.0-rc + react-dom: ^18 || ^19 || ^19.0.0-rc co@4.6.0: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} @@ -5201,8 +5283,8 @@ packages: date-fns-jalali@4.1.0-0: resolution: {integrity: sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==} - date-fns@3.6.0: - resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==} + date-fns@4.1.0: + resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} date.js@0.3.3: resolution: {integrity: sha512-HgigOS3h3k6HnW011nAb43c5xx5rBXk8P2v/WIT9Zv4koIaVXiH2BURguI78VVp+5Qc076T7OR378JViCnZtBw==} @@ -5257,10 +5339,6 @@ packages: resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} engines: {node: '>=0.10'} - decompress-response@4.2.1: - resolution: {integrity: sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==} - engines: {node: '>=8'} - dedent@1.7.2: resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} peerDependencies: @@ -5423,6 +5501,10 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} + dommatrix@1.0.3: + resolution: {integrity: sha512-l32Xp/TLgWb8ReqbVJAFIvXmY7go4nTxxlWiAFyhoQw9RKEOHBZNnyGvJWqDVSPmq3Y9HlM4npqF/T6VMOXhww==} + deprecated: dommatrix is no longer maintained. Please use @thednp/dommatrix. + dompurify@3.4.2: resolution: {integrity: sha512-lHeS9SA/IKeIFFyYciHBr2n0v1VMPlSj843HdLOwjb2OxNwdq9Xykxqhk+FE42MzAdHvInbAolSE4mhahPpjXA==} @@ -6070,8 +6152,8 @@ packages: resolution: {integrity: sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g==} peerDependencies: '@emotion/is-prop-valid': '*' - react: 18.3.1 - react-dom: 18.3.1 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@emotion/is-prop-valid': optional: true @@ -7316,24 +7398,28 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.32.0: resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.32.0: resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.32.0: resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.32.0: resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} @@ -7580,7 +7666,7 @@ packages: lucide-react@0.513.0: resolution: {integrity: sha512-CJZKq2g8Y8yN4Aq002GahSXbG2JpFv9kXwyiOAMvUBv7pxeOFHUWKB0mO7MiY4ZVFCV4aNjv2BJFq/z3DgKPQg==} peerDependencies: - react: 18.3.1 + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 luxon@3.7.2: resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==} @@ -7747,10 +7833,6 @@ packages: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} - mimic-response@2.1.0: - resolution: {integrity: sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==} - engines: {node: '>=8'} - minimalistic-assert@1.0.1: resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} @@ -7831,9 +7913,9 @@ packages: '@mui/icons-material': ^5.11.16 '@mui/material': ^5.13.3 '@mui/x-date-pickers': ^6.7.0 - date-fns: ^3.6.0 - react: 18.3.1 - react-dom: 18.3.1 + date-fns: ^2.30.0 + react: ^18.2.0 + react-dom: ^18.2.0 multer@2.1.1: resolution: {integrity: sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==} @@ -7892,8 +7974,8 @@ packages: next-themes@0.4.6: resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc next-tick@1.1.0: resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} @@ -8287,10 +8369,6 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - path2d-polyfill@2.0.1: - resolution: {integrity: sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==} - engines: {node: '>=8'} - path@0.12.7: resolution: {integrity: sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==} @@ -8308,9 +8386,17 @@ packages: resolution: {integrity: sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==} engines: {node: '>= 0.10'} - pdfjs-dist@3.11.174: - resolution: {integrity: sha512-TdTZPf1trZ8/UFu5Cx/GXB7GZM30LT+wWUNfsi6Bq8ePLnb+woNKtDymI2mxZYBpMbonNFqKmiz684DIfnd8dA==} - engines: {node: '>=18'} + pdfjs-dist@2.16.105: + resolution: {integrity: sha512-J4dn41spsAwUxCpEoVf6GVoz908IAA3mYiLmNxg8J9kfRXc2jxpbUepcP0ocp0alVNLFthTAM8DZ1RaHh8sU0A==} + peerDependencies: + worker-loader: ^3.0.8 + peerDependenciesMeta: + worker-loader: + optional: true + + pdfjs-dist@5.4.296: + resolution: {integrity: sha512-DlOzet0HO7OEnmUmB6wWGJrrdvbyJKftI1bhMitK7O2N8W2gc757yyYBbINy9IDafXAV9wmKr9t7xsTaNKRG5Q==} + engines: {node: '>=20.16.0 || >=22.3.0'} peek-readable@5.4.2: resolution: {integrity: sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg==} @@ -8651,48 +8737,58 @@ packages: react-cookie@8.1.2: resolution: {integrity: sha512-S45Z1y1dHyYfLEI4bFKQICuP+SwJqTPWbdc2ZpE6aQSdjSVJAjUDfwTPq8B7BWieIsgyyEWMb/QOrudtwJMjXA==} peerDependencies: - react: 18.3.1 + react: '>= 16.3.0' react-datepicker@8.10.0: resolution: {integrity: sha512-JIXuA+g+qP3c4MVJpx24o7n1gnv3WV/8A/D6964HucY1FlSEc30+ITPNUfbKZXYHl5rruCtxYCwi2lzn7gaz7g==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc react-day-picker@9.14.0: resolution: {integrity: sha512-tBaoDWjPwe0M5pGrum4H0SR6Lyk+BO9oHnp9JbKpGKW2mlraNPgP9BMfsg5pWpwrssARmeqk7YBl2oXutZTaHA==} engines: {node: '>=18'} peerDependencies: - react: 18.3.1 + react: '>=16.8.0' + + react-dom@16.14.0: + resolution: {integrity: sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==} + peerDependencies: + react: ^16.14.0 react-dom@18.3.1: resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} peerDependencies: - react: 18.3.1 + react: ^18.3.1 + + react-dom@19.2.6: + resolution: {integrity: sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==} + peerDependencies: + react: ^19.2.6 react-dropzone@14.4.1: resolution: {integrity: sha512-QDuV76v3uKbHiH34SpwifZ+gOLi1+RdsCO1kl5vxMT4wW8R82+sthjvBw4th3NHF/XX6FBsqDYZVNN+pnhaw0g==} engines: {node: '>= 10.13'} peerDependencies: - react: 18.3.1 + react: '>= 16.8 || 18.0.0' react-floater@0.7.9: resolution: {integrity: sha512-NXqyp9o8FAXOATOEo0ZpyaQ2KPb4cmPMXGWkx377QtJkIXHlHRAGer7ai0r0C1kG5gf+KJ6Gy+gdNIiosvSicg==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: 15 - 18 + react-dom: 15 - 18 react-hook-form@7.75.0: resolution: {integrity: sha512-Ovv94H+0p3sJ7B9B5QxPuCP1u8V/cHuVGyH55cSwodYDtoJwK+fqk3vjfIgSX59I2U/bU4z0nRJ9HMLpNiWEmw==} engines: {node: '>=18.0.0'} peerDependencies: - react: 18.3.1 + react: ^16.8.0 || ^17 || ^18 || ^19 react-i18next@15.7.4: resolution: {integrity: sha512-nyU8iKNrI5uDJch0z9+Y5XEr34b0wkyYj3Rp+tfbahxtlswxSCjcUL9H0nqXo9IR3/t5Y5PKIA3fx3MfUyR9Xw==} peerDependencies: i18next: '>= 23.4.0' - react: 18.3.1 + react: '>= 16.8.0' react-dom: '*' react-native: '*' typescript: ^5 @@ -8707,24 +8803,24 @@ packages: react-icons@5.6.0: resolution: {integrity: sha512-RH93p5ki6LfOiIt0UtDyNg/cee+HLVR6cHHtW3wALfo+eOHTp8RnU2kRkI6E+H19zMIs03DyxUG/GfZMOGvmiA==} peerDependencies: - react: 18.3.1 + react: '*' react-image-crop@11.0.10: resolution: {integrity: sha512-+5FfDXUgYLLqBh1Y/uQhIycpHCbXkI50a+nbfkB1C0xXXUTwkisHDo2QCB1SQJyHCqIuia4FeyReqXuMDKWQTQ==} peerDependencies: - react: 18.3.1 + react: '>=16.13.1' react-innertext@1.1.5: resolution: {integrity: sha512-PWAqdqhxhHIv80dT9znP2KvS+hfkbRovFp4zFYHFFlOoQLRiawIic81gKb3U1wEyJZgMwgs3JoLtwryASRWP3Q==} peerDependencies: '@types/react': '>=0.0.0 <=99' - react: 18.3.1 + react: '>=0.0.0 <=99' react-intersection-observer@9.16.0: resolution: {integrity: sha512-w9nJSEp+DrW9KmQmeWHQyfaP6b03v+TdXynaoA964Wxt7mdR3An11z4NNCQgL4gKSK7y1ver2Fq+JKH6CWEzUA==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: react-dom: optional: true @@ -8741,21 +8837,21 @@ packages: react-joyride@2.9.3: resolution: {integrity: sha512-1+Mg34XK5zaqJ63eeBhqdbk7dlGCFp36FXwsEvgpjqrtyywX2C6h9vr3jgxP0bGHCw8Ilsp/nRDzNVq6HJ3rNw==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: 15 - 18 + react-dom: 15 - 18 react-number-format@5.4.5: resolution: {integrity: sha512-y8O2yHHj3w0aE9XO8d2BCcUOOdQTRSVq+WIuMlLVucAm5XNjJAy+BoOJiuQMldVYVOKTMyvVNfnbl2Oqp+YxGw==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-pdf-html@2.1.5: resolution: {integrity: sha512-KhmiTUcnUNbLVdZbxMcV/+Rp+PyBt+eVJHu425eNwjSsDUtytvcwS/SBdBbbpM0c4+MnnOQBOs3AiColUesM8A==} engines: {node: '>=16.0.0'} peerDependencies: '@react-pdf/renderer': '>=3.4.4' - react: 18.3.1 + react: '>=16' react-pdf-viewer@0.1.0: resolution: {integrity: sha512-JO0bZEA6EMtljhTrLNyn9T03nIOXY6/tzK8guOdwfYpImdOpYfACy47G9AKXrVrtob9bEW2d1jR3MkC0NEGajw==} @@ -8764,8 +8860,8 @@ packages: resolution: {integrity: sha512-kS/35staVCBqS29verTQJQZXw7RfsRCPO3fdJoW1KXylcv7A9dw6DZ3vJXC2w+bIBgLw5FN4pOFvKSQtkQhPfA==} peerDependencies: '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@types/react': optional: true @@ -8774,7 +8870,7 @@ packages: resolution: {integrity: sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==} peerDependencies: '@types/react': ^18.2.25 || ^19 - react: 18.3.1 + react: ^18.0 || ^19 redux: ^5.0.0 peerDependenciesMeta: '@types/react': @@ -8791,7 +8887,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@types/react': optional: true @@ -8801,7 +8897,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -8809,35 +8905,35 @@ packages: react-resizable-panels@3.0.6: resolution: {integrity: sha512-b3qKHQ3MLqOgSS+FRYKapNkJZf5EQzuf6+RLiq1/IlTHw99YrZ2NJZLk4hQIzTnnIkRg2LUqyVinu6YWWpUYew==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc react-router-dom@6.30.3: resolution: {integrity: sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==} engines: {node: '>=14.0.0'} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=16.8' + react-dom: '>=16.8' react-router-dom@7.15.0: resolution: {integrity: sha512-VcrVg64Fo8nwBvDscajG8gRTLIuTC6N50nb22l2HOOV4PTOHgoGp8mUjy9wLiHYoYTSYI36tUnXZgasSRFZorQ==} engines: {node: '>=20.0.0'} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=18' + react-dom: '>=18' react-router@6.30.3: resolution: {integrity: sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==} engines: {node: '>=14.0.0'} peerDependencies: - react: 18.3.1 + react: '>=16.8' react-router@7.15.0: resolution: {integrity: sha512-HW9vYwuM8f4yx66Izy8xfrzCM+SBJluoZcCbww9A1TySax11S5Vgw6fi3ZjMONw9J4gQwngL7PzkyIpJJpJ7RQ==} engines: {node: '>=20.0.0'} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=18' + react-dom: '>=18' peerDependenciesMeta: react-dom: optional: true @@ -8848,8 +8944,8 @@ packages: '@types/prop-types': ^15.7.3 '@types/react': 0.14 - 19 prop-types: ^15.5.8 - react: 18.3.1 - react-dom: 18.3.1 + react: 0.14 - 19 + react-dom: 0.14 - 19 peerDependenciesMeta: '@types/prop-types': optional: true @@ -8861,7 +8957,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -8870,18 +8966,26 @@ packages: resolution: {integrity: sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A==} engines: {node: '>=10'} peerDependencies: - react: 18.3.1 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-transition-group@4.4.5: resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: '>=16.6.0' + react-dom: '>=16.6.0' + + react@16.14.0: + resolution: {integrity: sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==} + engines: {node: '>=0.10.0'} react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} + react@19.2.6: + resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} + engines: {node: '>=0.10.0'} + read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} @@ -8935,8 +9039,8 @@ packages: resolution: {integrity: sha512-mwzmO1s9sFL0TduUpwndxCUNoXsBw3u3E/0+A+cLcrSfQitSG62L32N69GhqUrrT5qKcAE3pCGVINC6pqkBBQg==} engines: {node: '>=18'} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-is: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 redent@1.0.0: @@ -9166,12 +9270,18 @@ packages: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} + scheduler@0.19.1: + resolution: {integrity: sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==} + scheduler@0.23.2: resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} scheduler@0.25.0-rc-603e6108-20241029: resolution: {integrity: sha512-pFwF6H1XrSdYYNLfOcGlM28/j8CGLu8IvdrxqhjWULe2bPcKiKW4CV+OWqR/9fT52mywx65l7ysNkjLKBda7eA==} + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + schema-utils@3.3.0: resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} engines: {node: '>= 10.13.0'} @@ -9311,12 +9421,6 @@ packages: signature_pad@2.3.2: resolution: {integrity: sha512-peYXLxOsIY6MES2TrRLDiNg2T++8gGbpP2yaC+6Ohtxr+a2dzoaqWosWDY9sWqTAAk6E/TyQO+LJw9zQwyu5kA==} - simple-concat@1.0.1: - resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} - - simple-get@3.1.1: - resolution: {integrity: sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==} - sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} @@ -9365,8 +9469,8 @@ packages: sonner@2.0.7: resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc source-list-map@2.0.1: resolution: {integrity: sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==} @@ -10247,7 +10351,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -10256,7 +10360,7 @@ packages: resolution: {integrity: sha512-djviaxuOOh7wkj0paeO1Q/4wMZ8Zrnag5H6yBvzN7AKKe8beOaED9SF5/ByLqsku8NP4zQqsvM2u3ew/tJK8/w==} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@types/react': optional: true @@ -10265,7 +10369,7 @@ packages: resolution: {integrity: sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@types/react': optional: true @@ -10274,7 +10378,7 @@ packages: resolution: {integrity: sha512-mhg3xdm9NaM8q+gLT8KryJPnRFOz1/5XPBhmDEVZK1webPzDjrPk7f/mbpeLqTgB9msytYWANxgALOCJKnLvcQ==} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: '@types/react': optional: true @@ -10284,7 +10388,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': '*' - react: 18.3.1 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true @@ -10292,7 +10396,7 @@ packages: use-sync-external-store@1.6.0: resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} peerDependencies: - react: 18.3.1 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 use@3.1.1: resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} @@ -10352,8 +10456,8 @@ packages: vaul@1.1.2: resolution: {integrity: sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==} peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 + react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc verror@1.10.0: resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} @@ -10473,6 +10577,10 @@ packages: web-encoding@1.1.5: resolution: {integrity: sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==} + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -10805,7 +10913,7 @@ packages: peerDependencies: '@types/react': '>=18.0.0' immer: '>=9.0.6' - react: 18.3.1 + react: '>=18.0.0' use-sync-external-store: '>=1.2.0' peerDependenciesMeta: '@types/react': @@ -10854,7 +10962,7 @@ snapshots: transitivePeerDependencies: - chokidar - '@ark-ui/react@5.36.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@ark-ui/react@5.36.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@internationalized/date': 3.12.0 '@zag-js/accordion': 1.40.0 @@ -10904,7 +11012,7 @@ snapshots: '@zag-js/qr-code': 1.40.0 '@zag-js/radio-group': 1.40.0 '@zag-js/rating-group': 1.40.0 - '@zag-js/react': 1.40.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@zag-js/react': 1.40.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@zag-js/scroll-area': 1.40.0 '@zag-js/select': 1.40.0 '@zag-js/signature-pad': 1.40.0 @@ -10923,8 +11031,8 @@ snapshots: '@zag-js/tree-view': 1.40.0 '@zag-js/types': 1.40.0 '@zag-js/utils': 1.40.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) '@asamuzakjp/css-color@3.2.0': dependencies: @@ -10955,7 +11063,7 @@ snapshots: '@babel/types': 7.29.0 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -11124,7 +11232,7 @@ snapshots: '@babel/parser': 7.29.3 '@babel/template': 7.28.6 '@babel/types': 7.29.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -11137,18 +11245,18 @@ snapshots: '@borewit/text-codec@0.2.2': {} - '@chakra-ui/react@3.35.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@chakra-ui/react@3.35.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@ark-ui/react': 5.36.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@ark-ui/react': 5.36.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@emotion/is-prop-valid': 1.4.0 - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@18.3.1) + '@emotion/react': 11.14.0(@types/react@18.3.28)(react@19.2.6) '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@18.3.1) + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.6) '@emotion/utils': 1.4.2 '@pandacss/is-valid-prop': 1.11.1 csstype: 3.2.3 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) '@colors/colors@1.5.0': optional: true @@ -11327,7 +11435,7 @@ snapshots: '@emotion/babel-plugin': 11.13.5 '@emotion/cache': 11.14.0 '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@18.3.1) + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.6) '@emotion/utils': 1.4.2 '@emotion/weak-memoize': 0.4.0 hoist-non-react-statics: 3.3.2 @@ -11337,6 +11445,22 @@ snapshots: transitivePeerDependencies: - supports-color + '@emotion/react@11.14.0(@types/react@18.3.28)(react@19.2.6)': + dependencies: + '@babel/runtime': 7.29.2 + '@emotion/babel-plugin': 11.13.5 + '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.6) + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + hoist-non-react-statics: 3.3.2 + react: 19.2.6 + optionalDependencies: + '@types/react': 18.3.28 + transitivePeerDependencies: + - supports-color + '@emotion/serialize@1.3.3': dependencies: '@emotion/hash': 0.9.2 @@ -11362,12 +11486,31 @@ snapshots: transitivePeerDependencies: - supports-color + '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@19.2.6)': + dependencies: + '@babel/runtime': 7.29.2 + '@emotion/babel-plugin': 11.13.5 + '@emotion/is-prop-valid': 1.4.0 + '@emotion/react': 11.14.0(@types/react@18.3.28)(react@19.2.6) + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.6) + '@emotion/utils': 1.4.2 + react: 19.2.6 + optionalDependencies: + '@types/react': 18.3.28 + transitivePeerDependencies: + - supports-color + '@emotion/unitless@0.10.0': {} '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@18.3.1)': dependencies: react: 18.3.1 + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.6)': + dependencies: + react: 19.2.6 + '@emotion/utils@1.4.2': {} '@emotion/weak-memoize@0.4.0': {} @@ -11451,7 +11594,7 @@ snapshots: '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.15.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) espree: 9.6.1 globals: 13.24.0 ignore: 5.3.2 @@ -11500,12 +11643,18 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@floating-ui/react@0.27.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@floating-ui/react-dom@2.1.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@floating-ui/react-dom': 2.1.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@floating-ui/dom': 1.7.6 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + + '@floating-ui/react@0.27.19(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@floating-ui/utils': 0.2.11 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) tabbable: 6.4.0 '@floating-ui/utils@0.2.11': {} @@ -11514,15 +11663,15 @@ snapshots: '@gilbarbara/deep-equal@0.3.1': {} - '@hookform/resolvers@5.2.2(react-hook-form@7.75.0(react@18.3.1))': + '@hookform/resolvers@5.2.2(react-hook-form@7.75.0(react@19.2.6))': dependencies: '@standard-schema/utils': 0.3.0 - react-hook-form: 7.75.0(react@18.3.1) + react-hook-form: 7.75.0(react@19.2.6) '@humanwhocodes/config-array@0.13.0': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) minimatch: 3.1.5 transitivePeerDependencies: - supports-color @@ -11891,39 +12040,39 @@ snapshots: '@leichtgewicht/ip-codec@2.0.5': {} - '@lottiefiles/react-lottie-player@3.6.0(react@18.3.1)': + '@lottiefiles/react-lottie-player@3.6.0(react@19.2.6)': dependencies: lottie-web: 5.13.0 - react: 18.3.1 + react: 19.2.6 '@lukeed/csprng@1.1.0': {} - '@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@19.2.6))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@floating-ui/react': 0.27.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mantine/hooks': 8.3.18(react@18.3.1) + '@floating-ui/react': 0.27.19(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@mantine/hooks': 8.3.18(react@19.2.6) clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-number-format: 5.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@18.3.1) - react-textarea-autosize: 8.5.9(@types/react@18.3.28)(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + react-number-format: 5.4.5(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@19.2.6) + react-textarea-autosize: 8.5.9(@types/react@18.3.28)(react@19.2.6) type-fest: 4.41.0 transitivePeerDependencies: - '@types/react' - '@mantine/dates@8.3.18(@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@8.3.18(react@18.3.1))(dayjs@1.11.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@mantine/dates@8.3.18(@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@19.2.6))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@8.3.18(react@19.2.6))(dayjs@1.11.20)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@mantine/core': 8.3.18(@mantine/hooks@8.3.18(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mantine/hooks': 8.3.18(react@18.3.1) + '@mantine/core': 8.3.18(@mantine/hooks@8.3.18(react@19.2.6))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@mantine/hooks': 8.3.18(react@19.2.6) clsx: 2.1.1 dayjs: 1.11.20 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) - '@mantine/hooks@8.3.18(react@18.3.1)': + '@mantine/hooks@8.3.18(react@19.2.6)': dependencies: - react: 18.3.1 + react: 19.2.6 '@mapbox/node-pre-gyp@1.0.11': dependencies: @@ -11985,8 +12134,8 @@ snapshots: react-is: 19.2.6 react-transition-group: 4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) optionalDependencies: - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@18.3.1) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) + '@emotion/react': 11.14.0(@types/react@18.3.28)(react@19.2.6) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@19.2.6) '@types/react': 18.3.28 '@mui/private-theming@5.17.1(@types/react@18.3.28)(react@18.3.1)': @@ -12007,8 +12156,8 @@ snapshots: prop-types: 15.8.1 react: 18.3.1 optionalDependencies: - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@18.3.1) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) + '@emotion/react': 11.14.0(@types/react@18.3.28)(react@19.2.6) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@19.2.6) '@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)': dependencies: @@ -12022,8 +12171,8 @@ snapshots: prop-types: 15.8.1 react: 18.3.1 optionalDependencies: - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@18.3.1) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) + '@emotion/react': 11.14.0(@types/react@18.3.28)(react@19.2.6) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@19.2.6) '@types/react': 18.3.28 '@mui/types@7.2.24(@types/react@18.3.28)': @@ -12054,7 +12203,30 @@ snapshots: optionalDependencies: '@types/react': 18.3.28 - '@mui/x-date-pickers@6.20.2(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(date-fns@3.6.0)(dayjs@1.11.20)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@mui/x-date-pickers@6.20.2(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(date-fns@4.1.0)(dayjs@1.11.20)(luxon@3.7.2)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.29.2 + '@mui/base': 5.0.0-beta.70(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/material': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/system': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) + '@mui/utils': 5.17.1(@types/react@18.3.28)(react@18.3.1) + '@types/react-transition-group': 4.4.12(@types/react@18.3.28) + clsx: 2.1.1 + prop-types: 15.8.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-transition-group: 4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + optionalDependencies: + '@emotion/react': 11.14.0(@types/react@18.3.28)(react@19.2.6) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@19.2.6) + date-fns: 4.1.0 + dayjs: 1.11.20 + luxon: 3.7.2 + moment: 2.30.1 + transitivePeerDependencies: + - '@types/react' + + '@mui/x-date-pickers@6.20.2(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(dayjs@1.11.20)(luxon@3.7.2)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.29.2 '@mui/base': 5.0.0-beta.70(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -12070,12 +12242,60 @@ snapshots: optionalDependencies: '@emotion/react': 11.14.0(@types/react@18.3.28)(react@18.3.1) '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) - date-fns: 3.6.0 dayjs: 1.11.20 + luxon: 3.7.2 moment: 2.30.1 transitivePeerDependencies: - '@types/react' + '@napi-rs/canvas-android-arm64@0.1.100': + optional: true + + '@napi-rs/canvas-darwin-arm64@0.1.100': + optional: true + + '@napi-rs/canvas-darwin-x64@0.1.100': + optional: true + + '@napi-rs/canvas-linux-arm-gnueabihf@0.1.100': + optional: true + + '@napi-rs/canvas-linux-arm64-gnu@0.1.100': + optional: true + + '@napi-rs/canvas-linux-arm64-musl@0.1.100': + optional: true + + '@napi-rs/canvas-linux-riscv64-gnu@0.1.100': + optional: true + + '@napi-rs/canvas-linux-x64-gnu@0.1.100': + optional: true + + '@napi-rs/canvas-linux-x64-musl@0.1.100': + optional: true + + '@napi-rs/canvas-win32-arm64-msvc@0.1.100': + optional: true + + '@napi-rs/canvas-win32-x64-msvc@0.1.100': + optional: true + + '@napi-rs/canvas@0.1.100': + optionalDependencies: + '@napi-rs/canvas-android-arm64': 0.1.100 + '@napi-rs/canvas-darwin-arm64': 0.1.100 + '@napi-rs/canvas-darwin-x64': 0.1.100 + '@napi-rs/canvas-linux-arm-gnueabihf': 0.1.100 + '@napi-rs/canvas-linux-arm64-gnu': 0.1.100 + '@napi-rs/canvas-linux-arm64-musl': 0.1.100 + '@napi-rs/canvas-linux-riscv64-gnu': 0.1.100 + '@napi-rs/canvas-linux-x64-gnu': 0.1.100 + '@napi-rs/canvas-linux-x64-musl': 0.1.100 + '@napi-rs/canvas-win32-arm64-msvc': 0.1.100 + '@napi-rs/canvas-win32-x64-msvc': 0.1.100 + optional: true + '@nestjs/axios@4.0.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.16.0)(rxjs@7.8.2)': dependencies: '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -12313,11 +12533,11 @@ snapshots: dependencies: consola: 3.4.2 - '@onlyoffice/document-editor-react@2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@onlyoffice/document-editor-react@2.1.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: lodash: 4.17.21 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) '@pandacss/is-valid-prop@1.11.1': {} @@ -12361,825 +12581,825 @@ snapshots: '@radix-ui/primitive@1.1.3': {} - '@radix-ui/react-accordion@1.2.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-accordion@1.2.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-arrow@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-arrow@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-avatar@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-avatar@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-context': 1.1.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-context': 1.1.3(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-checkbox@1.3.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-checkbox@1.3.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-collapsible@1.1.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-collapsible@1.1.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-collection@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-collection@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-compose-refs@1.1.2(@types/react@18.3.28)(react@18.3.1)': + '@radix-ui/react-compose-refs@1.1.2(@types/react@18.3.28)(react@19.2.6)': dependencies: - react: 18.3.1 + react: 19.2.6 optionalDependencies: '@types/react': 18.3.28 - '@radix-ui/react-context-menu@2.2.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-context-menu@2.2.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-context@1.1.2(@types/react@18.3.28)(react@18.3.1)': + '@radix-ui/react-context@1.1.2(@types/react@18.3.28)(react@19.2.6)': dependencies: - react: 18.3.1 + react: 19.2.6 optionalDependencies: '@types/react': 18.3.28 - '@radix-ui/react-context@1.1.3(@types/react@18.3.28)(react@18.3.1)': + '@radix-ui/react-context@1.1.3(@types/react@18.3.28)(react@19.2.6)': dependencies: - react: 18.3.1 + react: 19.2.6 optionalDependencies: '@types/react': 18.3.28 - '@radix-ui/react-dialog@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-dialog@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) aria-hidden: 1.2.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-direction@1.1.1(@types/react@18.3.28)(react@18.3.1)': + '@radix-ui/react-direction@1.1.1(@types/react@18.3.28)(react@19.2.6)': dependencies: - react: 18.3.1 + react: 19.2.6 optionalDependencies: '@types/react': 18.3.28 - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-focus-guards@1.1.3(@types/react@18.3.28)(react@18.3.1)': + '@radix-ui/react-focus-guards@1.1.3(@types/react@18.3.28)(react@19.2.6)': dependencies: - react: 18.3.1 + react: 19.2.6 optionalDependencies: '@types/react': 18.3.28 - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-hover-card@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-hover-card@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-id@1.1.1(@types/react@18.3.28)(react@18.3.1)': + '@radix-ui/react-id@1.1.1(@types/react@18.3.28)(react@19.2.6)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 optionalDependencies: '@types/react': 18.3.28 - '@radix-ui/react-label@2.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-label@2.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-menu@2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-menu@2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) aria-hidden: 1.2.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-navigation-menu@1.2.14(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-navigation-menu@1.2.14(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-popover@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-popover@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) aria-hidden: 1.2.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-popper@1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-popper@1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@floating-ui/react-dom': 2.1.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-rect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@18.3.1) + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-rect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@19.2.6) '@radix-ui/rect': 1.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-portal@1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-portal@1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-presence@1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-presence@1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-primitive@2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-primitive@2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-primitive@2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-primitive@2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-slot': 1.2.4(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-slot': 1.2.4(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-progress@1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-progress@1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-context': 1.1.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-context': 1.1.3(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-radio-group@1.3.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-radio-group@1.3.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/number': 1.1.1 '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-select@2.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-select@2.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/number': 1.1.1 '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) aria-hidden: 1.2.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-separator@1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-separator@1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-slider@1.3.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-slider@1.3.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/number': 1.1.1 '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-slot@1.2.3(@types/react@18.3.28)(react@18.3.1)': + '@radix-ui/react-slot@1.2.3(@types/react@18.3.28)(react@19.2.6)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 optionalDependencies: '@types/react': 18.3.28 - '@radix-ui/react-slot@1.2.4(@types/react@18.3.28)(react@18.3.1)': + '@radix-ui/react-slot@1.2.4(@types/react@18.3.28)(react@19.2.6)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 optionalDependencies: '@types/react': 18.3.28 - '@radix-ui/react-switch@1.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-switch@1.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-tabs@1.1.13(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-tabs@1.1.13(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-toast@1.2.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-toast@1.2.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-toggle-group@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-toggle-group@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-toggle': 1.1.10(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-toggle': 1.1.10(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-toggle@1.1.10(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-toggle@1.1.10(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-tooltip@1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-tooltip@1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@18.3.28)(react@18.3.1)': + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@18.3.28)(react@19.2.6)': dependencies: - react: 18.3.1 + react: 19.2.6 optionalDependencies: '@types/react': 18.3.28 - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@18.3.28)(react@18.3.1)': + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@18.3.28)(react@19.2.6)': dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 optionalDependencies: '@types/react': 18.3.28 - '@radix-ui/react-use-effect-event@0.0.2(@types/react@18.3.28)(react@18.3.1)': + '@radix-ui/react-use-effect-event@0.0.2(@types/react@18.3.28)(react@19.2.6)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 optionalDependencies: '@types/react': 18.3.28 - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@18.3.28)(react@18.3.1)': + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@18.3.28)(react@19.2.6)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 optionalDependencies: '@types/react': 18.3.28 - '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@18.3.28)(react@18.3.1)': + '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@18.3.28)(react@19.2.6)': dependencies: - react: 18.3.1 - use-sync-external-store: 1.6.0(react@18.3.1) + react: 19.2.6 + use-sync-external-store: 1.6.0(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@18.3.28)(react@18.3.1)': + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@18.3.28)(react@19.2.6)': dependencies: - react: 18.3.1 + react: 19.2.6 optionalDependencies: '@types/react': 18.3.28 - '@radix-ui/react-use-previous@1.1.1(@types/react@18.3.28)(react@18.3.1)': + '@radix-ui/react-use-previous@1.1.1(@types/react@18.3.28)(react@19.2.6)': dependencies: - react: 18.3.1 + react: 19.2.6 optionalDependencies: '@types/react': 18.3.28 - '@radix-ui/react-use-rect@1.1.1(@types/react@18.3.28)(react@18.3.1)': + '@radix-ui/react-use-rect@1.1.1(@types/react@18.3.28)(react@19.2.6)': dependencies: '@radix-ui/rect': 1.1.1 - react: 18.3.1 + react: 19.2.6 optionalDependencies: '@types/react': 18.3.28 - '@radix-ui/react-use-size@1.1.1(@types/react@18.3.28)(react@18.3.1)': + '@radix-ui/react-use-size@1.1.1(@types/react@18.3.28)(react@19.2.6)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + react: 19.2.6 optionalDependencies: '@types/react': 18.3.28 - '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 '@types/react-dom': 18.3.7(@types/react@18.3.28) '@radix-ui/rect@1.1.1': {} - '@react-pdf-viewer/attachment@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@react-pdf-viewer/attachment@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - pdfjs-dist - '@react-pdf-viewer/bookmark@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@react-pdf-viewer/bookmark@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - pdfjs-dist - '@react-pdf-viewer/core@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@react-pdf-viewer/core@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - pdfjs-dist: 3.11.174 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + pdfjs-dist: 5.4.296 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) - '@react-pdf-viewer/default-layout@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@react-pdf-viewer/default-layout@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@react-pdf-viewer/attachment': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/bookmark': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/thumbnail': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/toolbar': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@react-pdf-viewer/attachment': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/bookmark': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/thumbnail': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/toolbar': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - pdfjs-dist - '@react-pdf-viewer/full-screen@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@react-pdf-viewer/full-screen@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - pdfjs-dist - '@react-pdf-viewer/get-file@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@react-pdf-viewer/get-file@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - pdfjs-dist - '@react-pdf-viewer/open@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@react-pdf-viewer/open@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - pdfjs-dist - '@react-pdf-viewer/page-navigation@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@react-pdf-viewer/page-navigation@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - pdfjs-dist - '@react-pdf-viewer/print@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@react-pdf-viewer/print@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - pdfjs-dist - '@react-pdf-viewer/properties@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@react-pdf-viewer/properties@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - pdfjs-dist - '@react-pdf-viewer/rotate@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@react-pdf-viewer/rotate@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - pdfjs-dist - '@react-pdf-viewer/scroll-mode@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@react-pdf-viewer/scroll-mode@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - pdfjs-dist - '@react-pdf-viewer/search@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@react-pdf-viewer/search@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - pdfjs-dist - '@react-pdf-viewer/selection-mode@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@react-pdf-viewer/selection-mode@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - pdfjs-dist - '@react-pdf-viewer/theme@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@react-pdf-viewer/theme@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - pdfjs-dist - '@react-pdf-viewer/thumbnail@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@react-pdf-viewer/thumbnail@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - pdfjs-dist - '@react-pdf-viewer/toolbar@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@react-pdf-viewer/toolbar@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/full-screen': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/get-file': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/open': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/page-navigation': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/print': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/properties': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/rotate': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/scroll-mode': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/search': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/selection-mode': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/theme': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/zoom': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/full-screen': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/get-file': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/open': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/page-navigation': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/print': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/properties': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/rotate': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/scroll-mode': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/search': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/selection-mode': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/theme': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/zoom': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - pdfjs-dist - '@react-pdf-viewer/zoom@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@react-pdf-viewer/zoom@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - pdfjs-dist @@ -13225,10 +13445,10 @@ snapshots: '@react-pdf/primitives@4.3.0': {} - '@react-pdf/reconciler@2.0.0(react@18.3.1)': + '@react-pdf/reconciler@2.0.0(react@19.2.6)': dependencies: object-assign: 4.1.1 - react: 18.3.1 + react: 19.2.6 scheduler: 0.25.0-rc-603e6108-20241029 '@react-pdf/render@4.5.1': @@ -13244,7 +13464,7 @@ snapshots: parse-svg-path: 0.1.2 svg-arc-to-cubic-bezier: 3.2.0 - '@react-pdf/renderer@4.5.1(react@18.3.1)': + '@react-pdf/renderer@4.5.1(react@19.2.6)': dependencies: '@babel/runtime': 7.29.2 '@react-pdf/fns': 3.1.3 @@ -13252,14 +13472,14 @@ snapshots: '@react-pdf/layout': 4.6.1 '@react-pdf/pdfkit': 5.1.1 '@react-pdf/primitives': 4.3.0 - '@react-pdf/reconciler': 2.0.0(react@18.3.1) + '@react-pdf/reconciler': 2.0.0(react@19.2.6) '@react-pdf/render': 4.5.1 '@react-pdf/types': 2.11.1 events: 3.3.0 object-assign: 4.1.1 prop-types: 15.8.1 queue: 6.0.2 - react: 18.3.1 + react: 19.2.6 '@react-pdf/stylesheet@6.2.1': dependencies: @@ -13287,7 +13507,7 @@ snapshots: '@react-pdf/primitives': 4.3.0 '@react-pdf/stylesheet': 6.2.1 - '@reduxjs/toolkit@2.11.2(react-redux@9.2.0(@types/react@18.3.28)(react@18.3.1)(redux@5.0.1))(react@18.3.1)': + '@reduxjs/toolkit@2.11.2(react-redux@9.2.0(@types/react@18.3.28)(react@19.2.6)(redux@5.0.1))(react@19.2.6)': dependencies: '@standard-schema/spec': 1.1.0 '@standard-schema/utils': 0.3.0 @@ -13296,8 +13516,8 @@ snapshots: redux-thunk: 3.1.0(redux@5.0.1) reselect: 5.1.1 optionalDependencies: - react: 18.3.1 - react-redux: 9.2.0(@types/react@18.3.28)(react@18.3.1)(redux@5.0.1) + react: 19.2.6 + react-redux: 9.2.0(@types/react@18.3.28)(react@19.2.6)(redux@5.0.1) '@remix-run/router@1.23.2': {} @@ -13424,10 +13644,10 @@ snapshots: '@tabby_ai/hijri-converter@1.0.5': {} - '@tabler/icons-react@3.44.0(react@18.3.1)': + '@tabler/icons-react@3.44.0(react@19.2.6)': dependencies: '@tabler/icons': 3.44.0 - react: 18.3.1 + react: 19.2.6 '@tabler/icons@3.44.0': {} @@ -13503,30 +13723,35 @@ snapshots: '@tanstack/query-devtools@5.100.10': {} - '@tanstack/react-query-devtools@5.100.10(@tanstack/react-query@5.100.10(react@18.3.1))(react@18.3.1)': + '@tanstack/react-query-devtools@5.100.10(@tanstack/react-query@5.100.10(react@18.3.1))(react@19.2.6)': dependencies: '@tanstack/query-devtools': 5.100.10 '@tanstack/react-query': 5.100.10(react@18.3.1) - react: 18.3.1 + react: 19.2.6 '@tanstack/react-query@5.100.10(react@18.3.1)': dependencies: '@tanstack/query-core': 5.100.10 react: 18.3.1 - '@tanstack/react-table@8.21.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@tanstack/react-query@5.100.10(react@19.2.6)': + dependencies: + '@tanstack/query-core': 5.100.10 + react: 19.2.6 + + '@tanstack/react-table@8.21.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@tanstack/table-core': 8.21.3 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) '@tanstack/table-core@8.21.3': {} - '@tinymce/tinymce-react@6.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tinymce@7.9.2)': + '@tinymce/tinymce-react@6.3.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tinymce@7.9.2)': dependencies: prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: tinymce: 7.9.2 @@ -13677,7 +13902,7 @@ snapshots: prosemirror-transform: 1.12.0 prosemirror-view: 1.41.8 - '@tiptap/react@3.23.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@tiptap/react@3.23.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) '@tiptap/pm': 3.23.1 @@ -13685,9 +13910,9 @@ snapshots: '@types/react-dom': 18.3.7(@types/react@18.3.28) '@types/use-sync-external-store': 0.0.6 fast-equals: 5.4.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - use-sync-external-store: 1.6.0(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + use-sync-external-store: 1.6.0(react@19.2.6) optionalDependencies: '@tiptap/extension-bubble-menu': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) '@tiptap/extension-floating-menu': 3.23.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) @@ -13723,14 +13948,14 @@ snapshots: '@tokenizer/inflate@0.4.1': dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) token-types: 6.1.2 transitivePeerDependencies: - supports-color '@tokenizer/token@0.3.0': {} - '@tria-plc/api-common@0.1.4(dlk6rffkpcjlebt3tne6hjqwx4)': + '@tria-plc/api-common@0.1.4(42b11c4715772d7b83dab2dbc0ea2324)': dependencies: '@nestjs/axios': 4.0.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.16.0)(rxjs@7.8.2) '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -13741,7 +13966,7 @@ snapshots: '@nestjs/swagger': 11.4.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) '@nestjs/throttler': 6.5.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2) '@nestjs/typeorm': 11.0.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))) - '@tria-plc/iamapi-common': 0.1.6(nhzmwbpvzw5m5dv4mcbu7ilapi) + '@tria-plc/iamapi-common': 0.1.6(7eaf302065296f503c6ce1ae1c9ee51c) argon2: 0.43.1 axios: 1.16.0 change-case: 5.4.4 @@ -13774,7 +13999,7 @@ snapshots: - debug - supports-color - '@tria-plc/iamapi-common@0.1.6(nhzmwbpvzw5m5dv4mcbu7ilapi)': + '@tria-plc/iamapi-common@0.1.6(7eaf302065296f503c6ce1ae1c9ee51c)': dependencies: '@nestjs/axios': 4.0.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.16.0)(rxjs@7.8.2) '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -13785,7 +14010,7 @@ snapshots: '@nestjs/swagger': 11.4.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) '@nestjs/throttler': 6.5.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2) '@nestjs/typeorm': 11.0.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))) - '@tria-plc/api-common': 0.1.4(dlk6rffkpcjlebt3tne6hjqwx4) + '@tria-plc/api-common': 0.1.4(42b11c4715772d7b83dab2dbc0ea2324) argon2: 0.43.1 axios: 1.16.0 class-transformer: 0.5.1 @@ -13807,51 +14032,51 @@ snapshots: - '@faker-js/faker' - supports-color - '@tria-plc/iamui-common@1.0.3(iv2eyyfavqphryq7oznx6tfwre)': + '@tria-plc/iamui-common@1.0.3(9c106f46deace9660b1e6a7145f91ebf)': dependencies: - '@chakra-ui/react': 3.35.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@18.3.1) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) - '@hookform/resolvers': 5.2.2(react-hook-form@7.75.0(react@18.3.1)) - '@lottiefiles/react-lottie-player': 3.6.0(react@18.3.1) - '@mantine/core': 8.3.18(@mantine/hooks@8.3.18(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mantine/dates': 8.3.18(@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@8.3.18(react@18.3.1))(dayjs@1.11.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mantine/hooks': 8.3.18(react@18.3.1) - '@onlyoffice/document-editor-react': 2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-accordion': 1.2.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-alert-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-avatar': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-checkbox': 1.3.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-context-menu': 2.2.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-hover-card': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-label': 2.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-popover': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-progress': 1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-radio-group': 1.3.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-scroll-area': 1.2.10(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-select': 2.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-separator': 1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slider': 1.3.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.4(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-switch': 1.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-tabs': 1.1.13(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-toast': 1.2.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-tooltip': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/default-layout': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf/renderer': 4.5.1(react@18.3.1) - '@reduxjs/toolkit': 2.11.2(react-redux@9.2.0(@types/react@18.3.28)(react@18.3.1)(redux@5.0.1))(react@18.3.1) - '@tabler/icons-react': 3.44.0(react@18.3.1) + '@chakra-ui/react': 3.35.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@emotion/react': 11.14.0(@types/react@18.3.28)(react@19.2.6) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@19.2.6) + '@hookform/resolvers': 5.2.2(react-hook-form@7.75.0(react@19.2.6)) + '@lottiefiles/react-lottie-player': 3.6.0(react@19.2.6) + '@mantine/core': 8.3.18(@mantine/hooks@8.3.18(react@19.2.6))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@mantine/dates': 8.3.18(@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@19.2.6))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@8.3.18(react@19.2.6))(dayjs@1.11.20)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@mantine/hooks': 8.3.18(react@19.2.6) + '@onlyoffice/document-editor-react': 2.1.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-accordion': 1.2.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-alert-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-avatar': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-checkbox': 1.3.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-context-menu': 2.2.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-hover-card': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-label': 2.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-popover': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-progress': 1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-radio-group': 1.3.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-scroll-area': 1.2.10(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-select': 2.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-separator': 1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slider': 1.3.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.4(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-switch': 1.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-tabs': 1.1.13(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-toast': 1.2.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-tooltip': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/default-layout': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf/renderer': 4.5.1(react@19.2.6) + '@reduxjs/toolkit': 2.11.2(react-redux@9.2.0(@types/react@18.3.28)(react@19.2.6)(redux@5.0.1))(react@19.2.6) + '@tabler/icons-react': 3.44.0(react@19.2.6) '@tailwindcss/vite': 4.3.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1)) - '@tanstack/react-query': 5.100.10(react@18.3.1) - '@tanstack/react-query-devtools': 5.100.10(@tanstack/react-query@5.100.10(react@18.3.1))(react@18.3.1) - '@tanstack/react-table': 8.21.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@tinymce/tinymce-react': 6.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tinymce@7.9.2) + '@tanstack/react-query': 5.100.10(react@19.2.6) + '@tanstack/react-query-devtools': 5.100.10(@tanstack/react-query@5.100.10(react@18.3.1))(react@19.2.6) + '@tanstack/react-table': 8.21.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@tinymce/tinymce-react': 6.3.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tinymce@7.9.2) '@tiptap/extension-color': 3.23.1(@tiptap/extension-text-style@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))) '@tiptap/extension-highlight': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) '@tiptap/extension-image': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) @@ -13859,21 +14084,21 @@ snapshots: '@tiptap/extension-text-align': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) '@tiptap/extension-text-style': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) '@tiptap/extension-underline': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/react': 3.23.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@tiptap/react': 3.23.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@tiptap/starter-kit': 3.23.1 '@types/node': 24.12.4 '@types/tinymce': 4.6.9 axios: 1.16.0 class-variance-authority: 0.7.1 clsx: 2.1.1 - cmdk: 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - date-fns: 3.6.0 + cmdk: 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + date-fns: 4.1.0 dayjs: 1.11.20 ethiopian-calendar-date-converter: 2.1.6 ethiopian-calendar-new: 1.1.0 file-type: 18.7.0 force: 0.0.3 - framer-motion: 12.38.0(@emotion/is-prop-valid@1.4.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + framer-motion: 12.38.0(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) html2canvas: 1.4.1 i18next: 25.10.10(typescript@5.9.3) i18next-browser-languagedetector: 8.2.1 @@ -13882,34 +14107,34 @@ snapshots: jspdf: 3.0.4 loadash: 1.0.0 lodash: 4.18.1 - lucide-react: 0.513.0(react@18.3.1) - mui-ethiopian-datepicker: 0.3.2(hjxdxgubdlhng5uhyvidfkiyo4) - next-themes: 0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + lucide-react: 0.513.0(react@19.2.6) + mui-ethiopian-datepicker: 0.3.2(bb2b0a350b39c049005e46c2e15483da) + next-themes: 0.4.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) path: 0.12.7 qs: 6.15.1 - react: 18.3.1 - react-cookie: 8.1.2(@types/react@18.3.28)(react@18.3.1) - react-datepicker: 8.10.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-day-picker: 9.14.0(react@18.3.1) - react-dom: 18.3.1(react@18.3.1) - react-dropzone: 14.4.1(react@18.3.1) - react-hook-form: 7.75.0(react@18.3.1) - react-i18next: 15.7.4(i18next@25.10.10(typescript@5.9.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3) - react-icons: 5.6.0(react@18.3.1) - react-image-crop: 11.0.10(react@18.3.1) - react-intersection-observer: 9.16.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 19.2.6 + react-cookie: 8.1.2(@types/react@18.3.28)(react@19.2.6) + react-datepicker: 8.10.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-day-picker: 9.14.0(react@19.2.6) + react-dom: 19.2.6(react@19.2.6) + react-dropzone: 14.4.1(react@19.2.6) + react-hook-form: 7.75.0(react@19.2.6) + react-i18next: 15.7.4(i18next@25.10.10(typescript@5.9.3))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(typescript@5.9.3) + react-icons: 5.6.0(react@19.2.6) + react-image-crop: 11.0.10(react@19.2.6) + react-intersection-observer: 9.16.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react-is: 19.2.6 - react-joyride: 2.9.3(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-pdf: 10.4.1(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-pdf-html: 2.1.5(@react-pdf/renderer@4.5.1(react@18.3.1))(react@18.3.1) + react-joyride: 2.9.3(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-pdf: 10.4.1(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-pdf-html: 2.1.5(@react-pdf/renderer@4.5.1(react@18.3.1))(react@19.2.6) react-pdf-viewer: 0.1.0 - react-redux: 9.2.0(@types/react@18.3.28)(react@18.3.1)(redux@5.0.1) - react-resizable-panels: 3.0.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-router-dom: 7.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-signature-canvas: 1.1.0-alpha.2(@types/prop-types@15.7.15)(@types/react@18.3.28)(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - recharts: 3.8.1(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react-is@19.2.6)(react@18.3.1)(redux@5.0.1) + react-redux: 9.2.0(@types/react@18.3.28)(react@19.2.6)(redux@5.0.1) + react-resizable-panels: 3.0.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-router-dom: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-signature-canvas: 1.1.0-alpha.2(@types/prop-types@15.7.15)(@types/react@18.3.28)(prop-types@15.8.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + recharts: 3.8.1(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react-is@19.2.6)(react@19.2.6)(redux@5.0.1) socket.io-client: 4.8.3 - sonner: 2.0.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + sonner: 2.0.7(react-dom@19.2.6(react@19.2.6))(react@19.2.6) tailwind-merge: 3.6.0 tailwind-scrollbar-hide: 4.0.0(tailwindcss@4.3.0) tailwindcss: 4.3.0 @@ -13917,7 +14142,7 @@ snapshots: tesseract.js: 7.0.0 tinymce: 7.9.2 url: 0.11.4 - vaul: 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + vaul: 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) xlsx: 0.18.5 zod: 3.25.76 transitivePeerDependencies: @@ -13944,6 +14169,146 @@ snapshots: - vite - webpack-cli - webpack-command + - worker-loader + + '@tria-plc/iamui-common@1.0.3(b753628ac65312d9adb4ccd0069fe702)': + dependencies: + '@chakra-ui/react': 3.35.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@emotion/react': 11.14.0(@types/react@18.3.28)(react@19.2.6) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@19.2.6) + '@hookform/resolvers': 5.2.2(react-hook-form@7.75.0(react@19.2.6)) + '@lottiefiles/react-lottie-player': 3.6.0(react@19.2.6) + '@mantine/core': 8.3.18(@mantine/hooks@8.3.18(react@19.2.6))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@mantine/dates': 8.3.18(@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@19.2.6))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@8.3.18(react@19.2.6))(dayjs@1.11.20)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@mantine/hooks': 8.3.18(react@19.2.6) + '@onlyoffice/document-editor-react': 2.1.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-accordion': 1.2.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-alert-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-avatar': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-checkbox': 1.3.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-context-menu': 2.2.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-hover-card': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-label': 2.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-popover': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-progress': 1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-radio-group': 1.3.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-scroll-area': 1.2.10(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-select': 2.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-separator': 1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slider': 1.3.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.4(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-switch': 1.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-tabs': 1.1.13(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-toast': 1.2.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-tooltip': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf-viewer/default-layout': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@react-pdf/renderer': 4.5.1(react@19.2.6) + '@reduxjs/toolkit': 2.11.2(react-redux@9.2.0(@types/react@18.3.28)(react@19.2.6)(redux@5.0.1))(react@19.2.6) + '@tabler/icons-react': 3.44.0(react@19.2.6) + '@tailwindcss/vite': 4.3.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1)) + '@tanstack/react-query': 5.100.10(react@19.2.6) + '@tanstack/react-query-devtools': 5.100.10(@tanstack/react-query@5.100.10(react@18.3.1))(react@19.2.6) + '@tanstack/react-table': 8.21.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@tinymce/tinymce-react': 6.3.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tinymce@7.9.2) + '@tiptap/extension-color': 3.23.1(@tiptap/extension-text-style@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))) + '@tiptap/extension-highlight': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) + '@tiptap/extension-image': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) + '@tiptap/extension-link': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) + '@tiptap/extension-text-align': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) + '@tiptap/extension-text-style': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) + '@tiptap/extension-underline': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) + '@tiptap/react': 3.23.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@tiptap/starter-kit': 3.23.1 + '@types/node': 24.12.4 + '@types/tinymce': 4.6.9 + axios: 1.16.0 + class-variance-authority: 0.7.1 + clsx: 2.1.1 + cmdk: 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + date-fns: 4.1.0 + dayjs: 1.11.20 + ethiopian-calendar-date-converter: 2.1.6 + ethiopian-calendar-new: 1.1.0 + file-type: 18.7.0 + force: 0.0.3 + framer-motion: 12.38.0(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + html2canvas: 1.4.1 + i18next: 25.10.10(typescript@5.9.3) + i18next-browser-languagedetector: 8.2.1 + jquery: 3.7.1 + js-cookie: 3.0.5 + jspdf: 3.0.4 + loadash: 1.0.0 + lodash: 4.18.1 + lucide-react: 0.513.0(react@19.2.6) + mui-ethiopian-datepicker: 0.3.2(c914a98daf8e04e98459e8e367258069) + next-themes: 0.4.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + path: 0.12.7 + qs: 6.15.1 + react: 19.2.6 + react-cookie: 8.1.2(@types/react@18.3.28)(react@19.2.6) + react-datepicker: 8.10.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-day-picker: 9.14.0(react@19.2.6) + react-dom: 19.2.6(react@19.2.6) + react-dropzone: 14.4.1(react@19.2.6) + react-hook-form: 7.75.0(react@19.2.6) + react-i18next: 15.7.4(i18next@25.10.10(typescript@5.9.3))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(typescript@5.9.3) + react-icons: 5.6.0(react@19.2.6) + react-image-crop: 11.0.10(react@19.2.6) + react-intersection-observer: 9.16.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-is: 19.2.6 + react-joyride: 2.9.3(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-pdf: 10.4.1(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-pdf-html: 2.1.5(@react-pdf/renderer@4.5.1(react@18.3.1))(react@19.2.6) + react-pdf-viewer: 0.1.0 + react-redux: 9.2.0(@types/react@18.3.28)(react@19.2.6)(redux@5.0.1) + react-resizable-panels: 3.0.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-router-dom: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-signature-canvas: 1.1.0-alpha.2(@types/prop-types@15.7.15)(@types/react@18.3.28)(prop-types@15.8.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + recharts: 3.8.1(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react-is@19.2.6)(react@19.2.6)(redux@5.0.1) + socket.io-client: 4.8.3 + sonner: 2.0.7(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + tailwind-merge: 3.6.0 + tailwind-scrollbar-hide: 4.0.0(tailwindcss@4.3.0) + tailwindcss: 4.3.0 + tailwindcss-animate: 1.0.7(tailwindcss@4.3.0) + tesseract.js: 7.0.0 + tinymce: 7.9.2 + url: 0.11.4 + vaul: 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + xlsx: 0.18.5 + zod: 3.25.76 + transitivePeerDependencies: + - '@emotion/is-prop-valid' + - '@floating-ui/dom' + - '@mui/icons-material' + - '@mui/material' + - '@mui/x-date-pickers' + - '@tiptap/core' + - '@tiptap/pm' + - '@types/prop-types' + - '@types/react' + - '@types/react-dom' + - bufferutil + - debug + - encoding + - pdfjs-dist + - prop-types + - react-native + - redux + - supports-color + - typescript + - utf-8-validate + - vite + - webpack-cli + - webpack-command + - worker-loader '@tsconfig/node10@1.0.12': {} @@ -14227,7 +14592,7 @@ snapshots: '@typescript-eslint/types': 8.59.3 '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.59.3 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) eslint: 8.57.1 typescript: 5.9.3 transitivePeerDependencies: @@ -14237,7 +14602,7 @@ snapshots: dependencies: '@typescript-eslint/tsconfig-utils': 8.59.3(typescript@5.9.3) '@typescript-eslint/types': 8.59.3 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -14256,7 +14621,7 @@ snapshots: '@typescript-eslint/types': 8.59.3 '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) '@typescript-eslint/utils': 8.59.3(eslint@8.57.1)(typescript@5.9.3) - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) eslint: 8.57.1 ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 @@ -14271,7 +14636,7 @@ snapshots: '@typescript-eslint/tsconfig-utils': 8.59.3(typescript@5.9.3) '@typescript-eslint/types': 8.59.3 '@typescript-eslint/visitor-keys': 8.59.3 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) minimatch: 10.2.5 semver: 7.8.0 tinyglobby: 0.2.16 @@ -14823,14 +15188,14 @@ snapshots: '@zag-js/types': 1.40.0 '@zag-js/utils': 1.40.0 - '@zag-js/react@1.40.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@zag-js/react@1.40.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@zag-js/core': 1.40.0 '@zag-js/store': 1.40.0 '@zag-js/types': 1.40.0 '@zag-js/utils': 1.40.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) '@zag-js/rect-utils@1.40.0': {} @@ -15049,7 +15414,7 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -15515,7 +15880,7 @@ snapshots: axios@1.16.0: dependencies: - follow-redirects: 1.16.0 + follow-redirects: 1.16.0(debug@3.2.7(supports-color@5.5.0)) form-data: 4.0.5 proxy-from-env: 2.1.0 transitivePeerDependencies: @@ -15679,7 +16044,7 @@ snapshots: dependencies: bytes: 3.1.2 content-type: 1.0.5 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) http-errors: 2.0.1 iconv-lite: 0.7.2 on-finished: 2.4.1 @@ -15721,7 +16086,7 @@ snapshots: fill-range: 4.0.0 isobject: 3.0.1 repeat-element: 1.1.4 - snapdragon: 0.8.2 + snapdragon: 0.8.2(supports-color@5.5.0) snapdragon-node: 2.1.1 split-string: 3.1.0 to-regex: 3.0.2 @@ -15923,16 +16288,6 @@ snapshots: caniuse-lite@1.0.30001792: {} - canvas@2.11.2: - dependencies: - '@mapbox/node-pre-gyp': 1.0.11 - nan: 2.26.2 - simple-get: 3.1.1 - transitivePeerDependencies: - - encoding - - supports-color - optional: true - canvg@3.0.11: dependencies: '@babel/runtime': 7.29.2 @@ -16129,14 +16484,14 @@ snapshots: clsx@2.1.1: {} - cmdk@1.1.1(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + cmdk@1.1.1(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - '@types/react' - '@types/react-dom' @@ -16513,7 +16868,7 @@ snapshots: date-fns-jalali@4.1.0-0: {} - date-fns@3.6.0: {} + date-fns@4.1.0: {} date.js@0.3.3: dependencies: @@ -16540,20 +16895,12 @@ snapshots: dependencies: ms: 2.0.0 - debug@3.2.7: - dependencies: - ms: 2.1.3 - debug@3.2.7(supports-color@5.5.0): dependencies: ms: 2.1.3 optionalDependencies: supports-color: 5.5.0 - debug@4.4.3: - dependencies: - ms: 2.1.3 - debug@4.4.3(supports-color@5.5.0): dependencies: ms: 2.1.3 @@ -16568,11 +16915,6 @@ snapshots: decode-uri-component@0.2.2: {} - decompress-response@4.2.1: - dependencies: - mimic-response: 2.1.0 - optional: true - dedent@1.7.2(babel-plugin-macros@3.1.0): optionalDependencies: babel-plugin-macros: 3.1.0 @@ -16723,6 +17065,8 @@ snapshots: dependencies: domelementtype: 2.3.0 + dommatrix@1.0.3: {} + dompurify@3.4.2: optionalDependencies: '@types/trusted-types': 2.0.7 @@ -17057,7 +17401,7 @@ snapshots: eslint-import-resolver-node@0.3.10: dependencies: - debug: 3.2.7 + debug: 3.2.7(supports-color@5.5.0) is-core-module: 2.16.2 resolve: 2.0.0-next.6 transitivePeerDependencies: @@ -17065,7 +17409,7 @@ snapshots: eslint-module-utils@2.12.1(@typescript-eslint/parser@8.59.3(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint@8.57.1): dependencies: - debug: 3.2.7 + debug: 3.2.7(supports-color@5.5.0) optionalDependencies: '@typescript-eslint/parser': 8.59.3(eslint@8.57.1)(typescript@5.9.3) eslint: 8.57.1 @@ -17080,7 +17424,7 @@ snapshots: array.prototype.findlastindex: 1.2.6 array.prototype.flat: 1.3.3 array.prototype.flatmap: 1.3.3 - debug: 3.2.7 + debug: 3.2.7(supports-color@5.5.0) doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.10 @@ -17159,7 +17503,7 @@ snapshots: ajv: 6.15.0 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -17309,7 +17653,7 @@ snapshots: extend-shallow: 2.0.1 posix-character-classes: 0.1.1 regex-not: 1.0.2 - snapdragon: 0.8.2 + snapdragon: 0.8.2(supports-color@5.5.0) to-regex: 3.0.2 transitivePeerDependencies: - supports-color @@ -17393,7 +17737,7 @@ snapshots: content-type: 1.0.5 cookie: 0.7.2 cookie-signature: 1.2.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 @@ -17441,7 +17785,7 @@ snapshots: extend-shallow: 2.0.1 fragment-cache: 0.2.1 regex-not: 1.0.2 - snapdragon: 0.8.2 + snapdragon: 0.8.2(supports-color@5.5.0) to-regex: 3.0.2 transitivePeerDependencies: - supports-color @@ -17594,7 +17938,7 @@ snapshots: finalhandler@2.1.1: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 @@ -17640,8 +17984,6 @@ snapshots: flatted@3.4.2: {} - follow-redirects@1.16.0: {} - follow-redirects@1.16.0(debug@3.2.7(supports-color@5.5.0)): optionalDependencies: debug: 3.2.7(supports-color@5.5.0) @@ -17728,15 +18070,15 @@ snapshots: dependencies: map-cache: 0.2.2 - framer-motion@12.38.0(@emotion/is-prop-valid@1.4.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + framer-motion@12.38.0(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: motion-dom: 12.38.0 motion-utils: 12.36.0 tslib: 2.8.1 optionalDependencies: '@emotion/is-prop-valid': 1.4.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) fresh@0.5.2: {} @@ -18156,7 +18498,7 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -18189,14 +18531,14 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) transitivePeerDependencies: - supports-color https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -18593,7 +18935,7 @@ snapshots: istanbul-lib-source-maps@4.0.1: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -18973,7 +19315,7 @@ snapshots: jsbn@0.1.1: {} - jsdom@25.0.1(canvas@2.11.2): + jsdom@25.0.1: dependencies: cssstyle: 4.6.0 data-urls: 5.0.0 @@ -18996,8 +19338,6 @@ snapshots: whatwg-url: 14.2.0 ws: 8.20.0 xml-name-validator: 5.0.0 - optionalDependencies: - canvas: 2.11.2 transitivePeerDependencies: - bufferutil - supports-color @@ -19239,7 +19579,7 @@ snapshots: dependencies: chalk: 5.6.2 commander: 13.1.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) execa: 8.0.1 lilconfig: 3.1.3 listr2: 8.3.3 @@ -19450,9 +19790,9 @@ snapshots: dependencies: yallist: 3.1.1 - lucide-react@0.513.0(react@18.3.1): + lucide-react@0.513.0(react@19.2.6): dependencies: - react: 18.3.1 + react: 19.2.6 luxon@3.7.2: {} @@ -19561,7 +19901,7 @@ snapshots: nanomatch: 1.2.13 object.pick: 1.3.0 regex-not: 1.0.2 - snapdragon: 0.8.2 + snapdragon: 0.8.2(supports-color@5.5.0) to-regex: 3.0.2 transitivePeerDependencies: - supports-color @@ -19639,9 +19979,6 @@ snapshots: mimic-function@5.0.1: {} - mimic-response@2.1.0: - optional: true - minimalistic-assert@1.0.1: {} minimalistic-crypto-utils@1.0.1: {} @@ -19717,16 +20054,27 @@ snapshots: ms@2.1.3: {} - mui-ethiopian-datepicker@0.3.2(hjxdxgubdlhng5uhyvidfkiyo4): + mui-ethiopian-datepicker@0.3.2(bb2b0a350b39c049005e46c2e15483da): dependencies: '@emotion/react': 11.14.0(@types/react@18.3.28)(react@18.3.1) '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) '@mui/icons-material': 5.18.0(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) '@mui/material': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/x-date-pickers': 6.20.2(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(date-fns@3.6.0)(dayjs@1.11.20)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - date-fns: 3.6.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@mui/x-date-pickers': 6.20.2(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(dayjs@1.11.20)(luxon@3.7.2)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + date-fns: 4.1.0 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + + mui-ethiopian-datepicker@0.3.2(c914a98daf8e04e98459e8e367258069): + dependencies: + '@emotion/react': 11.14.0(@types/react@18.3.28)(react@19.2.6) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@19.2.6) + '@mui/icons-material': 5.18.0(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) + '@mui/material': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/x-date-pickers': 6.20.2(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(date-fns@4.1.0)(dayjs@1.11.20)(luxon@3.7.2)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + date-fns: 4.1.0 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) multer@2.1.1: dependencies: @@ -19766,7 +20114,7 @@ snapshots: kind-of: 6.0.3 object.pick: 1.3.0 regex-not: 1.0.2 - snapdragon: 0.8.2 + snapdragon: 0.8.2(supports-color@5.5.0) to-regex: 3.0.2 transitivePeerDependencies: - supports-color @@ -19822,10 +20170,10 @@ snapshots: reflect-metadata: 0.1.14 rxjs: 7.8.2 - next-themes@0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next-themes@0.4.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) next-tick@1.1.0: {} @@ -20235,9 +20583,6 @@ snapshots: path-type@4.0.0: {} - path2d-polyfill@2.0.1: - optional: true - path@0.12.7: dependencies: process: 0.11.10 @@ -20258,13 +20603,14 @@ snapshots: sha.js: 2.4.12 to-buffer: 1.2.2 - pdfjs-dist@3.11.174: + pdfjs-dist@2.16.105: + dependencies: + dommatrix: 1.0.3 + web-streams-polyfill: 3.3.3 + + pdfjs-dist@5.4.296: optionalDependencies: - canvas: 2.11.2 - path2d-polyfill: 2.0.1 - transitivePeerDependencies: - - encoding - - supports-color + '@napi-rs/canvas': 0.1.100 peek-readable@5.4.2: {} @@ -20604,30 +20950,38 @@ snapshots: iconv-lite: 0.7.2 unpipe: 1.0.0 - react-cookie@8.1.2(@types/react@18.3.28)(react@18.3.1): + react-cookie@8.1.2(@types/react@18.3.28)(react@19.2.6): dependencies: '@types/hoist-non-react-statics': 3.3.7(@types/react@18.3.28) hoist-non-react-statics: 3.3.2 - react: 18.3.1 + react: 19.2.6 universal-cookie: 8.1.2 transitivePeerDependencies: - '@types/react' - react-datepicker@8.10.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-datepicker@8.10.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: - '@floating-ui/react': 0.27.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@floating-ui/react': 0.27.19(react-dom@19.2.6(react@19.2.6))(react@19.2.6) clsx: 2.1.1 - date-fns: 3.6.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + date-fns: 4.1.0 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) - react-day-picker@9.14.0(react@18.3.1): + react-day-picker@9.14.0(react@19.2.6): dependencies: '@date-fns/tz': 1.4.1 '@tabby_ai/hijri-converter': 1.0.5 - date-fns: 3.6.0 + date-fns: 4.1.0 date-fns-jalali: 4.1.0-0 - react: 18.3.1 + react: 19.2.6 + + react-dom@16.14.0(react@16.14.0): + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + prop-types: 15.8.1 + react: 16.14.0 + scheduler: 0.19.1 react-dom@18.3.1(react@18.3.1): dependencies: @@ -20635,55 +20989,60 @@ snapshots: react: 18.3.1 scheduler: 0.23.2 - react-dropzone@14.4.1(react@18.3.1): + react-dom@19.2.6(react@19.2.6): + dependencies: + react: 19.2.6 + scheduler: 0.27.0 + + react-dropzone@14.4.1(react@19.2.6): dependencies: attr-accept: 2.2.5 file-selector: 2.1.2 prop-types: 15.8.1 - react: 18.3.1 + react: 19.2.6 - react-floater@0.7.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-floater@0.7.9(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: deepmerge: 4.3.1 is-lite: 0.8.2 popper.js: 1.16.1 prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) tree-changes: 0.9.3 - react-hook-form@7.75.0(react@18.3.1): + react-hook-form@7.75.0(react@19.2.6): dependencies: - react: 18.3.1 + react: 19.2.6 - react-i18next@15.7.4(i18next@25.10.10(typescript@5.9.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3): + react-i18next@15.7.4(i18next@25.10.10(typescript@5.9.3))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(typescript@5.9.3): dependencies: '@babel/runtime': 7.29.2 html-parse-stringify: 3.0.1 i18next: 25.10.10(typescript@5.9.3) - react: 18.3.1 + react: 19.2.6 optionalDependencies: - react-dom: 18.3.1(react@18.3.1) + react-dom: 19.2.6(react@19.2.6) typescript: 5.9.3 - react-icons@5.6.0(react@18.3.1): + react-icons@5.6.0(react@19.2.6): dependencies: - react: 18.3.1 + react: 19.2.6 - react-image-crop@11.0.10(react@18.3.1): + react-image-crop@11.0.10(react@19.2.6): dependencies: - react: 18.3.1 + react: 19.2.6 - react-innertext@1.1.5(@types/react@18.3.28)(react@18.3.1): + react-innertext@1.1.5(@types/react@18.3.28)(react@19.2.6): dependencies: '@types/react': 18.3.28 - react: 18.3.1 + react: 19.2.6 - react-intersection-observer@9.16.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-intersection-observer@9.16.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: - react: 18.3.1 + react: 19.2.6 optionalDependencies: - react-dom: 18.3.1(react@18.3.1) + react-dom: 19.2.6(react@19.2.6) react-is@16.13.1: {} @@ -20691,16 +21050,16 @@ snapshots: react-is@19.2.6: {} - react-joyride@2.9.3(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-joyride@2.9.3(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: '@gilbarbara/deep-equal': 0.3.1 deep-diff: 1.0.2 deepmerge: 4.3.1 is-lite: 1.2.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-floater: 0.7.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-innertext: 1.1.5(@types/react@18.3.28)(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + react-floater: 0.7.9(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-innertext: 1.1.5(@types/react@18.3.28)(react@19.2.6) react-is: 16.13.1 scroll: 3.0.1 scrollparent: 2.1.0 @@ -20709,83 +21068,79 @@ snapshots: transitivePeerDependencies: - '@types/react' - react-number-format@5.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-number-format@5.4.5(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) - react-pdf-html@2.1.5(@react-pdf/renderer@4.5.1(react@18.3.1))(react@18.3.1): + react-pdf-html@2.1.5(@react-pdf/renderer@4.5.1(react@18.3.1))(react@19.2.6): dependencies: - '@react-pdf/renderer': 4.5.1(react@18.3.1) + '@react-pdf/renderer': 4.5.1(react@19.2.6) css-tree: 1.1.3 node-html-parser: 6.1.13 - react: 18.3.1 + react: 19.2.6 react-pdf-viewer@0.1.0: dependencies: - pdfjs-dist: 3.11.174 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + pdfjs-dist: 2.16.105 + react: 16.14.0 + react-dom: 16.14.0(react@16.14.0) webpack: 3.12.0 webpack-dev-server: 2.11.5(webpack@3.12.0) transitivePeerDependencies: - - encoding - - supports-color - webpack-cli - webpack-command + - worker-loader - react-pdf@10.4.1(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-pdf@10.4.1(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: clsx: 2.1.1 dequal: 2.0.3 make-cancellable-promise: 2.0.0 make-event-props: 2.0.0 merge-refs: 2.0.0(@types/react@18.3.28) - pdfjs-dist: 3.11.174 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + pdfjs-dist: 5.4.296 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) tiny-invariant: 1.3.3 warning: 4.0.3 optionalDependencies: '@types/react': 18.3.28 - transitivePeerDependencies: - - encoding - - supports-color - react-redux@9.2.0(@types/react@18.3.28)(react@18.3.1)(redux@5.0.1): + react-redux@9.2.0(@types/react@18.3.28)(react@19.2.6)(redux@5.0.1): dependencies: '@types/use-sync-external-store': 0.0.6 - react: 18.3.1 - use-sync-external-store: 1.6.0(react@18.3.1) + react: 19.2.6 + use-sync-external-store: 1.6.0(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 redux: 5.0.1 react-refresh@0.17.0: {} - react-remove-scroll-bar@2.3.8(@types/react@18.3.28)(react@18.3.1): + react-remove-scroll-bar@2.3.8(@types/react@18.3.28)(react@19.2.6): dependencies: - react: 18.3.1 - react-style-singleton: 2.2.3(@types/react@18.3.28)(react@18.3.1) + react: 19.2.6 + react-style-singleton: 2.2.3(@types/react@18.3.28)(react@19.2.6) tslib: 2.8.1 optionalDependencies: '@types/react': 18.3.28 - react-remove-scroll@2.7.2(@types/react@18.3.28)(react@18.3.1): + react-remove-scroll@2.7.2(@types/react@18.3.28)(react@19.2.6): dependencies: - react: 18.3.1 - react-remove-scroll-bar: 2.3.8(@types/react@18.3.28)(react@18.3.1) - react-style-singleton: 2.2.3(@types/react@18.3.28)(react@18.3.1) + react: 19.2.6 + react-remove-scroll-bar: 2.3.8(@types/react@18.3.28)(react@19.2.6) + react-style-singleton: 2.2.3(@types/react@18.3.28)(react@19.2.6) tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@18.3.28)(react@18.3.1) - use-sidecar: 1.1.3(@types/react@18.3.28)(react@18.3.1) + use-callback-ref: 1.3.3(@types/react@18.3.28)(react@19.2.6) + use-sidecar: 1.1.3(@types/react@18.3.28)(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 - react-resizable-panels@3.0.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-resizable-panels@3.0.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) react-router-dom@6.30.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: @@ -20794,52 +21149,52 @@ snapshots: react-dom: 18.3.1(react@18.3.1) react-router: 6.30.3(react@18.3.1) - react-router-dom@7.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-router-dom@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-router: 7.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + react-router: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react-router@6.30.3(react@18.3.1): dependencies: '@remix-run/router': 1.23.2 react: 18.3.1 - react-router@7.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: cookie: 1.1.1 - react: 18.3.1 + react: 19.2.6 set-cookie-parser: 2.7.2 optionalDependencies: - react-dom: 18.3.1(react@18.3.1) + react-dom: 19.2.6(react@19.2.6) - react-signature-canvas@1.1.0-alpha.2(@types/prop-types@15.7.15)(@types/react@18.3.28)(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-signature-canvas@1.1.0-alpha.2(@types/prop-types@15.7.15)(@types/react@18.3.28)(prop-types@15.8.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: '@babel/runtime': 7.29.2 '@types/signature_pad': 2.3.6 prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) signature_pad: 2.3.2 trim-canvas: 0.1.2 optionalDependencies: '@types/prop-types': 15.7.15 '@types/react': 18.3.28 - react-style-singleton@2.2.3(@types/react@18.3.28)(react@18.3.1): + react-style-singleton@2.2.3(@types/react@18.3.28)(react@19.2.6): dependencies: get-nonce: 1.0.1 - react: 18.3.1 + react: 19.2.6 tslib: 2.8.1 optionalDependencies: '@types/react': 18.3.28 - react-textarea-autosize@8.5.9(@types/react@18.3.28)(react@18.3.1): + react-textarea-autosize@8.5.9(@types/react@18.3.28)(react@19.2.6): dependencies: '@babel/runtime': 7.29.2 - react: 18.3.1 - use-composed-ref: 1.4.0(@types/react@18.3.28)(react@18.3.1) - use-latest: 1.3.0(@types/react@18.3.28)(react@18.3.1) + react: 19.2.6 + use-composed-ref: 1.4.0(@types/react@18.3.28)(react@19.2.6) + use-latest: 1.3.0(@types/react@18.3.28)(react@19.2.6) transitivePeerDependencies: - '@types/react' @@ -20852,10 +21207,18 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) + react@16.14.0: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + prop-types: 15.8.1 + react@18.3.1: dependencies: loose-envify: 1.4.0 + react@19.2.6: {} + read-cache@1.0.0: dependencies: pify: 2.3.0 @@ -20937,21 +21300,21 @@ snapshots: readdirp@4.1.2: {} - recharts@3.8.1(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react-is@19.2.6)(react@18.3.1)(redux@5.0.1): + recharts@3.8.1(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react-is@19.2.6)(react@19.2.6)(redux@5.0.1): dependencies: - '@reduxjs/toolkit': 2.11.2(react-redux@9.2.0(@types/react@18.3.28)(react@18.3.1)(redux@5.0.1))(react@18.3.1) + '@reduxjs/toolkit': 2.11.2(react-redux@9.2.0(@types/react@18.3.28)(react@19.2.6)(redux@5.0.1))(react@19.2.6) clsx: 2.1.1 decimal.js-light: 2.5.1 es-toolkit: 1.46.1 eventemitter3: 5.0.4 immer: 10.2.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) react-is: 19.2.6 - react-redux: 9.2.0(@types/react@18.3.28)(react@18.3.1)(redux@5.0.1) + react-redux: 9.2.0(@types/react@18.3.28)(react@19.2.6)(redux@5.0.1) reselect: 5.1.1 tiny-invariant: 1.3.3 - use-sync-external-store: 1.6.0(react@18.3.1) + use-sync-external-store: 1.6.0(react@19.2.6) victory-vendor: 37.3.6 transitivePeerDependencies: - '@types/react' @@ -21160,7 +21523,7 @@ snapshots: router@2.2.0: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 @@ -21223,12 +21586,19 @@ snapshots: dependencies: xmlchars: 2.2.0 + scheduler@0.19.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + scheduler@0.23.2: dependencies: loose-envify: 1.4.0 scheduler@0.25.0-rc-603e6108-20241029: {} + scheduler@0.27.0: {} + schema-utils@3.3.0: dependencies: '@types/json-schema': 7.0.15 @@ -21280,7 +21650,7 @@ snapshots: send@1.2.1: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 @@ -21419,16 +21789,6 @@ snapshots: signature_pad@2.3.2: {} - simple-concat@1.0.1: - optional: true - - simple-get@3.1.1: - dependencies: - decompress-response: 4.2.1 - once: 1.4.0 - simple-concat: 1.0.1 - optional: true - sisteransi@1.0.5: {} slash@3.0.0: {} @@ -21455,19 +21815,6 @@ snapshots: dependencies: kind-of: 3.2.2 - snapdragon@0.8.2: - dependencies: - base: 0.11.2 - debug: 2.6.9(supports-color@5.5.0) - define-property: 0.2.5 - extend-shallow: 2.0.1 - map-cache: 0.2.2 - source-map: 0.5.7 - source-map-resolve: 0.5.3 - use: 3.1.1 - transitivePeerDependencies: - - supports-color - snapdragon@0.8.2(supports-color@4.5.0): dependencies: base: 0.11.2 @@ -21529,10 +21876,10 @@ snapshots: faye-websocket: 0.10.0 uuid: 3.4.0 - sonner@2.0.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + sonner@2.0.7(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) source-list-map@2.0.1: {} @@ -21828,7 +22175,7 @@ snapshots: dependencies: component-emitter: 1.3.1 cookiejar: 2.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) fast-safe-stringify: 2.1.1 form-data: 4.0.5 formidable: 3.5.4 @@ -22305,7 +22652,7 @@ snapshots: app-root-path: 3.1.0 buffer: 6.0.3 dayjs: 1.11.20 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) dedent: 1.7.2(babel-plugin-macros@3.1.0) dotenv: 16.6.1 glob: 10.5.0 @@ -22432,36 +22779,36 @@ snapshots: punycode: 1.4.1 qs: 6.15.1 - use-callback-ref@1.3.3(@types/react@18.3.28)(react@18.3.1): + use-callback-ref@1.3.3(@types/react@18.3.28)(react@19.2.6): dependencies: - react: 18.3.1 + react: 19.2.6 tslib: 2.8.1 optionalDependencies: '@types/react': 18.3.28 - use-composed-ref@1.4.0(@types/react@18.3.28)(react@18.3.1): + use-composed-ref@1.4.0(@types/react@18.3.28)(react@19.2.6): dependencies: - react: 18.3.1 + react: 19.2.6 optionalDependencies: '@types/react': 18.3.28 - use-isomorphic-layout-effect@1.2.1(@types/react@18.3.28)(react@18.3.1): + use-isomorphic-layout-effect@1.2.1(@types/react@18.3.28)(react@19.2.6): dependencies: - react: 18.3.1 + react: 19.2.6 optionalDependencies: '@types/react': 18.3.28 - use-latest@1.3.0(@types/react@18.3.28)(react@18.3.1): + use-latest@1.3.0(@types/react@18.3.28)(react@19.2.6): dependencies: - react: 18.3.1 - use-isomorphic-layout-effect: 1.2.1(@types/react@18.3.28)(react@18.3.1) + react: 19.2.6 + use-isomorphic-layout-effect: 1.2.1(@types/react@18.3.28)(react@19.2.6) optionalDependencies: '@types/react': 18.3.28 - use-sidecar@1.1.3(@types/react@18.3.28)(react@18.3.1): + use-sidecar@1.1.3(@types/react@18.3.28)(react@19.2.6): dependencies: detect-node-es: 1.1.0 - react: 18.3.1 + react: 19.2.6 tslib: 2.8.1 optionalDependencies: '@types/react': 18.3.28 @@ -22469,6 +22816,11 @@ snapshots: use-sync-external-store@1.6.0(react@18.3.1): dependencies: react: 18.3.1 + optional: true + + use-sync-external-store@1.6.0(react@19.2.6): + dependencies: + react: 19.2.6 use@3.1.1: {} @@ -22519,11 +22871,11 @@ snapshots: vary@1.1.2: {} - vaul@1.1.2(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + vaul@1.1.2(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - '@types/react' - '@types/react-dom' @@ -22560,7 +22912,7 @@ snapshots: vite-node@2.1.9(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1): dependencies: cac: 6.7.14 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) es-module-lexer: 1.7.0 pathe: 1.1.2 vite: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1) @@ -22586,7 +22938,7 @@ snapshots: lightningcss: 1.32.0 terser: 5.47.1 - vitest@2.1.9(@types/node@24.12.4)(jsdom@25.0.1(canvas@2.11.2))(lightningcss@1.32.0)(terser@5.47.1): + vitest@2.1.9(@types/node@24.12.4)(jsdom@25.0.1)(lightningcss@1.32.0)(terser@5.47.1): dependencies: '@vitest/expect': 2.1.9 '@vitest/mocker': 2.1.9(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1)) @@ -22596,7 +22948,7 @@ snapshots: '@vitest/spy': 2.1.9 '@vitest/utils': 2.1.9 chai: 5.3.3 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) expect-type: 1.3.0 magic-string: 0.30.21 pathe: 1.1.2 @@ -22610,7 +22962,7 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.12.4 - jsdom: 25.0.1(canvas@2.11.2) + jsdom: 25.0.1 transitivePeerDependencies: - less - lightningcss @@ -22680,6 +23032,8 @@ snapshots: optionalDependencies: '@zxing/text-encoding': 0.9.0 + web-streams-polyfill@3.3.3: {} + webidl-conversions@3.0.1: {} webidl-conversions@7.0.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 448988a79..8b6b87c6a 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -5,3 +5,17 @@ packages: - "apps/edr-passenger-web/*" - "packages/*" - "packages/config/*" +allowBuilds: + '@nestjs/core': true + '@prisma/client': true + '@prisma/engines': true + '@scarf/scarf': true + argon2: true + bcrypt: true + core-js: true + es5-ext: true + esbuild: true + highlight.js: true + prisma: true + tesseract.js: true + uglifyjs-webpack-plugin: true From e62273c8de741c4b85658f7e641bc81e4a12ee3a Mon Sep 17 00:00:00 2001 From: SennayT Date: Thu, 14 May 2026 14:30:09 +0300 Subject: [PATCH 05/38] remove dockerfiles --- apps/edr-freight-api/Dockerfile | 28 -------------------- apps/edr-freight-web/Dockerfile.backoffice | 18 ------------- apps/edr-freight-web/Dockerfile.portal | 18 ------------- apps/edr-passenger-api/Dockerfile | 28 -------------------- apps/edr-passenger-web/Dockerfile.backoffice | 18 ------------- apps/edr-passenger-web/Dockerfile.portal | 18 ------------- 6 files changed, 128 deletions(-) delete mode 100644 apps/edr-freight-api/Dockerfile delete mode 100644 apps/edr-freight-web/Dockerfile.backoffice delete mode 100644 apps/edr-freight-web/Dockerfile.portal delete mode 100644 apps/edr-passenger-api/Dockerfile delete mode 100644 apps/edr-passenger-web/Dockerfile.backoffice delete mode 100644 apps/edr-passenger-web/Dockerfile.portal diff --git a/apps/edr-freight-api/Dockerfile b/apps/edr-freight-api/Dockerfile deleted file mode 100644 index 7755900f4..000000000 --- a/apps/edr-freight-api/Dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -FROM node:20-alpine AS base -RUN corepack enable && corepack prepare pnpm@9.12.0 --activate -WORKDIR /app - -FROM base AS deps -COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./ -COPY apps/edr-freight-api/package.json ./apps/edr-freight-api/ -COPY packages ./packages -RUN --mount=type=cache,id=pnpm,target=/pnpm/store\ - --mount=type=secret,id=npmrc,target=./.npmrc \ - pnpm install --frozen-lockfile --filter @edr/freight-api... - -FROM deps AS build -COPY apps/edr-freight-api ./apps/edr-freight-api -RUN pnpm --filter @edr/freight-api build - -FROM node:20-alpine AS runtime -RUN corepack enable && corepack prepare pnpm@9.12.0 --activate -WORKDIR /app/apps/edr-freight-api -ENV NODE_ENV=production - -COPY --from=deps /app/node_modules ./../../node_modules -COPY --from=deps /app/apps/edr-freight-api/node_modules ./node_modules -COPY --from=build /app/apps/edr-freight-api/dist ./dist -COPY --from=build /app/apps/edr-freight-api/package.json ./package.json - -EXPOSE 3001 -CMD ["node", "dist/main.js"] diff --git a/apps/edr-freight-web/Dockerfile.backoffice b/apps/edr-freight-web/Dockerfile.backoffice deleted file mode 100644 index 62bec7399..000000000 --- a/apps/edr-freight-web/Dockerfile.backoffice +++ /dev/null @@ -1,18 +0,0 @@ -FROM node:20-alpine AS base -RUN corepack enable && corepack prepare pnpm@9.12.0 --activate -WORKDIR /app - -FROM base AS deps -COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./ -COPY apps/edr-freight-web/backoffice/package.json ./apps/edr-freight-web/backoffice/ -COPY packages ./packages -RUN pnpm install --frozen-lockfile --filter @edr/freight-backoffice... - -FROM deps AS build -COPY apps/edr-freight-web/backoffice ./apps/edr-freight-web/backoffice -RUN pnpm --filter @edr/freight-backoffice build - -FROM nginx:1.27-alpine AS runtime -COPY --from=build /app/apps/edr-freight-web/backoffice/dist /usr/share/nginx/html -EXPOSE 5183 -CMD ["nginx", "-g", "daemon off;"] diff --git a/apps/edr-freight-web/Dockerfile.portal b/apps/edr-freight-web/Dockerfile.portal deleted file mode 100644 index 32b71f672..000000000 --- a/apps/edr-freight-web/Dockerfile.portal +++ /dev/null @@ -1,18 +0,0 @@ -FROM node:20-alpine AS base -RUN corepack enable && corepack prepare pnpm@9.12.0 --activate -WORKDIR /app - -FROM base AS deps -COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./ -COPY apps/edr-freight-web/portal/package.json ./apps/edr-freight-web/portal/ -COPY packages ./packages -RUN pnpm install --frozen-lockfile --filter @edr/freight-portal... - -FROM deps AS build -COPY apps/edr-freight-web/portal ./apps/edr-freight-web/portal -RUN pnpm --filter @edr/freight-portal build - -FROM nginx:1.27-alpine AS runtime -COPY --from=build /app/apps/edr-freight-web/portal/dist /usr/share/nginx/html -EXPOSE 5173 -CMD ["nginx", "-g", "daemon off;"] diff --git a/apps/edr-passenger-api/Dockerfile b/apps/edr-passenger-api/Dockerfile deleted file mode 100644 index 0306b0f70..000000000 --- a/apps/edr-passenger-api/Dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -FROM node:20-alpine AS base -RUN corepack enable && corepack prepare pnpm@9.12.0 --activate -WORKDIR /app - -FROM base AS deps -COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./ -COPY apps/edr-passenger-api/package.json ./apps/edr-passenger-api/ -COPY packages ./packages -RUN pnpm install --frozen-lockfile --filter @edr/passenger-api... - -FROM deps AS build -COPY apps/edr-passenger-api ./apps/edr-passenger-api -RUN pnpm --filter @edr/passenger-api run prisma:generate -RUN pnpm --filter @edr/passenger-api build - -FROM node:20-alpine AS runtime -RUN corepack enable && corepack prepare pnpm@9.12.0 --activate -WORKDIR /app/apps/edr-passenger-api -ENV NODE_ENV=production - -COPY --from=deps /app/node_modules ./../../node_modules -COPY --from=deps /app/apps/edr-passenger-api/node_modules ./node_modules -COPY --from=build /app/apps/edr-passenger-api/dist ./dist -COPY --from=build /app/apps/edr-passenger-api/package.json ./package.json -COPY --from=build /app/apps/edr-passenger-api/prisma ./prisma - -EXPOSE 4000 -CMD ["node", "dist/main.js"] diff --git a/apps/edr-passenger-web/Dockerfile.backoffice b/apps/edr-passenger-web/Dockerfile.backoffice deleted file mode 100644 index d5ef88041..000000000 --- a/apps/edr-passenger-web/Dockerfile.backoffice +++ /dev/null @@ -1,18 +0,0 @@ -FROM node:20-alpine AS base -RUN corepack enable && corepack prepare pnpm@9.12.0 --activate -WORKDIR /app - -FROM base AS deps -COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./ -COPY apps/edr-passenger-web/backoffice/package.json ./apps/edr-passenger-web/backoffice/ -COPY packages ./packages -RUN pnpm install --frozen-lockfile --filter @edr/passenger-backoffice... - -FROM deps AS build -COPY apps/edr-passenger-web/backoffice ./apps/edr-passenger-web/backoffice -RUN pnpm --filter @edr/passenger-backoffice build - -FROM nginx:1.27-alpine AS runtime -COPY --from=build /app/apps/edr-passenger-web/backoffice/dist /usr/share/nginx/html -EXPOSE 5184 -CMD ["nginx", "-g", "daemon off;"] diff --git a/apps/edr-passenger-web/Dockerfile.portal b/apps/edr-passenger-web/Dockerfile.portal deleted file mode 100644 index 0c50843b0..000000000 --- a/apps/edr-passenger-web/Dockerfile.portal +++ /dev/null @@ -1,18 +0,0 @@ -FROM node:20-alpine AS base -RUN corepack enable && corepack prepare pnpm@9.12.0 --activate -WORKDIR /app - -FROM base AS deps -COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./ -COPY apps/edr-passenger-web/portal/package.json ./apps/edr-passenger-web/portal/ -COPY packages ./packages -RUN pnpm install --frozen-lockfile --filter @edr/passenger-portal... - -FROM deps AS build -COPY apps/edr-passenger-web/portal ./apps/edr-passenger-web/portal -RUN pnpm --filter @edr/passenger-portal build - -FROM nginx:1.27-alpine AS runtime -COPY --from=build /app/apps/edr-passenger-web/portal/dist /usr/share/nginx/html -EXPOSE 5174 -CMD ["nginx", "-g", "daemon off;"] From ae950edae004a553fd61dca1cd13653202c9d0b8 Mon Sep 17 00:00:00 2001 From: SennayT Date: Thu, 14 May 2026 14:30:19 +0300 Subject: [PATCH 06/38] add deployment pipeline --- .github/workflows/deploy.yaml | 80 +++++++++++++++++++++++++++++++++++ docker-compose.yaml | 21 +++++++++ 2 files changed, 101 insertions(+) create mode 100644 .github/workflows/deploy.yaml create mode 100644 docker-compose.yaml diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml new file mode 100644 index 000000000..e54e89b31 --- /dev/null +++ b/.github/workflows/deploy.yaml @@ -0,0 +1,80 @@ +name: Automatic Deployment + +on: + push: + branches: + - dev +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + environment: + name: 🌍 Setup Environment + runs-on: [self-hosted] + outputs: + target: ${{ steps.dev.outputs.target || steps.staging.outputs.target }} + steps: + - name: 🛠️ Set Development Environment + id: dev + if: ${{github.ref_name == 'dev'}} + run: | + echo "target=dev" >> $GITHUB_OUTPUT + - name: 🚀 Set Staging Environment + id: staging + if: ${{github.ref_name == 'staging'}} + run: | + echo "target=staging" >> $GITHUB_OUTPUT + + build-base-image: + name: 🏗️ Build Base Image + runs-on: [self-hosted, dev] + needs: [environment] + steps: + - name: 🔍 Checkout + uses: actions/checkout@v4 + + - name: 🐳 Build Docker Image + run: docker build -t edr-${{needs.environment.outputs.target}} . + + deploy-service: + name: ${{ matrix.display_name }} + runs-on: [self-hosted, dev] + needs: [build-base-image, environment] + strategy: + fail-fast: false + matrix: + include: + - service: freight-api + env_file: .env.freight-api + display_name: 🚚 Deploy Freight API Service + - service: passenger-api + env_file: .env.passenger-api + display_name: 🧑‍🦲 Deploy Passenger API Service + + steps: + - name: 🔍 Checkout + uses: actions/checkout@v4 + + - name: 📋 Copy ${{ matrix.service }} Environment + run: cp ~/environment/edr/${{needs.environment.outputs.target}}/${{ matrix.env_file }} .env + + - name: 🚀 Start ${{ matrix.service }} Service + run: docker compose --project-name="edr-${{needs.environment.outputs.target}}" up -d --force-recreate ${{ matrix.service }} --build + + cleanup: + name: 🧹 Cleanup Docker Resources + runs-on: [self-hosted] + needs: + - deploy-service + if: always() # Run even if previous jobs fail + steps: + - name: 🗑️ Remove unused Docker resources + run: | + echo "🧹 Cleaning up Docker resources..." + # Remove all stopped containers + docker container prune -f + # Remove unused images (both dangling and unreferenced) + docker image prune -a -f + + echo "✅ Docker cleanup completed!" diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 000000000..aa9ec58e2 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,21 @@ +services: + freight-api: + build: + context: . + dockerfile: ./Dockerfile + target: freight-api + env_file: + - .env + ports: + - ${PORT}:${PORT} + restart: unless-stopped + passenger-api: + build: + context: . + dockerfile: ./Dockerfile + target: passenger-api + env_file: + - .env + ports: + - ${PORT}:${PORT} + restart: unless-stopped From 839bde137f6a0ac225430433d6e36929442ce6e7 Mon Sep 17 00:00:00 2001 From: SennayT Date: Thu, 14 May 2026 15:01:36 +0300 Subject: [PATCH 07/38] fix build errors on passenger api --- Dockerfile | 9 +++++---- apps/edr-passenger-api/nest-cli.json | 2 ++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 086b5d751..420fe619e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,10 +30,8 @@ RUN --mount=type=cache,id=pnpm,target=/pnpm/store\ pnpm install --frozen-lockfile FROM deps AS build COPY . . -# ENV CI=true RUN pnpm run build -RUN find . -name "main.js" FROM base AS freight-api # RUN corepack enable && corepack prepare pnpm@9.12.0 --activate @@ -55,8 +53,11 @@ FROM base AS passenger-api WORKDIR /app/apps/edr-passenger-api ENV NODE_ENV=production -COPY --from=deps /app/node_modules ./../../node_modules -COPY --from=deps /app/apps/edr-passenger-api/node_modules ./node_modules +# Use build-stage node_modules (not deps): `pnpm run build` runs `prisma generate`, which +# writes the real @prisma/client (enums, types). deps never runs generate, so @IsEnum(ServiceClass) +# and similar would see undefined at runtime if we copied deps only. +COPY --from=build /app/node_modules ./../../node_modules +COPY --from=build /app/apps/edr-passenger-api/node_modules ./node_modules COPY --from=build /app/apps/edr-passenger-api/dist ./dist COPY --from=build /app/apps/edr-passenger-api/package.json ./package.json COPY --from=build /app/packages ./../../packages diff --git a/apps/edr-passenger-api/nest-cli.json b/apps/edr-passenger-api/nest-cli.json index 6e3db4584..a7fb60dd2 100644 --- a/apps/edr-passenger-api/nest-cli.json +++ b/apps/edr-passenger-api/nest-cli.json @@ -1,7 +1,9 @@ { + "$schema": "https://json.schemastore.org/nest-cli", "collection": "@nestjs/schematics", "sourceRoot": "src", "compilerOptions": { + "deleteOutDir": true, "plugins": ["@nestjs/swagger"], "tsConfigPath": "tsconfig.build.json", "watchAssets": true From a4ad24f47105726e81704b5e2320ca3ca876852b Mon Sep 17 00:00:00 2001 From: SennayT Date: Thu, 14 May 2026 15:06:50 +0300 Subject: [PATCH 08/38] remove npmrc file --- .npmrc | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 .npmrc diff --git a/.npmrc b/.npmrc deleted file mode 100644 index 063d75376..000000000 --- a/.npmrc +++ /dev/null @@ -1,2 +0,0 @@ -@tria-plc:registry=https://npm.pkg.github.com -//npm.pkg.github.com/:_authToken=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 \ No newline at end of file From d279022f94d3decd891a99a8018adf24b8c93c43 Mon Sep 17 00:00:00 2001 From: SennayT Date: Thu, 14 May 2026 15:10:52 +0300 Subject: [PATCH 09/38] add npm secret --- .github/workflows/deploy.yaml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index e54e89b31..fc92793d6 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -15,6 +15,17 @@ jobs: outputs: target: ${{ steps.dev.outputs.target || steps.staging.outputs.target }} steps: + - name: Verify NPM Token + env: + # We map the secret here to check its existence + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + if [ -z "$NPM_TOKEN" ]; then + echo "::error::The NPM_TOKEN secret is missing or empty. Please add it to your GitHub Secrets." + exit 1 + fi + echo "NPM_TOKEN is present, proceeding with build..." + - name: 🛠️ Set Development Environment id: dev if: ${{github.ref_name == 'dev'}} @@ -36,6 +47,24 @@ jobs: - name: 🐳 Build Docker Image run: docker build -t edr-${{needs.environment.outputs.target}} . + - name: 🐳 Build Docker Image + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + set -euo pipefail + + # Create the multi-line file + cat < .npmrc_temp + @tria-plc:registry=https://npm.pkg.github.com + //npm.pkg.github.com/:_authToken=${NPM_TOKEN} + always-auth=true + EOF + + # Build using the file + docker build --secret id=npmrc,src=.npmrc_temp -t edr-${{needs.environment.outputs.target}} . + + # Shred/Remove the sensitive file + rm .npmrc_temp deploy-service: name: ${{ matrix.display_name }} From 5b28050529972501503c4177d18d93c0fb9228f7 Mon Sep 17 00:00:00 2001 From: SennayT Date: Thu, 14 May 2026 15:17:11 +0300 Subject: [PATCH 10/38] remvoe old build step --- .github/workflows/deploy.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index fc92793d6..8a6feff2f 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -45,8 +45,6 @@ jobs: - name: 🔍 Checkout uses: actions/checkout@v4 - - name: 🐳 Build Docker Image - run: docker build -t edr-${{needs.environment.outputs.target}} . - name: 🐳 Build Docker Image env: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} From 10e2b1b5df3bdd6fb3f83214a83ab3d7e461360f Mon Sep 17 00:00:00 2001 From: SennayT Date: Thu, 14 May 2026 15:40:06 +0300 Subject: [PATCH 11/38] install openssl for prisma --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 420fe619e..34afaeeac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,6 +49,7 @@ CMD ["node", "dist/main.js"] FROM base AS passenger-api +RUN apt-get update -y && apt-get install -y openssl # RUN corepack enable && corepack prepare pnpm@9.12.0 --activate WORKDIR /app/apps/edr-passenger-api ENV NODE_ENV=production From ecd3b0aca8abfcb4a22a586a9a0ccffa89bc5d25 Mon Sep 17 00:00:00 2001 From: SennayT Date: Thu, 14 May 2026 15:52:57 +0300 Subject: [PATCH 12/38] fix: use non alpine image --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 34afaeeac..ce7a77ab8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:24.15.0-alpine AS base +FROM node:24.15.0 AS base RUN corepack enable && corepack prepare pnpm@latest-11 --activate WORKDIR /app From 38e99e7baba6a30edf55ef40e88fd119d2f91a2d Mon Sep 17 00:00:00 2001 From: SennayT Date: Tue, 19 May 2026 09:28:54 +0300 Subject: [PATCH 13/38] run migrations in pipeline --- .github/workflows/deploy.yaml | 6 ++++++ .gitignore | 3 ++- Dockerfile | 4 ++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 8a6feff2f..abcc237d7 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -60,6 +60,7 @@ jobs: # Build using the file docker build --secret id=npmrc,src=.npmrc_temp -t edr-${{needs.environment.outputs.target}} . + docker build --secret id=npmrc,src=.npmrc_temp --target passenger-migration -t edr-passenger-migration-${{needs.environment.outputs.target}} . . # Shred/Remove the sensitive file rm .npmrc_temp @@ -86,6 +87,11 @@ jobs: - name: 📋 Copy ${{ matrix.service }} Environment run: cp ~/environment/edr/${{needs.environment.outputs.target}}/${{ matrix.env_file }} .env + - name: 🧪 Run Passenger API migrations + if: ${{ matrix.service == 'passenger-api' }} + run: | + docker run --rm --env-file .env edr-passenger-migration-${{needs.environment.outputs.target}} + - name: 🚀 Start ${{ matrix.service }} Service run: docker compose --project-name="edr-${{needs.environment.outputs.target}}" up -d --force-recreate ${{ matrix.service }} --build diff --git a/.gitignore b/.gitignore index 132db3f2a..f03097e83 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,5 @@ coverage/ # OS/editor .DS_Store .idea/ -.vscode/ \ No newline at end of file +.vscode/ +.npmrc \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index ce7a77ab8..b98a51043 100644 --- a/Dockerfile +++ b/Dockerfile @@ -66,6 +66,10 @@ COPY --from=build /app/packages ./../../packages EXPOSE 3001 CMD ["node", "dist/main.js"] +FROM build as passenger-migration +WORKDIR /app/apps/edr-passenger-api +CMD ["pnpm","run","prisma:migrate"] + FROM nginx:1.27-alpine AS freight-web-portal From 6daeba6fb0c3830fed6a5094ae4c147a7695dc5a Mon Sep 17 00:00:00 2001 From: SennayT Date: Tue, 19 May 2026 09:30:35 +0300 Subject: [PATCH 14/38] fix typo --- .github/workflows/deploy.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index abcc237d7..d9146848b 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -60,7 +60,7 @@ jobs: # Build using the file docker build --secret id=npmrc,src=.npmrc_temp -t edr-${{needs.environment.outputs.target}} . - docker build --secret id=npmrc,src=.npmrc_temp --target passenger-migration -t edr-passenger-migration-${{needs.environment.outputs.target}} . . + docker build --secret id=npmrc,src=.npmrc_temp --target passenger-migration -t edr-passenger-migration-${{needs.environment.outputs.target}} . # Shred/Remove the sensitive file rm .npmrc_temp From d865891f2809c64a13d7320cb6fab2f55d88a4b3 Mon Sep 17 00:00:00 2001 From: SennayT Date: Tue, 19 May 2026 09:39:52 +0300 Subject: [PATCH 15/38] remove cleanup step --- .github/workflows/deploy.yaml | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index d9146848b..fa4bef238 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -94,20 +94,3 @@ jobs: - name: 🚀 Start ${{ matrix.service }} Service run: docker compose --project-name="edr-${{needs.environment.outputs.target}}" up -d --force-recreate ${{ matrix.service }} --build - - cleanup: - name: 🧹 Cleanup Docker Resources - runs-on: [self-hosted] - needs: - - deploy-service - if: always() # Run even if previous jobs fail - steps: - - name: 🗑️ Remove unused Docker resources - run: | - echo "🧹 Cleaning up Docker resources..." - # Remove all stopped containers - docker container prune -f - # Remove unused images (both dangling and unreferenced) - docker image prune -a -f - - echo "✅ Docker cleanup completed!" From 2097b275cc82f1a7349e8275d8b0669156ab974b Mon Sep 17 00:00:00 2001 From: SennayT Date: Tue, 19 May 2026 09:40:08 +0300 Subject: [PATCH 16/38] remove localhost on swagger --- apps/edr-passenger-api/src/main.ts | 77 ++++++++++++++++-------------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/apps/edr-passenger-api/src/main.ts b/apps/edr-passenger-api/src/main.ts index 71de72738..c0ca48097 100644 --- a/apps/edr-passenger-api/src/main.ts +++ b/apps/edr-passenger-api/src/main.ts @@ -1,18 +1,18 @@ -import 'reflect-metadata'; -import { NestFactory } from '@nestjs/core'; -import { ValidationPipe } from '@nestjs/common'; -import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; -import { AppModule } from './app.module'; -import { HttpExceptionFilter } from './common/filters/http-exception.filter'; -import { ResponseTransformInterceptor } from './common/interceptors/response-transform.interceptor'; +import "reflect-metadata"; +import { NestFactory } from "@nestjs/core"; +import { ValidationPipe } from "@nestjs/common"; +import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger"; +import { AppModule } from "./app.module"; +import { HttpExceptionFilter } from "./common/filters/http-exception.filter"; +import { ResponseTransformInterceptor } from "./common/interceptors/response-transform.interceptor"; async function bootstrap() { const app = await NestFactory.create(AppModule); app.enableCors({ origin: [ - process.env.FRONTEND_URL ?? 'http://localhost:3000', - process.env.PORTAL_URL ?? 'http://localhost:3001', + process.env.FRONTEND_URL ?? "http://localhost:3000", + process.env.PORTAL_URL ?? "http://localhost:3001", ], }); @@ -21,37 +21,44 @@ async function bootstrap() { app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true })); const config = new DocumentBuilder() - .setTitle('EDR Passenger API') + .setTitle("EDR Passenger API") .setDescription( - 'Ethio-Djibouti Railway Passenger API — booking lifecycle, seat inventory, payment (Telebirr, CBE Birr, eBirr, Card, Wallet), loyalty, live tracking, and support.', + "Ethio-Djibouti Railway Passenger API — booking lifecycle, seat inventory, payment (Telebirr, CBE Birr, eBirr, Card, Wallet), loyalty, live tracking, and support.", ) - .setVersion('1.0.0') - .addBearerAuth({ type: 'http', scheme: 'bearer', bearerFormat: 'JWT', in: 'header' }, 'JWT-auth') - .addTag('Auth', 'Registration and login') - .addTag('Stations', 'Station directory') - .addTag('Fleet', 'Train services and coaches') - .addTag('Schedule', 'Trips and fare rules') - .addTag('Search', 'Trip search and fare quotes') - .addTag('Seats', 'Seat maps and holds') - .addTag('Booking', 'Booking lifecycle') - .addTag('Payment', 'Payment intents and refunds') - .addTag('Tickets', 'QR ticket generation and validation') - .addTag('Passenger', 'Profiles, traveler profiles, saved routes') - .addTag('Notifications', 'Push and email notifications') - .addTag('Loyalty', 'Points, tiers, and rewards') - .addTag('Wallet', 'Wallet balance and ledger') - .addTag('Promotions', 'Promo codes and campaigns') - .addTag('Live Tracking', 'Real-time trip status and crowd signals') - .addTag('Support', 'FAQ and chat support') - .addTag('Dashboard', 'Home dashboard aggregate') - .addServer('http://localhost:4000', 'Development') - .addServer('https://api.edr-platform.com', 'Production') + .setVersion("1.0.0") + .addBearerAuth( + { type: "http", scheme: "bearer", bearerFormat: "JWT", in: "header" }, + "JWT-auth", + ) + .addTag("Auth", "Registration and login") + .addTag("Stations", "Station directory") + .addTag("Fleet", "Train services and coaches") + .addTag("Schedule", "Trips and fare rules") + .addTag("Search", "Trip search and fare quotes") + .addTag("Seats", "Seat maps and holds") + .addTag("Booking", "Booking lifecycle") + .addTag("Payment", "Payment intents and refunds") + .addTag("Tickets", "QR ticket generation and validation") + .addTag("Passenger", "Profiles, traveler profiles, saved routes") + .addTag("Notifications", "Push and email notifications") + .addTag("Loyalty", "Points, tiers, and rewards") + .addTag("Wallet", "Wallet balance and ledger") + .addTag("Promotions", "Promo codes and campaigns") + .addTag("Live Tracking", "Real-time trip status and crowd signals") + .addTag("Support", "FAQ and chat support") + .addTag("Dashboard", "Home dashboard aggregate") + //.addServer('http://localhost:4000', 'Development') + // .addServer("https://api.edr-platform.com", "Production") .build(); const document = SwaggerModule.createDocument(app, config); - SwaggerModule.setup('api-docs', app, document, { - customSiteTitle: 'EDR Passenger API', - swaggerOptions: { persistAuthorization: true, docExpansion: 'none', filter: true }, + SwaggerModule.setup("api-docs", app, document, { + customSiteTitle: "EDR Passenger API", + swaggerOptions: { + persistAuthorization: true, + docExpansion: "none", + filter: true, + }, }); const port = process.env.PORT ?? 4000; From e43d6f9ebdd65af2849fde63a5e89742a53766b2 Mon Sep 17 00:00:00 2001 From: SennayT Date: Tue, 19 May 2026 13:56:36 +0300 Subject: [PATCH 17/38] include seed command after migration --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index b98a51043..b9ab2a2b7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -68,7 +68,7 @@ CMD ["node", "dist/main.js"] FROM build as passenger-migration WORKDIR /app/apps/edr-passenger-api -CMD ["pnpm","run","prisma:migrate"] +CMD pnpm run prisma:migrate && pnpm run prisma:seed From 69b27ecb4be72c04673b0519c27324e575c21cba Mon Sep 17 00:00:00 2001 From: Stephanos A Date: Thu, 21 May 2026 08:48:28 +0300 Subject: [PATCH 18/38] Refactored the whole app based on the requirements shared --- README.md | 584 +- apps/edr-passenger-api/.env.example | 52 +- apps/edr-passenger-api/.npmrc | 6 + apps/edr-passenger-api/SEGMENT_BASED_SEATS.md | 364 - apps/edr-passenger-api/package.json | 4 +- .../migration.sql | 31 - .../migration.sql | 63 - .../migration.sql | 463 +- .../migration.sql | 2 + .../migration.sql | 74 + .../edr-passenger-api/prisma/reset-admin.d.ts | 2 - .../prisma/reset-admin.d.ts.map | 1 - apps/edr-passenger-api/prisma/reset-admin.js | 49 - .../prisma/reset-admin.js.map | 1 - apps/edr-passenger-api/prisma/reset-admin.ts | 16 - apps/edr-passenger-api/prisma/schema.prisma | 288 +- apps/edr-passenger-api/prisma/seed.d.ts | 2 - apps/edr-passenger-api/prisma/seed.d.ts.map | 1 - apps/edr-passenger-api/prisma/seed.js | 73 - apps/edr-passenger-api/prisma/seed.js.map | 1 - apps/edr-passenger-api/prisma/seed.ts | 231 +- apps/edr-passenger-api/src/app.module.ts | 27 +- .../src/common/i18n/i18n.module.ts | 9 + .../src/common/i18n/i18n.service.spec.ts | 49 + .../src/common/i18n/i18n.service.ts | 63 + .../src/common/i18n/locale.decorator.ts | 9 + .../src/common/i18n/locale.middleware.ts | 16 + .../src/common/i18n/translations/am.json | 23 + .../src/common/i18n/translations/en.json | 23 + .../src/common/i18n/translations/fr.json | 23 + .../src/common/i18n/translations/om.json | 23 + .../src/common/iam-adapter.spec.ts | 264 + .../src/common/iam-adapter.ts | 144 + .../src/common/iam.module.ts | 11 + .../session-activity.interceptor.ts | 49 + .../src/common/prisma.module.ts | 3 +- .../src/common/roles.decorator.ts | 5 + .../src/common/roles.guard.ts | 19 + .../src/config/card.config.ts | 9 + .../src/config/cbe.config.ts | 9 + .../src/config/ebirr.config.ts | 9 + apps/edr-passenger-api/src/main.ts | 210 +- .../src/modules/agents/agents.controller.ts | 57 + .../src/modules/agents/agents.dto.ts | 33 + .../src/modules/agents/agents.module.ts | 12 + .../src/modules/agents/agents.service.ts | 131 + .../src/modules/auth/auth.controller.ts | 73 +- .../src/modules/auth/auth.dto.ts | 154 +- .../src/modules/auth/auth.service.ts | 106 +- .../modules/bookings/bookings.controller.ts | 31 +- .../src/modules/bookings/bookings.dto.ts | 20 +- .../src/modules/bookings/bookings.service.ts | 91 +- .../src/modules/fraud/fraud.controller.ts | 74 + .../src/modules/fraud/fraud.module.ts | 12 + .../src/modules/fraud/fraud.service.ts | 252 + .../notifications/notification.adapters.ts | 216 + .../notifications/notifications.controller.ts | 29 +- .../notifications/notifications.dto.ts | 20 +- .../notifications/notifications.module.ts | 9 +- .../notifications/notifications.service.ts | 260 +- .../src/modules/payments/payments.e2e-spec.ts | 270 + .../src/modules/payments/payments.module.ts | 18 +- .../modules/payments/payments.service.spec.ts | 328 + .../src/modules/payments/payments.service.ts | 49 +- .../payments/providers/card.provider.ts | 218 + .../payments/providers/cbe-birr.provider.ts | 215 + .../payments/providers/ebirr.provider.ts | 228 + .../payments/webhooks/card-webhook.service.ts | 147 + .../webhooks/cbe-birr-webhook.service.ts | 133 + .../webhooks/ebirr-webhook.service.ts | 133 + .../payments/webhooks/webhooks.controller.ts | 63 +- .../src/modules/reports/reports.controller.ts | 35 + .../src/modules/reports/reports.dto.ts | 29 + .../src/modules/reports/reports.module.ts | 12 + .../src/modules/reports/reports.service.ts | 185 + .../src/modules/search/search.dto.ts | 6 +- .../src/modules/search/search.service.ts | 28 +- .../src/modules/seats/seats.controller.ts | 16 + .../src/modules/seats/seats.service.spec.ts | 82 + .../src/modules/seats/seats.service.ts | 122 + .../src/modules/tickets/tickets.controller.ts | 38 +- .../modules/tickets/tickets.service.spec.ts | 126 + .../src/modules/tickets/tickets.service.ts | 115 +- pnpm-lock.yaml | 12058 +--------------- 84 files changed, 6880 insertions(+), 12659 deletions(-) create mode 100644 apps/edr-passenger-api/.npmrc delete mode 100644 apps/edr-passenger-api/SEGMENT_BASED_SEATS.md delete mode 100644 apps/edr-passenger-api/prisma/migrations/20260515133041_segment_updates/migration.sql delete mode 100644 apps/edr-passenger-api/prisma/migrations/20260516170103_add_telebirr_async_fields/migration.sql rename apps/edr-passenger-api/prisma/migrations/{20260513080558_initial_migration => 20260519124728_initial_migration}/migration.sql (59%) create mode 100644 apps/edr-passenger-api/prisma/migrations/20260520000002_language_field_note/migration.sql create mode 100644 apps/edr-passenger-api/prisma/migrations/20260521000001_add_fraud_detection/migration.sql delete mode 100644 apps/edr-passenger-api/prisma/reset-admin.d.ts delete mode 100644 apps/edr-passenger-api/prisma/reset-admin.d.ts.map delete mode 100644 apps/edr-passenger-api/prisma/reset-admin.js delete mode 100644 apps/edr-passenger-api/prisma/reset-admin.js.map delete mode 100644 apps/edr-passenger-api/prisma/reset-admin.ts delete mode 100644 apps/edr-passenger-api/prisma/seed.d.ts delete mode 100644 apps/edr-passenger-api/prisma/seed.d.ts.map delete mode 100644 apps/edr-passenger-api/prisma/seed.js delete mode 100644 apps/edr-passenger-api/prisma/seed.js.map create mode 100644 apps/edr-passenger-api/src/common/i18n/i18n.module.ts create mode 100644 apps/edr-passenger-api/src/common/i18n/i18n.service.spec.ts create mode 100644 apps/edr-passenger-api/src/common/i18n/i18n.service.ts create mode 100644 apps/edr-passenger-api/src/common/i18n/locale.decorator.ts create mode 100644 apps/edr-passenger-api/src/common/i18n/locale.middleware.ts create mode 100644 apps/edr-passenger-api/src/common/i18n/translations/am.json create mode 100644 apps/edr-passenger-api/src/common/i18n/translations/en.json create mode 100644 apps/edr-passenger-api/src/common/i18n/translations/fr.json create mode 100644 apps/edr-passenger-api/src/common/i18n/translations/om.json create mode 100644 apps/edr-passenger-api/src/common/iam-adapter.spec.ts create mode 100644 apps/edr-passenger-api/src/common/iam-adapter.ts create mode 100644 apps/edr-passenger-api/src/common/iam.module.ts create mode 100644 apps/edr-passenger-api/src/common/interceptors/session-activity.interceptor.ts create mode 100644 apps/edr-passenger-api/src/common/roles.decorator.ts create mode 100644 apps/edr-passenger-api/src/common/roles.guard.ts create mode 100644 apps/edr-passenger-api/src/config/card.config.ts create mode 100644 apps/edr-passenger-api/src/config/cbe.config.ts create mode 100644 apps/edr-passenger-api/src/config/ebirr.config.ts create mode 100644 apps/edr-passenger-api/src/modules/agents/agents.controller.ts create mode 100644 apps/edr-passenger-api/src/modules/agents/agents.dto.ts create mode 100644 apps/edr-passenger-api/src/modules/agents/agents.module.ts create mode 100644 apps/edr-passenger-api/src/modules/agents/agents.service.ts create mode 100644 apps/edr-passenger-api/src/modules/fraud/fraud.controller.ts create mode 100644 apps/edr-passenger-api/src/modules/fraud/fraud.module.ts create mode 100644 apps/edr-passenger-api/src/modules/fraud/fraud.service.ts create mode 100644 apps/edr-passenger-api/src/modules/notifications/notification.adapters.ts create mode 100644 apps/edr-passenger-api/src/modules/payments/payments.e2e-spec.ts create mode 100644 apps/edr-passenger-api/src/modules/payments/payments.service.spec.ts create mode 100644 apps/edr-passenger-api/src/modules/payments/providers/card.provider.ts create mode 100644 apps/edr-passenger-api/src/modules/payments/providers/cbe-birr.provider.ts create mode 100644 apps/edr-passenger-api/src/modules/payments/providers/ebirr.provider.ts create mode 100644 apps/edr-passenger-api/src/modules/payments/webhooks/card-webhook.service.ts create mode 100644 apps/edr-passenger-api/src/modules/payments/webhooks/cbe-birr-webhook.service.ts create mode 100644 apps/edr-passenger-api/src/modules/payments/webhooks/ebirr-webhook.service.ts create mode 100644 apps/edr-passenger-api/src/modules/reports/reports.controller.ts create mode 100644 apps/edr-passenger-api/src/modules/reports/reports.dto.ts create mode 100644 apps/edr-passenger-api/src/modules/reports/reports.module.ts create mode 100644 apps/edr-passenger-api/src/modules/reports/reports.service.ts create mode 100644 apps/edr-passenger-api/src/modules/seats/seats.service.spec.ts create mode 100644 apps/edr-passenger-api/src/modules/tickets/tickets.service.spec.ts diff --git a/README.md b/README.md index 33f22dc0a..eb7cccae0 100644 --- a/README.md +++ b/README.md @@ -1,141 +1,513 @@ -# EDR Passenger API +# EDR Platform - Ethio-Djibouti Railway Passenger API -NestJS REST API for the Ethio-Djibouti Railway passenger platform. Handles booking lifecycle, seat inventory, payments (Telebirr, CBE Birr, eBirr, Card, Wallet), loyalty, live tracking, notifications, and support. +Enterprise-grade NestJS REST API for the Ethio-Djibouti Railway passenger booking and management platform. Built with TypeScript, PostgreSQL, and Prisma ORM. -## Tech Stack +## 🚀 Features -- **Runtime**: Node.js 20, TypeScript -- **Framework**: NestJS 11 -- **Database**: PostgreSQL via Prisma ORM -- **Auth**: JWT (Passport) -- **Docs**: Swagger / OpenAPI (`/api-docs`) -- **Package manager**: pnpm 9 +### Core Modules +- **Authentication & Authorization** - Dual authentication system: + - **Passenger Auth**: JWT-based auth with OTP verification, password reset, account lockout + - **Corporate IAM**: Integration with @tria-plc corporate identity system for back-office operations (agents, supervisors, admins) + - Role-based access control (RBAC) with granular permissions +- **Booking Management** - Complete booking lifecycle with modification, cancellation, refunds, and fare breakdown +- **Payment Integration** - Multi-provider support (Telebirr, CBE Birr, eBirr, Card, Wallet) with webhook handling +- **Seat Management** - Real-time seat inventory, holds, releases, and blocking with coach/class management +- **Ticketing** - QR code and barcode generation, PDF tickets, gate validation with audit logs +- **Agent Operations** - Counter booking, shift management, commission tracking, and reconciliation +- **Passenger Services** - Profile management, traveler profiles, saved routes, and preferences +- **Loyalty Program** - Points accumulation, tier management (Bronze/Silver/Gold/Platinum), and rewards +- **Wallet System** - Balance management, top-up, transaction ledger +- **Live Tracking** - Real-time trip status, location updates, delay notifications, crowd signals +- **Notifications** - Multi-channel (Email, SMS, Push) with templating engine +- **Support System** - FAQ management, live chat conversations +- **Reports & Analytics** - Revenue reports, occupancy analytics, agent sales tracking +- **Route Management** - Route configuration, stops, fare rules, baggage allowance -## Prerequisites +### Technical Features +- **Security** - Password hashing (bcrypt), JWT tokens, rate limiting, audit logging +- **Validation** - Request validation with class-validator, DTO transformation +- **Documentation** - Auto-generated Swagger/OpenAPI docs at `/api-docs` +- **Error Handling** - Global exception filters with standardized error responses +- **Database** - PostgreSQL with Prisma ORM, migrations, and comprehensive seeding +- **Scheduling** - Cron jobs for automated tasks (seat release, report generation) +- **Event System** - Event-driven architecture with @nestjs/event-emitter -- Node.js >= 20 -- pnpm >= 9 (`npm i -g pnpm`) -- PostgreSQL 15+ +## 📋 Prerequisites -## Quick Start +- **Node.js** >= 20.x +- **pnpm** >= 9.x (`npm install -g pnpm`) +- **PostgreSQL** >= 15.x +- **Git** +## 🛠️ Installation & Setup + +### 1. Clone Repository ```bash -# 1. Install dependencies (from monorepo root) -pnpm install +git clone +cd edr-platform +``` -# 2. Copy and fill environment variables +### 2. Install Dependencies +```bash +pnpm install +``` + +### 3. Environment Configuration +```bash +# Copy environment template cp apps/edr-passenger-api/.env.example apps/edr-passenger-api/.env -# 3. Generate Prisma client +# Edit .env file with your configuration +``` + +#### Required Environment Variables + +| Variable | Description | Example | +|----------|-------------|---------| +| `NODE_ENV` | Environment mode | `development` | +| `PORT` | HTTP server port | `4000` | +| `DATABASE_URL` | PostgreSQL connection string | `postgresql://user:pass@localhost:5432/edr_passenger` | +| `JWT_SECRET` | JWT signing secret (change in production) | `your-secret-key` | +| `JWT_EXPIRES_IN` | JWT token expiry | `7d` | +| `FRONTEND_URL` | Web app CORS origin | `http://localhost:3000` | +| `PORTAL_URL` | Admin portal CORS origin | `http://localhost:3001` | +| `SENDGRID_API_KEY` | SendGrid API key (optional) | `SG.xxx` | +| `SENDGRID_FROM_EMAIL` | Email sender address | `noreply@edr-platform.com` | + +#### Corporate IAM Configuration (Back-office Authentication) + +| Variable | Description | Example | +|----------|-------------|---------| +| `IAM_ENABLED` | Enable corporate IAM integration | `true` or `false` | +| `IAM_API_URL` | Corporate IAM API endpoint | `https://iam.tria-plc.com/api` | +| `IAM_API_KEY` | API key for IAM service | `your-iam-api-key` | + +**Note:** When `IAM_ENABLED=false`, IAM-protected routes allow access without validation (development mode only). + +#### Optional: Payment Provider Configuration +```bash +# Telebirr Configuration +TELEBIRR_BASE_URL=https://api.telebirr.com +TELEBIRR_MERCHANT_CODE=your-merchant-code +TELEBIRR_APP_SECRET=your-app-secret +# ... see .env.example for complete list +``` + +### 4. Database Setup + +#### Start PostgreSQL +```bash +# Using Docker (recommended) +docker run --name edr-postgres \ + -e POSTGRES_USER=edr \ + -e POSTGRES_PASSWORD=edr_secret \ + -e POSTGRES_DB=edr_passenger \ + -p 5432:5432 \ + -d postgres:15 + +# Or use your local PostgreSQL installation +``` + +#### Generate Prisma Client +```bash pnpm --filter @edr/passenger-api run prisma:generate +``` -# 4. Run database migrations +#### Run Migrations +```bash pnpm --filter @edr/passenger-api run prisma:migrate +``` -# 5. Seed the database +#### Seed Database +```bash pnpm --filter @edr/passenger-api run prisma:seed +``` -# 6. Start in development mode +**Seed Data Includes:** +- 5 Stations (Addis Ababa, Adama, Awash, Dire Dawa, Djibouti) +- 1 Route with 5 stops and fare rules +- 2 Train services with 2 trips +- 360 seats across 6 coaches (Economy, Bed, VIP classes) +- 3 User accounts (Admin, Passenger, Agent) +- Baggage allowance rules +- Notification templates +- Promotions and FAQ content +- Menu items and station crowd signals + +### 5. Start Development Server +```bash pnpm --filter @edr/passenger-api run dev ``` -API runs at **http://localhost:4000** -Swagger UI at **http://localhost:4000/api-docs** +**API Server:** http://localhost:4000 +**Swagger Docs:** http://localhost:4000/api-docs -## Environment Variables +## 🔑 Default Credentials -| Variable | Description | Default | -| --------------------- | ------------------------------------ | -------------------------------- | -| `PORT` | HTTP port | `4000` | -| `DATABASE_URL` | PostgreSQL connection string | — | -| `JWT_SECRET` | JWT signing secret | — | -| `JWT_EXPIRES_IN` | JWT expiry | `7d` | -| `FRONTEND_URL` | Allowed CORS origin (web app) | `http://localhost:3000` | -| `PORTAL_URL` | Allowed CORS origin (portal) | `http://localhost:3001` | -| `SENDGRID_API_KEY` | SendGrid key for email notifications | _(optional — logs if absent)_ | -| `SENDGRID_FROM_EMAIL` | Sender email address | `noreply@edr-platform.com` | +After seeding, use these credentials to test the API: -## API Modules +| Role | Email | Password | Description | +|------|-------|----------|-------------| +| **Admin** | `admin@edr-platform.com` | `admin123` | Full system access, reports, agent management | +| **Passenger** | `kelemu@email.com` | `password123` | Regular user with loyalty (Silver) and wallet | +| **Agent** | `agent@edr-platform.com` | `agent123` | Counter booking agent with commission tracking | -| Tag | Base path | Description | -| -------------- | ----------------- | ---------------------------------------- | -| Auth | `/auth` | Register, login, JWT | -| Stations | `/stations` | Station directory | -| Fleet | `/fleet` | Train services, coaches, seat batches | -| Schedule | `/schedule` | Trips, fare rules, status updates | -| Search | `/search` | Trip search, fare quotes | -| Seats | `/seats` | Seat maps, holds, releases | -| Booking | `/bookings` | Create, retrieve, cancel bookings | -| Payment | `/payments` | Initiate payment, refunds, methods | -| Tickets | `/tickets` | QR ticket generation and validation | -| Passenger | `/passengers` | Profiles, traveler profiles, saved routes| -| Notifications | `/notifications` | In-app notifications | -| Loyalty | `/loyalty` | Points, tiers, rewards | -| Wallet | `/wallet` | Balance, top-up, ledger | -| Promotions | `/promos` | Active promos, promo code validation | -| Live Tracking | `/live` | Real-time trip status, crowd signals | -| Support | `/support` | FAQ, chat conversations | -| Dashboard | `/dashboard` | Home screen aggregate | +## 📚 API Documentation -## Seed Credentials +### Swagger UI +Interactive API documentation available at: **http://localhost:4000/api-docs** -After running `prisma:seed`: +### Authentication Methods -| Role | Email | Password | -| --------- | ------------------------ | ------------- | -| Passenger | `kelemu@email.com` | `password123` | -| Admin | `admin@edr-platform.com` | `admin123` | +The API uses two authentication schemes: -## Docker +#### 1. JWT Authentication (Passenger-facing) +- **Used for**: Passenger bookings, profile management, wallet, loyalty +- **Header**: `Authorization: Bearer ` +- **Obtain token**: `POST /auth/login` with passenger credentials +- **Swagger Security**: `JWT-auth` + +#### 2. IAM Authentication (Back-office) +- **Used for**: Agent operations, fraud detection, reports, admin functions +- **Header**: `Authorization: Bearer ` +- **Obtain token**: From corporate IAM system (https://iam.tria-plc.com) +- **Swagger Security**: `IAM-auth` +- **Roles**: AGENT, SUPERVISOR, ADMIN, STAFF + +### API Endpoints Overview + +| Module | Base Path | Auth Type | Description | +|--------|-----------|-----------|-------------| +| **Auth** | `/auth` | Public/JWT | Register, login, OTP verification, password reset | +| **Agents** | `/agents` | IAM | Agent booking, shifts, commissions, reconciliation | +| **Fraud Detection** | `/fraud` | IAM | Fraud alerts, rules management, user blocking | +| **Reports** | `/reports` | IAM | Revenue, occupancy, agent sales analytics | +| **Stations** | `/stations` | JWT | Station directory and information | +| **Fleet** | `/fleet` | JWT/IAM | Train services, coaches, seat configurations | +| **Schedules** | `/schedules` | JWT/IAM | Trip schedules, fare rules, status updates | +| **Search** | `/search` | JWT | Trip search, availability, fare quotes | +| **Seats** | `/seats` | JWT/IAM | Seat maps, holds, releases, blocking | +| **Bookings** | `/bookings` | JWT | Create, modify, cancel bookings | +| **Payments** | `/payments` | JWT/Public | Payment initiation, webhooks, refunds | +| **Tickets** | `/tickets` | JWT/IAM | Ticket generation, QR/barcode, validation | +| **Passengers** | `/passengers` | JWT | Profile management, traveler profiles | +| **Notifications** | `/notifications` | JWT | In-app notifications, preferences | +| **Loyalty** | `/loyalty` | JWT | Points, tiers, rewards redemption | +| **Wallet** | `/wallet` | JWT | Balance, top-up, transaction history | +| **Promotions** | `/promos` | JWT | Active promotions, promo code validation | +| **Live Tracking** | `/live` | JWT | Real-time trip status, crowd signals | +| **Support** | `/support` | JWT | FAQ, chat conversations | +| **Dashboard** | `/dashboard` | JWT | Home screen aggregated data | + +### Example API Calls + +#### 1. Register Passenger +```bash +POST /auth/register +Content-Type: application/json + +{ + "email": "user@example.com", + "phone": "+251911234567", + "fullName": "John Doe", + "password": "SecurePass123" +} +``` + +#### 2. Login (Passenger) +```bash +POST /auth/login +Content-Type: application/json + +{ + "email": "user@example.com", + "password": "SecurePass123" +} + +# Response includes JWT token +{ + "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", + "user": { "id": "uuid", "role": "PASSENGER" } +} +``` + +#### 2b. Agent Booking (IAM Auth) +```bash +POST /agents/bookings +Authorization: Bearer +Content-Type: application/json + +{ + "tripId": "uuid", + "seats": [...], + "paymentMethod": "CASH", + "cashReceived": 50000 +} +``` + +#### 3. Search Trips +```bash +GET /search/trips?originStationId={id}&destinationStationId={id}&date=2026-06-15 +Authorization: Bearer {token} +``` + +#### 4. Create Booking +```bash +POST /bookings +Authorization: Bearer {token} +Content-Type: application/json + +{ + "tripId": "uuid", + "seats": [ + { + "seatId": "uuid", + "passengerName": "John Doe", + "idDocumentType": "PASSPORT", + "idDocumentNumber": "ET123456" + } + ] +} +``` + +## 🏗️ Project Structure + +``` +apps/edr-passenger-api/ +├── prisma/ +│ ├── schema.prisma # Database schema (40+ models) +│ ├── seed.ts # Comprehensive seed script +│ └── migrations/ # Database migrations +├── src/ +│ ├── common/ # Shared utilities +│ │ ├── filters/ # Exception filters +│ │ ├── interceptors/ # Response interceptors +│ │ ├── pipes/ # Validation pipes +│ │ ├── i18n/ # Internationalization +│ │ ├── jwt.guard.ts # JWT authentication guard (passengers) +│ │ ├── jwt.strategy.ts # Passport JWT strategy +│ │ ├── iam-adapter.ts # Corporate IAM guard (back-office) +│ │ ├── iam.module.ts # IAM module +│ │ ├── roles.guard.ts # RBAC authorization guard +│ │ ├── roles.decorator.ts # Roles decorator +│ │ ├── prisma.service.ts # Prisma client service +│ │ └── prisma.module.ts # Prisma module +│ ├── config/ # Configuration files +│ │ ├── app.config.ts # App configuration +│ │ ├── database.config.ts # Database configuration +│ │ └── telebirr.config.ts # Payment provider config +│ ├── modules/ # Feature modules +│ │ ├── auth/ # Authentication & authorization (JWT) +│ │ ├── agents/ # Agent operations (IAM-protected) +│ │ ├── bookings/ # Booking management (JWT) +│ │ ├── dashboard/ # Dashboard aggregations (JWT) +│ │ ├── fleet/ # Train fleet management (JWT/IAM) +│ │ ├── fraud/ # Fraud detection (IAM-protected) +│ │ ├── live/ # Live tracking (JWT) +│ │ ├── loyalty/ # Loyalty program (JWT) +│ │ ├── notifications/ # Notification system (JWT) +│ │ ├── passengers/ # Passenger management (JWT) +│ │ ├── payments/ # Payment processing (JWT/Webhooks) +│ │ ├── promos/ # Promotions (JWT) +│ │ ├── reports/ # Reports & analytics (IAM-protected) +│ │ ├── schedules/ # Trip schedules (JWT/IAM) +│ │ ├── search/ # Trip search (JWT) +│ │ ├── seats/ # Seat management (JWT/IAM) +│ │ ├── segments/ # Journey segments (JWT) +│ │ ├── stations/ # Station management (JWT) +│ │ ├── support/ # Customer support (JWT) +│ │ ├── tickets/ # Ticketing (JWT/IAM) +│ │ └── wallet/ # Wallet system (JWT) +│ ├── app.module.ts # Root application module +│ └── main.ts # Application entry point +├── test/ # E2E tests +├── .env.example # Environment template +├── Dockerfile # Docker configuration +├── nest-cli.json # NestJS CLI configuration +├── package.json # Dependencies & scripts +├── tsconfig.json # TypeScript configuration +└── tsconfig.build.json # Build configuration +``` + +## 🗄️ Database Schema + +### Key Models (40+ total) + +**Core Entities:** +- `User`, `Session`, `Passenger`, `Agent` +- `Station`, `Route`, `RouteStop`, `RouteFareRule` +- `TrainService`, `Trip`, `TripStopTime`, `Coach`, `Seat` +- `Booking`, `BookingSeat`, `Ticket` +- `PaymentIntent`, `PaymentRefund`, `PaymentWebhookEvent` + +**Enhanced Features:** +- `OtpCode`, `PasswordResetToken` (Auth) +- `AgentBooking`, `AgentShift`, `AgentCommission` (Agents) +- `BookingModification`, `BookingCancellation` (Booking lifecycle) +- `GateValidationLog` (Ticket validation) +- `BaggageAllowance`, `BaggageBooking` (Baggage) +- `LoyaltyAccount`, `LoyaltyLedgerEntry`, `LoyaltyReward` +- `WalletAccount`, `WalletLedgerEntry` +- `Notification`, `NotificationTemplate` +- `AuditLog`, `OperationalReport` +- `SeatBlock`, `SeatHold` + +## 🔧 Available Scripts ```bash -# Build image (run from monorepo root) +# Development +pnpm --filter @edr/passenger-api run dev # Start with hot-reload + +# Build +pnpm --filter @edr/passenger-api run build # Compile TypeScript + +# Production +pnpm --filter @edr/passenger-api run start # Run compiled code + +# Testing +pnpm --filter @edr/passenger-api run test # Unit tests +pnpm --filter @edr/passenger-api run test:e2e # E2E tests + +# Code Quality +pnpm --filter @edr/passenger-api run lint # ESLint +pnpm --filter @edr/passenger-api run type-check # TypeScript check + +# Database +pnpm --filter @edr/passenger-api run prisma:generate # Generate Prisma client +pnpm --filter @edr/passenger-api run prisma:migrate # Run migrations +pnpm --filter @edr/passenger-api run prisma:seed # Seed database +``` + +## 🐳 Docker Deployment + +### Build Image +```bash +# From monorepo root docker build -f apps/edr-passenger-api/Dockerfile -t edr-passenger-api . - -# Run -docker run -p 4000:4000 --env-file apps/edr-passenger-api/.env edr-passenger-api ``` -## Scripts - -| Command | Description | -| ---------------------- | ------------------------------ | -| `pnpm dev` | Start with hot-reload | -| `pnpm build` | Compile to `dist/` | -| `pnpm start` | Run compiled output | -| `pnpm test` | Run unit tests | -| `pnpm lint` | ESLint | -| `pnpm type-check` | TypeScript type check | -| `pnpm prisma:generate` | Regenerate Prisma client | -| `pnpm prisma:migrate` | Run pending migrations | -| `pnpm prisma:seed` | Seed the database | - -## Project Structure - +### Run Container +```bash +docker run -d \ + --name edr-api \ + -p 4000:4000 \ + --env-file apps/edr-passenger-api/.env \ + edr-passenger-api ``` -src/ -├── common/ # PrismaService, JwtGuard, JwtStrategy, filters, interceptors -├── config/ # app.config.ts, database.config.ts -└── modules/ - ├── auth/ - ├── stations/ - ├── fleet/ - ├── schedules/ - ├── search/ - ├── seats/ - ├── bookings/ - ├── payments/ - ├── tickets/ - ├── passengers/ - ├── notifications/ - ├── loyalty/ - ├── wallet/ - ├── promos/ - ├── live/ - ├── support/ - └── dashboard/ -prisma/ -├── schema.prisma -├── seed.ts -└── migrations/ + +### Docker Compose (Recommended) +```yaml +version: '3.8' +services: + postgres: + image: postgres:15 + environment: + POSTGRES_USER: edr + POSTGRES_PASSWORD: edr_secret + POSTGRES_DB: edr_passenger + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + + api: + build: + context: . + dockerfile: apps/edr-passenger-api/Dockerfile + ports: + - "4000:4000" + environment: + DATABASE_URL: postgresql://edr:edr_secret@postgres:5432/edr_passenger + JWT_SECRET: your-secret-key + PORT: 4000 + depends_on: + - postgres + +volumes: + postgres_data: ``` + +## 🔒 Security Best Practices + +1. **Environment Variables** - Never commit `.env` files. Use secrets management in production. +2. **JWT Secret** - Use strong, randomly generated secrets (min 32 characters). +3. **Password Hashing** - Bcrypt with salt rounds (default: 10). +4. **Rate Limiting** - Implement rate limiting for auth endpoints. +5. **CORS** - Configure allowed origins in production. +6. **HTTPS** - Always use HTTPS in production. +7. **Database** - Use connection pooling and prepared statements (Prisma handles this). +8. **Audit Logging** - All sensitive operations are logged in `AuditLog` table. +9. **Dual Authentication** - Passenger routes use JWT, back-office routes use corporate IAM. +10. **IAM Integration** - Corporate IAM validates tokens against centralized identity service. +11. **Role-Based Access** - Granular permissions enforced via IAM roles (AGENT, SUPERVISOR, ADMIN). +12. **Token Validation** - IAM tokens validated in real-time with 5-second timeout. + +## 📊 Monitoring & Logging + +- **Application Logs** - NestJS built-in logger +- **Database Queries** - Prisma query logging (enable in development) +- **Audit Trail** - All user actions logged in `AuditLog` table +- **Error Tracking** - Global exception filters with detailed error responses + +## 🧪 Testing + +```bash +# Unit tests +pnpm --filter @edr/passenger-api run test + +# E2E tests +pnpm --filter @edr/passenger-api run test:e2e + +# Test coverage +pnpm --filter @edr/passenger-api run test:cov +``` + +## 🚀 Production Deployment + +### Pre-deployment Checklist +- [ ] Update environment variables (JWT_SECRET, DATABASE_URL, etc.) +- [ ] Configure IAM integration (IAM_ENABLED=true, IAM_API_URL, IAM_API_KEY) +- [ ] Set NODE_ENV=production +- [ ] Configure CORS origins (FRONTEND_URL, PORTAL_URL) +- [ ] Set up SSL/TLS certificates +- [ ] Configure database connection pooling +- [ ] Set up monitoring and logging +- [ ] Configure backup strategy +- [ ] Test payment provider integrations +- [ ] Verify IAM token validation endpoint +- [ ] Review security settings and audit logs +- [ ] Test both JWT and IAM authentication flows + +### Deployment Steps +```bash +# 1. Build application +pnpm --filter @edr/passenger-api run build + +# 2. Run migrations +pnpm --filter @edr/passenger-api run prisma:migrate + +# 3. Start production server +NODE_ENV=production pnpm --filter @edr/passenger-api run start:prod +``` + +## 🤝 Contributing + +1. Fork the repository +2. Create feature branch (`git checkout -b feature/amazing-feature`) +3. Commit changes (`git commit -m 'Add amazing feature'`) +4. Push to branch (`git push origin feature/amazing-feature`) +5. Open Pull Request + +## 📝 License + +This project is proprietary and confidential. + +## 📧 Support + +For technical support or questions: +- Email: support@edr-platform.com +- Documentation: http://localhost:4000/api-docs + +--- + +**Built with ❤️ for Ethio-Djibouti Railway** diff --git a/apps/edr-passenger-api/.env.example b/apps/edr-passenger-api/.env.example index fa6f76e90..d3f17cdd1 100644 --- a/apps/edr-passenger-api/.env.example +++ b/apps/edr-passenger-api/.env.example @@ -17,6 +17,19 @@ JWT_EXPIRES_IN=7d SENDGRID_API_KEY= SENDGRID_FROM_EMAIL=noreply@edr-platform.com +# SMS Configuration +SMS_PROVIDER=twilio +SMS_API_KEY= + +# Twilio (if SMS_PROVIDER=twilio) +TWILIO_ACCOUNT_SID= +TWILIO_AUTH_TOKEN= +TWILIO_FROM_NUMBER= + +# Africa's Talking (if SMS_PROVIDER=africastalking) +AFRICASTALKING_USERNAME= +AFRICASTALKING_FROM= + # Telebirr TELEBIRR_BASE_URL= TELEBIRR_WEB_BASE_URL= @@ -29,4 +42,41 @@ TELEBIRR_RETURN_URL= TELEBIRR_TIMEOUT_EXPRESS=15m TELEBIRR_PRIVATE_KEY= TELEBIRR_PUBLIC_KEY= -TELEBIRR_INSECURE_TLS=false \ No newline at end of file +TELEBIRR_INSECURE_TLS=false + +# CBE Birr +CBE_BASE_URL= +CBE_MERCHANT_ID= +CBE_SECRET_KEY= +CBE_NOTIFY_URL= +CBE_RETURN_URL= + +# eBirr +EBIRR_BASE_URL= +EBIRR_MERCHANT_CODE= +EBIRR_SECRET_KEY= +EBIRR_NOTIFY_URL= +EBIRR_RETURN_URL= + +# Card Gateway (Stripe-like) +CARD_BASE_URL= +CARD_API_KEY= +CARD_WEBHOOK_SECRET= +CARD_WEBHOOK_URL= +CARD_RETURN_URL= + +# Payment Configuration +PAYMENT_PROVIDERS_ENABLED=TELEBIRR,CBE_BIRR,EBIRR,CARD,WALLET + +# Session Configuration +SESSION_INACTIVITY_MINUTES=30 + +# i18n Configuration +DEFAULT_LOCALE=en +SUPPORTED_LOCALES=en,am,fr,om + +# Corporate IAM Configuration (for back-office authentication) +IAM_ENABLED=false +IAM_API_URL=https://iam.tria-plc.com/api +IAM_API_KEY= +GITHUB_PACKAGE_TOKEN= \ No newline at end of file diff --git a/apps/edr-passenger-api/.npmrc b/apps/edr-passenger-api/.npmrc new file mode 100644 index 000000000..f1a000f80 --- /dev/null +++ b/apps/edr-passenger-api/.npmrc @@ -0,0 +1,6 @@ +# GitHub Packages configuration for @tria-plc scope +@tria-plc:registry=https://npm.pkg.github.com +//npm.pkg.github.com/:_authToken=${GITHUB_PACKAGE_TOKEN} + +# Default registry for other packages +registry=https://registry.npmjs.org/ diff --git a/apps/edr-passenger-api/SEGMENT_BASED_SEATS.md b/apps/edr-passenger-api/SEGMENT_BASED_SEATS.md deleted file mode 100644 index d1d1a6212..000000000 --- a/apps/edr-passenger-api/SEGMENT_BASED_SEATS.md +++ /dev/null @@ -1,364 +0,0 @@ -# Segment-Based Seat Reservation - -## Overview - -This implementation introduces segment-based seat reservation and release logic for the Ethio-Djibouti Railway passenger booking system. It allows passengers to book partial journeys while ensuring optimal seat utilization through automatic release when passengers reach their destinations. - -## Key Features - -- **Segment-based reservations**: Book seats for specific route segments (e.g., Addis Ababa → Dire Dawa) -- **Automatic seat release**: Seats are released when passengers reach their destination -- **Concurrency control**: Database transactions ensure consistency -- **Real-time updates**: Event-driven notifications for seat availability changes -- **Hold expiration**: Automatic cleanup of expired seat holds - -## Route Example - -**Full Route**: Addis Ababa → Adama → Awash → Dire Dawa → Djibouti - -**Passenger Journey**: Addis Ababa → Dire Dawa -- **Segments**: [Addis→Adama, Adama→Awash, Awash→Dire Dawa] -- **Seat Status**: HELD → BOOKED → AVAILABLE (when reaching Dire Dawa) - -## Database Schema Integration - -### Core Tables Used - -```sql --- Trip and route structure -Trip, TripStopTime, Station - --- Seat management -Seat, SeatHold, BookingSeat, Booking - --- Journey tracking -JourneySegment (stores segment-to-seat mapping) - --- Real-time progress -TripLiveStatus (triggers seat releases) -``` - -### Key Enums - -```typescript -enum SeatStatus { - AVAILABLE = 'AVAILABLE', - HELD = 'HELD', - BOOKED = 'BOOKED', - BLOCKED = 'BLOCKED' -} -``` - -## API Endpoints - -### 1. Check Seat Availability - -```http -GET /segments/seats/availability?tripId=trip_001&originStationId=st_ADD&destinationStationId=st_DRE -``` - -**Response:** -```json -{ - "segments": [ - { "fromName": "Addis Ababa", "toName": "Adama", "fromSequence": 0, "toSequence": 1 }, - { "fromName": "Adama", "toName": "Awash", "fromSequence": 1, "toSequence": 2 }, - { "fromName": "Awash", "toName": "Dire Dawa", "fromSequence": 2, "toSequence": 3 } - ], - "availableSeats": [ - { "id": "seat_1", "label": "1A", "coach": "A", "serviceClass": "ECONOMY" } - ], - "totalAvailable": 1 -} -``` - -### 2. Hold Seats - -```http -POST /segments/seats/hold -``` - -**Request:** -```json -{ - "tripId": "trip_001", - "seatIds": ["seat_1", "seat_2"], - "passengerId": "passenger_123", - "originStationId": "st_ADD", - "destinationStationId": "st_DRE", - "fareQuoteId": "quote_456" -} -``` - -**Response:** -```json -{ - "holdId": "hold_789", - "expiresAt": "2024-01-15T10:10:00Z", - "segments": [ - { "fromName": "Addis Ababa", "toName": "Adama" }, - { "fromName": "Adama", "toName": "Awash" }, - { "fromName": "Awash", "toName": "Dire Dawa" } - ], - "seats": ["seat_1", "seat_2"] -} -``` - -### 3. Confirm Booking - -```http -POST /segments/seats/confirm -``` - -**Request:** -```json -{ - "holdId": "hold_789", - "bookingId": "booking_123" -} -``` - -### 4. Release Seats (Automatic) - -```http -POST /segments/seats/release -``` - -**Request:** -```json -{ - "tripId": "trip_001", - "currentStationId": "st_DRE" -} -``` - -## Database Transaction Flow - -### 1. Seat Hold Transaction - -```typescript -async function holdSeatsTransaction(request: SeatHoldRequest) { - return prisma.$transaction(async (tx) => { - // 1. Validate seat availability - const seats = await tx.seat.findMany({ - where: { id: { in: request.seatIds } } - }); - - // 2. Check for overlapping reservations - for (const seatId of request.seatIds) { - const overlaps = await checkOverlaps(tx, tripId, seatId, segments); - if (overlaps.length > 0) throw new ConflictException(); - } - - // 3. Create hold record - const hold = await tx.seatHold.create({ - data: { - tripId: request.tripId, - seatIds: request.seatIds, - passengerId: request.passengerId, - expiresAt: new Date(Date.now() + 10 * 60 * 1000) - } - }); - - // 4. Update seat status - await tx.seat.updateMany({ - where: { id: { in: request.seatIds } }, - data: { status: 'HELD', heldUntil: hold.expiresAt } - }); - - return hold; - }); -} -``` - -### 2. Booking Confirmation Transaction - -```typescript -async function confirmBookingTransaction(holdId: string, bookingId: string) { - return prisma.$transaction(async (tx) => { - // 1. Validate hold - const hold = await tx.seatHold.findUnique({ where: { id: holdId } }); - if (!hold || hold.expiresAt < new Date()) { - throw new BadRequestException('Hold expired'); - } - - // 2. Create journey segments - for (const seatId of hold.seatIds) { - for (let i = 0; i < segments.length; i++) { - await tx.journeySegment.create({ - data: { - journeyId: bookingId, - tripId: hold.tripId, - segmentOrder: i + 1, - seatId, - departureStationId: segments[i].fromStationId, - arrivalStationId: segments[i].toStationId - } - }); - } - } - - // 3. Update seat status to BOOKED - await tx.seat.updateMany({ - where: { id: { in: hold.seatIds } }, - data: { status: 'BOOKED', heldUntil: null } - }); - - // 4. Delete hold - await tx.seatHold.delete({ where: { id: holdId } }); - - return { bookingId, confirmedSeats: hold.seatIds }; - }); -} -``` - -### 3. Seat Release Transaction - -```typescript -async function releaseSeatsTransaction(tripId: string, currentStationId: string) { - return prisma.$transaction(async (tx) => { - // 1. Find completed journey segments - const completedSegments = await tx.journeySegment.findMany({ - where: { tripId, arrivalStationId: currentStationId }, - include: { journey: { include: { journeySegments: true } } } - }); - - const seatsToRelease = []; - - // 2. Check if passenger's entire journey is complete - for (const segment of completedSegments) { - const allSegments = segment.journey.journeySegments - .filter(js => js.seatId === segment.seatId); - const maxOrder = Math.max(...allSegments.map(js => js.segmentOrder)); - - if (segment.segmentOrder === maxOrder) { - seatsToRelease.push(segment.seatId); - } - } - - // 3. Release seats - if (seatsToRelease.length > 0) { - await tx.seat.updateMany({ - where: { id: { in: seatsToRelease } }, - data: { status: 'AVAILABLE' } - }); - } - - return { releasedSeats: seatsToRelease }; - }); -} -``` - -## Real-Time Integration - -### Trip Progress Updates - -```typescript -// When train reaches a station -await tripProgressService.updateTripProgress(tripId, stationId, progressPercent); - -// Automatically triggers seat release -this.eventEmitter.emit('trip.station.arrived', { - tripId, - stationId, - stationName: 'Dire Dawa' -}); -``` - -### Event Listeners - -```typescript -@OnEvent('trip.station.arrived') -async handleStationArrival(payload: { tripId: string, stationId: string }) { - await this.enhancedSeatsService.releaseSeats(payload.tripId, payload.stationId); -} - -@OnEvent('seats.released') -async handleSeatsReleased(payload: { releasedSeats: string[] }) { - // Notify waiting passengers about newly available seats - this.notificationService.notifyAvailability(payload.releasedSeats); -} -``` - -## Background Jobs - -### Hold Expiration (Every Minute) - -```typescript -@Cron(CronExpression.EVERY_MINUTE) -async expireHolds() { - const expired = await this.prisma.seatHold.findMany({ - where: { expiresAt: { lt: new Date() } } - }); - - // Release expired seats - await this.prisma.seat.updateMany({ - where: { id: { in: expiredSeatIds } }, - data: { status: 'AVAILABLE', heldUntil: null } - }); -} -``` - -## Usage Examples - -### Complete Booking Flow - -```typescript -// 1. Check availability -const availability = await segmentSeatsService.getSeatAvailability( - 'trip_001', 'st_ADD', 'st_DRE' -); - -// 2. Hold seats (10-minute expiry) -const hold = await segmentSeatsService.holdSeats({ - tripId: 'trip_001', - seatIds: ['seat_1'], - passengerId: 'passenger_123', - originStationId: 'st_ADD', - destinationStationId: 'st_DRE' -}); - -// 3. Process payment... -await paymentService.processPayment(bookingId); - -// 4. Confirm booking -const booking = await segmentSeatsService.confirmBooking({ - holdId: hold.holdId, - bookingId: 'booking_456' -}); - -// 5. Seats automatically released when train reaches Dire Dawa -``` - -## Error Handling - -- **Seat Conflicts**: `ConflictException` when seats overlap with existing reservations -- **Expired Holds**: `BadRequestException` when trying to confirm expired holds -- **Invalid Segments**: `BadRequestException` for invalid origin/destination combinations -- **Transaction Rollback**: Automatic rollback on any failure within transactions - -## Performance Considerations - -- **Indexing**: Ensure indexes on `tripId`, `seatId`, `stationId`, `expiresAt` -- **Batch Operations**: Use `updateMany` for bulk seat status updates -- **Event Queuing**: Consider message queues for high-volume seat release events -- **Caching**: Cache frequently accessed route/station data - -## Integration Notes - -1. **Existing Booking System**: Extends current booking flow with segment awareness -2. **Payment Integration**: Hold expiry provides payment processing window -3. **Real-time Updates**: WebSocket notifications for seat availability changes -4. **Mobile Apps**: Push notifications when seats become available on preferred routes -5. **Analytics**: Track seat utilization patterns by segment for route optimization - -## Testing - -Run the example booking flow: - -```bash -cd apps/edr-passenger-api -npx ts-node src/modules/segments/booking-flow-example.ts -``` - -This demonstrates the complete segment-based reservation lifecycle with database transactions and real-time seat releases. \ No newline at end of file diff --git a/apps/edr-passenger-api/package.json b/apps/edr-passenger-api/package.json index 66558965a..122a7897f 100644 --- a/apps/edr-passenger-api/package.json +++ b/apps/edr-passenger-api/package.json @@ -29,7 +29,6 @@ "@nestjs/platform-express": "^11.1.19", "@nestjs/schedule": "^6.1.3", "@nestjs/swagger": "^7.4.0", - "@prisma/client": "^5.8.0", "@sendgrid/mail": "^8.1.0", "axios": "^1.7.7", "bcrypt": "^5.1.1", @@ -49,6 +48,7 @@ "@nestjs/cli": "^11.0.21", "@nestjs/schematics": "^11.1.0", "@nestjs/testing": "^11.1.19", + "@prisma/client": "^6.19.3", "@types/bcrypt": "^5.0.2", "@types/jest": "^29.5.11", "@types/node": "^20.10.6", @@ -56,7 +56,7 @@ "@types/qrcode": "^1.5.5", "@types/supertest": "^6.0.2", "jest": "^29.7.0", - "prisma": "^5.8.0", + "prisma": "^6.19.3", "supertest": "^7.0.0", "ts-jest": "^29.1.1", "ts-node": "^10.9.2", diff --git a/apps/edr-passenger-api/prisma/migrations/20260515133041_segment_updates/migration.sql b/apps/edr-passenger-api/prisma/migrations/20260515133041_segment_updates/migration.sql deleted file mode 100644 index e1091458f..000000000 --- a/apps/edr-passenger-api/prisma/migrations/20260515133041_segment_updates/migration.sql +++ /dev/null @@ -1,31 +0,0 @@ --- CreateTable -CREATE TABLE "Journey" ( - "id" TEXT NOT NULL, - "passengerId" TEXT NOT NULL, - "status" TEXT NOT NULL, - "totalMinor" INTEGER NOT NULL, - "currency" TEXT NOT NULL DEFAULT 'ETB', - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "Journey_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "JourneySegment" ( - "id" TEXT NOT NULL, - "journeyId" TEXT NOT NULL, - "tripId" TEXT NOT NULL, - "segmentOrder" INTEGER NOT NULL, - "seatId" TEXT, - "coachId" TEXT, - "departureStationId" TEXT NOT NULL, - "arrivalStationId" TEXT NOT NULL, - - CONSTRAINT "JourneySegment_pkey" PRIMARY KEY ("id") -); - --- AddForeignKey -ALTER TABLE "JourneySegment" ADD CONSTRAINT "JourneySegment_journeyId_fkey" FOREIGN KEY ("journeyId") REFERENCES "Journey"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "JourneySegment" ADD CONSTRAINT "JourneySegment_tripId_fkey" FOREIGN KEY ("tripId") REFERENCES "Trip"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/apps/edr-passenger-api/prisma/migrations/20260516170103_add_telebirr_async_fields/migration.sql b/apps/edr-passenger-api/prisma/migrations/20260516170103_add_telebirr_async_fields/migration.sql deleted file mode 100644 index d3cd87873..000000000 --- a/apps/edr-passenger-api/prisma/migrations/20260516170103_add_telebirr_async_fields/migration.sql +++ /dev/null @@ -1,63 +0,0 @@ -/* - Warnings: - - - A unique constraint covering the columns `[merchantOrderId]` on the table `PaymentIntent` will be added. If there are existing duplicate values, this will fail. - -*/ --- AlterTable -ALTER TABLE "PaymentIntent" ADD COLUMN "expiresAt" TIMESTAMP(3), -ADD COLUMN "failureCode" TEXT, -ADD COLUMN "failureMessage" TEXT, -ADD COLUMN "merchantOrderId" TEXT, -ADD COLUMN "paidAt" TIMESTAMP(3), -ADD COLUMN "providerOrderId" TEXT, -ADD COLUMN "providerTxnId" TEXT, -ADD COLUMN "rawInitiation" JSONB; - --- CreateTable -CREATE TABLE "PaymentWebhookEvent" ( - "id" TEXT NOT NULL, - "provider" "PaymentMethodType" NOT NULL, - "externalEventId" TEXT NOT NULL, - "merchantOrderId" TEXT, - "providerTxnId" TEXT, - "signatureValid" BOOLEAN NOT NULL, - "status" TEXT NOT NULL, - "payload" JSONB NOT NULL, - "receivedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "processedAt" TIMESTAMP(3), - "processingError" TEXT, - - CONSTRAINT "PaymentWebhookEvent_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "PaymentRefund" ( - "id" TEXT NOT NULL, - "paymentIntentId" TEXT NOT NULL, - "amountMinor" INTEGER NOT NULL, - "reason" TEXT, - "providerRefundId" TEXT, - "status" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "PaymentRefund_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE INDEX "PaymentWebhookEvent_merchantOrderId_idx" ON "PaymentWebhookEvent"("merchantOrderId"); - --- CreateIndex -CREATE UNIQUE INDEX "PaymentWebhookEvent_provider_externalEventId_key" ON "PaymentWebhookEvent"("provider", "externalEventId"); - --- CreateIndex -CREATE UNIQUE INDEX "PaymentIntent_merchantOrderId_key" ON "PaymentIntent"("merchantOrderId"); - --- CreateIndex -CREATE INDEX "PaymentIntent_providerOrderId_idx" ON "PaymentIntent"("providerOrderId"); - --- CreateIndex -CREATE INDEX "PaymentIntent_providerTxnId_idx" ON "PaymentIntent"("providerTxnId"); - --- AddForeignKey -ALTER TABLE "PaymentRefund" ADD CONSTRAINT "PaymentRefund_paymentIntentId_fkey" FOREIGN KEY ("paymentIntentId") REFERENCES "PaymentIntent"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/apps/edr-passenger-api/prisma/migrations/20260513080558_initial_migration/migration.sql b/apps/edr-passenger-api/prisma/migrations/20260519124728_initial_migration/migration.sql similarity index 59% rename from apps/edr-passenger-api/prisma/migrations/20260513080558_initial_migration/migration.sql rename to apps/edr-passenger-api/prisma/migrations/20260519124728_initial_migration/migration.sql index 5ba579dca..17c28678c 100644 --- a/apps/edr-passenger-api/prisma/migrations/20260513080558_initial_migration/migration.sql +++ b/apps/edr-passenger-api/prisma/migrations/20260519124728_initial_migration/migration.sql @@ -1,5 +1,5 @@ -- CreateEnum -CREATE TYPE "UserRole" AS ENUM ('PASSENGER', 'ADMIN', 'STAFF'); +CREATE TYPE "UserRole" AS ENUM ('PASSENGER', 'AGENT', 'SUPERVISOR', 'ADMIN', 'STAFF'); -- CreateEnum CREATE TYPE "TripStatus" AS ENUM ('SCHEDULED', 'BOARDING', 'EN_ROUTE', 'ARRIVED', 'CANCELLED', 'DELAYED'); @@ -11,16 +11,16 @@ CREATE TYPE "SeatKind" AS ENUM ('STANDARD', 'PREMIUM', 'ACCESSIBLE'); CREATE TYPE "SeatStatus" AS ENUM ('AVAILABLE', 'HELD', 'BOOKED', 'BLOCKED'); -- CreateEnum -CREATE TYPE "ServiceClass" AS ENUM ('ECONOMY', 'BUSINESS', 'FIRST'); +CREATE TYPE "ServiceClass" AS ENUM ('ECONOMY_REGULAR', 'ECONOMY_BED_LOWER', 'ECONOMY_BED_MIDDLE', 'ECONOMY_BED_UPPER', 'VIP_BED_LOWER', 'VIP_BED_UPPER'); -- CreateEnum -CREATE TYPE "BookingStatus" AS ENUM ('DRAFT', 'PENDING_PAYMENT', 'CONFIRMED', 'CANCELLED', 'COMPLETED', 'NO_SHOW'); +CREATE TYPE "BookingStatus" AS ENUM ('DRAFT', 'PENDING_PAYMENT', 'CONFIRMED', 'CANCELLED', 'COMPLETED', 'NO_SHOW', 'REFUNDED'); -- CreateEnum CREATE TYPE "PaymentMethodType" AS ENUM ('TELEBIRR', 'CBE_BIRR', 'EBIRR', 'CARD', 'WALLET'); -- CreateEnum -CREATE TYPE "PaymentIntentStatus" AS ENUM ('REQUIRES_ACTION', 'PROCESSING', 'SUCCEEDED', 'FAILED', 'CANCELLED'); +CREATE TYPE "PaymentIntentStatus" AS ENUM ('REQUIRES_ACTION', 'PROCESSING', 'SUCCEEDED', 'FAILED', 'CANCELLED', 'REFUNDED'); -- CreateEnum CREATE TYPE "WalletLedgerType" AS ENUM ('CREDIT', 'DEBIT'); @@ -57,6 +57,11 @@ CREATE TABLE "User" ( "fullName" TEXT NOT NULL, "passwordHash" TEXT NOT NULL, "role" "UserRole" NOT NULL DEFAULT 'PASSENGER', + "nationality" TEXT, + "passportNumber" TEXT, + "nationalId" TEXT, + "failedLoginAttempts" INTEGER NOT NULL DEFAULT 0, + "lockedUntil" TIMESTAMP(3), "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updatedAt" TIMESTAMP(3) NOT NULL, @@ -69,6 +74,9 @@ CREATE TABLE "Session" ( "userId" TEXT NOT NULL, "token" TEXT NOT NULL, "expiresAt" TIMESTAMP(3) NOT NULL, + "ipAddress" TEXT, + "userAgent" TEXT, + "lastActivityAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "Session_pkey" PRIMARY KEY ("id") @@ -186,6 +194,8 @@ CREATE TABLE "Seat" ( "kind" "SeatKind" NOT NULL DEFAULT 'STANDARD', "status" "SeatStatus" NOT NULL DEFAULT 'AVAILABLE', "heldUntil" TIMESTAMP(3), + "premiumFeeMinor" INTEGER NOT NULL DEFAULT 0, + "eligibility" TEXT, CONSTRAINT "Seat_pkey" PRIMARY KEY ("id") ); @@ -228,6 +238,7 @@ CREATE TABLE "Booking" ( "status" "BookingStatus" NOT NULL DEFAULT 'DRAFT', "currency" TEXT NOT NULL DEFAULT 'ETB', "totalMinor" INTEGER NOT NULL, + "bookingType" TEXT NOT NULL DEFAULT 'ONE_WAY', "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updatedAt" TIMESTAMP(3) NOT NULL, @@ -269,12 +280,50 @@ CREATE TABLE "PaymentIntent" ( "status" "PaymentIntentStatus" NOT NULL DEFAULT 'REQUIRES_ACTION', "providerRef" TEXT, "clientAction" JSONB, + "merchantOrderId" TEXT, + "providerOrderId" TEXT, + "providerTxnId" TEXT, + "rawInitiation" JSONB, + "paidAt" TIMESTAMP(3), + "failureCode" TEXT, + "failureMessage" TEXT, + "expiresAt" TIMESTAMP(3), "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updatedAt" TIMESTAMP(3) NOT NULL, CONSTRAINT "PaymentIntent_pkey" PRIMARY KEY ("id") ); +-- CreateTable +CREATE TABLE "PaymentWebhookEvent" ( + "id" TEXT NOT NULL, + "provider" "PaymentMethodType" NOT NULL, + "externalEventId" TEXT NOT NULL, + "merchantOrderId" TEXT, + "providerTxnId" TEXT, + "signatureValid" BOOLEAN NOT NULL, + "status" TEXT NOT NULL, + "payload" JSONB NOT NULL, + "receivedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "processedAt" TIMESTAMP(3), + "processingError" TEXT, + + CONSTRAINT "PaymentWebhookEvent_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "PaymentRefund" ( + "id" TEXT NOT NULL, + "paymentIntentId" TEXT NOT NULL, + "amountMinor" INTEGER NOT NULL, + "reason" TEXT, + "providerRefundId" TEXT, + "status" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "PaymentRefund_pkey" PRIMARY KEY ("id") +); + -- CreateTable CREATE TABLE "Ticket" ( "id" TEXT NOT NULL, @@ -282,6 +331,9 @@ CREATE TABLE "Ticket" ( "bookingRef" TEXT NOT NULL, "status" TEXT NOT NULL DEFAULT 'CONFIRMED', "qrPayload" TEXT NOT NULL, + "barcodePayload" TEXT, + "pdfUrl" TEXT, + "deliveryChannel" TEXT NOT NULL DEFAULT 'EMAIL', "issuedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "validatedAt" TIMESTAMP(3), "validatorId" TEXT, @@ -508,6 +560,7 @@ CREATE TABLE "UserPreferences" ( "dataSharing" BOOLEAN NOT NULL DEFAULT false, "locale" TEXT NOT NULL DEFAULT 'en', "darkMode" BOOLEAN NOT NULL DEFAULT false, + "language" TEXT NOT NULL DEFAULT 'en', CONSTRAINT "UserPreferences_pkey" PRIMARY KEY ("id") ); @@ -539,6 +592,279 @@ CREATE TABLE "SavedRoute" ( CONSTRAINT "SavedRoute_pkey" PRIMARY KEY ("id") ); +-- CreateTable +CREATE TABLE "Journey" ( + "id" TEXT NOT NULL, + "passengerId" TEXT NOT NULL, + "status" TEXT NOT NULL, + "totalMinor" INTEGER NOT NULL, + "currency" TEXT NOT NULL DEFAULT 'ETB', + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "Journey_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "JourneySegment" ( + "id" TEXT NOT NULL, + "journeyId" TEXT NOT NULL, + "tripId" TEXT NOT NULL, + "segmentOrder" INTEGER NOT NULL, + "seatId" TEXT, + "coachId" TEXT, + "departureStationId" TEXT NOT NULL, + "arrivalStationId" TEXT NOT NULL, + + CONSTRAINT "JourneySegment_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "OtpCode" ( + "id" TEXT NOT NULL, + "userId" TEXT, + "email" TEXT, + "phone" TEXT, + "code" TEXT NOT NULL, + "purpose" TEXT NOT NULL, + "expiresAt" TIMESTAMP(3) NOT NULL, + "verified" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "OtpCode_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "PasswordResetToken" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "token" TEXT NOT NULL, + "expiresAt" TIMESTAMP(3) NOT NULL, + "used" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "PasswordResetToken_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Route" ( + "id" TEXT NOT NULL, + "code" TEXT NOT NULL, + "name" TEXT NOT NULL, + "description" TEXT, + "effectiveFrom" TIMESTAMP(3) NOT NULL, + "effectiveUntil" TIMESTAMP(3), + "active" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "Route_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "RouteStop" ( + "id" TEXT NOT NULL, + "routeId" TEXT NOT NULL, + "stationId" TEXT NOT NULL, + "sequence" INTEGER NOT NULL, + "distanceKm" INTEGER, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "RouteStop_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "RouteFareRule" ( + "id" TEXT NOT NULL, + "routeId" TEXT NOT NULL, + "serviceClass" "ServiceClass" NOT NULL, + "passengerCategory" TEXT NOT NULL DEFAULT 'ADULT', + "baseFareMinor" INTEGER NOT NULL, + "discountPercent" INTEGER, + "currency" TEXT NOT NULL DEFAULT 'ETB', + "validFrom" TIMESTAMP(3) NOT NULL, + "validUntil" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "RouteFareRule_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Agent" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "agentCode" TEXT NOT NULL, + "stationId" TEXT, + "commissionRate" INTEGER NOT NULL DEFAULT 5, + "active" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "Agent_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "AgentBooking" ( + "id" TEXT NOT NULL, + "agentId" TEXT NOT NULL, + "bookingId" TEXT NOT NULL, + "paymentMethod" TEXT NOT NULL, + "cashReceived" INTEGER, + "changeGiven" INTEGER, + "paperTicket" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "AgentBooking_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "AgentShift" ( + "id" TEXT NOT NULL, + "agentId" TEXT NOT NULL, + "openedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "closedAt" TIMESTAMP(3), + "openingBalance" INTEGER NOT NULL DEFAULT 0, + "closingBalance" INTEGER, + "reconciled" BOOLEAN NOT NULL DEFAULT false, + "notes" TEXT, + + CONSTRAINT "AgentShift_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "AgentCommission" ( + "id" TEXT NOT NULL, + "agentId" TEXT NOT NULL, + "bookingId" TEXT NOT NULL, + "amountMinor" INTEGER NOT NULL, + "rate" INTEGER NOT NULL, + "paidAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "AgentCommission_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "BookingModification" ( + "id" TEXT NOT NULL, + "bookingId" TEXT NOT NULL, + "modifiedBy" TEXT NOT NULL, + "modificationType" TEXT NOT NULL, + "oldData" JSONB NOT NULL, + "newData" JSONB NOT NULL, + "fareAdjustment" INTEGER NOT NULL DEFAULT 0, + "reason" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "BookingModification_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "BookingCancellation" ( + "id" TEXT NOT NULL, + "bookingId" TEXT NOT NULL, + "cancelledBy" TEXT NOT NULL, + "reason" TEXT, + "refundAmount" INTEGER NOT NULL, + "refundMethod" TEXT NOT NULL, + "refundStatus" TEXT NOT NULL, + "processedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "BookingCancellation_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "GateValidationLog" ( + "id" TEXT NOT NULL, + "ticketId" TEXT NOT NULL, + "validatorId" TEXT NOT NULL, + "gateId" TEXT, + "status" TEXT NOT NULL, + "reason" TEXT, + "validatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "GateValidationLog_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "BaggageAllowance" ( + "id" TEXT NOT NULL, + "serviceClass" "ServiceClass" NOT NULL, + "maxWeightKg" INTEGER NOT NULL, + "maxPiecesCount" INTEGER NOT NULL, + "excessFeePerKg" INTEGER NOT NULL, + "currency" TEXT NOT NULL DEFAULT 'ETB', + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "BaggageAllowance_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "BaggageBooking" ( + "id" TEXT NOT NULL, + "bookingId" TEXT NOT NULL, + "weightKg" INTEGER NOT NULL, + "piecesCount" INTEGER NOT NULL, + "excessFeeMinor" INTEGER NOT NULL DEFAULT 0, + "paid" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "BaggageBooking_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "AuditLog" ( + "id" TEXT NOT NULL, + "userId" TEXT, + "action" TEXT NOT NULL, + "entityType" TEXT NOT NULL, + "entityId" TEXT, + "oldData" JSONB, + "newData" JSONB, + "ipAddress" TEXT, + "userAgent" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "AuditLog_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "NotificationTemplate" ( + "id" TEXT NOT NULL, + "code" TEXT NOT NULL, + "channel" TEXT NOT NULL, + "subject" TEXT, + "bodyTemplate" TEXT NOT NULL, + "active" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "NotificationTemplate_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "SeatBlock" ( + "id" TEXT NOT NULL, + "seatId" TEXT NOT NULL, + "reason" TEXT NOT NULL, + "blockedBy" TEXT NOT NULL, + "approvedBy" TEXT, + "blockedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "unblockAt" TIMESTAMP(3), + + CONSTRAINT "SeatBlock_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "OperationalReport" ( + "id" TEXT NOT NULL, + "reportType" TEXT NOT NULL, + "dateFrom" TIMESTAMP(3) NOT NULL, + "dateTo" TIMESTAMP(3) NOT NULL, + "data" JSONB NOT NULL, + "generatedBy" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "OperationalReport_pkey" PRIMARY KEY ("id") +); + -- CreateIndex CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); @@ -575,6 +901,21 @@ CREATE UNIQUE INDEX "Booking_bookingRef_key" ON "Booking"("bookingRef"); -- CreateIndex CREATE UNIQUE INDEX "PaymentIntent_bookingId_key" ON "PaymentIntent"("bookingId"); +-- CreateIndex +CREATE UNIQUE INDEX "PaymentIntent_merchantOrderId_key" ON "PaymentIntent"("merchantOrderId"); + +-- CreateIndex +CREATE INDEX "PaymentIntent_providerOrderId_idx" ON "PaymentIntent"("providerOrderId"); + +-- CreateIndex +CREATE INDEX "PaymentIntent_providerTxnId_idx" ON "PaymentIntent"("providerTxnId"); + +-- CreateIndex +CREATE INDEX "PaymentWebhookEvent_merchantOrderId_idx" ON "PaymentWebhookEvent"("merchantOrderId"); + +-- CreateIndex +CREATE UNIQUE INDEX "PaymentWebhookEvent_provider_externalEventId_key" ON "PaymentWebhookEvent"("provider", "externalEventId"); + -- CreateIndex CREATE UNIQUE INDEX "Ticket_bookingId_key" ON "Ticket"("bookingId"); @@ -590,6 +931,72 @@ CREATE UNIQUE INDEX "Promotion_code_key" ON "Promotion"("code"); -- CreateIndex CREATE UNIQUE INDEX "UserPreferences_userId_key" ON "UserPreferences"("userId"); +-- CreateIndex +CREATE INDEX "OtpCode_email_phone_idx" ON "OtpCode"("email", "phone"); + +-- CreateIndex +CREATE UNIQUE INDEX "PasswordResetToken_token_key" ON "PasswordResetToken"("token"); + +-- CreateIndex +CREATE INDEX "PasswordResetToken_userId_idx" ON "PasswordResetToken"("userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Route_code_key" ON "Route"("code"); + +-- CreateIndex +CREATE INDEX "RouteStop_routeId_stationId_idx" ON "RouteStop"("routeId", "stationId"); + +-- CreateIndex +CREATE UNIQUE INDEX "RouteStop_routeId_sequence_key" ON "RouteStop"("routeId", "sequence"); + +-- CreateIndex +CREATE INDEX "RouteFareRule_routeId_serviceClass_idx" ON "RouteFareRule"("routeId", "serviceClass"); + +-- CreateIndex +CREATE UNIQUE INDEX "Agent_userId_key" ON "Agent"("userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Agent_agentCode_key" ON "Agent"("agentCode"); + +-- CreateIndex +CREATE UNIQUE INDEX "AgentBooking_bookingId_key" ON "AgentBooking"("bookingId"); + +-- CreateIndex +CREATE INDEX "AgentShift_agentId_openedAt_idx" ON "AgentShift"("agentId", "openedAt"); + +-- CreateIndex +CREATE INDEX "AgentCommission_agentId_paidAt_idx" ON "AgentCommission"("agentId", "paidAt"); + +-- CreateIndex +CREATE INDEX "BookingModification_bookingId_idx" ON "BookingModification"("bookingId"); + +-- CreateIndex +CREATE UNIQUE INDEX "BookingCancellation_bookingId_key" ON "BookingCancellation"("bookingId"); + +-- CreateIndex +CREATE INDEX "GateValidationLog_ticketId_idx" ON "GateValidationLog"("ticketId"); + +-- CreateIndex +CREATE INDEX "GateValidationLog_validatorId_idx" ON "GateValidationLog"("validatorId"); + +-- CreateIndex +CREATE INDEX "BaggageBooking_bookingId_idx" ON "BaggageBooking"("bookingId"); + +-- CreateIndex +CREATE INDEX "AuditLog_userId_createdAt_idx" ON "AuditLog"("userId", "createdAt"); + +-- CreateIndex +CREATE INDEX "AuditLog_entityType_entityId_idx" ON "AuditLog"("entityType", "entityId"); + +-- CreateIndex +CREATE UNIQUE INDEX "NotificationTemplate_code_key" ON "NotificationTemplate"("code"); + +-- CreateIndex +CREATE INDEX "SeatBlock_seatId_idx" ON "SeatBlock"("seatId"); + +-- CreateIndex +CREATE INDEX "OperationalReport_reportType_dateFrom_idx" ON "OperationalReport"("reportType", "dateFrom"); + -- AddForeignKey ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; @@ -638,6 +1045,9 @@ ALTER TABLE "BookingSeat" ADD CONSTRAINT "BookingSeat_seatId_fkey" FOREIGN KEY ( -- AddForeignKey ALTER TABLE "PaymentIntent" ADD CONSTRAINT "PaymentIntent_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; +-- AddForeignKey +ALTER TABLE "PaymentRefund" ADD CONSTRAINT "PaymentRefund_paymentIntentId_fkey" FOREIGN KEY ("paymentIntentId") REFERENCES "PaymentIntent"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + -- AddForeignKey ALTER TABLE "Ticket" ADD CONSTRAINT "Ticket_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; @@ -688,3 +1098,48 @@ ALTER TABLE "Device" ADD CONSTRAINT "Device_userId_fkey" FOREIGN KEY ("userId") -- AddForeignKey ALTER TABLE "SavedRoute" ADD CONSTRAINT "SavedRoute_passengerId_fkey" FOREIGN KEY ("passengerId") REFERENCES "Passenger"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "JourneySegment" ADD CONSTRAINT "JourneySegment_journeyId_fkey" FOREIGN KEY ("journeyId") REFERENCES "Journey"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "JourneySegment" ADD CONSTRAINT "JourneySegment_tripId_fkey" FOREIGN KEY ("tripId") REFERENCES "Trip"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "RouteStop" ADD CONSTRAINT "RouteStop_routeId_fkey" FOREIGN KEY ("routeId") REFERENCES "Route"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "RouteFareRule" ADD CONSTRAINT "RouteFareRule_routeId_fkey" FOREIGN KEY ("routeId") REFERENCES "Route"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Agent" ADD CONSTRAINT "Agent_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "AgentBooking" ADD CONSTRAINT "AgentBooking_agentId_fkey" FOREIGN KEY ("agentId") REFERENCES "Agent"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "AgentBooking" ADD CONSTRAINT "AgentBooking_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "AgentShift" ADD CONSTRAINT "AgentShift_agentId_fkey" FOREIGN KEY ("agentId") REFERENCES "Agent"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "AgentCommission" ADD CONSTRAINT "AgentCommission_agentId_fkey" FOREIGN KEY ("agentId") REFERENCES "Agent"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "BookingModification" ADD CONSTRAINT "BookingModification_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "BookingCancellation" ADD CONSTRAINT "BookingCancellation_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "GateValidationLog" ADD CONSTRAINT "GateValidationLog_ticketId_fkey" FOREIGN KEY ("ticketId") REFERENCES "Ticket"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "BaggageBooking" ADD CONSTRAINT "BaggageBooking_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "AuditLog" ADD CONSTRAINT "AuditLog_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "SeatBlock" ADD CONSTRAINT "SeatBlock_seatId_fkey" FOREIGN KEY ("seatId") REFERENCES "Seat"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/apps/edr-passenger-api/prisma/migrations/20260520000002_language_field_note/migration.sql b/apps/edr-passenger-api/prisma/migrations/20260520000002_language_field_note/migration.sql new file mode 100644 index 000000000..70f6b75d7 --- /dev/null +++ b/apps/edr-passenger-api/prisma/migrations/20260520000002_language_field_note/migration.sql @@ -0,0 +1,2 @@ +-- Language field already exists in UserPreferences table +-- No migration needed diff --git a/apps/edr-passenger-api/prisma/migrations/20260521000001_add_fraud_detection/migration.sql b/apps/edr-passenger-api/prisma/migrations/20260521000001_add_fraud_detection/migration.sql new file mode 100644 index 000000000..ba2115db9 --- /dev/null +++ b/apps/edr-passenger-api/prisma/migrations/20260521000001_add_fraud_detection/migration.sql @@ -0,0 +1,74 @@ +-- Migration: Add Fraud Detection Tables and User.blockedUntil field +-- Date: 2026-05-21 +-- Description: Adds FraudRule and FraudAlert tables, and blockedUntil field to User table + +-- Add blockedUntil field to User table if not exists +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = 'User' AND column_name = 'blockedUntil' + ) THEN + ALTER TABLE "User" ADD COLUMN "blockedUntil" TIMESTAMP(3); + END IF; +END $$; + +-- CreateTable FraudRule +CREATE TABLE IF NOT EXISTS "FraudRule" ( + "id" TEXT NOT NULL, + "type" TEXT NOT NULL, + "enabled" BOOLEAN NOT NULL DEFAULT true, + "threshold" DOUBLE PRECISION NOT NULL, + "config" JSONB, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "FraudRule_pkey" PRIMARY KEY ("id") +); + +-- CreateTable FraudAlert +CREATE TABLE IF NOT EXISTS "FraudAlert" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "eventType" TEXT NOT NULL, + "triggeredRules" TEXT[], + "context" JSONB NOT NULL, + "severity" TEXT NOT NULL DEFAULT 'MEDIUM', + "acknowledged" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "FraudAlert_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX IF NOT EXISTS "FraudRule_type_key" ON "FraudRule"("type"); + +-- CreateIndex +CREATE INDEX IF NOT EXISTS "FraudAlert_userId_createdAt_idx" ON "FraudAlert"("userId", "createdAt"); + +-- CreateIndex +CREATE INDEX IF NOT EXISTS "FraudAlert_acknowledged_idx" ON "FraudAlert"("acknowledged"); + +-- AddForeignKey +DO $$ +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM pg_constraint WHERE conname = 'FraudAlert_userId_fkey' + ) THEN + ALTER TABLE "FraudAlert" ADD CONSTRAINT "FraudAlert_userId_fkey" + FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + END IF; +END $$; + +-- Insert default fraud rules +INSERT INTO "FraudRule" ("id", "type", "enabled", "threshold", "config", "createdAt", "updatedAt") +VALUES + (gen_random_uuid(), 'VELOCITY', true, 5, '{"timeWindowMinutes": 30, "blockDurationMinutes": 30}'::jsonb, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + (gen_random_uuid(), 'HIGH_VALUE', true, 10000, '{"blockDurationMinutes": 60}'::jsonb, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), + (gen_random_uuid(), 'FAILED_PAYMENTS', true, 3, '{"timeWindowMinutes": 60, "blockDurationMinutes": 30}'::jsonb, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) +ON CONFLICT (type) DO NOTHING; + +-- Add comments +COMMENT ON TABLE "FraudRule" IS 'Fraud detection rules for monitoring suspicious activities'; +COMMENT ON TABLE "FraudAlert" IS 'Fraud alerts triggered by rule violations'; +COMMENT ON COLUMN "User"."blockedUntil" IS 'Timestamp until which the user is blocked due to fraud or security reasons'; \ No newline at end of file diff --git a/apps/edr-passenger-api/prisma/reset-admin.d.ts b/apps/edr-passenger-api/prisma/reset-admin.d.ts deleted file mode 100644 index a4595fd95..000000000 --- a/apps/edr-passenger-api/prisma/reset-admin.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=reset-admin.d.ts.map \ No newline at end of file diff --git a/apps/edr-passenger-api/prisma/reset-admin.d.ts.map b/apps/edr-passenger-api/prisma/reset-admin.d.ts.map deleted file mode 100644 index d0f62a26c..000000000 --- a/apps/edr-passenger-api/prisma/reset-admin.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"reset-admin.d.ts","sourceRoot":"","sources":["reset-admin.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/apps/edr-passenger-api/prisma/reset-admin.js b/apps/edr-passenger-api/prisma/reset-admin.js deleted file mode 100644 index c00b804f6..000000000 --- a/apps/edr-passenger-api/prisma/reset-admin.js +++ /dev/null @@ -1,49 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || (function () { - var ownKeys = function(o) { - ownKeys = Object.getOwnPropertyNames || function (o) { - var ar = []; - for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; - return ar; - }; - return ownKeys(o); - }; - return function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); - __setModuleDefault(result, mod); - return result; - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -const client_1 = require("@prisma/client"); -const bcrypt = __importStar(require("bcrypt")); -const prisma = new client_1.PrismaClient(); -async function main() { - const passwordHash = await bcrypt.hash('admin123', 10); - const user = await prisma.user.upsert({ - where: { email: 'admin@edr-platform.com' }, - update: { passwordHash, role: 'ADMIN' }, - create: { fullName: 'EDR Admin', email: 'admin@edr-platform.com', phone: '+251900000000', passwordHash, role: 'ADMIN' }, - }); - console.log('✅ Admin ready:', user.email); -} -main().catch(console.error).finally(() => prisma.$disconnect()); -//# sourceMappingURL=reset-admin.js.map \ No newline at end of file diff --git a/apps/edr-passenger-api/prisma/reset-admin.js.map b/apps/edr-passenger-api/prisma/reset-admin.js.map deleted file mode 100644 index a47b50176..000000000 --- a/apps/edr-passenger-api/prisma/reset-admin.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"reset-admin.js","sourceRoot":"","sources":["reset-admin.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAA8C;AAC9C,+CAAiC;AAEjC,MAAM,MAAM,GAAG,IAAI,qBAAY,EAAE,CAAC;AAElC,KAAK,UAAU,IAAI;IACjB,MAAM,YAAY,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IACvD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;QACpC,KAAK,EAAE,EAAE,KAAK,EAAE,wBAAwB,EAAE;QAC1C,MAAM,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE;QACvC,MAAM,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,wBAAwB,EAAE,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE;KACxH,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;AAC5C,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC"} \ No newline at end of file diff --git a/apps/edr-passenger-api/prisma/reset-admin.ts b/apps/edr-passenger-api/prisma/reset-admin.ts deleted file mode 100644 index da9e5313f..000000000 --- a/apps/edr-passenger-api/prisma/reset-admin.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { PrismaClient } from '@prisma/client'; -import * as bcrypt from 'bcrypt'; - -const prisma = new PrismaClient(); - -async function main() { - const passwordHash = await bcrypt.hash('admin123', 10); - const user = await prisma.user.upsert({ - where: { email: 'admin@edr-platform.com' }, - update: { passwordHash, role: 'ADMIN' }, - create: { fullName: 'EDR Admin', email: 'admin@edr-platform.com', phone: '+251900000000', passwordHash, role: 'ADMIN' }, - }); - console.log('✅ Admin ready:', user.email); -} - -main().catch(console.error).finally(() => prisma.$disconnect()); diff --git a/apps/edr-passenger-api/prisma/schema.prisma b/apps/edr-passenger-api/prisma/schema.prisma index da1b6811b..72fb4b15b 100644 --- a/apps/edr-passenger-api/prisma/schema.prisma +++ b/apps/edr-passenger-api/prisma/schema.prisma @@ -9,6 +9,8 @@ datasource db { enum UserRole { PASSENGER + AGENT + SUPERVISOR ADMIN STAFF } @@ -36,9 +38,12 @@ enum SeatStatus { } enum ServiceClass { - ECONOMY - BUSINESS - FIRST + ECONOMY_REGULAR + ECONOMY_BED_LOWER + ECONOMY_BED_MIDDLE + ECONOMY_BED_UPPER + VIP_BED_LOWER + VIP_BED_UPPER } enum BookingStatus { @@ -48,6 +53,7 @@ enum BookingStatus { CANCELLED COMPLETED NO_SHOW + REFUNDED } enum PaymentMethodType { @@ -64,6 +70,7 @@ enum PaymentIntentStatus { SUCCEEDED FAILED CANCELLED + REFUNDED } enum WalletLedgerType { @@ -134,12 +141,21 @@ model User { fullName String passwordHash String role UserRole @default(PASSENGER) + nationality String? + passportNumber String? + nationalId String? + failedLoginAttempts Int @default(0) + lockedUntil DateTime? + blockedUntil DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt passenger Passenger? + agent Agent? sessions Session[] devices Device[] preferences UserPreferences? + auditLogs AuditLog[] + fraudAlerts FraudAlert[] } model Session { @@ -147,6 +163,9 @@ model Session { userId String token String @unique expiresAt DateTime + ipAddress String? + userAgent String? + lastActivityAt DateTime @default(now()) createdAt DateTime @default(now()) user User @relation(fields: [userId], references: [id], onDelete: Cascade) } @@ -267,8 +286,11 @@ model Seat { kind SeatKind @default(STANDARD) status SeatStatus @default(AVAILABLE) heldUntil DateTime? + premiumFeeMinor Int @default(0) + eligibility String? coach Coach @relation(fields: [coachId], references: [id]) bookingSeats BookingSeat[] + blocks SeatBlock[] @@unique([coachId, row, col]) } @@ -303,6 +325,7 @@ model Booking { status BookingStatus @default(DRAFT) currency String @default("ETB") totalMinor Int + bookingType String @default("ONE_WAY") createdAt DateTime @default(now()) updatedAt DateTime @updatedAt passenger Passenger @relation(fields: [passengerId], references: [id]) @@ -311,6 +334,10 @@ model Booking { paymentIntent PaymentIntent? ticket Ticket? foodOrders FoodOrder[] + agentBooking AgentBooking? + modifications BookingModification[] + cancellation BookingCancellation? + baggage BaggageBooking[] } model BookingSeat { @@ -392,10 +419,14 @@ model Ticket { bookingRef String status String @default("CONFIRMED") qrPayload String + barcodePayload String? + pdfUrl String? + deliveryChannel String @default("EMAIL") issuedAt DateTime @default(now()) validatedAt DateTime? validatorId String? booking Booking @relation(fields: [bookingId], references: [id]) + validationLogs GateValidationLog[] } model LoyaltyAccount { @@ -585,6 +616,7 @@ model UserPreferences { dataSharing Boolean @default(false) locale String @default("en") darkMode Boolean @default(false) + language String @default("en") user User @relation(fields: [userId], references: [id]) } @@ -633,3 +665,253 @@ model JourneySegment { journey Journey @relation(fields: [journeyId], references: [id]) trip Trip @relation(fields: [tripId], references: [id]) } + +model OtpCode { + id String @id @default(uuid()) + userId String? + email String? + phone String? + code String + purpose String + expiresAt DateTime + verified Boolean @default(false) + createdAt DateTime @default(now()) + @@index([email, phone]) +} + +model PasswordResetToken { + id String @id @default(uuid()) + userId String + token String @unique + expiresAt DateTime + used Boolean @default(false) + createdAt DateTime @default(now()) + @@index([userId]) +} + +model Route { + id String @id @default(uuid()) + code String @unique + name String + description String? + effectiveFrom DateTime + effectiveUntil DateTime? + active Boolean @default(true) + createdAt DateTime @default(now()) + stops RouteStop[] + fareRules RouteFareRule[] +} + +model RouteStop { + id String @id @default(uuid()) + routeId String + stationId String + sequence Int + distanceKm Int? + createdAt DateTime @default(now()) + route Route @relation(fields: [routeId], references: [id], onDelete: Cascade) + @@unique([routeId, sequence]) + @@index([routeId, stationId]) +} + +model RouteFareRule { + id String @id @default(uuid()) + routeId String + serviceClass ServiceClass + passengerCategory String @default("ADULT") + baseFareMinor Int + discountPercent Int? + currency String @default("ETB") + validFrom DateTime + validUntil DateTime? + createdAt DateTime @default(now()) + route Route @relation(fields: [routeId], references: [id], onDelete: Cascade) + @@index([routeId, serviceClass]) +} + +model Agent { + id String @id @default(uuid()) + userId String @unique + agentCode String @unique + stationId String? + commissionRate Int @default(5) + active Boolean @default(true) + createdAt DateTime @default(now()) + user User @relation(fields: [userId], references: [id]) + bookings AgentBooking[] + shifts AgentShift[] + commissions AgentCommission[] +} + +model AgentBooking { + id String @id @default(uuid()) + agentId String + bookingId String @unique + paymentMethod String + cashReceived Int? + changeGiven Int? + paperTicket Boolean @default(false) + createdAt DateTime @default(now()) + agent Agent @relation(fields: [agentId], references: [id]) + booking Booking @relation(fields: [bookingId], references: [id]) +} + +model AgentShift { + id String @id @default(uuid()) + agentId String + openedAt DateTime @default(now()) + closedAt DateTime? + openingBalance Int @default(0) + closingBalance Int? + reconciled Boolean @default(false) + notes String? + agent Agent @relation(fields: [agentId], references: [id]) + @@index([agentId, openedAt]) +} + +model AgentCommission { + id String @id @default(uuid()) + agentId String + bookingId String + amountMinor Int + rate Int + paidAt DateTime? + createdAt DateTime @default(now()) + agent Agent @relation(fields: [agentId], references: [id]) + @@index([agentId, paidAt]) +} + +model BookingModification { + id String @id @default(uuid()) + bookingId String + modifiedBy String + modificationType String + oldData Json + newData Json + fareAdjustment Int @default(0) + reason String? + createdAt DateTime @default(now()) + booking Booking @relation(fields: [bookingId], references: [id]) + @@index([bookingId]) +} + +model BookingCancellation { + id String @id @default(uuid()) + bookingId String @unique + cancelledBy String + reason String? + refundAmount Int + refundMethod String + refundStatus String + processedAt DateTime? + createdAt DateTime @default(now()) + booking Booking @relation(fields: [bookingId], references: [id]) +} + +model GateValidationLog { + id String @id @default(uuid()) + ticketId String + validatorId String + gateId String? + status String + reason String? + validatedAt DateTime @default(now()) + ticket Ticket @relation(fields: [ticketId], references: [id]) + @@index([ticketId]) + @@index([validatorId]) +} + +model BaggageAllowance { + id String @id @default(uuid()) + serviceClass ServiceClass + maxWeightKg Int + maxPiecesCount Int + excessFeePerKg Int + currency String @default("ETB") + createdAt DateTime @default(now()) +} + +model BaggageBooking { + id String @id @default(uuid()) + bookingId String + weightKg Int + piecesCount Int + excessFeeMinor Int @default(0) + paid Boolean @default(false) + createdAt DateTime @default(now()) + booking Booking @relation(fields: [bookingId], references: [id]) + @@index([bookingId]) +} + +model AuditLog { + id String @id @default(uuid()) + userId String? + action String + entityType String + entityId String? + oldData Json? + newData Json? + ipAddress String? + userAgent String? + createdAt DateTime @default(now()) + user User? @relation(fields: [userId], references: [id]) + @@index([userId, createdAt]) + @@index([entityType, entityId]) +} + +model NotificationTemplate { + id String @id @default(uuid()) + code String @unique + channel String + subject String? + bodyTemplate String + active Boolean @default(true) + createdAt DateTime @default(now()) +} + +model SeatBlock { + id String @id @default(uuid()) + seatId String + reason String + blockedBy String + approvedBy String? + blockedAt DateTime @default(now()) + unblockAt DateTime? + seat Seat @relation(fields: [seatId], references: [id]) + @@index([seatId]) +} + +model OperationalReport { + id String @id @default(uuid()) + reportType String + dateFrom DateTime + dateTo DateTime + data Json + generatedBy String? + createdAt DateTime @default(now()) + @@index([reportType, dateFrom]) +} + +model FraudRule { + id String @id @default(uuid()) + type String @unique + enabled Boolean @default(true) + threshold Float + config Json? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + +model FraudAlert { + id String @id @default(uuid()) + userId String + eventType String + triggeredRules String[] + context Json + severity String @default("MEDIUM") + acknowledged Boolean @default(false) + createdAt DateTime @default(now()) + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + @@index([userId, createdAt]) + @@index([acknowledged]) +} diff --git a/apps/edr-passenger-api/prisma/seed.d.ts b/apps/edr-passenger-api/prisma/seed.d.ts deleted file mode 100644 index 0986b1c3a..000000000 --- a/apps/edr-passenger-api/prisma/seed.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=seed.d.ts.map \ No newline at end of file diff --git a/apps/edr-passenger-api/prisma/seed.d.ts.map b/apps/edr-passenger-api/prisma/seed.d.ts.map deleted file mode 100644 index c1a0e0b3d..000000000 --- a/apps/edr-passenger-api/prisma/seed.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["seed.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/apps/edr-passenger-api/prisma/seed.js b/apps/edr-passenger-api/prisma/seed.js deleted file mode 100644 index 924e06d85..000000000 --- a/apps/edr-passenger-api/prisma/seed.js +++ /dev/null @@ -1,73 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m, k); - if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { return m[k]; } }; - } - Object.defineProperty(o, k2, desc); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || (function () { - var ownKeys = function(o) { - ownKeys = Object.getOwnPropertyNames || function (o) { - var ar = []; - for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; - return ar; - }; - return ownKeys(o); - }; - return function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); - __setModuleDefault(result, mod); - return result; - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -const client_1 = require("@prisma/client"); -const bcrypt = __importStar(require("bcrypt")); -const prisma = new client_1.PrismaClient(); -async function main() { - const addis = await prisma.station.upsert({ where: { code: 'ADD' }, update: {}, create: { code: 'ADD', name: 'Addis Ababa', city: 'Addis Ababa', lat: 9.0054, lng: 38.7636 } }); - const direDawa = await prisma.station.upsert({ where: { code: 'DDW' }, update: {}, create: { code: 'DDW', name: 'Dire Dawa', city: 'Dire Dawa', lat: 9.5931, lng: 41.8661 } }); - const djibouti = await prisma.station.upsert({ where: { code: 'DJI' }, update: {}, create: { code: 'DJI', name: 'Djibouti', city: 'Djibouti', timezone: 'Africa/Djibouti', lat: 11.5720, lng: 43.1456 } }); - const service = await prisma.trainService.upsert({ where: { number: '301' }, update: {}, create: { number: '301', name: 'Express 301' } }); - const trip = await prisma.trip.create({ - data: { serviceId: service.id, originStationId: addis.id, destinationStationId: djibouti.id, departureAt: new Date('2026-05-11T08:30:00Z'), arrivalAt: new Date('2026-05-11T20:00:00Z'), durationMinutes: 690, stopsCount: 1 }, - }); - for (const [label, cls] of [['A', 'ECONOMY'], ['B', 'BUSINESS']]) { - const coach = await prisma.coach.create({ data: { tripId: trip.id, label, serviceClass: cls } }); - const seats = []; - for (let row = 1; row <= 10; row++) { - for (const col of ['A', 'B', 'C', 'D']) - seats.push({ coachId: coach.id, row, col, label: `${row}${col}` }); - } - await prisma.seat.createMany({ data: seats }); - } - await prisma.fareRule.create({ data: { tripId: trip.id, serviceClass: 'ECONOMY', baseFareMinor: 45000, validFrom: new Date('2026-01-01') } }); - const hash = await bcrypt.hash('password123', 10); - const user = await prisma.user.upsert({ where: { email: 'kelemu@email.com' }, update: {}, create: { fullName: 'Kelemu Ketsela', email: 'kelemu@email.com', phone: '+251912345678', passwordHash: hash } }); - let passenger = await prisma.passenger.findUnique({ where: { userId: user.id } }); - if (!passenger) { - passenger = await prisma.passenger.create({ data: { userId: user.id } }); - await prisma.loyaltyAccount.create({ data: { passengerId: passenger.id, pointsBalance: 2450, tier: 'SILVER' } }); - await prisma.walletAccount.create({ data: { passengerId: passenger.id, balanceMinor: 125000 } }); - } - await prisma.userPreferences.upsert({ where: { userId: user.id }, update: {}, create: { userId: user.id } }); - await prisma.user.upsert({ where: { email: 'admin@edr-platform.com' }, update: { passwordHash: await bcrypt.hash('admin123', 10), role: 'ADMIN' }, create: { fullName: 'EDR Admin', email: 'admin@edr-platform.com', phone: '+251900000000', passwordHash: await bcrypt.hash('admin123', 10), role: 'ADMIN' } }); - await prisma.promotion.upsert({ where: { code: 'WEEKEND15' }, update: {}, create: { title: 'Weekend Sale', code: 'WEEKEND15', percentOff: 15, validUntil: new Date('2026-12-31') } }); - const faqCat = await prisma.faqCategory.create({ data: { title: 'Booking & Tickets', iconKey: 'description_outlined' } }); - await prisma.faqArticle.create({ data: { categoryId: faqCat.id, question: 'How do I book a train ticket?', answerMarkdown: 'Open Search, pick stations and date, select seats, and proceed to payment.', rank: 1 } }); - console.log('✅ Seed complete'); -} -main().catch(console.error).finally(() => prisma.$disconnect()); -//# sourceMappingURL=seed.js.map \ No newline at end of file diff --git a/apps/edr-passenger-api/prisma/seed.js.map b/apps/edr-passenger-api/prisma/seed.js.map deleted file mode 100644 index bcc581885..000000000 --- a/apps/edr-passenger-api/prisma/seed.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"seed.js","sourceRoot":"","sources":["seed.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAA8C;AAC9C,+CAAiC;AAEjC,MAAM,MAAM,GAAG,IAAI,qBAAY,EAAE,CAAC;AAElC,KAAK,UAAU,IAAI;IACjB,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IAChL,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IAC/K,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,iBAAiB,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IAE3M,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC;IAE3I,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;QACpC,IAAI,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,eAAe,EAAE,KAAK,CAAC,EAAE,EAAE,oBAAoB,EAAE,QAAQ,CAAC,EAAE,EAAE,WAAW,EAAE,IAAI,IAAI,CAAC,sBAAsB,CAAC,EAAE,SAAS,EAAE,IAAI,IAAI,CAAC,sBAAsB,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,EAAE;KAC/N,CAAC,CAAC;IAEH,KAAK,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,UAAU,CAAC,CAAU,EAAE,CAAC;QAC1E,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;QACjG,MAAM,KAAK,GAAG,EAAE,CAAC;QACjB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC;YACnC,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,GAAG,GAAG,GAAG,EAAE,EAAE,CAAC,CAAC;QAC7G,CAAC;QACD,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC,CAAC;IAE9I,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,gBAAgB,EAAE,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IAC3M,IAAI,SAAS,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IAClF,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,SAAS,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACzE,MAAM,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;QACjH,MAAM,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;IACnG,CAAC;IACD,MAAM,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IAE7G,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,wBAAwB,EAAE,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,wBAAwB,EAAE,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IAEjT,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC,CAAC;IAEtL,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE,OAAO,EAAE,sBAAsB,EAAE,EAAE,CAAC,CAAC;IAC1H,MAAM,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,+BAA+B,EAAE,cAAc,EAAE,4EAA4E,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAEtN,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AACjC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC"} \ No newline at end of file diff --git a/apps/edr-passenger-api/prisma/seed.ts b/apps/edr-passenger-api/prisma/seed.ts index f2bbb1332..65607813e 100644 --- a/apps/edr-passenger-api/prisma/seed.ts +++ b/apps/edr-passenger-api/prisma/seed.ts @@ -1,48 +1,237 @@ -import { PrismaClient } from '@prisma/client'; +import { PrismaClient, ServiceClass, UserRole, LoyaltyTier, SeatKind } from '@prisma/client'; import * as bcrypt from 'bcrypt'; const prisma = new PrismaClient(); async function main() { - const addis = await prisma.station.upsert({ where: { code: 'ADD' }, update: {}, create: { code: 'ADD', name: 'Addis Ababa', city: 'Addis Ababa', lat: 9.0054, lng: 38.7636 } }); + console.log('🌱 Starting comprehensive seed...'); + + // All 18 Stations (Ethiopian-Djibouti Railway) + const addis = await prisma.station.upsert({ where: { code: 'ADD' }, update: {}, create: { code: 'ADD', name: 'Addis Ababa Central', city: 'Addis Ababa', lat: 9.0054, lng: 38.7636 } }); + const sebeta = await prisma.station.upsert({ where: { code: 'SBT' }, update: {}, create: { code: 'SBT', name: 'Sebeta', city: 'Sebeta', lat: 8.9167, lng: 38.6167 } }); + const labu = await prisma.station.upsert({ where: { code: 'LBU' }, update: {}, create: { code: 'LBU', name: 'Labu', city: 'Labu', lat: 8.8500, lng: 38.8500 } }); + const indode = await prisma.station.upsert({ where: { code: 'IND' }, update: {}, create: { code: 'IND', name: 'Indode', city: 'Indode', lat: 8.7833, lng: 39.0167 } }); + const bishoftu = await prisma.station.upsert({ where: { code: 'BSH' }, update: {}, create: { code: 'BSH', name: 'Bishoftu', city: 'Bishoftu', lat: 8.7500, lng: 38.9833 } }); + const mojo = await prisma.station.upsert({ where: { code: 'MJO' }, update: {}, create: { code: 'MJO', name: 'Mojo', city: 'Mojo', lat: 8.5833, lng: 39.1167 } }); + const adama = await prisma.station.upsert({ where: { code: 'ADM' }, update: {}, create: { code: 'ADM', name: 'Adama', city: 'Adama', lat: 8.5400, lng: 39.2675 } }); + const feto = await prisma.station.upsert({ where: { code: 'FTO' }, update: {}, create: { code: 'FTO', name: 'Feto', city: 'Feto', lat: 8.7167, lng: 39.5833 } }); + const metahara = await prisma.station.upsert({ where: { code: 'MTH' }, update: {}, create: { code: 'MTH', name: 'Metahara', city: 'Metahara', lat: 8.9000, lng: 39.9167 } }); + const awash = await prisma.station.upsert({ where: { code: 'AWS' }, update: {}, create: { code: 'AWS', name: 'Awash', city: 'Awash', lat: 8.9833, lng: 40.1667 } }); + const mieso = await prisma.station.upsert({ where: { code: 'MSO' }, update: {}, create: { code: 'MSO', name: 'Mieso', city: 'Mieso', lat: 9.2333, lng: 40.7500 } }); + const bike = await prisma.station.upsert({ where: { code: 'BKE' }, update: {}, create: { code: 'BKE', name: 'Bike', city: 'Bike', lat: 9.4167, lng: 41.2500 } }); const direDawa = await prisma.station.upsert({ where: { code: 'DDW' }, update: {}, create: { code: 'DDW', name: 'Dire Dawa', city: 'Dire Dawa', lat: 9.5931, lng: 41.8661 } }); + const arawa = await prisma.station.upsert({ where: { code: 'ARW' }, update: {}, create: { code: 'ARW', name: 'Arawa', city: 'Arawa', lat: 10.0833, lng: 42.2500 } }); + const adigala = await prisma.station.upsert({ where: { code: 'ADG' }, update: {}, create: { code: 'ADG', name: 'Adigala', city: 'Adigala', lat: 10.5000, lng: 42.5833 } }); + const aysha = await prisma.station.upsert({ where: { code: 'AYS' }, update: {}, create: { code: 'AYS', name: 'Aysha', city: 'Aysha', lat: 11.5500, lng: 42.7167 } }); + const dawanle = await prisma.station.upsert({ where: { code: 'DWN' }, update: {}, create: { code: 'DWN', name: 'Dawanle', city: 'Dawanle', timezone: 'Africa/Djibouti', lat: 11.3833, lng: 42.8500 } }); + const alisabieh = await prisma.station.upsert({ where: { code: 'ALI' }, update: {}, create: { code: 'ALI', name: 'Alisabieh', city: 'Alisabieh', timezone: 'Africa/Djibouti', lat: 11.1667, lng: 42.7167 } }); + const holhol = await prisma.station.upsert({ where: { code: 'HLH' }, update: {}, create: { code: 'HLH', name: 'Holhol', city: 'Holhol', timezone: 'Africa/Djibouti', lat: 11.4167, lng: 43.0000 } }); + const nagad = await prisma.station.upsert({ where: { code: 'NGD' }, update: {}, create: { code: 'NGD', name: 'Nagad', city: 'Nagad', timezone: 'Africa/Djibouti', lat: 11.5167, lng: 43.1000 } }); const djibouti = await prisma.station.upsert({ where: { code: 'DJI' }, update: {}, create: { code: 'DJI', name: 'Djibouti', city: 'Djibouti', timezone: 'Africa/Djibouti', lat: 11.5720, lng: 43.1456 } }); - const service = await prisma.trainService.upsert({ where: { number: '301' }, update: {}, create: { number: '301', name: 'Express 301' } }); + // Routes + const route1 = await prisma.route.upsert({ + where: { code: 'R001' }, + update: {}, + create: { code: 'R001', name: 'Addis Ababa - Djibouti Express', effectiveFrom: new Date('2026-01-01'), active: true } + }); + + // Delete existing route stops and recreate + await prisma.routeStop.deleteMany({ where: { routeId: route1.id } }); + await prisma.routeStop.createMany({ data: [ + { routeId: route1.id, stationId: addis.id, sequence: 1, distanceKm: 0 }, + { routeId: route1.id, stationId: sebeta.id, sequence: 2, distanceKm: 23 }, + { routeId: route1.id, stationId: labu.id, sequence: 3, distanceKm: 45 }, + { routeId: route1.id, stationId: indode.id, sequence: 4, distanceKm: 62 }, + { routeId: route1.id, stationId: bishoftu.id, sequence: 5, distanceKm: 47 }, + { routeId: route1.id, stationId: mojo.id, sequence: 6, distanceKm: 73 }, + { routeId: route1.id, stationId: adama.id, sequence: 7, distanceKm: 99 }, + { routeId: route1.id, stationId: feto.id, sequence: 8, distanceKm: 145 }, + { routeId: route1.id, stationId: metahara.id, sequence: 9, distanceKm: 198 }, + { routeId: route1.id, stationId: awash.id, sequence: 10, distanceKm: 225 }, + { routeId: route1.id, stationId: mieso.id, sequence: 11, distanceKm: 305 }, + { routeId: route1.id, stationId: bike.id, sequence: 12, distanceKm: 375 }, + { routeId: route1.id, stationId: direDawa.id, sequence: 13, distanceKm: 453 }, + { routeId: route1.id, stationId: arawa.id, sequence: 14, distanceKm: 520 }, + { routeId: route1.id, stationId: adigala.id, sequence: 15, distanceKm: 580 }, + { routeId: route1.id, stationId: aysha.id, sequence: 16, distanceKm: 656 }, + { routeId: route1.id, stationId: dawanle.id, sequence: 17, distanceKm: 680 }, + { routeId: route1.id, stationId: alisabieh.id, sequence: 18, distanceKm: 700 }, + { routeId: route1.id, stationId: holhol.id, sequence: 19, distanceKm: 730 }, + { routeId: route1.id, stationId: nagad.id, sequence: 20, distanceKm: 750 }, + { routeId: route1.id, stationId: djibouti.id, sequence: 21, distanceKm: 756 }, + ]}); - const trip = await prisma.trip.create({ - data: { serviceId: service.id, originStationId: addis.id, destinationStationId: djibouti.id, departureAt: new Date('2026-05-11T08:30:00Z'), arrivalAt: new Date('2026-05-11T20:00:00Z'), durationMinutes: 690, stopsCount: 1 }, + // Route Fare Rules + await prisma.routeFareRule.deleteMany({ where: { routeId: route1.id } }); + await prisma.routeFareRule.createMany({ data: [ + { routeId: route1.id, serviceClass: 'ECONOMY_REGULAR', baseFareMinor: 45000, validFrom: new Date('2026-01-01') }, + { routeId: route1.id, serviceClass: 'ECONOMY_BED_LOWER', baseFareMinor: 65000, validFrom: new Date('2026-01-01') }, + { routeId: route1.id, serviceClass: 'VIP_BED_LOWER', baseFareMinor: 95000, validFrom: new Date('2026-01-01') }, + ]}); + + // Train Services + const service301 = await prisma.trainService.upsert({ where: { number: '301' }, update: {}, create: { number: '301', name: 'Express 301' } }); + const service302 = await prisma.trainService.upsert({ where: { number: '302' }, update: {}, create: { number: '302', name: 'Express 302' } }); + + // Trips (Multiple schedules) - Delete existing trips for clean seed + await prisma.trip.deleteMany({ where: { serviceId: { in: [service301.id, service302.id] } } }); + const trip1 = await prisma.trip.create({ + data: { serviceId: service301.id, originStationId: addis.id, destinationStationId: djibouti.id, departureAt: new Date('2026-06-15T08:00:00Z'), arrivalAt: new Date('2026-06-15T20:00:00Z'), durationMinutes: 720, stopsCount: 19 }, + }); + const trip2 = await prisma.trip.create({ + data: { serviceId: service302.id, originStationId: djibouti.id, destinationStationId: addis.id, departureAt: new Date('2026-06-16T09:00:00Z'), arrivalAt: new Date('2026-06-16T21:30:00Z'), durationMinutes: 750, stopsCount: 19 }, + }); + const trip3 = await prisma.trip.create({ + data: { serviceId: service301.id, originStationId: addis.id, destinationStationId: djibouti.id, departureAt: new Date('2026-06-17T07:30:00Z'), arrivalAt: new Date('2026-06-17T19:45:00Z'), durationMinutes: 735, stopsCount: 19 }, + }); + const trip4 = await prisma.trip.create({ + data: { serviceId: service302.id, originStationId: djibouti.id, destinationStationId: addis.id, departureAt: new Date('2026-06-18T08:30:00Z'), arrivalAt: new Date('2026-06-18T21:00:00Z'), durationMinutes: 750, stopsCount: 19 }, }); - for (const [label, cls] of [['A', 'ECONOMY'], ['B', 'BUSINESS']] as const) { - const coach = await prisma.coach.create({ data: { tripId: trip.id, label, serviceClass: cls } }); - const seats = []; - for (let row = 1; row <= 10; row++) { - for (const col of ['A', 'B', 'C', 'D']) seats.push({ coachId: coach.id, row, col, label: `${row}${col}` }); + // Trip Stop Times (Major stops only for brevity) + await prisma.tripStopTime.createMany({ data: [ + { tripId: trip1.id, stationId: addis.id, sequence: 1, plannedDepartureAt: new Date('2026-06-15T08:00:00Z'), status: 'UPCOMING' }, + { tripId: trip1.id, stationId: adama.id, sequence: 7, plannedArrivalAt: new Date('2026-06-15T09:30:00Z'), plannedDepartureAt: new Date('2026-06-15T09:45:00Z'), status: 'UPCOMING' }, + { tripId: trip1.id, stationId: awash.id, sequence: 10, plannedArrivalAt: new Date('2026-06-15T11:30:00Z'), plannedDepartureAt: new Date('2026-06-15T11:45:00Z'), status: 'UPCOMING' }, + { tripId: trip1.id, stationId: direDawa.id, sequence: 13, plannedArrivalAt: new Date('2026-06-15T15:00:00Z'), plannedDepartureAt: new Date('2026-06-15T15:20:00Z'), status: 'UPCOMING' }, + { tripId: trip1.id, stationId: aysha.id, sequence: 16, plannedArrivalAt: new Date('2026-06-15T18:00:00Z'), plannedDepartureAt: new Date('2026-06-15T18:10:00Z'), status: 'UPCOMING' }, + { tripId: trip1.id, stationId: djibouti.id, sequence: 21, plannedArrivalAt: new Date('2026-06-15T20:00:00Z'), status: 'UPCOMING' }, + ]}); + + // Coaches & Seats + for (const trip of [trip1, trip2, trip3, trip4]) { + const coaches = [ + { label: 'A', serviceClass: 'ECONOMY_REGULAR' as ServiceClass, seatCount: 60 }, + { label: 'B', serviceClass: 'ECONOMY_BED_LOWER' as ServiceClass, seatCount: 40 }, + { label: 'C', serviceClass: 'VIP_BED_LOWER' as ServiceClass, seatCount: 20 }, + ]; + for (const { label, serviceClass, seatCount } of coaches) { + const coach = await prisma.coach.create({ data: { tripId: trip.id, label, serviceClass } }); + const seats = []; + const rows = Math.ceil(seatCount / 4); + for (let row = 1; row <= rows; row++) { + for (const col of ['A', 'B', 'C', 'D']) { + if (seats.length >= seatCount) break; + seats.push({ coachId: coach.id, row, col, label: `${row}${col}`, kind: (row === 1 && col === 'A' ? 'ACCESSIBLE' : 'STANDARD') as SeatKind }); + } + } + await prisma.seat.createMany({ data: seats }); } - await prisma.seat.createMany({ data: seats }); } - await prisma.fareRule.create({ data: { tripId: trip.id, serviceClass: 'ECONOMY', baseFareMinor: 45000, validFrom: new Date('2026-01-01') } }); + // Fare Rules (All trips) + for (const trip of [trip1, trip2, trip3, trip4]) { + await prisma.fareRule.createMany({ data: [ + { tripId: trip.id, serviceClass: 'ECONOMY_REGULAR', baseFareMinor: 45000, validFrom: new Date('2026-01-01'), refundable: true }, + { tripId: trip.id, serviceClass: 'ECONOMY_BED_LOWER', baseFareMinor: 65000, validFrom: new Date('2026-01-01'), refundable: true }, + { tripId: trip.id, serviceClass: 'VIP_BED_LOWER', baseFareMinor: 95000, validFrom: new Date('2026-01-01'), refundable: true }, + ]}); + } + // Users const hash = await bcrypt.hash('password123', 10); - const user = await prisma.user.upsert({ where: { email: 'kelemu@email.com' }, update: {}, create: { fullName: 'Kelemu Ketsela', email: 'kelemu@email.com', phone: '+251912345678', passwordHash: hash } }); - let passenger = await prisma.passenger.findUnique({ where: { userId: user.id } }); + const adminHash = await bcrypt.hash('admin123', 10); + const agentHash = await bcrypt.hash('agent123', 10); + + const adminUser = await prisma.user.upsert({ where: { email: 'admin@edr-platform.com' }, update: { passwordHash: adminHash, role: 'ADMIN' }, create: { fullName: 'EDR Admin', email: 'admin@edr-platform.com', phone: '+251900000000', passwordHash: adminHash, role: 'ADMIN' } }); + + const passengerUser = await prisma.user.upsert({ where: { email: 'kelemu@email.com' }, update: {}, create: { fullName: 'Kelemu Ketsela', email: 'kelemu@email.com', phone: '+251912345678', passwordHash: hash, nationality: 'Ethiopian', nationalId: 'ET123456789' } }); + let passenger = await prisma.passenger.findUnique({ where: { userId: passengerUser.id } }); if (!passenger) { - passenger = await prisma.passenger.create({ data: { userId: user.id } }); + passenger = await prisma.passenger.create({ data: { userId: passengerUser.id } }); await prisma.loyaltyAccount.create({ data: { passengerId: passenger.id, pointsBalance: 2450, tier: 'SILVER' } }); await prisma.walletAccount.create({ data: { passengerId: passenger.id, balanceMinor: 125000 } }); } - await prisma.userPreferences.upsert({ where: { userId: user.id }, update: {}, create: { userId: user.id } }); + await prisma.userPreferences.upsert({ where: { userId: passengerUser.id }, update: {}, create: { userId: passengerUser.id, language: 'en' } }); - await prisma.user.upsert({ where: { email: 'admin@edr-platform.com' }, update: { passwordHash: await bcrypt.hash('admin123', 10), role: 'ADMIN' }, create: { fullName: 'EDR Admin', email: 'admin@edr-platform.com', phone: '+251900000000', passwordHash: await bcrypt.hash('admin123', 10), role: 'ADMIN' } }); + const agentUser = await prisma.user.upsert({ where: { email: 'agent@edr-platform.com' }, update: { passwordHash: agentHash, role: 'AGENT' }, create: { fullName: 'Agent Abebe', email: 'agent@edr-platform.com', phone: '+251911111111', passwordHash: agentHash, role: 'AGENT' } }); + await prisma.agent.upsert({ where: { userId: agentUser.id }, update: {}, create: { userId: agentUser.id, agentCode: 'AG001', stationId: addis.id, commissionRate: 5, active: true } }); - await prisma.promotion.upsert({ where: { code: 'WEEKEND15' }, update: {}, create: { title: 'Weekend Sale', code: 'WEEKEND15', percentOff: 15, validUntil: new Date('2026-12-31') } }); + // Baggage Allowance - Delete and recreate + await prisma.baggageAllowance.deleteMany({}); + await prisma.baggageAllowance.createMany({ data: [ + { serviceClass: 'ECONOMY_REGULAR', maxWeightKg: 20, maxPiecesCount: 2, excessFeePerKg: 500 }, + { serviceClass: 'ECONOMY_BED_LOWER', maxWeightKg: 25, maxPiecesCount: 2, excessFeePerKg: 450 }, + { serviceClass: 'VIP_BED_LOWER', maxWeightKg: 30, maxPiecesCount: 3, excessFeePerKg: 400 }, + ]}); - const faqCat = await prisma.faqCategory.create({ data: { title: 'Booking & Tickets', iconKey: 'description_outlined' } }); - await prisma.faqArticle.create({ data: { categoryId: faqCat.id, question: 'How do I book a train ticket?', answerMarkdown: 'Open Search, pick stations and date, select seats, and proceed to payment.', rank: 1 } }); + // Notification Templates + await prisma.notificationTemplate.upsert({ where: { code: 'BOOKING_CONFIRMED' }, update: {}, create: { code: 'BOOKING_CONFIRMED', channel: 'EMAIL', subject: 'Booking Confirmed', bodyTemplate: 'Your booking {{bookingRef}} is confirmed for {{tripDate}}.', active: true } }); + await prisma.notificationTemplate.upsert({ where: { code: 'PAYMENT_SUCCESS' }, update: {}, create: { code: 'PAYMENT_SUCCESS', channel: 'SMS', bodyTemplate: 'Payment successful for {{bookingRef}}. Amount: {{amount}} ETB', active: true } }); + await prisma.notificationTemplate.upsert({ where: { code: 'TRIP_REMINDER' }, update: {}, create: { code: 'TRIP_REMINDER', channel: 'PUSH', subject: 'Trip Reminder', bodyTemplate: 'Your trip departs in {{hours}} hours from {{station}}.', active: true } }); - console.log('✅ Seed complete'); + // Promotions + await prisma.promotion.upsert({ where: { code: 'WEEKEND15' }, update: {}, create: { title: 'Weekend Sale', subtitle: '15% off all trips', code: 'WEEKEND15', percentOff: 15, validUntil: new Date('2026-12-31'), ctaLabel: 'Book Now', active: true } }); + await prisma.promotion.upsert({ where: { code: 'NEWUSER20' }, update: {}, create: { title: 'New User Bonus', code: 'NEWUSER20', percentOff: 20, validUntil: new Date('2026-12-31'), active: true } }); + + // FAQ - Delete and recreate for clean seed + await prisma.faqArticle.deleteMany({}); + await prisma.faqCategory.deleteMany({}); + const faqBooking = await prisma.faqCategory.create({ data: { title: 'Booking & Tickets', iconKey: 'confirmation_number' } }); + const faqPayment = await prisma.faqCategory.create({ data: { title: 'Payment & Refunds', iconKey: 'payment' } }); + + await prisma.faqArticle.createMany({ data: [ + { categoryId: faqBooking.id, question: 'How do I book a train ticket?', answerMarkdown: 'Open Search, select origin and destination stations, choose date, select seats, and proceed to payment.', rank: 1 }, + { categoryId: faqBooking.id, question: 'Can I modify my booking?', answerMarkdown: 'Yes, you can modify your booking up to 24 hours before departure through the Bookings section.', rank: 2 }, + { categoryId: faqPayment.id, question: 'What payment methods are accepted?', answerMarkdown: 'We accept Telebirr, CBE Birr, eBirr, Card, and Wallet payments.', rank: 1 }, + { categoryId: faqPayment.id, question: 'How do refunds work?', answerMarkdown: 'Refunds are processed within 5-7 business days to your original payment method.', rank: 2 }, + ]}); + + // Menu Categories & Items - Delete and recreate + await prisma.menuItem.deleteMany({}); + await prisma.menuCategory.deleteMany({}); + const menuBeverages = await prisma.menuCategory.create({ data: { name: 'Beverages' } }); + const menuSnacks = await prisma.menuCategory.create({ data: { name: 'Snacks' } }); + + await prisma.menuItem.createMany({ data: [ + { tripId: trip1.id, categoryId: menuBeverages.id, name: 'Coffee', priceMinor: 2500, available: true }, + { tripId: trip1.id, categoryId: menuBeverages.id, name: 'Tea', priceMinor: 2000, available: true }, + { tripId: trip1.id, categoryId: menuSnacks.id, name: 'Sandwich', priceMinor: 5000, available: true }, + ]}); + + // Station Crowd Signals - Delete and recreate + await prisma.stationCrowdSignal.deleteMany({}); + await prisma.stationCrowdSignal.createMany({ data: [ + { stationId: addis.id, level: 'MODERATE', label: 'Moderate', statusLabel: 'Normal operations' }, + { stationId: adama.id, level: 'LOW', label: 'Low', statusLabel: 'Quiet' }, + { stationId: direDawa.id, level: 'LOW', label: 'Low', statusLabel: 'Quiet' }, + { stationId: djibouti.id, level: 'HIGH', label: 'High', statusLabel: 'Busy terminal' }, + ]}); + + // Fraud Detection Rules + await prisma.fraudRule.upsert({ where: { type: 'VELOCITY' }, update: {}, create: { type: 'VELOCITY', enabled: true, threshold: 3, config: { windowMinutes: 60, action: 'FLAG' } } }); + await prisma.fraudRule.upsert({ where: { type: 'HIGH_VALUE' }, update: {}, create: { type: 'HIGH_VALUE', enabled: true, threshold: 500000, config: { action: 'REVIEW' } } }); + await prisma.fraudRule.upsert({ where: { type: 'FAILED_PAYMENTS' }, update: {}, create: { type: 'FAILED_PAYMENTS', enabled: true, threshold: 5, config: { windowMinutes: 1440, action: 'BLOCK' } } }); + + // Loyalty Rewards (linked to loyalty account) - Delete and recreate + if (passenger) { + const loyaltyAccount = await prisma.loyaltyAccount.findUnique({ where: { passengerId: passenger.id } }); + if (loyaltyAccount) { + await prisma.loyaltyReward.deleteMany({ where: { accountId: loyaltyAccount.id } }); + await prisma.loyaltyReward.createMany({ data: [ + { accountId: loyaltyAccount.id, title: '10% Discount Voucher', costPoints: 1000, available: true, description: 'Get 10% off your next booking' }, + { accountId: loyaltyAccount.id, title: 'Free Upgrade to VIP', costPoints: 2500, available: true, description: 'Upgrade to VIP class on any trip' }, + { accountId: loyaltyAccount.id, title: '500 ETB Wallet Credit', costPoints: 5000, available: true, description: 'Add 500 ETB to your wallet' }, + ]}); + } + } + + console.log('✅ Comprehensive seed complete'); + console.log('\n📋 Seed Summary:'); + console.log(' - 18 Stations (Complete Ethiopian-Djibouti Railway)'); + console.log(' - 1 Route with 21 stops'); + console.log(' - 2 Train services, 4 trips'); + console.log(' - 3 Coaches per trip (Economy, Bed, VIP)'); + console.log(' - 3 Users: Admin, Passenger (Silver tier + wallet), Agent'); + console.log(' - 3 Fraud detection rules'); + console.log(' - 3 Loyalty rewards'); + console.log(' - Baggage rules, Notification templates, Promotions, FAQ'); + console.log('\n🔑 Login Credentials:'); + console.log(' Admin: admin@edr-platform.com / admin123'); + console.log(' Passenger: kelemu@email.com / password123'); + console.log(' Agent: agent@edr-platform.com / agent123'); + console.log('\n🚉 Stations: Addis Ababa → Sebeta → Labu → Indode → Bishoftu → Mojo → Adama → Feto → Metahara → Awash → Mieso → Bike → Dire Dawa → Arawa → Adigala → Aysha → Dawanle → Alisabieh → Holhol → Nagad → Djibouti'); } main().catch(console.error).finally(() => prisma.$disconnect()); diff --git a/apps/edr-passenger-api/src/app.module.ts b/apps/edr-passenger-api/src/app.module.ts index 0fda94657..e5c62a2bb 100644 --- a/apps/edr-passenger-api/src/app.module.ts +++ b/apps/edr-passenger-api/src/app.module.ts @@ -1,11 +1,17 @@ -import { Module } from '@nestjs/common'; +import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { ScheduleModule } from '@nestjs/schedule'; import { EventEmitterModule } from '@nestjs/event-emitter'; import { PrismaModule } from './common/prisma.module'; +import { I18nModule } from './common/i18n/i18n.module'; +import { IamModule } from './common/iam.module'; +import { LocaleMiddleware } from './common/i18n/locale.middleware'; import appConfig from './config/app.config'; import dbConfig from './config/database.config'; import telebirrConfig from './config/telebirr.config'; +import cbeConfig from './config/cbe.config'; +import ebirrConfig from './config/ebirr.config'; +import cardConfig from './config/card.config'; import { AuthModule } from './modules/auth/auth.module'; import { StationsModule } from './modules/stations/stations.module'; import { FleetModule } from './modules/fleet/fleet.module'; @@ -24,13 +30,21 @@ import { LiveModule } from './modules/live/live.module'; import { SupportModule } from './modules/support/support.module'; import { DashboardModule } from './modules/dashboard/dashboard.module'; import { SegmentsModule } from './modules/segments/segments.module'; +import { AgentsModule } from './modules/agents/agents.module'; +import { ReportsModule } from './modules/reports/reports.module'; +import { FraudModule } from './modules/fraud/fraud.module'; @Module({ imports: [ - ConfigModule.forRoot({ isGlobal: true, load: [appConfig, dbConfig, telebirrConfig] }), + ConfigModule.forRoot({ + isGlobal: true, + load: [appConfig, dbConfig, telebirrConfig, cbeConfig, ebirrConfig, cardConfig], + }), ScheduleModule.forRoot(), EventEmitterModule.forRoot(), PrismaModule, + I18nModule, + IamModule, AuthModule, StationsModule, FleetModule, @@ -49,6 +63,13 @@ import { SegmentsModule } from './modules/segments/segments.module'; SupportModule, DashboardModule, SegmentsModule, + AgentsModule, + ReportsModule, + FraudModule, ], }) -export class AppModule {} +export class AppModule implements NestModule { + configure(consumer: MiddlewareConsumer) { + consumer.apply(LocaleMiddleware).forRoutes('*'); + } +} diff --git a/apps/edr-passenger-api/src/common/i18n/i18n.module.ts b/apps/edr-passenger-api/src/common/i18n/i18n.module.ts new file mode 100644 index 000000000..99d70185c --- /dev/null +++ b/apps/edr-passenger-api/src/common/i18n/i18n.module.ts @@ -0,0 +1,9 @@ +import { Module, Global } from '@nestjs/common'; +import { I18nService } from './i18n.service'; + +@Global() +@Module({ + providers: [I18nService], + exports: [I18nService], +}) +export class I18nModule {} diff --git a/apps/edr-passenger-api/src/common/i18n/i18n.service.spec.ts b/apps/edr-passenger-api/src/common/i18n/i18n.service.spec.ts new file mode 100644 index 000000000..37c74c04b --- /dev/null +++ b/apps/edr-passenger-api/src/common/i18n/i18n.service.spec.ts @@ -0,0 +1,49 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { I18nService } from './i18n.service'; + +describe('I18nService', () => { + let service: I18nService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [I18nService], + }).compile(); + + service = module.get(I18nService); + }); + + it('should translate English keys', () => { + expect(service.translate('common.welcome', 'en')).toBe('Welcome'); + expect(service.translate('booking.created', 'en')).toBe('Booking created successfully'); + }); + + it('should translate Amharic keys', () => { + expect(service.translate('common.welcome', 'am')).toBe('እንኳን ደህና መጡ'); + }); + + it('should translate French keys', () => { + expect(service.translate('common.welcome', 'fr')).toBe('Bienvenue'); + }); + + it('should translate Oromo keys', () => { + expect(service.translate('common.welcome', 'om')).toBe('Baga nagaan dhuftan'); + }); + + it('should fallback to English for unsupported locale', () => { + expect(service.translate('common.welcome', 'de')).toBe('Welcome'); + }); + + it('should return key if translation not found', () => { + expect(service.translate('nonexistent.key', 'en')).toBe('nonexistent.key'); + }); + + it('should interpolate parameters', () => { + const result = service.translate('common.welcome', 'en', { name: 'John' }); + expect(result).toBeDefined(); + }); + + it('should return supported locales', () => { + const locales = service.getSupportedLocales(); + expect(locales).toEqual(['en', 'am', 'fr', 'om']); + }); +}); diff --git a/apps/edr-passenger-api/src/common/i18n/i18n.service.ts b/apps/edr-passenger-api/src/common/i18n/i18n.service.ts new file mode 100644 index 000000000..9c3eee5fc --- /dev/null +++ b/apps/edr-passenger-api/src/common/i18n/i18n.service.ts @@ -0,0 +1,63 @@ +import { Injectable } from '@nestjs/common'; +import * as fs from 'fs'; +import * as path from 'path'; + +type TranslationMap = Record; + +@Injectable() +export class I18nService { + private translations: Map = new Map(); + private readonly supportedLocales = ['en', 'am', 'fr', 'om']; + private readonly defaultLocale = 'en'; + + constructor() { + this.loadTranslations(); + } + + private loadTranslations() { + for (const locale of this.supportedLocales) { + const filePath = path.join(__dirname, 'translations', `${locale}.json`); + try { + const content = fs.readFileSync(filePath, 'utf-8'); + this.translations.set(locale, JSON.parse(content)); + } catch (err) { + console.warn(`Failed to load translation file for locale: ${locale}`); + } + } + } + + translate(key: string, locale: string = this.defaultLocale, params?: Record): string { + const normalizedLocale = this.normalizeLocale(locale); + const translations = this.translations.get(normalizedLocale) || this.translations.get(this.defaultLocale); + + if (!translations) return key; + + const keys = key.split('.'); + let value: any = translations; + + for (const k of keys) { + value = value?.[k]; + if (value === undefined) return key; + } + + if (typeof value !== 'string') return key; + + if (params) { + return Object.entries(params).reduce( + (text, [param, val]) => text.replace(new RegExp(`{{${param}}}`, 'g'), val), + value + ); + } + + return value; + } + + private normalizeLocale(locale: string): string { + const normalized = locale.toLowerCase().split('-')[0]; + return this.supportedLocales.includes(normalized) ? normalized : this.defaultLocale; + } + + getSupportedLocales(): string[] { + return this.supportedLocales; + } +} diff --git a/apps/edr-passenger-api/src/common/i18n/locale.decorator.ts b/apps/edr-passenger-api/src/common/i18n/locale.decorator.ts new file mode 100644 index 000000000..388582795 --- /dev/null +++ b/apps/edr-passenger-api/src/common/i18n/locale.decorator.ts @@ -0,0 +1,9 @@ +import { createParamDecorator, ExecutionContext } from '@nestjs/common'; +import { LOCALE_KEY } from './locale.middleware'; + +export const Locale = createParamDecorator( + (data: unknown, ctx: ExecutionContext): string => { + const request = ctx.switchToHttp().getRequest(); + return request[LOCALE_KEY] || 'en'; + }, +); diff --git a/apps/edr-passenger-api/src/common/i18n/locale.middleware.ts b/apps/edr-passenger-api/src/common/i18n/locale.middleware.ts new file mode 100644 index 000000000..81bbc6990 --- /dev/null +++ b/apps/edr-passenger-api/src/common/i18n/locale.middleware.ts @@ -0,0 +1,16 @@ +import { Injectable, NestMiddleware } from '@nestjs/common'; + +export const LOCALE_KEY = 'locale'; + +@Injectable() +export class LocaleMiddleware implements NestMiddleware { + use(req: any, res: any, next: () => void) { + const locale = + req.query.lang as string || + req.headers['accept-language']?.split(',')[0]?.split('-')[0] || + 'en'; + + req[LOCALE_KEY] = locale; + next(); + } +} diff --git a/apps/edr-passenger-api/src/common/i18n/translations/am.json b/apps/edr-passenger-api/src/common/i18n/translations/am.json new file mode 100644 index 000000000..16250494d --- /dev/null +++ b/apps/edr-passenger-api/src/common/i18n/translations/am.json @@ -0,0 +1,23 @@ +{ + "common": { + "welcome": "እንኳን ደህና መጡ", + "error": "ስህተት ተከስቷል", + "success": "ተሳክቷል" + }, + "booking": { + "created": "ቦታ ማስያዝ በተሳካ ሁኔታ ተፈጥሯል", + "notFound": "ቦታ ማስያዝ አልተገኘም", + "cancelled": "ቦታ ማስያዝ ተሰርዟል", + "confirmed": "ቦታ ማስያዝ ተረጋግጧል" + }, + "payment": { + "succeeded": "ክፍያ ተሳክቷል", + "failed": "ክፍያ አልተሳካም", + "pending": "ክፍያ በመጠባበቅ ላይ" + }, + "ticket": { + "issued": "ትኬት ተሰጥቷል", + "validated": "ትኬት ተረጋግጧል", + "alreadyValidated": "ትኬት ቀድሞውኑ ተረጋግጧል" + } +} diff --git a/apps/edr-passenger-api/src/common/i18n/translations/en.json b/apps/edr-passenger-api/src/common/i18n/translations/en.json new file mode 100644 index 000000000..dd1428f02 --- /dev/null +++ b/apps/edr-passenger-api/src/common/i18n/translations/en.json @@ -0,0 +1,23 @@ +{ + "common": { + "welcome": "Welcome", + "error": "An error occurred", + "success": "Success" + }, + "booking": { + "created": "Booking created successfully", + "notFound": "Booking not found", + "cancelled": "Booking cancelled", + "confirmed": "Booking confirmed" + }, + "payment": { + "succeeded": "Payment successful", + "failed": "Payment failed", + "pending": "Payment pending" + }, + "ticket": { + "issued": "Ticket issued", + "validated": "Ticket validated", + "alreadyValidated": "Ticket already validated" + } +} diff --git a/apps/edr-passenger-api/src/common/i18n/translations/fr.json b/apps/edr-passenger-api/src/common/i18n/translations/fr.json new file mode 100644 index 000000000..8fdd7da89 --- /dev/null +++ b/apps/edr-passenger-api/src/common/i18n/translations/fr.json @@ -0,0 +1,23 @@ +{ + "common": { + "welcome": "Bienvenue", + "error": "Une erreur s'est produite", + "success": "Succès" + }, + "booking": { + "created": "Réservation créée avec succès", + "notFound": "Réservation introuvable", + "cancelled": "Réservation annulée", + "confirmed": "Réservation confirmée" + }, + "payment": { + "succeeded": "Paiement réussi", + "failed": "Échec du paiement", + "pending": "Paiement en attente" + }, + "ticket": { + "issued": "Billet émis", + "validated": "Billet validé", + "alreadyValidated": "Billet déjà validé" + } +} diff --git a/apps/edr-passenger-api/src/common/i18n/translations/om.json b/apps/edr-passenger-api/src/common/i18n/translations/om.json new file mode 100644 index 000000000..1c1b4a77b --- /dev/null +++ b/apps/edr-passenger-api/src/common/i18n/translations/om.json @@ -0,0 +1,23 @@ +{ + "common": { + "welcome": "Baga nagaan dhuftan", + "error": "Dogongora uumame", + "success": "Milkaa'ina" + }, + "booking": { + "created": "Bakka qabachuu milkaa'inaan uumame", + "notFound": "Bakka qabachuu hin argamne", + "cancelled": "Bakka qabachuu haqame", + "confirmed": "Bakka qabachuu mirkaneeffame" + }, + "payment": { + "succeeded": "Kaffaltiin milkaa'e", + "failed": "Kaffaltiin hin milkoofne", + "pending": "Kaffaltiin eegaa jira" + }, + "ticket": { + "issued": "Tiikeetiin kenname", + "validated": "Tiikeetiin mirkaneeffame", + "alreadyValidated": "Tiikeetiin duraan mirkaneeffame" + } +} diff --git a/apps/edr-passenger-api/src/common/iam-adapter.spec.ts b/apps/edr-passenger-api/src/common/iam-adapter.spec.ts new file mode 100644 index 000000000..d0c404366 --- /dev/null +++ b/apps/edr-passenger-api/src/common/iam-adapter.spec.ts @@ -0,0 +1,264 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { ExecutionContext, UnauthorizedException, ForbiddenException } from '@nestjs/common'; +import { Reflector } from '@nestjs/core'; +import { ConfigService } from '@nestjs/config'; +import { HttpService } from '@nestjs/axios'; +import { IamGuard } from './iam-adapter'; +import { of, throwError } from 'rxjs'; + +describe('IamGuard', () => { + let guard: IamGuard; + let httpService: HttpService; + let configService: ConfigService; + let reflector: Reflector; + + const mockConfigService = { + get: jest.fn((key: string) => { + const config: Record = { + IAM_API_URL: 'https://iam.test.com/api', + IAM_ENABLED: 'true', + IAM_API_KEY: 'test-api-key', + }; + return config[key]; + }), + }; + + const mockHttpService = { + post: jest.fn(), + }; + + const mockReflector = { + get: jest.fn(), + }; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + IamGuard, + { provide: ConfigService, useValue: mockConfigService }, + { provide: HttpService, useValue: mockHttpService }, + { provide: Reflector, useValue: mockReflector }, + ], + }).compile(); + + guard = module.get(IamGuard); + httpService = module.get(HttpService); + configService = module.get(ConfigService); + reflector = module.get(Reflector); + + jest.clearAllMocks(); + }); + + const createMockContext = (token?: string, roles?: string[]): ExecutionContext => { + const request = { + headers: token ? { authorization: `Bearer ${token}` } : {}, + user: undefined, + }; + + return { + switchToHttp: () => ({ + getRequest: () => request, + }), + getHandler: () => ({}), + } as ExecutionContext; + }; + + describe('canActivate', () => { + it('should allow access when IAM is disabled', async () => { + mockConfigService.get.mockReturnValueOnce('false'); // IAM_ENABLED + + const context = createMockContext(); + const result = await guard.canActivate(context); + + expect(result).toBe(true); + }); + + it('should throw UnauthorizedException when no token provided', async () => { + const context = createMockContext(); + + await expect(guard.canActivate(context)).rejects.toThrow(UnauthorizedException); + }); + + it('should validate token and allow access', async () => { + const mockValidationResponse = { + data: { + valid: true, + payload: { + sub: 'user-123', + email: 'admin@test.com', + roles: ['ADMIN'], + permissions: ['read', 'write'], + exp: Date.now() + 3600000, + iat: Date.now(), + }, + }, + }; + + mockHttpService.post.mockReturnValue(of(mockValidationResponse)); + mockReflector.get.mockReturnValue(null); + + const context = createMockContext('valid-token'); + const result = await guard.canActivate(context); + + expect(result).toBe(true); + expect(mockHttpService.post).toHaveBeenCalledWith( + 'https://iam.test.com/api/v1/auth/validate', + { token: 'valid-token' }, + expect.objectContaining({ + headers: expect.objectContaining({ + 'X-API-Key': 'test-api-key', + }), + }), + ); + }); + + it('should throw UnauthorizedException for invalid token', async () => { + const mockValidationResponse = { + data: { + valid: false, + error: 'Token expired', + }, + }; + + mockHttpService.post.mockReturnValue(of(mockValidationResponse)); + + const context = createMockContext('invalid-token'); + + await expect(guard.canActivate(context)).rejects.toThrow(UnauthorizedException); + }); + + it('should check required roles', async () => { + const mockValidationResponse = { + data: { + valid: true, + payload: { + sub: 'user-123', + email: 'agent@test.com', + roles: ['AGENT'], + permissions: [], + exp: Date.now() + 3600000, + iat: Date.now(), + }, + }, + }; + + mockHttpService.post.mockReturnValue(of(mockValidationResponse)); + mockReflector.get.mockReturnValue(['ADMIN', 'SUPERVISOR']); + + const context = createMockContext('valid-token'); + + await expect(guard.canActivate(context)).rejects.toThrow(ForbiddenException); + }); + + it('should allow access when user has required role', async () => { + const mockValidationResponse = { + data: { + valid: true, + payload: { + sub: 'user-123', + email: 'admin@test.com', + roles: ['ADMIN'], + permissions: [], + exp: Date.now() + 3600000, + iat: Date.now(), + }, + }, + }; + + mockHttpService.post.mockReturnValue(of(mockValidationResponse)); + mockReflector.get.mockReturnValue(['ADMIN', 'SUPERVISOR']); + + const context = createMockContext('valid-token'); + const result = await guard.canActivate(context); + + expect(result).toBe(true); + }); + + it('should handle HTTP errors gracefully', async () => { + mockHttpService.post.mockReturnValue( + throwError(() => new Error('Network error')), + ); + + const context = createMockContext('valid-token'); + + await expect(guard.canActivate(context)).rejects.toThrow(UnauthorizedException); + }); + + it('should attach user to request', async () => { + const mockValidationResponse = { + data: { + valid: true, + payload: { + sub: 'user-123', + email: 'admin@test.com', + roles: ['ADMIN'], + permissions: ['read', 'write'], + organizationId: 'org-456', + exp: Date.now() + 3600000, + iat: Date.now(), + }, + }, + }; + + mockHttpService.post.mockReturnValue(of(mockValidationResponse)); + mockReflector.get.mockReturnValue(null); + + const context = createMockContext('valid-token'); + await guard.canActivate(context); + + const request = context.switchToHttp().getRequest(); + expect(request.user).toEqual({ + userId: 'user-123', + email: 'admin@test.com', + roles: ['ADMIN'], + permissions: ['read', 'write'], + organizationId: 'org-456', + }); + }); + }); + + describe('token extraction', () => { + it('should extract token from Bearer header', async () => { + const mockValidationResponse = { + data: { + valid: true, + payload: { + sub: 'user-123', + email: 'test@test.com', + roles: [], + permissions: [], + exp: Date.now() + 3600000, + iat: Date.now(), + }, + }, + }; + + mockHttpService.post.mockReturnValue(of(mockValidationResponse)); + mockReflector.get.mockReturnValue(null); + + const context = createMockContext('my-token-123'); + await guard.canActivate(context); + + expect(mockHttpService.post).toHaveBeenCalledWith( + expect.any(String), + { token: 'my-token-123' }, + expect.any(Object), + ); + }); + + it('should reject malformed authorization header', async () => { + const request = { + headers: { authorization: 'InvalidFormat token' }, + }; + + const context = { + switchToHttp: () => ({ + getRequest: () => request, + }), + getHandler: () => ({}), + } as ExecutionContext; + + await expect(guard.canActivate(context)).rejects.toThrow(UnauthorizedException); + }); + }); +}); diff --git a/apps/edr-passenger-api/src/common/iam-adapter.ts b/apps/edr-passenger-api/src/common/iam-adapter.ts new file mode 100644 index 000000000..fb32d9ec6 --- /dev/null +++ b/apps/edr-passenger-api/src/common/iam-adapter.ts @@ -0,0 +1,144 @@ +import { Injectable, CanActivate, ExecutionContext, UnauthorizedException, ForbiddenException } from '@nestjs/common'; +import { Reflector } from '@nestjs/core'; +import { ConfigService } from '@nestjs/config'; +import { HttpService } from '@nestjs/axios'; +import { firstValueFrom } from 'rxjs'; + +/** + * IAM Adapter for @tria-plc corporate identity integration + * + * This adapter wraps the corporate IAM guards and provides a bridge + * between the corporate identity system and the EDR passenger API. + * + * For back-office roles (agent, supervisor, admin, staff), this guard + * validates tokens against the corporate IAM service. + * + * For passenger-facing routes, the existing JWT guard is used. + */ + +export interface IamTokenPayload { + sub: string; + email: string; + roles: string[]; + permissions: string[]; + organizationId?: string; + exp: number; + iat: number; +} + +export interface IamValidationResponse { + valid: boolean; + payload?: IamTokenPayload; + error?: string; +} + +@Injectable() +export class IamGuard implements CanActivate { + private readonly iamApiUrl: string; + private readonly iamEnabled: boolean; + + constructor( + private readonly reflector: Reflector, + private readonly config: ConfigService, + private readonly http: HttpService, + ) { + this.iamApiUrl = this.config.get('IAM_API_URL') || 'https://iam.tria-plc.com/api'; + this.iamEnabled = this.config.get('IAM_ENABLED') === 'true'; + } + + async canActivate(context: ExecutionContext): Promise { + if (!this.iamEnabled) { + // IAM disabled - allow access (for development) + return true; + } + + const request = context.switchToHttp().getRequest(); + const token = this.extractToken(request); + + if (!token) { + throw new UnauthorizedException('No authentication token provided'); + } + + const validation = await this.validateToken(token); + + if (!validation.valid || !validation.payload) { + throw new UnauthorizedException(validation.error || 'Invalid token'); + } + + // Check required roles + const requiredRoles = this.reflector.get('roles', context.getHandler()); + if (requiredRoles && requiredRoles.length > 0) { + const hasRole = requiredRoles.some((role) => validation.payload!.roles.includes(role)); + if (!hasRole) { + throw new ForbiddenException('Insufficient permissions'); + } + } + + // Attach user to request + request.user = { + userId: validation.payload.sub, + email: validation.payload.email, + roles: validation.payload.roles, + permissions: validation.payload.permissions, + organizationId: validation.payload.organizationId, + }; + + return true; + } + + private extractToken(request: any): string | null { + const authHeader = request.headers.authorization; + if (!authHeader) return null; + + const parts = authHeader.split(' '); + if (parts.length !== 2 || parts[0] !== 'Bearer') return null; + + return parts[1]; + } + + private async validateToken(token: string): Promise { + try { + const response = await firstValueFrom( + this.http.post( + `${this.iamApiUrl}/v1/auth/validate`, + { token }, + { + headers: { + 'Content-Type': 'application/json', + 'X-API-Key': this.config.get('IAM_API_KEY') || '', + }, + timeout: 5000, + }, + ), + ); + + return response.data; + } catch (err) { + return { + valid: false, + error: err instanceof Error ? err.message : 'Token validation failed', + }; + } + } +} + +/** + * Decorator to mark routes as requiring IAM authentication + */ +export const UseIamAuth = () => { + // This is a marker decorator that can be used with @UseGuards(IamGuard) + return (target: any, propertyKey?: string, descriptor?: PropertyDescriptor) => { + // Marker only - actual guard is applied via @UseGuards + }; +}; + +/** + * Decorator to specify required roles for IAM-protected routes + */ +export const IamRoles = (...roles: string[]) => { + return (target: any, propertyKey?: string, descriptor?: PropertyDescriptor) => { + if (descriptor) { + Reflect.defineMetadata('roles', roles, descriptor.value); + } + }; +}; diff --git a/apps/edr-passenger-api/src/common/iam.module.ts b/apps/edr-passenger-api/src/common/iam.module.ts new file mode 100644 index 000000000..7a8ec9599 --- /dev/null +++ b/apps/edr-passenger-api/src/common/iam.module.ts @@ -0,0 +1,11 @@ +import { Module, Global } from '@nestjs/common'; +import { HttpModule } from '@nestjs/axios'; +import { IamGuard } from './iam-adapter'; + +@Global() +@Module({ + imports: [HttpModule.register({ timeout: 5000 })], + providers: [IamGuard], + exports: [IamGuard], +}) +export class IamModule {} diff --git a/apps/edr-passenger-api/src/common/interceptors/session-activity.interceptor.ts b/apps/edr-passenger-api/src/common/interceptors/session-activity.interceptor.ts new file mode 100644 index 000000000..9c962ba60 --- /dev/null +++ b/apps/edr-passenger-api/src/common/interceptors/session-activity.interceptor.ts @@ -0,0 +1,49 @@ +import { Injectable, NestInterceptor, ExecutionContext, CallHandler, UnauthorizedException } from '@nestjs/common'; +import { Observable } from 'rxjs'; +import { tap } from 'rxjs/operators'; +import { PrismaService } from '../prisma.service'; +import { ConfigService } from '@nestjs/config'; + +@Injectable() +export class SessionActivityInterceptor implements NestInterceptor { + private readonly inactivityMinutes: number; + + constructor( + private readonly prisma: PrismaService, + private readonly config: ConfigService, + ) { + this.inactivityMinutes = parseInt(this.config.get('SESSION_INACTIVITY_MINUTES') || '30', 10); + } + + async intercept(context: ExecutionContext, next: CallHandler): Promise> { + const request = context.switchToHttp().getRequest(); + const response = context.switchToHttp().getResponse(); + const user = request.user; + + if (user?.userId) { + const session = await this.prisma.session.findFirst({ + where: { userId: user.userId }, + orderBy: { lastActivityAt: 'desc' }, + }); + + if (session) { + const inactiveMinutes = (Date.now() - session.lastActivityAt.getTime()) / 60000; + + if (inactiveMinutes > this.inactivityMinutes) { + await this.prisma.session.delete({ where: { id: session.id } }); + throw new UnauthorizedException('Session expired due to inactivity'); + } + + const expiryWarningMinutes = Math.max(0, this.inactivityMinutes - inactiveMinutes); + response.setHeader('X-Session-Expiry-Warning', Math.floor(expiryWarningMinutes).toString()); + + await this.prisma.session.update({ + where: { id: session.id }, + data: { lastActivityAt: new Date() }, + }); + } + } + + return next.handle().pipe(tap(() => {})); + } +} diff --git a/apps/edr-passenger-api/src/common/prisma.module.ts b/apps/edr-passenger-api/src/common/prisma.module.ts index dd4abed26..36c2ebadf 100644 --- a/apps/edr-passenger-api/src/common/prisma.module.ts +++ b/apps/edr-passenger-api/src/common/prisma.module.ts @@ -1,6 +1,7 @@ import { Module, Global } from '@nestjs/common'; import { PrismaService } from './prisma.service'; +import { SessionActivityInterceptor } from './interceptors/session-activity.interceptor'; @Global() -@Module({ providers: [PrismaService], exports: [PrismaService] }) +@Module({ providers: [PrismaService, SessionActivityInterceptor], exports: [PrismaService, SessionActivityInterceptor] }) export class PrismaModule {} diff --git a/apps/edr-passenger-api/src/common/roles.decorator.ts b/apps/edr-passenger-api/src/common/roles.decorator.ts new file mode 100644 index 000000000..ec0c377c6 --- /dev/null +++ b/apps/edr-passenger-api/src/common/roles.decorator.ts @@ -0,0 +1,5 @@ +import { SetMetadata } from '@nestjs/common'; +import { UserRole } from '@prisma/client'; + +export const ROLES_KEY = 'roles'; +export const Roles = (...roles: UserRole[]) => SetMetadata(ROLES_KEY, roles); diff --git a/apps/edr-passenger-api/src/common/roles.guard.ts b/apps/edr-passenger-api/src/common/roles.guard.ts new file mode 100644 index 000000000..7b4b3eafc --- /dev/null +++ b/apps/edr-passenger-api/src/common/roles.guard.ts @@ -0,0 +1,19 @@ +import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; +import { Reflector } from '@nestjs/core'; +import { UserRole } from '@prisma/client'; +import { ROLES_KEY } from './roles.decorator'; + +@Injectable() +export class RolesGuard implements CanActivate { + constructor(private reflector: Reflector) {} + + canActivate(context: ExecutionContext): boolean { + const requiredRoles = this.reflector.getAllAndOverride(ROLES_KEY, [ + context.getHandler(), + context.getClass(), + ]); + if (!requiredRoles) return true; + const { user } = context.switchToHttp().getRequest(); + return requiredRoles.some((role) => user?.role === role); + } +} diff --git a/apps/edr-passenger-api/src/config/card.config.ts b/apps/edr-passenger-api/src/config/card.config.ts new file mode 100644 index 000000000..1fd36f419 --- /dev/null +++ b/apps/edr-passenger-api/src/config/card.config.ts @@ -0,0 +1,9 @@ +import { registerAs } from '@nestjs/config'; + +export default registerAs('card', () => ({ + baseUrl: process.env.CARD_BASE_URL || '', + apiKey: process.env.CARD_API_KEY || '', + webhookSecret: process.env.CARD_WEBHOOK_SECRET || '', + webhookUrl: process.env.CARD_WEBHOOK_URL || '', + returnUrl: process.env.CARD_RETURN_URL || '', +})); diff --git a/apps/edr-passenger-api/src/config/cbe.config.ts b/apps/edr-passenger-api/src/config/cbe.config.ts new file mode 100644 index 000000000..14ecd1eae --- /dev/null +++ b/apps/edr-passenger-api/src/config/cbe.config.ts @@ -0,0 +1,9 @@ +import { registerAs } from '@nestjs/config'; + +export default registerAs('cbe', () => ({ + baseUrl: process.env.CBE_BASE_URL || '', + merchantId: process.env.CBE_MERCHANT_ID || '', + secretKey: process.env.CBE_SECRET_KEY || '', + notifyUrl: process.env.CBE_NOTIFY_URL || '', + returnUrl: process.env.CBE_RETURN_URL || '', +})); diff --git a/apps/edr-passenger-api/src/config/ebirr.config.ts b/apps/edr-passenger-api/src/config/ebirr.config.ts new file mode 100644 index 000000000..0a00bca2a --- /dev/null +++ b/apps/edr-passenger-api/src/config/ebirr.config.ts @@ -0,0 +1,9 @@ +import { registerAs } from '@nestjs/config'; + +export default registerAs('ebirr', () => ({ + baseUrl: process.env.EBIRR_BASE_URL || '', + merchantCode: process.env.EBIRR_MERCHANT_CODE || '', + secretKey: process.env.EBIRR_SECRET_KEY || '', + notifyUrl: process.env.EBIRR_NOTIFY_URL || '', + returnUrl: process.env.EBIRR_RETURN_URL || '', +})); diff --git a/apps/edr-passenger-api/src/main.ts b/apps/edr-passenger-api/src/main.ts index 71de72738..130fcf3ca 100644 --- a/apps/edr-passenger-api/src/main.ts +++ b/apps/edr-passenger-api/src/main.ts @@ -5,6 +5,7 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import { AppModule } from './app.module'; import { HttpExceptionFilter } from './common/filters/http-exception.filter'; import { ResponseTransformInterceptor } from './common/interceptors/response-transform.interceptor'; +import { SessionActivityInterceptor } from './common/interceptors/session-activity.interceptor'; async function bootstrap() { const app = await NestFactory.create(AppModule); @@ -17,41 +18,202 @@ async function bootstrap() { }); app.useGlobalFilters(new HttpExceptionFilter()); - app.useGlobalInterceptors(new ResponseTransformInterceptor()); + app.useGlobalInterceptors( + new ResponseTransformInterceptor(), + app.get(SessionActivityInterceptor), + ); app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true })); const config = new DocumentBuilder() .setTitle('EDR Passenger API') .setDescription( - 'Ethio-Djibouti Railway Passenger API — booking lifecycle, seat inventory, payment (Telebirr, CBE Birr, eBirr, Card, Wallet), loyalty, live tracking, and support.', + `# Ethio-Djibouti Railway Passenger Booking API + +## Overview +Enterprise-grade REST API for the Ethio-Djibouti Railway passenger booking and management platform. Built with NestJS, TypeScript, PostgreSQL, and Prisma ORM. + +## Authentication + +### Passenger Authentication (JWT-auth) +Used for passenger-facing endpoints. Obtain token via \`POST /auth/login\`. + +**Usage:** Add header \`Authorization: Bearer \` + +### Back-office Authentication (IAM-auth) +Used for agent, fraud, and reporting endpoints. Requires corporate IAM token. + +**Usage:** Add header \`Authorization: Bearer \` + +## Key Features + +### 🎫 Booking Lifecycle +- Search trips with real-time availability +- Create bookings with seat selection +- Modify bookings (seat changes, passenger updates) +- Cancel bookings with automatic refunds +- Multi-segment journey support + +### 💳 Payment Integration +- **Telebirr** - Ethiopia's leading mobile money +- **CBE Birr** - Commercial Bank of Ethiopia +- **eBirr** - Electronic payment gateway +- **Card** - International card payments +- **Wallet** - Internal wallet system + +### 🪑 Seat Management +- Real-time seat availability +- Seat holds (15-minute expiry) +- Auto-assign seats with contiguous algorithm +- Seat blocking for maintenance +- Coach-level seat maps + +### 🎟️ Ticketing +- QR code and barcode generation +- PDF ticket generation +- Gate validation with audit logs +- Offline validation support + +### 🏆 Loyalty Program +- 4 tiers: Bronze, Silver, Gold, Platinum +- Points accumulation on trips +- Reward redemption +- Tier-based benefits + +### 💰 Wallet System +- Top-up via payment methods +- Pay with wallet balance +- Transaction ledger +- Refund to wallet + +### 📍 Live Tracking +- Real-time trip status +- Location updates +- Delay notifications +- Station crowd signals + +### 🔒 Fraud Detection +- Velocity checks (multiple bookings) +- High-value transaction monitoring +- Failed payment pattern detection +- Automatic user blocking + +### 🌍 Internationalization +- Multi-language support (English, Amharic, French, Oromo) +- Locale-based responses +- Currency formatting + +### 👨‍💼 Agent Operations +- Counter booking +- Shift management +- Commission tracking +- Cash reconciliation + +## Rate Limiting +- Auth endpoints: 5 requests/minute +- General endpoints: 100 requests/minute +- Webhook endpoints: No limit + +## Error Handling +All errors follow standard format: +\`\`\`json +{ + "statusCode": 400, + "message": "Validation failed", + "error": "Bad Request", + "timestamp": "2026-05-20T14:30:00.000Z", + "path": "/bookings" +} +\`\`\` + +## Pagination +List endpoints support pagination: +- \`limit\`: Number of items (default: 20, max: 100) +- \`offset\`: Skip items (default: 0) + +## Webhooks +Payment providers send notifications to: +- \`POST /payments/webhooks/telebirr\` +- \`POST /payments/webhooks/cbe-birr\` +- \`POST /payments/webhooks/ebirr\` +- \`POST /payments/webhooks/card\` + +## Support +- **Email:** support@edr-platform.com +- **Documentation:** https://docs.edr-platform.com +- **Status Page:** https://status.edr-platform.com + `, ) - .setVersion('1.0.0') - .addBearerAuth({ type: 'http', scheme: 'bearer', bearerFormat: 'JWT', in: 'header' }, 'JWT-auth') - .addTag('Auth', 'Registration and login') - .addTag('Stations', 'Station directory') - .addTag('Fleet', 'Train services and coaches') - .addTag('Schedule', 'Trips and fare rules') - .addTag('Search', 'Trip search and fare quotes') - .addTag('Seats', 'Seat maps and holds') - .addTag('Booking', 'Booking lifecycle') - .addTag('Payment', 'Payment intents and refunds') - .addTag('Tickets', 'QR ticket generation and validation') - .addTag('Passenger', 'Profiles, traveler profiles, saved routes') - .addTag('Notifications', 'Push and email notifications') - .addTag('Loyalty', 'Points, tiers, and rewards') - .addTag('Wallet', 'Wallet balance and ledger') - .addTag('Promotions', 'Promo codes and campaigns') - .addTag('Live Tracking', 'Real-time trip status and crowd signals') - .addTag('Support', 'FAQ and chat support') - .addTag('Dashboard', 'Home dashboard aggregate') - .addServer('http://localhost:4000', 'Development') + .setVersion('1.0.0') + .addBearerAuth( + { + type: 'http', + scheme: 'bearer', + bearerFormat: 'JWT', + in: 'header', + description: 'JWT token for passenger authentication. Obtain via POST /auth/login' + }, + 'JWT-auth' + ) + .addBearerAuth( + { + type: 'http', + scheme: 'bearer', + bearerFormat: 'JWT', + in: 'header', + description: 'Corporate IAM token for back-office operations (agents, fraud, reports)' + }, + 'IAM-auth' + ) + .addTag('Auth', '🔐 Registration, login, OTP verification, password reset') + .addTag('Agents', '👨‍💼 Agent booking, shifts, commissions, reconciliation') + .addTag('Booking', '🎫 Booking lifecycle, modification, cancellation, refunds') + .addTag('Dashboard', '📊 Home dashboard aggregated data') + .addTag('Fleet', '🚂 Train services, coaches, seat configurations') + .addTag('Fraud Detection', '🔒 Fraud detection, risk scoring, user blocking') + .addTag('Live Tracking', '📍 Real-time trip status, location updates, crowd signals') + .addTag('Loyalty', '🏆 Points accumulation, tier management, rewards redemption') + .addTag('Notifications', '🔔 Push, email, SMS notifications, preferences') + .addTag('Passenger', '👤 Profiles, traveler profiles, saved routes, preferences') + .addTag('Payment', '💳 Payment intents, status queries, refunds') + .addTag('Payment Webhooks', '🔗 Payment provider callback endpoints') + .addTag('Promotions', '🎁 Promo codes, campaigns, discount validation') + .addTag('Reports', '📈 Revenue reports, occupancy analytics, agent sales') + .addTag('Schedule', '🗓️ Trip schedules, fare rules, status updates') + .addTag('Search', '🔍 Trip search, availability, fare quotes') + .addTag('Seats', '🪑 Seat maps, holds, releases, blocking, auto-assign') + .addTag('Segment-based Seats', '🎯 Segment-based seat availability and booking') + .addTag('Stations', '🚉 Station directory, information, crowd signals') + .addTag('Support', '💬 FAQ management, live chat conversations') + .addTag('Tickets', '🎟️ QR/barcode generation, PDF tickets, gate validation') + .addTag('Wallet', '💰 Wallet balance, top-up, transaction ledger') + .addServer('http://localhost:4000', 'Local Development') + .addServer('https://api-staging.edr-platform.com', 'Staging Environment') .addServer('https://api.edr-platform.com', 'Production') .build(); const document = SwaggerModule.createDocument(app, config); SwaggerModule.setup('api-docs', app, document, { - customSiteTitle: 'EDR Passenger API', - swaggerOptions: { persistAuthorization: true, docExpansion: 'none', filter: true }, + customSiteTitle: 'EDR Passenger API Documentation', + customfavIcon: 'https://edr-platform.com/favicon.ico', + customCss: ` + .swagger-ui .topbar { display: none } + .swagger-ui .info { margin: 20px 0 } + .swagger-ui .info .title { font-size: 36px; font-weight: bold } + .swagger-ui .scheme-container { background: #fafafa; padding: 15px; border-radius: 4px } + `, + swaggerOptions: { + persistAuthorization: true, + docExpansion: 'none', + filter: true, + tagsSorter: 'alpha', + operationsSorter: 'alpha', + displayRequestDuration: true, + tryItOutEnabled: true, + syntaxHighlight: { + activate: true, + theme: 'monokai' + } + }, }); const port = process.env.PORT ?? 4000; diff --git a/apps/edr-passenger-api/src/modules/agents/agents.controller.ts b/apps/edr-passenger-api/src/modules/agents/agents.controller.ts new file mode 100644 index 000000000..aa23fe6d0 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/agents/agents.controller.ts @@ -0,0 +1,57 @@ +import { Body, Controller, Get, Param, Post, Query, UseGuards } from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger'; +import { AgentsService } from './agents.service'; +import { CreateAgentBookingDto, OpenShiftDto, CloseShiftDto } from './agents.dto'; +import { IamGuard, IamRoles } from '../../common/iam-adapter'; +import { UserRole } from '@prisma/client'; + +@ApiTags('Agents') +@Controller('agents') +@UseGuards(IamGuard) +@ApiBearerAuth('IAM-auth') +export class AgentsController { + constructor(private service: AgentsService) {} + + @Post('bookings') + @IamRoles('AGENT', 'ADMIN') + @ApiOperation({ summary: 'Create agent booking with cash payment' }) + createBooking(@Body() dto: CreateAgentBookingDto) { + return this.service.createAgentBooking(dto); + } + + @Post('shifts/open') + @IamRoles('AGENT', 'ADMIN') + @ApiOperation({ summary: 'Open agent shift' }) + openShift(@Body() dto: OpenShiftDto) { + return this.service.openShift(dto); + } + + @Post('shifts/close') + @IamRoles('AGENT', 'ADMIN') + @ApiOperation({ summary: 'Close agent shift' }) + closeShift(@Body() dto: CloseShiftDto) { + return this.service.closeShift(dto); + } + + @Get(':agentId/commissions') + @IamRoles('AGENT', 'ADMIN') + @ApiOperation({ summary: 'Get agent commissions' }) + getCommissions( + @Param('agentId') agentId: string, + @Query('dateFrom') dateFrom?: string, + @Query('dateTo') dateTo?: string + ) { + return this.service.getCommissions( + agentId, + dateFrom ? new Date(dateFrom) : undefined, + dateTo ? new Date(dateTo) : undefined + ); + } + + @Get(':agentId/shifts') + @IamRoles('AGENT', 'ADMIN') + @ApiOperation({ summary: 'Get agent shifts' }) + getShifts(@Param('agentId') agentId: string) { + return this.service.getShifts(agentId); + } +} diff --git a/apps/edr-passenger-api/src/modules/agents/agents.dto.ts b/apps/edr-passenger-api/src/modules/agents/agents.dto.ts new file mode 100644 index 000000000..62bdc59ad --- /dev/null +++ b/apps/edr-passenger-api/src/modules/agents/agents.dto.ts @@ -0,0 +1,33 @@ +import { IsString, IsInt, IsBoolean, IsOptional, IsArray, ValidateNested } from 'class-validator'; +import { Type } from 'class-transformer'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; + +export class AgentPassengerDto { + @ApiProperty() @IsString() fullName: string; + @ApiProperty() @IsString() phone: string; + @ApiProperty() @IsString() email: string; + @ApiProperty() @IsString() seatId: string; + @ApiPropertyOptional() @IsOptional() @IsString() idDocumentType?: string; + @ApiPropertyOptional() @IsOptional() @IsString() idDocumentNumber?: string; +} + +export class CreateAgentBookingDto { + @ApiProperty() @IsString() agentId: string; + @ApiProperty() @IsString() tripId: string; + @ApiProperty({ type: [AgentPassengerDto] }) @IsArray() @ValidateNested({ each: true }) @Type(() => AgentPassengerDto) passengers: AgentPassengerDto[]; + @ApiProperty() @IsString() paymentMethod: string; + @ApiPropertyOptional() @IsOptional() @IsInt() cashReceived?: number; + @ApiPropertyOptional() @IsOptional() @IsBoolean() paperTicket?: boolean; + @ApiPropertyOptional() @IsOptional() @IsString() serviceClass?: string; +} + +export class OpenShiftDto { + @ApiProperty() @IsString() agentId: string; + @ApiPropertyOptional() @IsOptional() @IsInt() openingBalance?: number; +} + +export class CloseShiftDto { + @ApiProperty() @IsString() shiftId: string; + @ApiProperty() @IsInt() closingBalance: number; + @ApiPropertyOptional() @IsOptional() @IsString() notes?: string; +} diff --git a/apps/edr-passenger-api/src/modules/agents/agents.module.ts b/apps/edr-passenger-api/src/modules/agents/agents.module.ts new file mode 100644 index 000000000..5c5c2bb61 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/agents/agents.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; +import { HttpModule } from '@nestjs/axios'; +import { AgentsController } from './agents.controller'; +import { AgentsService } from './agents.service'; + +@Module({ + imports: [HttpModule], + controllers: [AgentsController], + providers: [AgentsService], + exports: [AgentsService] +}) +export class AgentsModule {} diff --git a/apps/edr-passenger-api/src/modules/agents/agents.service.ts b/apps/edr-passenger-api/src/modules/agents/agents.service.ts new file mode 100644 index 000000000..37f4fc433 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/agents/agents.service.ts @@ -0,0 +1,131 @@ +import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common'; +import { PrismaService } from '../../common/prisma.service'; +import { CreateAgentBookingDto, OpenShiftDto, CloseShiftDto } from './agents.dto'; + +function generateRef(): string { + const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + return Array.from({ length: 6 }, () => chars[Math.floor(Math.random() * chars.length)]).join(''); +} + +@Injectable() +export class AgentsService { + constructor(private prisma: PrismaService) {} + + async createAgentBooking(dto: CreateAgentBookingDto) { + const agent = await this.prisma.agent.findUnique({ where: { id: dto.agentId }, include: { user: { include: { passenger: true } } } }); + if (!agent || !agent.active) throw new NotFoundException('Agent not found or inactive'); + if (!agent.user.passenger) throw new BadRequestException('Agent must have passenger account'); + + const trip = await this.prisma.trip.findUnique({ where: { id: dto.tripId } }); + if (!trip) throw new NotFoundException('Trip not found'); + + const seatIds = dto.passengers.map(p => p.seatId); + const seats = await this.prisma.seat.findMany({ where: { id: { in: seatIds } } }); + if (seats.length !== seatIds.length) throw new BadRequestException('Invalid seat selection'); + + const baseFare = 45000 * dto.passengers.length; + const totalMinor = baseFare; + + const booking = await this.prisma.booking.create({ + data: { + bookingRef: generateRef(), + passengerId: agent.user.passenger.id, + tripId: dto.tripId, + status: dto.paymentMethod === 'CASH' ? 'CONFIRMED' : 'PENDING_PAYMENT', + totalMinor, + seats: { + create: dto.passengers.map(p => ({ + seatId: p.seatId, + passengerName: p.fullName, + idDocumentType: p.idDocumentType, + idDocumentNumber: p.idDocumentNumber + })) + } + }, + include: { seats: true } + }); + + await this.prisma.seat.updateMany({ + where: { id: { in: seatIds } }, + data: { status: 'BOOKED' } + }); + + const changeGiven = dto.cashReceived ? dto.cashReceived - totalMinor : 0; + await this.prisma.agentBooking.create({ + data: { + agentId: dto.agentId, + bookingId: booking.id, + paymentMethod: dto.paymentMethod, + cashReceived: dto.cashReceived, + changeGiven, + paperTicket: dto.paperTicket ?? false + } + }); + + const commissionAmount = Math.floor(totalMinor * agent.commissionRate / 100); + await this.prisma.agentCommission.create({ + data: { + agentId: dto.agentId, + bookingId: booking.id, + amountMinor: commissionAmount, + rate: agent.commissionRate + } + }); + + return { booking, commission: commissionAmount }; + } + + async openShift(dto: OpenShiftDto) { + const agent = await this.prisma.agent.findUnique({ where: { id: dto.agentId } }); + if (!agent) throw new NotFoundException('Agent not found'); + + const openShift = await this.prisma.agentShift.findFirst({ + where: { agentId: dto.agentId, closedAt: null } + }); + if (openShift) throw new BadRequestException('Shift already open'); + + return this.prisma.agentShift.create({ + data: { + agentId: dto.agentId, + openingBalance: dto.openingBalance ?? 0 + } + }); + } + + async closeShift(dto: CloseShiftDto) { + const shift = await this.prisma.agentShift.findUnique({ where: { id: dto.shiftId } }); + if (!shift) throw new NotFoundException('Shift not found'); + if (shift.closedAt) throw new BadRequestException('Shift already closed'); + + return this.prisma.agentShift.update({ + where: { id: dto.shiftId }, + data: { + closedAt: new Date(), + closingBalance: dto.closingBalance, + notes: dto.notes, + reconciled: true + } + }); + } + + async getCommissions(agentId: string, dateFrom?: Date, dateTo?: Date) { + return this.prisma.agentCommission.findMany({ + where: { + agentId, + createdAt: { + gte: dateFrom, + lte: dateTo + } + }, + orderBy: { createdAt: 'desc' } + }); + } + + async getShifts(agentId: string) { + return this.prisma.agentShift.findMany({ + where: { agentId }, + orderBy: { openedAt: 'desc' }, + take: 20 + }); + } +} diff --git a/apps/edr-passenger-api/src/modules/auth/auth.controller.ts b/apps/edr-passenger-api/src/modules/auth/auth.controller.ts index ea128b261..6d31c8323 100644 --- a/apps/edr-passenger-api/src/modules/auth/auth.controller.ts +++ b/apps/edr-passenger-api/src/modules/auth/auth.controller.ts @@ -1,7 +1,7 @@ -import { Body, Controller, Post } from '@nestjs/common'; -import { ApiTags, ApiOperation } from '@nestjs/swagger'; +import { Body, Controller, Post, HttpCode, HttpStatus } from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiResponse, ApiBody } from '@nestjs/swagger'; import { AuthService } from './auth.service'; -import { RegisterDto, LoginDto } from './auth.dto'; +import { RegisterDto, LoginDto, RequestOtpDto, VerifyOtpDto, RequestPasswordResetDto, ResetPasswordDto } from './auth.dto'; @ApiTags('Auth') @Controller('auth') @@ -9,10 +9,73 @@ export class AuthController { constructor(private service: AuthService) {} @Post('register') - @ApiOperation({ summary: 'Register new user' }) + @ApiOperation({ + summary: 'Register new passenger account', + description: 'Create a new passenger account with email, phone, and password. Returns user details and JWT token for immediate login.' + }) + @ApiResponse({ status: 201, description: 'Account created successfully. Returns user object and JWT token.' }) + @ApiResponse({ status: 400, description: 'Validation error (invalid email, weak password, etc.)' }) + @ApiResponse({ status: 409, description: 'Email or phone already registered' }) + @ApiBody({ type: RegisterDto }) register(@Body() dto: RegisterDto) { return this.service.register(dto); } @Post('login') - @ApiOperation({ summary: 'Login and get JWT' }) + @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Login with email and password', + description: 'Authenticate user and receive JWT token. Token expires in 7 days by default. Failed login attempts are tracked and account may be locked after 5 consecutive failures.' + }) + @ApiResponse({ status: 200, description: 'Login successful. Returns JWT token and user details.' }) + @ApiResponse({ status: 401, description: 'Invalid credentials or account locked' }) + @ApiResponse({ status: 403, description: 'Account temporarily blocked due to fraud detection' }) + @ApiBody({ type: LoginDto }) login(@Body() dto: LoginDto) { return this.service.login(dto); } + + @Post('otp/request') + @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Request OTP verification code', + description: 'Send a 6-digit OTP code to user email. Code expires in 10 minutes. Used for registration verification, password reset, or two-factor authentication.' + }) + @ApiResponse({ status: 200, description: 'OTP sent successfully to email' }) + @ApiResponse({ status: 404, description: 'Email not found (for PASSWORD_RESET purpose)' }) + @ApiResponse({ status: 429, description: 'Too many OTP requests. Please wait before requesting again.' }) + @ApiBody({ type: RequestOtpDto }) + requestOtp(@Body() dto: RequestOtpDto) { return this.service.requestOtp(dto); } + + @Post('otp/verify') + @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Verify OTP code', + description: 'Validate the 6-digit OTP code sent to user email. Code must match and not be expired.' + }) + @ApiResponse({ status: 200, description: 'OTP verified successfully' }) + @ApiResponse({ status: 400, description: 'Invalid or expired OTP code' }) + @ApiResponse({ status: 404, description: 'No OTP found for this email and purpose' }) + @ApiBody({ type: VerifyOtpDto }) + verifyOtp(@Body() dto: VerifyOtpDto) { return this.service.verifyOtp(dto); } + + @Post('password/reset-request') + @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Request password reset link', + description: 'Send password reset link to user email. Link contains a secure token valid for 1 hour.' + }) + @ApiResponse({ status: 200, description: 'Password reset email sent successfully' }) + @ApiResponse({ status: 404, description: 'Email not found' }) + @ApiResponse({ status: 429, description: 'Too many reset requests. Please wait before trying again.' }) + @ApiBody({ type: RequestPasswordResetDto }) + requestPasswordReset(@Body() dto: RequestPasswordResetDto) { return this.service.requestPasswordReset(dto); } + + @Post('password/reset') + @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Reset password with token', + description: 'Reset user password using the token received via email. Token is single-use and expires after 1 hour.' + }) + @ApiResponse({ status: 200, description: 'Password reset successfully' }) + @ApiResponse({ status: 400, description: 'Invalid, expired, or already used token' }) + @ApiResponse({ status: 404, description: 'User not found' }) + @ApiBody({ type: ResetPasswordDto }) + resetPassword(@Body() dto: ResetPasswordDto) { return this.service.resetPassword(dto); } } diff --git a/apps/edr-passenger-api/src/modules/auth/auth.dto.ts b/apps/edr-passenger-api/src/modules/auth/auth.dto.ts index 8cfe1ac65..d44159c67 100644 --- a/apps/edr-passenger-api/src/modules/auth/auth.dto.ts +++ b/apps/edr-passenger-api/src/modules/auth/auth.dto.ts @@ -1,14 +1,152 @@ -import { IsEmail, IsString, MinLength } from 'class-validator'; -import { ApiProperty } from '@nestjs/swagger'; +import { IsEmail, IsString, MinLength, IsOptional } from 'class-validator'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; export class RegisterDto { - @ApiProperty({ example: 'Kelemu Ketsela' }) @IsString() fullName: string; - @ApiProperty({ example: 'kelemu@email.com' }) @IsEmail() email: string; - @ApiProperty({ example: '+251912345678' }) @IsString() phone: string; - @ApiProperty({ example: 'password123', minLength: 8 }) @IsString() @MinLength(8) password: string; + @ApiProperty({ + description: 'Full name of the passenger', + example: 'Kelemu Ketsela', + minLength: 2, + maxLength: 100 + }) + @IsString() + fullName: string; + + @ApiProperty({ + description: 'Email address (must be unique)', + example: 'kelemu@email.com', + format: 'email' + }) + @IsEmail() + email: string; + + @ApiProperty({ + description: 'Phone number with country code', + example: '+251912345678', + pattern: '^\\+[1-9]\\d{1,14}$' + }) + @IsString() + phone: string; + + @ApiProperty({ + description: 'Password (minimum 8 characters)', + example: 'SecurePass123', + minLength: 8, + format: 'password' + }) + @IsString() + @MinLength(8) + password: string; + + @ApiPropertyOptional({ + description: 'Nationality of the passenger', + example: 'Ethiopian' + }) + @IsOptional() + @IsString() + nationality?: string; + + @ApiPropertyOptional({ + description: 'National ID number', + example: 'ET123456789' + }) + @IsOptional() + @IsString() + nationalId?: string; + + @ApiPropertyOptional({ + description: 'Passport number for international travelers', + example: 'P1234567' + }) + @IsOptional() + @IsString() + passportNumber?: string; } export class LoginDto { - @ApiProperty({ example: 'kelemu@email.com' }) @IsEmail() email: string; - @ApiProperty({ example: 'password123' }) @IsString() password: string; + @ApiProperty({ + description: 'Registered email address', + example: 'kelemu@email.com', + format: 'email' + }) + @IsEmail() + email: string; + + @ApiProperty({ + description: 'Account password', + example: 'password123', + format: 'password' + }) + @IsString() + password: string; +} + +export class RequestOtpDto { + @ApiProperty({ + description: 'Email address to send OTP', + example: 'kelemu@email.com' + }) + @IsEmail() + email: string; + + @ApiProperty({ + description: 'Purpose of OTP (REGISTRATION, PASSWORD_RESET, VERIFICATION)', + example: 'REGISTRATION', + enum: ['REGISTRATION', 'PASSWORD_RESET', 'VERIFICATION'] + }) + @IsString() + purpose: string; +} + +export class VerifyOtpDto { + @ApiProperty({ + description: 'Email address', + example: 'kelemu@email.com' + }) + @IsEmail() + email: string; + + @ApiProperty({ + description: '6-digit OTP code', + example: '123456', + minLength: 6, + maxLength: 6 + }) + @IsString() + code: string; + + @ApiProperty({ + description: 'Purpose of OTP verification', + example: 'REGISTRATION', + enum: ['REGISTRATION', 'PASSWORD_RESET', 'VERIFICATION'] + }) + @IsString() + purpose: string; +} + +export class RequestPasswordResetDto { + @ApiProperty({ + description: 'Email address of the account', + example: 'kelemu@email.com' + }) + @IsEmail() + email: string; +} + +export class ResetPasswordDto { + @ApiProperty({ + description: 'Password reset token received via email', + example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' + }) + @IsString() + token: string; + + @ApiProperty({ + description: 'New password (minimum 8 characters)', + example: 'NewSecurePass123', + minLength: 8, + format: 'password' + }) + @IsString() + @MinLength(8) + newPassword: string; } diff --git a/apps/edr-passenger-api/src/modules/auth/auth.service.ts b/apps/edr-passenger-api/src/modules/auth/auth.service.ts index 7ba9937d8..deb2e9da4 100644 --- a/apps/edr-passenger-api/src/modules/auth/auth.service.ts +++ b/apps/edr-passenger-api/src/modules/auth/auth.service.ts @@ -1,8 +1,9 @@ -import { Injectable, UnauthorizedException, ConflictException } from '@nestjs/common'; +import { Injectable, UnauthorizedException, ConflictException, BadRequestException } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { PrismaService } from '../../common/prisma.service'; -import { RegisterDto, LoginDto } from './auth.dto'; +import { RegisterDto, LoginDto, RequestOtpDto, VerifyOtpDto, RequestPasswordResetDto, ResetPasswordDto } from './auth.dto'; import * as bcrypt from 'bcrypt'; +import * as crypto from 'crypto'; @Injectable() export class AuthService { @@ -15,28 +16,115 @@ export class AuthService { if (exists) throw new ConflictException('Email or phone already registered'); const passwordHash = await bcrypt.hash(dto.password, 10); const user = await this.prisma.user.create({ - data: { fullName: dto.fullName, email: dto.email, phone: dto.phone, passwordHash }, + data: { + fullName: dto.fullName, + email: dto.email, + phone: dto.phone, + passwordHash, + nationality: dto.nationality, + nationalId: dto.nationalId, + passportNumber: dto.passportNumber + }, }); const passenger = await this.prisma.passenger.create({ data: { userId: user.id } }); await this.prisma.loyaltyAccount.create({ data: { passengerId: passenger.id } }); await this.prisma.walletAccount.create({ data: { passengerId: passenger.id } }); await this.prisma.userPreferences.create({ data: { userId: user.id } }); + await this.createAuditLog(user.id, 'USER_REGISTERED', 'User', user.id, null, { email: user.email }); return this.signToken(user.id, user.email, user.role, passenger.id); } async login(dto: LoginDto) { const user = await this.prisma.user.findUnique({ where: { email: dto.email }, - include: { passenger: true }, + include: { passenger: true, agent: true }, }); - if (!user || !(await bcrypt.compare(dto.password, user.passwordHash))) { + if (!user) throw new UnauthorizedException('Invalid credentials'); + + if (user.lockedUntil && user.lockedUntil > new Date()) { + throw new UnauthorizedException(`Account locked until ${user.lockedUntil.toISOString()}`); + } + + if (!(await bcrypt.compare(dto.password, user.passwordHash))) { + await this.prisma.user.update({ + where: { id: user.id }, + data: { + failedLoginAttempts: { increment: 1 }, + lockedUntil: user.failedLoginAttempts >= 4 ? new Date(Date.now() + 15 * 60 * 1000) : null + } + }); throw new UnauthorizedException('Invalid credentials'); } - return this.signToken(user.id, user.email, user.role, user.passenger?.id); + + await this.prisma.user.update({ + where: { id: user.id }, + data: { failedLoginAttempts: 0, lockedUntil: null } + }); + + await this.createAuditLog(user.id, 'USER_LOGIN', 'User', user.id, null, null); + return this.signToken(user.id, user.email, user.role, user.passenger?.id, user.agent?.id); } - private signToken(userId: string, email: string, role: string, passengerId?: string) { - const token = this.jwt.sign({ sub: userId, email, role, passengerId }); - return { token, user: { id: userId, email, role, passengerId } }; + async requestOtp(dto: RequestOtpDto) { + const code = Math.floor(100000 + Math.random() * 900000).toString(); + const expiresAt = new Date(Date.now() + 10 * 60 * 1000); + await this.prisma.otpCode.create({ + data: { email: dto.email, code, purpose: dto.purpose, expiresAt } + }); + console.log(`[OTP] ${dto.email} - ${code} (${dto.purpose})`); + return { sent: true, expiresIn: 600 }; + } + + async verifyOtp(dto: VerifyOtpDto) { + const otp = await this.prisma.otpCode.findFirst({ + where: { email: dto.email, code: dto.code, purpose: dto.purpose, verified: false, expiresAt: { gt: new Date() } }, + orderBy: { createdAt: 'desc' } + }); + if (!otp) throw new BadRequestException('Invalid or expired OTP'); + await this.prisma.otpCode.update({ where: { id: otp.id }, data: { verified: true } }); + return { verified: true }; + } + + async requestPasswordReset(dto: RequestPasswordResetDto) { + const user = await this.prisma.user.findUnique({ where: { email: dto.email } }); + if (!user) return { sent: true }; + const token = crypto.randomBytes(32).toString('hex'); + const expiresAt = new Date(Date.now() + 60 * 60 * 1000); + await this.prisma.passwordResetToken.create({ + data: { userId: user.id, token, expiresAt } + }); + console.log(`[PASSWORD_RESET] ${dto.email} - ${token}`); + return { sent: true }; + } + + async resetPassword(dto: ResetPasswordDto) { + const resetToken = await this.prisma.passwordResetToken.findUnique({ + where: { token: dto.token } + }); + if (!resetToken || resetToken.used || resetToken.expiresAt < new Date()) { + throw new BadRequestException('Invalid or expired reset token'); + } + const passwordHash = await bcrypt.hash(dto.newPassword, 10); + await this.prisma.user.update({ + where: { id: resetToken.userId }, + data: { passwordHash, failedLoginAttempts: 0, lockedUntil: null } + }); + await this.prisma.passwordResetToken.update({ + where: { id: resetToken.id }, + data: { used: true } + }); + await this.createAuditLog(resetToken.userId, 'PASSWORD_RESET', 'User', resetToken.userId, null, null); + return { reset: true }; + } + + private signToken(userId: string, email: string, role: string, passengerId?: string, agentId?: string) { + const token = this.jwt.sign({ sub: userId, email, role, passengerId, agentId }); + return { token, user: { id: userId, email, role, passengerId, agentId } }; + } + + private async createAuditLog(userId: string, action: string, entityType: string, entityId: string, oldData: any, newData: any) { + await this.prisma.auditLog.create({ + data: { userId, action, entityType, entityId, oldData, newData } + }); } } diff --git a/apps/edr-passenger-api/src/modules/bookings/bookings.controller.ts b/apps/edr-passenger-api/src/modules/bookings/bookings.controller.ts index eb7e533b5..b7363ec70 100644 --- a/apps/edr-passenger-api/src/modules/bookings/bookings.controller.ts +++ b/apps/edr-passenger-api/src/modules/bookings/bookings.controller.ts @@ -1,7 +1,7 @@ -import { Body, Controller, Delete, Get, Param, Post, UseGuards } from '@nestjs/common'; +import { Body, Controller, Delete, Get, Param, Post, Patch, UseGuards } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger'; import { BookingsService } from './bookings.service'; -import { CreateBookingDto } from './bookings.dto'; +import { CreateBookingDto, ModifyBookingDto, CancelBookingDto } from './bookings.dto'; import { JwtGuard } from '../../common/jwt.guard'; @ApiTags('Booking') @@ -10,7 +10,28 @@ import { JwtGuard } from '../../common/jwt.guard'; @ApiBearerAuth('JWT-auth') export class BookingsController { constructor(private service: BookingsService) {} - @Post() @ApiOperation({ summary: 'Create booking from seat hold' }) create(@Body() dto: CreateBookingDto) { return this.service.create(dto); } - @Get(':bookingRef') @ApiOperation({ summary: 'Get booking by reference' }) getByRef(@Param('bookingRef') ref: string) { return this.service.getByRef(ref); } - @Delete(':bookingRef')@ApiOperation({ summary: 'Cancel booking' }) cancel(@Param('bookingRef') ref: string) { return this.service.cancel(ref); } + + @Post() + @ApiOperation({ summary: 'Create booking from seat hold' }) + create(@Body() dto: CreateBookingDto) { + return this.service.create(dto); + } + + @Get(':bookingRef') + @ApiOperation({ summary: 'Get booking by reference' }) + getByRef(@Param('bookingRef') ref: string) { + return this.service.getByRef(ref); + } + + @Patch(':bookingRef/modify') + @ApiOperation({ summary: 'Modify booking seats or trip' }) + modify(@Body() dto: ModifyBookingDto) { + return this.service.modify(dto); + } + + @Delete(':bookingRef') + @ApiOperation({ summary: 'Cancel booking' }) + cancel(@Param('bookingRef') ref: string, @Body() dto: CancelBookingDto) { + return this.service.cancel(ref, dto.reason); + } } diff --git a/apps/edr-passenger-api/src/modules/bookings/bookings.dto.ts b/apps/edr-passenger-api/src/modules/bookings/bookings.dto.ts index a2e208d2c..eae26111e 100644 --- a/apps/edr-passenger-api/src/modules/bookings/bookings.dto.ts +++ b/apps/edr-passenger-api/src/modules/bookings/bookings.dto.ts @@ -16,7 +16,25 @@ export class CreateBookingDto { @ApiProperty() @IsString() tripId: string; @ApiProperty() @IsString() holdId: string; @ApiProperty({ type: [PassengerInputDto] }) @IsArray() @ValidateNested({ each: true }) @Type(() => PassengerInputDto) passengers: PassengerInputDto[]; - @ApiPropertyOptional({ example: 'ECONOMY', enum: ['ECONOMY', 'BUSINESS', 'FIRST'] }) @IsOptional() @IsString() serviceClass?: string; + @ApiPropertyOptional({ + example: 'ECONOMY_REGULAR', + enum: ['ECONOMY_REGULAR', 'ECONOMY_BED_LOWER', 'ECONOMY_BED_MIDDLE', 'ECONOMY_BED_UPPER', 'VIP_BED_LOWER', 'VIP_BED_UPPER'] + }) + @IsOptional() @IsString() serviceClass?: string; @ApiPropertyOptional() @IsOptional() @IsString() promoCode?: string; @ApiPropertyOptional() @IsOptional() @IsInt() loyaltyRedemptionPoints?: number; + @ApiPropertyOptional({ example: 'ONE_WAY' }) @IsOptional() @IsString() bookingType?: string; + @ApiPropertyOptional({ description: 'Auto-assign seats instead of manual selection' }) @IsOptional() autoAssign?: boolean; +} + +export class ModifyBookingDto { + @ApiProperty() @IsString() bookingRef: string; + @ApiProperty() @IsString() newTripId: string; + @ApiProperty({ type: [String] }) @IsArray() newSeatIds: string[]; + @ApiPropertyOptional() @IsOptional() @IsString() reason?: string; +} + +export class CancelBookingDto { + @ApiProperty() @IsString() bookingRef: string; + @ApiPropertyOptional() @IsOptional() @IsString() reason?: string; } diff --git a/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts b/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts index cb6158639..9532531f3 100644 --- a/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts +++ b/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts @@ -2,7 +2,7 @@ import { Injectable, NotFoundException, BadRequestException } from '@nestjs/comm import { PrismaService } from '../../common/prisma.service'; import { SeatsService } from '../seats/seats.service'; import { EventEmitter2 } from '@nestjs/event-emitter'; -import { CreateBookingDto } from './bookings.dto'; +import { CreateBookingDto, ModifyBookingDto, CancelBookingDto } from './bookings.dto'; import { Cron, CronExpression } from '@nestjs/schedule'; import { SearchService } from '../search/search.service'; @@ -20,13 +20,44 @@ export class BookingsService { if (!hold || hold.expiresAt < new Date()) throw new BadRequestException('Seat hold expired'); const trip = await this.prisma.trip.findUnique({ where: { id: dto.tripId }, include: { originStation: true, destinationStation: true } }); if (!trip) throw new NotFoundException('Trip not found'); - const fareQuote = await this.searchService.getFareQuote({ tripId: dto.tripId, serviceClass: dto.serviceClass ?? 'ECONOMY', passengerCount: dto.passengers.length, promoCode: dto.promoCode, loyaltyRedemptionPoints: dto.loyaltyRedemptionPoints }); + + let seatIds: string[]; + if (dto.autoAssign) { + seatIds = await this.seatsService.autoAssignSeats( + dto.tripId, + dto.passengers.length, + dto.serviceClass ?? 'ECONOMY_REGULAR', + ); + await this.seatsService.confirmSeats(seatIds); + } else { + seatIds = dto.passengers.map((p) => p.seatId); + } + + const fareQuote = await this.searchService.getFareQuote({ tripId: dto.tripId, serviceClass: dto.serviceClass ?? 'ECONOMY_REGULAR', passengerCount: dto.passengers.length, promoCode: dto.promoCode, loyaltyRedemptionPoints: dto.loyaltyRedemptionPoints }); const booking = await this.prisma.booking.create({ - data: { bookingRef: generateRef(), passengerId: dto.passengerId, tripId: dto.tripId, status: 'PENDING_PAYMENT', totalMinor: fareQuote.totalMinor, seats: { create: dto.passengers.map((p) => ({ seatId: p.seatId, passengerName: p.fullName, idDocumentType: p.idDocumentType, idDocumentNumber: p.idDocumentNumber })) } }, + data: { + bookingRef: generateRef(), + passengerId: dto.passengerId, + tripId: dto.tripId, + status: 'PENDING_PAYMENT', + totalMinor: fareQuote.totalMinor, + bookingType: dto.bookingType ?? 'ONE_WAY', + seats: { create: dto.passengers.map((p, i) => ({ seatId: seatIds[i], passengerName: p.fullName, idDocumentType: p.idDocumentType, idDocumentNumber: p.idDocumentNumber })) } + }, include: { seats: { include: { seat: true } }, trip: { include: { originStation: true, destinationStation: true, service: true } } }, }); this.eventEmitter.emit('booking.created', { booking }); - return booking; + return { + ...booking, + fareBreakdown: { + baseFare: fareQuote.baseFareMinor / 100, + discount: fareQuote.discountMinor / 100, + loyaltyRedemption: fareQuote.loyaltyRedemptionMinor / 100, + taxesFees: fareQuote.taxesFeesMinor / 100, + total: fareQuote.totalMinor / 100, + currency: fareQuote.currency + } + }; } async getByRef(bookingRef: string) { @@ -37,6 +68,7 @@ export class BookingsService { bookingRef: booking.bookingRef, status: booking.status, totalFare: booking.totalMinor / 100, + bookingType: booking.bookingType, createdAt: booking.createdAt, trip: { number: booking.trip.service.number, @@ -53,12 +85,55 @@ export class BookingsService { }; } - async cancel(bookingRef: string) { - const booking = await this.prisma.booking.findUnique({ where: { bookingRef }, include: { seats: true } }); + async modify(dto: ModifyBookingDto) { + const booking = await this.prisma.booking.findUnique({ where: { bookingRef: dto.bookingRef }, include: { seats: true, trip: true } }); if (!booking) throw new NotFoundException('Booking not found'); - if (booking.status === 'CONFIRMED') throw new BadRequestException('Use refund for confirmed bookings'); + if (booking.status !== 'CONFIRMED') throw new BadRequestException('Only confirmed bookings can be modified'); + if (booking.trip.departureAt < new Date()) throw new BadRequestException('Cannot modify past bookings'); + + const oldSeats = booking.seats.map(s => s.seatId); + const fareAdjustment = 0; + + await this.prisma.bookingModification.create({ + data: { + bookingId: booking.id, + modifiedBy: booking.passengerId, + modificationType: 'SEAT_CHANGE', + oldData: { tripId: booking.tripId, seatIds: oldSeats }, + newData: { tripId: dto.newTripId, seatIds: dto.newSeatIds }, + fareAdjustment, + reason: dto.reason + } + }); + + await this.seatsService.releaseSeats(oldSeats); + await this.seatsService.confirmSeats(dto.newSeatIds); + + return { modified: true, bookingRef: dto.bookingRef }; + } + + async cancel(bookingRef: string, reason?: string) { + const booking = await this.prisma.booking.findUnique({ where: { bookingRef }, include: { seats: true, paymentIntent: true } }); + if (!booking) throw new NotFoundException('Booking not found'); + if (booking.status === 'CANCELLED') throw new BadRequestException('Booking already cancelled'); + + const refundAmount = booking.status === 'CONFIRMED' ? Math.floor(booking.totalMinor * 0.8) : 0; + + await this.prisma.bookingCancellation.create({ + data: { + bookingId: booking.id, + cancelledBy: booking.passengerId, + reason, + refundAmount, + refundMethod: booking.paymentIntent?.method ?? 'ORIGINAL', + refundStatus: 'PENDING' + } + }); + await this.seatsService.releaseSeats(booking.seats.map((s) => s.seatId)); - return this.prisma.booking.update({ where: { bookingRef }, data: { status: 'CANCELLED' } }); + await this.prisma.booking.update({ where: { bookingRef }, data: { status: 'CANCELLED' } }); + + return { cancelled: true, refundAmount: refundAmount / 100, currency: 'ETB' }; } @Cron(CronExpression.EVERY_MINUTE) diff --git a/apps/edr-passenger-api/src/modules/fraud/fraud.controller.ts b/apps/edr-passenger-api/src/modules/fraud/fraud.controller.ts new file mode 100644 index 000000000..4056b4259 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/fraud/fraud.controller.ts @@ -0,0 +1,74 @@ +import { Controller, Get, Post, Body, Query, UseGuards, Logger } from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger'; +import { FraudService, FraudRuleConfig } from './fraud.service'; +import { IamGuard, IamRoles } from '../../common/iam-adapter'; +import { UserRole } from '@prisma/client'; + +@ApiTags('Fraud Detection') +@Controller('fraud') +@UseGuards(IamGuard) +@ApiBearerAuth('IAM-auth') +export class FraudController { + private readonly logger = new Logger(FraudController.name); + + constructor(private fraudService: FraudService) {} + + /** + * Get fraud alerts + */ + @Get('alerts') + @IamRoles('ADMIN', 'SUPERVISOR') + @ApiOperation({ summary: 'Get fraud alerts' }) + async getAlerts( + @Query('userId') userId?: string, + @Query('limit') limit?: string, + @Query('offset') offset?: string, + ) { + const alerts = await this.fraudService.getAlerts(userId, parseInt(limit || '100'), parseInt(offset || '0')); + return { data: alerts, total: alerts.length }; + } + + /** + * Get fraud rules + */ + @Get('rules') + @IamRoles('ADMIN') + @ApiOperation({ summary: 'Get fraud detection rules' }) + async getRules() { + const rules = await this.fraudService.getRules(); + return { data: rules }; + } + + /** + * Create or update fraud rule + */ + @Post('rules') + @IamRoles('ADMIN') + @ApiOperation({ summary: 'Create or update fraud rule' }) + async upsertRule(@Body() body: { type: string; config: FraudRuleConfig }) { + const rule = await this.fraudService.upsertRule(body.type, body.config); + return { data: rule, message: 'Rule updated successfully' }; + } + + /** + * Block user temporarily + */ + @Post('actions/block') + @IamRoles('ADMIN', 'SUPERVISOR') + @ApiOperation({ summary: 'Block user temporarily' }) + async blockUser(@Body() body: { userId: string; durationMinutes: number }) { + await this.fraudService.blockUserTemporarily(body.userId, body.durationMinutes); + return { message: `User blocked for ${body.durationMinutes} minutes` }; + } + + /** + * Unblock user + */ + @Post('actions/unblock') + @IamRoles('ADMIN', 'SUPERVISOR') + @ApiOperation({ summary: 'Unblock user' }) + async unblockUser(@Body() body: { userId: string }) { + await this.fraudService.unblockUser(body.userId); + return { message: 'User unblocked' }; + } +} diff --git a/apps/edr-passenger-api/src/modules/fraud/fraud.module.ts b/apps/edr-passenger-api/src/modules/fraud/fraud.module.ts new file mode 100644 index 000000000..a95078578 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/fraud/fraud.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; +import { HttpModule } from '@nestjs/axios'; +import { FraudService } from './fraud.service'; +import { FraudController } from './fraud.controller'; + +@Module({ + imports: [HttpModule], + providers: [FraudService], + controllers: [FraudController], + exports: [FraudService], +}) +export class FraudModule {} diff --git a/apps/edr-passenger-api/src/modules/fraud/fraud.service.ts b/apps/edr-passenger-api/src/modules/fraud/fraud.service.ts new file mode 100644 index 000000000..7c3b66e6b --- /dev/null +++ b/apps/edr-passenger-api/src/modules/fraud/fraud.service.ts @@ -0,0 +1,252 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { OnEvent } from '@nestjs/event-emitter'; +import { PrismaService } from '../../common/prisma.service'; + +export interface FraudRuleConfig { + type: 'VELOCITY' | 'HIGH_VALUE' | 'FAILED_PAYMENTS' | 'MULTIPLE_METHODS'; + enabled: boolean; + threshold: number; + timeWindowMinutes?: number; + blockDurationMinutes?: number; +} + +@Injectable() +export class FraudService { + private readonly logger = new Logger(FraudService.name); + + constructor(private prisma: PrismaService) {} + + /** + * Evaluate fraud rules and create alerts if triggered + */ + async evaluateRules( + userId: string, + eventType: 'booking.created' | 'payment.failed' | 'auth.login.failed', + context: Record, + ): Promise<{ triggered: boolean; rules: string[] }> { + const triggeredRules: string[] = []; + const user = await this.prisma.user.findUnique({ where: { id: userId } }); + + if (!user) return { triggered: false, rules: [] }; + + // Check velocity rule (multiple bookings in short time) + if (eventType === 'booking.created') { + const velocityTriggered = await this.checkVelocityRule(userId); + if (velocityTriggered) { + triggeredRules.push('VELOCITY'); + } + + // Check high-value booking + const amount = (context.amountMinor as number) || 0; + const highValueTriggered = await this.checkHighValueRule(amount); + if (highValueTriggered) { + triggeredRules.push('HIGH_VALUE'); + } + } + + // Check repeated failed payments + if (eventType === 'payment.failed') { + const failedPaymentTriggered = await this.checkFailedPaymentRule(userId); + if (failedPaymentTriggered) { + triggeredRules.push('FAILED_PAYMENTS'); + } + } + + // Create alert if rules triggered + if (triggeredRules.length > 0) { + await this.createFraudAlert(userId, eventType, triggeredRules, context); + return { triggered: true, rules: triggeredRules }; + } + + return { triggered: false, rules: [] }; + } + + /** + * Check velocity rule: X bookings in Y minutes + */ + private async checkVelocityRule(userId: string): Promise { + const rule = await this.prisma.fraudRule.findFirst({ + where: { type: 'VELOCITY', enabled: true }, + }); + + if (!rule) return false; + + const timeWindowMinutes = (rule.config as any)?.timeWindowMinutes || 30; + const threshold = rule.threshold; + + const bookingCount = await this.prisma.booking.count({ + where: { + passengerId: userId, + createdAt: { + gte: new Date(Date.now() - timeWindowMinutes * 60 * 1000), + }, + }, + }); + + return bookingCount > threshold; + } + + /** + * Check high-value booking rule + */ + private async checkHighValueRule(amountMinor: number): Promise { + const rule = await this.prisma.fraudRule.findFirst({ + where: { type: 'HIGH_VALUE', enabled: true }, + }); + + if (!rule) return false; + + // threshold is in ETB (convert minor units to ETB) + const amountEtb = amountMinor / 100; + return amountEtb > rule.threshold; + } + + /** + * Check failed payment rule: X failed attempts in Y minutes + */ + private async checkFailedPaymentRule(userId: string): Promise { + const rule = await this.prisma.fraudRule.findFirst({ + where: { type: 'FAILED_PAYMENTS', enabled: true }, + }); + + if (!rule) return false; + + const timeWindowMinutes = (rule.config as any)?.timeWindowMinutes || 60; + const threshold = rule.threshold; + + const failedCount = await this.prisma.paymentIntent.count({ + where: { + booking: { passengerId: userId }, + status: 'FAILED', + updatedAt: { + gte: new Date(Date.now() - timeWindowMinutes * 60 * 1000), + }, + }, + }); + + return failedCount > threshold; + } + + /** + * Create a fraud alert + */ + private async createFraudAlert( + userId: string, + eventType: string, + triggeredRules: string[], + context: Record, + ): Promise { + const alert = await this.prisma.fraudAlert.create({ + data: { + userId, + eventType, + triggeredRules, + context: context as any, + severity: triggeredRules.length > 1 ? 'HIGH' : 'MEDIUM', + }, + }); + + this.logger.warn(`Fraud alert created: ${alert.id} for user ${userId} - rules: ${triggeredRules.join(', ')}`); + + // Trigger blocking if needed + if (triggeredRules.includes('HIGH_VALUE') || triggeredRules.length > 1) { + await this.blockUserTemporarily(userId, 30); // Block for 30 minutes + } + } + + /** + * Block user temporarily + */ + async blockUserTemporarily(userId: string, durationMinutes: number): Promise { + const blockedUntil = new Date(Date.now() + durationMinutes * 60 * 1000); + await this.prisma.user.update({ + where: { id: userId }, + data: { blockedUntil }, + }); + this.logger.warn(`User ${userId} blocked until ${blockedUntil.toISOString()}`); + } + + /** + * Unblock user + */ + async unblockUser(userId: string): Promise { + await this.prisma.user.update({ + where: { id: userId }, + data: { blockedUntil: null }, + }); + this.logger.log(`User ${userId} unblocked`); + } + + /** + * Get all fraud alerts + */ + async getAlerts(userId?: string, limit = 100, offset = 0) { + return this.prisma.fraudAlert.findMany({ + where: userId ? { userId } : {}, + orderBy: { createdAt: 'desc' }, + take: limit, + skip: offset, + }); + } + + /** + * Create or update a fraud rule + */ + async upsertRule( + type: string, + config: FraudRuleConfig, + ) { + return this.prisma.fraudRule.upsert({ + where: { type: type as any }, + update: { + enabled: config.enabled, + threshold: config.threshold, + config: config as any, + }, + create: { + type: type as any, + enabled: config.enabled, + threshold: config.threshold, + config: config as any, + }, + }); + } + + /** + * Get all fraud rules + */ + async getRules() { + return this.prisma.fraudRule.findMany(); + } + + /** + * Event listener for booking created + */ + @OnEvent('booking.created') + async onBookingCreated(payload: { booking: any }) { + await this.evaluateRules(payload.booking.passengerId, 'booking.created', { + bookingId: payload.booking.id, + amountMinor: payload.booking.totalMinor, + }); + } + + /** + * Event listener for payment failed + */ + @OnEvent('payment.failed') + async onPaymentFailed(payload: { intentId: string; userId: string }) { + await this.evaluateRules(payload.userId, 'payment.failed', { + intentId: payload.intentId, + }); + } + + /** + * Event listener for auth login failed + */ + @OnEvent('auth.login.failed') + async onLoginFailed(payload: { userId: string; email: string }) { + await this.evaluateRules(payload.userId, 'auth.login.failed', { + email: payload.email, + }); + } +} diff --git a/apps/edr-passenger-api/src/modules/notifications/notification.adapters.ts b/apps/edr-passenger-api/src/modules/notifications/notification.adapters.ts new file mode 100644 index 000000000..c7db1a0a4 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/notifications/notification.adapters.ts @@ -0,0 +1,216 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import * as sgMail from '@sendgrid/mail'; +import { HttpService } from '@nestjs/axios'; +import { firstValueFrom } from 'rxjs'; + +export interface NotificationChannel { + send(recipient: string, subject: string, body: string, context?: Record): Promise; +} + +@Injectable() +export class EmailAdapter implements NotificationChannel { + private readonly logger = new Logger(EmailAdapter.name); + + constructor(private readonly config: ConfigService) { + const apiKey = this.config.get('SENDGRID_API_KEY'); + if (apiKey) { + sgMail.setApiKey(apiKey); + this.logger.log('SendGrid Email adapter initialized'); + } else { + this.logger.warn('SENDGRID_API_KEY not configured - emails will be logged only'); + } + } + + async send( + recipient: string, + subject: string, + body: string, + context?: Record, + ): Promise { + const apiKey = this.config.get('SENDGRID_API_KEY'); + const fromEmail = this.config.get('SENDGRID_FROM_EMAIL') || 'noreply@edr-platform.com'; + + if (!apiKey) { + this.logger.log(`[EMAIL MOCK] To: ${recipient} | Subject: ${subject} | Body: ${body.substring(0, 100)}`); + return true; + } + + try { + const msg: sgMail.MailDataRequired = { + to: recipient, + from: fromEmail, + subject, + text: body, + html: this.formatHtml(body, context), + }; + + await sgMail.send(msg); + this.logger.log(`Email sent successfully to ${recipient}`); + return true; + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + this.logger.error(`Failed to send email to ${recipient}: ${message}`); + return false; + } + } + + private formatHtml(body: string, context?: Record): string { + const contextHtml = context + ? `
+ ${JSON.stringify(context, null, 2)} +
` + : ''; + + return ` + + + + + + + +
+
+

Ethio-Djibouti Railway

+
+
+ ${body.replace(/\n/g, '
')} + ${contextHtml} +
+ +
+ + + `; + } +} + +@Injectable() +export class SmsAdapter implements NotificationChannel { + private readonly logger = new Logger(SmsAdapter.name); + + constructor( + private readonly config: ConfigService, + private readonly http: HttpService, + ) { + const provider = this.config.get('SMS_PROVIDER'); + this.logger.log(`SMS adapter initialized with provider: ${provider || 'MOCK'}`); + } + + async send( + recipient: string, + subject: string, + body: string, + _context?: Record, + ): Promise { + const provider = this.config.get('SMS_PROVIDER'); + const apiKey = this.config.get('SMS_API_KEY'); + + if (!provider || !apiKey) { + this.logger.log(`[SMS MOCK] To: ${recipient} | Message: ${body.substring(0, 100)}`); + return true; + } + + try { + switch (provider.toLowerCase()) { + case 'twilio': + return await this.sendViaTwilio(recipient, body); + case 'africastalking': + return await this.sendViaAfricasTalking(recipient, body); + default: + this.logger.warn(`Unknown SMS provider: ${provider}`); + return false; + } + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + this.logger.error(`Failed to send SMS to ${recipient}: ${message}`); + return false; + } + } + + private async sendViaTwilio(to: string, body: string): Promise { + const accountSid = this.config.get('TWILIO_ACCOUNT_SID'); + const authToken = this.config.get('TWILIO_AUTH_TOKEN'); + const fromNumber = this.config.get('TWILIO_FROM_NUMBER'); + + const url = `https://api.twilio.com/2010-04-01/Accounts/${accountSid}/Messages.json`; + const auth = Buffer.from(`${accountSid}:${authToken}`).toString('base64'); + + const response = await firstValueFrom( + this.http.post( + url, + new URLSearchParams({ + To: to, + From: fromNumber || '', + Body: body, + }), + { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Authorization': `Basic ${auth}`, + }, + }, + ), + ); + + return response.status === 201; + } + + private async sendViaAfricasTalking(to: string, body: string): Promise { + const apiKey = this.config.get('SMS_API_KEY'); + const username = this.config.get('AFRICASTALKING_USERNAME'); + const from = this.config.get('AFRICASTALKING_FROM'); + + const url = 'https://api.africastalking.com/version1/messaging'; + + const response = await firstValueFrom( + this.http.post( + url, + new URLSearchParams({ + username: username || '', + to, + message: body, + from: from || '', + }), + { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'apiKey': apiKey || '', + }, + }, + ), + ); + + return response.status === 201; + } +} + +@Injectable() +export class PushAdapter implements NotificationChannel { + private readonly logger = new Logger(PushAdapter.name); + + constructor(private readonly config: ConfigService) { + this.logger.log('Push notification adapter initialized'); + } + + async send( + recipient: string, + subject: string, + body: string, + context?: Record, + ): Promise { + // Push notifications would typically use FCM/APNS + // For now, just log + this.logger.log(`[PUSH MOCK] To: ${recipient} | Title: ${subject} | Body: ${body.substring(0, 100)}`); + return true; + } +} diff --git a/apps/edr-passenger-api/src/modules/notifications/notifications.controller.ts b/apps/edr-passenger-api/src/modules/notifications/notifications.controller.ts index 076c023a1..9b363c04f 100644 --- a/apps/edr-passenger-api/src/modules/notifications/notifications.controller.ts +++ b/apps/edr-passenger-api/src/modules/notifications/notifications.controller.ts @@ -1,7 +1,9 @@ -import { Controller, Get, Param, Patch, UseGuards } from '@nestjs/common'; +import { Controller, Get, Param, Patch, Post, Body, UseGuards } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger'; import { NotificationsService } from './notifications.service'; import { JwtGuard } from '../../common/jwt.guard'; +import { IamGuard, IamRoles } from '../../common/iam-adapter'; +import { TestNotificationDto } from './notifications.dto'; @ApiTags('Notifications') @Controller('notifications') @@ -12,13 +14,32 @@ export class NotificationsController { @Get(':passengerId') @ApiOperation({ summary: 'Get notifications for passenger' }) - getForPassenger(@Param('passengerId') id: string) { return this.service.getForPassenger(id); } + getForPassenger(@Param('passengerId') id: string) { + return this.service.getForPassenger(id); + } @Patch(':id/read') @ApiOperation({ summary: 'Mark notification as read' }) - markRead(@Param('id') id: string) { return this.service.markRead(id); } + markRead(@Param('id') id: string) { + return this.service.markRead(id); + } @Patch(':passengerId/read-all') @ApiOperation({ summary: 'Mark all notifications as read' }) - markAllRead(@Param('passengerId') id: string) { return this.service.markAllRead(id); } + markAllRead(@Param('passengerId') id: string) { + return this.service.markAllRead(id); + } + + @Post('test') + @UseGuards(IamGuard) + @IamRoles('ADMIN', 'STAFF') + @ApiOperation({ summary: 'Test notification delivery (Admin only)' }) + async testNotification(@Body() dto: TestNotificationDto) { + return this.service.send( + dto.templateKey, + dto.recipient, + dto.context, + dto.channels as any, + ); + } } diff --git a/apps/edr-passenger-api/src/modules/notifications/notifications.dto.ts b/apps/edr-passenger-api/src/modules/notifications/notifications.dto.ts index 07bd9dd40..e55535a2a 100644 --- a/apps/edr-passenger-api/src/modules/notifications/notifications.dto.ts +++ b/apps/edr-passenger-api/src/modules/notifications/notifications.dto.ts @@ -1,4 +1,4 @@ -import { IsString, IsEnum, IsOptional } from 'class-validator'; +import { IsString, IsEnum, IsOptional, IsArray } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; export enum NotificationCategoryEnum { @@ -17,3 +17,21 @@ export class SendNotificationDto { @ApiPropertyOptional({ example: 'edr://tickets/tkt_01' }) @IsOptional() @IsString() deepLink?: string; @ApiPropertyOptional() @IsOptional() metadata?: Record; } + +export class TestNotificationDto { + @ApiProperty({ example: 'booking.created' }) + @IsString() + templateKey: string; + + @ApiProperty({ example: 'user@example.com' }) + @IsString() + recipient: string; + + @ApiProperty({ example: { bookingRef: 'EDR123456', passengerName: 'John Doe' } }) + context: Record; + + @ApiPropertyOptional({ example: ['EMAIL', 'SMS', 'IN_APP'] }) + @IsOptional() + @IsArray() + channels?: string[]; +} diff --git a/apps/edr-passenger-api/src/modules/notifications/notifications.module.ts b/apps/edr-passenger-api/src/modules/notifications/notifications.module.ts index 8a1322a50..b4c28405f 100644 --- a/apps/edr-passenger-api/src/modules/notifications/notifications.module.ts +++ b/apps/edr-passenger-api/src/modules/notifications/notifications.module.ts @@ -1,6 +1,13 @@ import { Module } from '@nestjs/common'; +import { HttpModule } from '@nestjs/axios'; import { NotificationsController } from './notifications.controller'; import { NotificationsService } from './notifications.service'; +import { EmailAdapter, SmsAdapter, PushAdapter } from './notification.adapters'; -@Module({ controllers: [NotificationsController], providers: [NotificationsService], exports: [NotificationsService] }) +@Module({ + imports: [HttpModule.register({ timeout: 10_000 })], + controllers: [NotificationsController], + providers: [NotificationsService, EmailAdapter, SmsAdapter, PushAdapter], + exports: [NotificationsService], +}) export class NotificationsModule {} diff --git a/apps/edr-passenger-api/src/modules/notifications/notifications.service.ts b/apps/edr-passenger-api/src/modules/notifications/notifications.service.ts index a92c4c71f..e793a1322 100644 --- a/apps/edr-passenger-api/src/modules/notifications/notifications.service.ts +++ b/apps/edr-passenger-api/src/modules/notifications/notifications.service.ts @@ -1,45 +1,263 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, Logger, NotFoundException } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; import { PrismaService } from '../../common/prisma.service'; import { SendNotificationDto, NotificationCategoryEnum } from './notifications.dto'; -import * as sgMail from '@sendgrid/mail'; +import { EmailAdapter, SmsAdapter, PushAdapter, NotificationChannel } from './notification.adapters'; + +export type NotificationChannelType = 'EMAIL' | 'SMS' | 'PUSH' | 'IN_APP'; @Injectable() export class NotificationsService { - constructor(private prisma: PrismaService) { - if (process.env.SENDGRID_API_KEY) sgMail.setApiKey(process.env.SENDGRID_API_KEY); + private readonly logger = new Logger(NotificationsService.name); + private readonly channels: Map; + + constructor( + private prisma: PrismaService, + private emailAdapter: EmailAdapter, + private smsAdapter: SmsAdapter, + private pushAdapter: PushAdapter, + ) { + this.channels = new Map([ + ['EMAIL', this.emailAdapter as NotificationChannel], + ['SMS', this.smsAdapter as NotificationChannel], + ['PUSH', this.pushAdapter as NotificationChannel], + ]); } - private sanitize(value: string): string { - return value.replace(/[\r\n]/g, ' ').replace(/[<>&"']/g, (c) => ({ '<': '<', '>': '>', '&': '&', '"': '"', "'": ''' }[c] ?? c)); + /** + * Send notification using template key and context + * @param templateKey - Template code from NotificationTemplate table + * @param recipient - User/Passenger ID or email/phone + * @param context - Variables to interpolate in template + * @param channels - Optional array of channels to use (defaults to user preferences) + */ + async send( + templateKey: string, + recipient: string, + context: Record, + channels?: NotificationChannelType[], + ): Promise<{ sent: boolean; channels: string[] }> { + const template = await this.prisma.notificationTemplate.findUnique({ + where: { code: templateKey }, + }); + + if (!template || !template.active) { + this.logger.warn(`Template ${templateKey} not found or inactive`); + return { sent: false, channels: [] }; + } + + const { subject, body } = this.interpolate(template, context); + const targetChannels = channels || await this.getUserPreferredChannels(recipient); + const sentChannels: string[] = []; + + // Always create in-app notification + if (targetChannels.includes('IN_APP')) { + await this.createInAppNotification(recipient, subject, body, context); + sentChannels.push('IN_APP'); + } + + // Send via other channels + for (const channelType of targetChannels) { + if (channelType === 'IN_APP') continue; + + const adapter = this.channels.get(channelType); + if (!adapter) { + this.logger.warn(`No adapter for channel: ${channelType}`); + continue; + } + + const recipientAddress = await this.getRecipientAddress(recipient, channelType); + if (!recipientAddress) { + this.logger.warn(`No ${channelType} address for recipient: ${recipient}`); + continue; + } + + const success = await adapter.send(recipientAddress, subject, body, context); + if (success) { + sentChannels.push(channelType); + } + } + + return { sent: sentChannels.length > 0, channels: sentChannels }; } - async send(dto: SendNotificationDto) { - const notification = await this.prisma.notification.create({ data: { passengerId: dto.passengerId, title: dto.title, body: dto.body, category: dto.category as any, deepLink: dto.deepLink, metadata: dto.metadata } }); - const passenger = await this.prisma.passenger.findUnique({ where: { id: dto.passengerId }, include: { user: true } }); - if (passenger?.user) await this.sendEmail(passenger.user.email, this.sanitize(dto.title), this.sanitize(dto.body)); + /** + * Legacy method for backward compatibility + */ + async sendDirect(dto: SendNotificationDto) { + const notification = await this.prisma.notification.create({ + data: { + passengerId: dto.passengerId, + title: dto.title, + body: dto.body, + category: dto.category as any, + deepLink: dto.deepLink, + metadata: dto.metadata, + }, + }); + + const passenger = await this.prisma.passenger.findUnique({ + where: { id: dto.passengerId }, + include: { user: true }, + }); + + if (passenger?.user) { + await this.emailAdapter.send( + passenger.user.email, + this.sanitize(dto.title), + this.sanitize(dto.body), + ); + } + return notification; } - getForPassenger(passengerId: string) { return this.prisma.notification.findMany({ where: { passengerId }, orderBy: { createdAt: 'desc' }, take: 50 }); } + private async createInAppNotification( + recipient: string, + title: string, + body: string, + context: Record, + ): Promise { + // Try to find passenger by ID or email + let passengerId = recipient; - markRead(id: string) { return this.prisma.notification.update({ where: { id }, data: { read: true } }); } + if (!recipient.match(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)) { + const user = await this.prisma.user.findFirst({ + where: { + OR: [{ email: recipient }, { phone: recipient }], + }, + include: { passenger: true }, + }); + if (user?.passenger) { + passengerId = user.passenger.id; + } else { + this.logger.warn(`Could not find passenger for recipient: ${recipient}`); + return; + } + } - async markAllRead(passengerId: string) { await this.prisma.notification.updateMany({ where: { passengerId, read: false }, data: { read: true } }); return { updated: true }; } + await this.prisma.notification.create({ + data: { + passengerId, + title, + body, + category: (context.category as any) || 'SYSTEM', + deepLink: context.deepLink as string, + metadata: context as any, + }, + }); + } + + private interpolate( + template: { subject?: string | null; bodyTemplate: string }, + context: Record, + ): { subject: string; body: string } { + const subject = template.subject || 'Notification'; + let body = template.bodyTemplate; + + // Simple template interpolation: {{variable}} + for (const [key, value] of Object.entries(context)) { + const regex = new RegExp(`{{\\s*${key}\\s*}}`, 'g'); + body = body.replace(regex, String(value)); + } + + return { subject, body }; + } + + private async getUserPreferredChannels(recipient: string): Promise { + const user = await this.prisma.user.findFirst({ + where: { + OR: [{ id: recipient }, { email: recipient }, { phone: recipient }], + }, + include: { preferences: true }, + }); + + if (!user?.preferences) { + return ['IN_APP', 'EMAIL']; + } + + const channels: NotificationChannelType[] = ['IN_APP']; + if (user.preferences.emailEnabled) channels.push('EMAIL'); + if (user.preferences.smsEnabled) channels.push('SMS'); + if (user.preferences.pushEnabled) channels.push('PUSH'); + + return channels; + } + + private async getRecipientAddress( + recipient: string, + channel: NotificationChannelType, + ): Promise { + const user = await this.prisma.user.findFirst({ + where: { + OR: [{ id: recipient }, { email: recipient }, { phone: recipient }], + }, + }); + + if (!user) return null; + + switch (channel) { + case 'EMAIL': + return user.email; + case 'SMS': + return user.phone; + case 'PUSH': + // Would need to fetch device push token + return user.id; + default: + return null; + } + } + + private sanitize(value: string): string { + return value + .replace(/[\r\n]/g, ' ') + .replace(/[<>&"']/g, (c) => ({ '<': '<', '>': '>', '&': '&', '"': '"', "'": ''' }[c] ?? c)); + } + + getForPassenger(passengerId: string) { + return this.prisma.notification.findMany({ + where: { passengerId }, + orderBy: { createdAt: 'desc' }, + take: 50, + }); + } + + markRead(id: string) { + return this.prisma.notification.update({ where: { id }, data: { read: true } }); + } + + async markAllRead(passengerId: string) { + await this.prisma.notification.updateMany({ + where: { passengerId, read: false }, + data: { read: true }, + }); + return { updated: true }; + } @OnEvent('booking.created') async onBookingCreated(payload: any) { - await this.send({ passengerId: payload.booking.passengerId, title: 'Booking Created', body: `Booking ${payload.booking.bookingRef} created. Complete payment within 15 minutes.`, category: NotificationCategoryEnum.BOOKING, deepLink: `edr://bookings/${payload.booking.bookingRef}`, metadata: { bookingRef: payload.booking.bookingRef } }); + await this.send( + 'booking.created', + payload.booking.passengerId, + { + bookingRef: payload.booking.bookingRef, + category: 'BOOKING', + deepLink: `edr://bookings/${payload.booking.bookingRef}`, + }, + ); } @OnEvent('payment.succeeded') async onPaymentSucceeded(payload: any) { - await this.send({ passengerId: payload.booking.passengerId, title: 'Payment Successful', body: `Your ticket for ${payload.booking.bookingRef} is confirmed. Have a great journey!`, category: NotificationCategoryEnum.PAYMENT, deepLink: `edr://tickets/${payload.booking.bookingRef}`, metadata: { bookingRef: payload.booking.bookingRef } }); - } - - private async sendEmail(to: string, subject: string, text: string) { - if (!process.env.SENDGRID_API_KEY) { console.log(`[EMAIL] To: ${to} | Subject: ${subject}`); return; } - try { await sgMail.send({ to, from: process.env.SENDGRID_FROM_EMAIL || 'noreply@edr-platform.com', subject, text }); } - catch (e) { console.error('[EMAIL] Send error:', String(e instanceof Error ? e.message : e).replace(/[\r\n<>&"']/g, ' ')); } + await this.send( + 'payment.succeeded', + payload.booking.passengerId, + { + bookingRef: payload.booking.bookingRef, + category: 'PAYMENT', + deepLink: `edr://tickets/${payload.booking.bookingRef}`, + }, + ); } } \ No newline at end of file diff --git a/apps/edr-passenger-api/src/modules/payments/payments.e2e-spec.ts b/apps/edr-passenger-api/src/modules/payments/payments.e2e-spec.ts new file mode 100644 index 000000000..4918ce4fd --- /dev/null +++ b/apps/edr-passenger-api/src/modules/payments/payments.e2e-spec.ts @@ -0,0 +1,270 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { INestApplication, ValidationPipe } from '@nestjs/common'; +import request from 'supertest'; +import { AppModule } from '../../app.module'; +import { PrismaService } from '../../common/prisma.service'; + +describe('Payments E2E', () => { + let app: INestApplication; + let prisma: PrismaService; + let authToken: string; + let bookingId: string; + + beforeAll(async () => { + const moduleFixture: TestingModule = await Test.createTestingModule({ + imports: [AppModule], + }).compile(); + + app = moduleFixture.createNestApplication(); + app.useGlobalPipes(new ValidationPipe({ transform: true, whitelist: true })); + await app.init(); + + prisma = app.get(PrismaService); + + // Create test user and authenticate + const testUser = await prisma.user.create({ + data: { + email: 'payment-test@example.com', + phone: '+251911111111', + fullName: 'Payment Test User', + passwordHash: '$2b$10$abcdefghijklmnopqrstuvwxyz', // Mock hash + role: 'PASSENGER', + }, + }); + + const passenger = await prisma.passenger.create({ + data: { + userId: testUser.id, + }, + }); + + // Create wallet for test user + await prisma.walletAccount.create({ + data: { + passengerId: passenger.id, + balanceMinor: 100000, // 1000 ETB + currency: 'ETB', + }, + }); + + // Mock JWT token (in real test, call /auth/login) + authToken = 'mock-jwt-token'; + + // Create test booking + const station1 = await prisma.station.create({ + data: { + code: 'TEST1', + name: 'Test Station 1', + city: 'Test City', + lat: 9.0, + lng: 38.0, + }, + }); + + const station2 = await prisma.station.create({ + data: { + code: 'TEST2', + name: 'Test Station 2', + city: 'Test City 2', + lat: 9.5, + lng: 38.5, + }, + }); + + const service = await prisma.trainService.create({ + data: { + number: 'TEST-001', + name: 'Test Service', + }, + }); + + const trip = await prisma.trip.create({ + data: { + serviceId: service.id, + originStationId: station1.id, + destinationStationId: station2.id, + departureAt: new Date(Date.now() + 86400000), + arrivalAt: new Date(Date.now() + 90000000), + durationMinutes: 60, + }, + }); + + const coach = await prisma.coach.create({ + data: { + tripId: trip.id, + label: 'A', + serviceClass: 'ECONOMY_REGULAR', + }, + }); + + const seat = await prisma.seat.create({ + data: { + coachId: coach.id, + row: 1, + col: 'A', + label: '1A', + status: 'AVAILABLE', + }, + }); + + const booking = await prisma.booking.create({ + data: { + bookingRef: 'TEST-BOOK-001', + passengerId: passenger.id, + tripId: trip.id, + status: 'PENDING_PAYMENT', + totalMinor: 50000, // 500 ETB + currency: 'ETB', + }, + }); + + await prisma.bookingSeat.create({ + data: { + bookingId: booking.id, + seatId: seat.id, + passengerName: 'Test Passenger', + }, + }); + + bookingId = booking.id; + }); + + afterAll(async () => { + await prisma.$transaction([ + prisma.bookingSeat.deleteMany(), + prisma.paymentIntent.deleteMany(), + prisma.booking.deleteMany(), + prisma.seat.deleteMany(), + prisma.coach.deleteMany(), + prisma.trip.deleteMany(), + prisma.trainService.deleteMany(), + prisma.station.deleteMany(), + prisma.walletLedgerEntry.deleteMany(), + prisma.walletAccount.deleteMany(), + prisma.passenger.deleteMany(), + prisma.user.deleteMany(), + ]); + await app.close(); + }); + + describe('POST /payments/initiate', () => { + it('should initiate wallet payment successfully', async () => { + const response = await request(app.getHttpServer()) + .post('/payments/initiate') + .set('Authorization', `Bearer ${authToken}`) + .send({ + bookingId, + method: 'WALLET', + }) + .expect(201); + + expect(response.body.intentId).toBeDefined(); + expect(response.body.status).toBe('SUCCEEDED'); + }); + + it('should return 400 for invalid payment method', async () => { + await request(app.getHttpServer()) + .post('/payments/initiate') + .set('Authorization', `Bearer ${authToken}`) + .send({ + bookingId, + method: 'INVALID_METHOD', + }) + .expect(400); + }); + + it('should return 404 for non-existent booking', async () => { + await request(app.getHttpServer()) + .post('/payments/initiate') + .set('Authorization', `Bearer ${authToken}`) + .send({ + bookingId: 'non-existent-id', + method: 'WALLET', + }) + .expect(404); + }); + }); + + describe('GET /payments/intents/:bookingId', () => { + it('should get payment intent status', async () => { + const response = await request(app.getHttpServer()) + .get(`/payments/intents/${bookingId}`) + .set('Authorization', `Bearer ${authToken}`) + .expect(200); + + expect(response.body.intentId).toBeDefined(); + expect(response.body.status).toBeDefined(); + }); + + it('should return 404 for non-existent intent', async () => { + await request(app.getHttpServer()) + .get('/payments/intents/non-existent-booking') + .set('Authorization', `Bearer ${authToken}`) + .expect(404); + }); + }); + + describe('Webhook endpoints', () => { + it('should handle Telebirr webhook', async () => { + await request(app.getHttpServer()) + .post('/payments/webhooks/telebirr') + .send({ + merch_order_id: 'TEST-ORDER-123', + payment_order_id: 'PAY-123', + trade_status: 'Completed', + sign: 'mock-signature', + }) + .expect(200); + }); + + it('should handle CBE Birr webhook', async () => { + await request(app.getHttpServer()) + .post('/payments/webhooks/cbe-birr') + .send({ + merchantId: 'TEST-MERCHANT', + merchantOrderId: 'TEST-ORDER-123', + orderId: 'CBE-ORDER-123', + status: 'SUCCESS', + signature: 'mock-signature', + }) + .expect(200); + }); + + it('should handle eBirr webhook', async () => { + await request(app.getHttpServer()) + .post('/payments/webhooks/ebirr') + .send({ + merchantCode: 'TEST-MERCHANT', + orderNo: 'TEST-ORDER-123', + tradeStatus: 'TRADE_SUCCESS', + timestamp: Date.now(), + sign: 'mock-signature', + }) + .expect(200); + }); + + it('should handle Card webhook', async () => { + await request(app.getHttpServer()) + .post('/payments/webhooks/card') + .set('stripe-signature', 'mock-signature') + .send({ + id: 'evt_123', + type: 'payment_intent.succeeded', + data: { + object: { + id: 'pi_123', + status: 'succeeded', + amount: 50000, + currency: 'ETB', + metadata: { + merchantOrderId: 'TEST-ORDER-123', + bookingRef: 'TEST-BOOK-001', + }, + }, + }, + created: Math.floor(Date.now() / 1000), + }) + .expect(200); + }); + }); +}); diff --git a/apps/edr-passenger-api/src/modules/payments/payments.module.ts b/apps/edr-passenger-api/src/modules/payments/payments.module.ts index 0b898f467..387ce5244 100644 --- a/apps/edr-passenger-api/src/modules/payments/payments.module.ts +++ b/apps/edr-passenger-api/src/modules/payments/payments.module.ts @@ -5,12 +5,28 @@ import { PaymentsService } from './payments.service'; import { SeatsModule } from '../seats/seats.module'; import { TicketsModule } from '../tickets/tickets.module'; import { TelebirrProvider } from './providers/telebirr.provider'; +import { CbeBirrProvider } from './providers/cbe-birr.provider'; +import { EBirrProvider } from './providers/ebirr.provider'; +import { CardProvider } from './providers/card.provider'; import { WebhooksController } from './webhooks/webhooks.controller'; import { TelebirrWebhookService } from './webhooks/telebirr-webhook.service'; +import { CbeBirrWebhookService } from './webhooks/cbe-birr-webhook.service'; +import { EBirrWebhookService } from './webhooks/ebirr-webhook.service'; +import { CardWebhookService } from './webhooks/card-webhook.service'; @Module({ imports: [SeatsModule, TicketsModule, HttpModule.register({ timeout: 10_000 })], controllers: [PaymentsController, WebhooksController], - providers: [PaymentsService, TelebirrProvider, TelebirrWebhookService], + providers: [ + PaymentsService, + TelebirrProvider, + CbeBirrProvider, + EBirrProvider, + CardProvider, + TelebirrWebhookService, + CbeBirrWebhookService, + EBirrWebhookService, + CardWebhookService, + ], }) export class PaymentsModule {} diff --git a/apps/edr-passenger-api/src/modules/payments/payments.service.spec.ts b/apps/edr-passenger-api/src/modules/payments/payments.service.spec.ts new file mode 100644 index 000000000..e6ebd9035 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/payments/payments.service.spec.ts @@ -0,0 +1,328 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { PaymentsService } from './payments.service'; +import { PrismaService } from '../../common/prisma.service'; +import { SeatsService } from '../seats/seats.service'; +import { TicketsService } from '../tickets/tickets.service'; +import { EventEmitter2 } from '@nestjs/event-emitter'; +import { TelebirrProvider } from './providers/telebirr.provider'; +import { CbeBirrProvider } from './providers/cbe-birr.provider'; +import { EBirrProvider } from './providers/ebirr.provider'; +import { CardProvider } from './providers/card.provider'; +import { PaymentIntentStatus, PaymentMethodType } from '@prisma/client'; +import { BadRequestException, NotFoundException } from '@nestjs/common'; + +describe('PaymentsService', () => { + let service: PaymentsService; + let prisma: PrismaService; + let seatsService: SeatsService; + let ticketsService: TicketsService; + let eventEmitter: EventEmitter2; + + const mockPrisma = { + booking: { + findUnique: jest.fn(), + update: jest.fn(), + }, + paymentIntent: { + findUnique: jest.fn(), + findUniqueOrThrow: jest.fn(), + upsert: jest.fn(), + update: jest.fn(), + create: jest.fn(), + }, + walletAccount: { + findUnique: jest.fn(), + update: jest.fn(), + }, + walletLedgerEntry: { + create: jest.fn(), + }, + loyaltyAccount: { + findUnique: jest.fn(), + update: jest.fn(), + }, + loyaltyLedgerEntry: { + create: jest.fn(), + }, + $transaction: jest.fn((callback) => callback(mockPrisma)), + }; + + const mockSeatsService = { + confirmSeats: jest.fn(), + releaseSeats: jest.fn(), + }; + + const mockTicketsService = { + generate: jest.fn(), + }; + + const mockEventEmitter = { + emit: jest.fn(), + }; + + const mockTelebirrProvider = { + method: PaymentMethodType.TELEBIRR, + initiate: jest.fn(), + queryStatus: jest.fn(), + }; + + const mockCbeBirrProvider = { + method: PaymentMethodType.CBE_BIRR, + initiate: jest.fn(), + queryStatus: jest.fn(), + }; + + const mockEBirrProvider = { + method: PaymentMethodType.EBIRR, + initiate: jest.fn(), + queryStatus: jest.fn(), + }; + + const mockCardProvider = { + method: PaymentMethodType.CARD, + initiate: jest.fn(), + queryStatus: jest.fn(), + }; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + PaymentsService, + { provide: PrismaService, useValue: mockPrisma }, + { provide: SeatsService, useValue: mockSeatsService }, + { provide: TicketsService, useValue: mockTicketsService }, + { provide: EventEmitter2, useValue: mockEventEmitter }, + { provide: TelebirrProvider, useValue: mockTelebirrProvider }, + { provide: CbeBirrProvider, useValue: mockCbeBirrProvider }, + { provide: EBirrProvider, useValue: mockEBirrProvider }, + { provide: CardProvider, useValue: mockCardProvider }, + ], + }).compile(); + + service = module.get(PaymentsService); + prisma = module.get(PrismaService); + seatsService = module.get(SeatsService); + ticketsService = module.get(TicketsService); + eventEmitter = module.get(EventEmitter2); + + jest.clearAllMocks(); + }); + + describe('initiatePayment', () => { + const mockBooking = { + id: 'booking-1', + bookingRef: 'EDR123456', + passengerId: 'passenger-1', + totalMinor: 50000, + currency: 'ETB', + status: 'PENDING_PAYMENT', + seats: [{ id: 'seat-1', seatId: 'seat-id-1' }], + }; + + it('should throw NotFoundException if booking not found', async () => { + mockPrisma.booking.findUnique.mockResolvedValue(null); + + await expect( + service.initiatePayment({ + bookingId: 'invalid', + method: 'TELEBIRR' as any, + }), + ).rejects.toThrow(NotFoundException); + }); + + it('should throw BadRequestException if booking not payable', async () => { + mockPrisma.booking.findUnique.mockResolvedValue({ + ...mockBooking, + status: 'CONFIRMED', + }); + + await expect( + service.initiatePayment({ + bookingId: 'booking-1', + method: 'TELEBIRR' as any, + }), + ).rejects.toThrow(BadRequestException); + }); + + it('should initiate Telebirr payment successfully', async () => { + mockPrisma.booking.findUnique.mockResolvedValue(mockBooking); + mockPrisma.paymentIntent.findUnique.mockResolvedValue(null); + mockTelebirrProvider.initiate.mockResolvedValue({ + providerOrderId: 'TB-ORDER-123', + clientAction: { type: 'REDIRECT', url: 'https://telebirr.com/pay' }, + expiresAt: new Date(), + rawInitiation: {}, + }); + mockPrisma.paymentIntent.upsert.mockResolvedValue({ + id: 'intent-1', + status: PaymentIntentStatus.REQUIRES_ACTION, + merchantOrderId: 'MERCH-123', + clientAction: { type: 'REDIRECT', url: 'https://telebirr.com/pay' }, + }); + + const result = await service.initiatePayment({ + bookingId: 'booking-1', + method: 'TELEBIRR' as any, + }); + + expect(result.status).toBe(PaymentIntentStatus.REQUIRES_ACTION); + expect(mockTelebirrProvider.initiate).toHaveBeenCalled(); + }); + + it('should initiate CBE Birr payment successfully', async () => { + mockPrisma.booking.findUnique.mockResolvedValue(mockBooking); + mockPrisma.paymentIntent.findUnique.mockResolvedValue(null); + mockCbeBirrProvider.initiate.mockResolvedValue({ + providerOrderId: 'CBE-ORDER-123', + clientAction: { type: 'REDIRECT', url: 'https://cbe.com/pay' }, + expiresAt: new Date(), + rawInitiation: {}, + }); + mockPrisma.paymentIntent.upsert.mockResolvedValue({ + id: 'intent-1', + status: PaymentIntentStatus.REQUIRES_ACTION, + merchantOrderId: 'MERCH-123', + clientAction: { type: 'REDIRECT', url: 'https://cbe.com/pay' }, + }); + + const result = await service.initiatePayment({ + bookingId: 'booking-1', + method: 'CBE_BIRR' as any, + }); + + expect(result.status).toBe(PaymentIntentStatus.REQUIRES_ACTION); + expect(mockCbeBirrProvider.initiate).toHaveBeenCalled(); + }); + + it('should initiate wallet payment and debit successfully', async () => { + mockPrisma.booking.findUnique.mockResolvedValue(mockBooking); + mockPrisma.paymentIntent.findUnique.mockResolvedValue(null); + mockPrisma.walletAccount.findUnique.mockResolvedValue({ + id: 'wallet-1', + passengerId: 'passenger-1', + balanceMinor: 100000, + }); + mockPrisma.paymentIntent.upsert.mockResolvedValue({ + id: 'intent-1', + status: PaymentIntentStatus.PROCESSING, + }); + mockPrisma.paymentIntent.findUniqueOrThrow.mockResolvedValue({ + id: 'intent-1', + status: PaymentIntentStatus.SUCCEEDED, + bookingId: 'booking-1', + }); + mockPrisma.loyaltyAccount.findUnique.mockResolvedValue({ + id: 'loyalty-1', + pointsBalance: 100, + }); + + const result = await service.initiatePayment({ + bookingId: 'booking-1', + method: 'WALLET' as any, + }); + + expect(result.status).toBe(PaymentIntentStatus.SUCCEEDED); + expect(mockSeatsService.confirmSeats).toHaveBeenCalled(); + expect(mockTicketsService.generate).toHaveBeenCalled(); + }); + + it('should fail wallet payment with insufficient balance', async () => { + mockPrisma.booking.findUnique.mockResolvedValue(mockBooking); + mockPrisma.paymentIntent.findUnique.mockResolvedValue(null); + mockPrisma.walletAccount.findUnique.mockResolvedValue({ + id: 'wallet-1', + passengerId: 'passenger-1', + balanceMinor: 10000, // Less than booking total + }); + mockPrisma.paymentIntent.upsert.mockResolvedValue({ + id: 'intent-1', + status: PaymentIntentStatus.FAILED, + failureCode: 'INSUFFICIENT_BALANCE', + }); + + const result = await service.initiatePayment({ + bookingId: 'booking-1', + method: 'WALLET' as any, + }); + + expect(result.status).toBe(PaymentIntentStatus.FAILED); + }); + }); + + describe('finalizePaymentSuccess', () => { + it('should finalize payment and issue ticket', async () => { + const mockIntent = { + id: 'intent-1', + bookingId: 'booking-1', + status: PaymentIntentStatus.PROCESSING, + }; + const mockBooking = { + id: 'booking-1', + passengerId: 'passenger-1', + totalMinor: 50000, + seats: [{ seatId: 'seat-1' }], + }; + + mockPrisma.paymentIntent.findUnique.mockResolvedValue(mockIntent); + mockPrisma.booking.findUnique.mockResolvedValue(mockBooking); + mockPrisma.loyaltyAccount.findUnique.mockResolvedValue({ + id: 'loyalty-1', + pointsBalance: 100, + }); + + const result = await service.finalizePaymentSuccess({ + intentId: 'intent-1', + providerTxnId: 'TXN-123', + }); + + expect(result.alreadyFinalized).toBe(false); + expect(mockSeatsService.confirmSeats).toHaveBeenCalledWith(['seat-1']); + expect(mockTicketsService.generate).toHaveBeenCalledWith('booking-1'); + expect(mockEventEmitter.emit).toHaveBeenCalledWith('payment.succeeded', { + booking: mockBooking, + }); + }); + + it('should return alreadyFinalized if payment already succeeded', async () => { + mockPrisma.paymentIntent.findUnique.mockResolvedValue({ + id: 'intent-1', + status: PaymentIntentStatus.SUCCEEDED, + }); + + const result = await service.finalizePaymentSuccess({ + intentId: 'intent-1', + }); + + expect(result.alreadyFinalized).toBe(true); + }); + }); + + describe('getIntentByBookingId', () => { + it('should return intent status', async () => { + const mockIntent = { + id: 'intent-1', + bookingId: 'booking-1', + status: PaymentIntentStatus.SUCCEEDED, + method: PaymentMethodType.TELEBIRR, + paidAt: new Date(), + merchantOrderId: 'MERCH-123', + updatedAt: new Date(), + }; + + mockPrisma.paymentIntent.findUnique.mockResolvedValue(mockIntent); + + const result = await service.getIntentByBookingId('booking-1'); + + expect(result.intentId).toBe('intent-1'); + expect(result.status).toBe(PaymentIntentStatus.SUCCEEDED); + }); + + it('should throw NotFoundException if intent not found', async () => { + mockPrisma.paymentIntent.findUnique.mockResolvedValue(null); + + await expect(service.getIntentByBookingId('invalid')).rejects.toThrow( + NotFoundException, + ); + }); + }); +}); diff --git a/apps/edr-passenger-api/src/modules/payments/payments.service.ts b/apps/edr-passenger-api/src/modules/payments/payments.service.ts index 4eeb6bbe4..9f1ae5341 100644 --- a/apps/edr-passenger-api/src/modules/payments/payments.service.ts +++ b/apps/edr-passenger-api/src/modules/payments/payments.service.ts @@ -5,9 +5,11 @@ import { TicketsService } from '../tickets/tickets.service'; import { EventEmitter2 } from '@nestjs/event-emitter'; import { Prisma, PaymentIntentStatus, PaymentMethodType } from '@prisma/client'; import { InitiatePaymentDto, RefundDto, AddPaymentMethodDto, InitiateResponseDto, IntentStatusDto } from './payments.dto'; -import { cbeBirrAdapter, eBirrAdapter, cardAdapter } from './payments.adapters'; import { PaymentProvider, ProviderStatus } from './payments.types'; import { TelebirrProvider } from './providers/telebirr.provider'; +import { CbeBirrProvider } from './providers/cbe-birr.provider'; +import { EBirrProvider } from './providers/ebirr.provider'; +import { CardProvider } from './providers/card.provider'; import { createMerchantOrderId } from './providers/telebirr.crypto'; const NON_TERMINAL_STATUSES: PaymentIntentStatus[] = [ @@ -27,9 +29,15 @@ export class PaymentsService { private ticketsService: TicketsService, private eventEmitter: EventEmitter2, private telebirrProvider: TelebirrProvider, + private cbeBirrProvider: CbeBirrProvider, + private eBirrProvider: EBirrProvider, + private cardProvider: CardProvider, ) { this.providers = new Map([ [PaymentMethodType.TELEBIRR, this.telebirrProvider], + [PaymentMethodType.CBE_BIRR, this.cbeBirrProvider], + [PaymentMethodType.EBIRR, this.eBirrProvider], + [PaymentMethodType.CARD, this.cardProvider], ]); } @@ -61,8 +69,7 @@ export class PaymentsService { return this.initiateProviderPayment(booking, provider); } - // TODO: convert CBE_BIRR, EBIRR, CARD into PaymentProvider implementations. - return this.initiateStubPayment(booking, method); + throw new BadRequestException(`Unsupported payment method: ${method}`); } private async initiateWalletPayment( @@ -170,41 +177,7 @@ export class PaymentsService { return this.formatIntentResponse(intent); } - private async initiateStubPayment( - booking: Prisma.BookingGetPayload<{ include: { seats: true } }>, - method: PaymentMethodType, - ): Promise { - const adapters = { - [PaymentMethodType.CBE_BIRR]: cbeBirrAdapter, - [PaymentMethodType.EBIRR]: eBirrAdapter, - [PaymentMethodType.CARD]: cardAdapter, - } as Partial Promise<{ success: boolean; providerRef: string }>>>; - const adapter = adapters[method]; - if (!adapter) { - throw new BadRequestException(`Unsupported payment method: ${method}`); - } - const result = await adapter(booking.totalMinor, booking.bookingRef); - const status = result.success ? PaymentIntentStatus.PROCESSING : PaymentIntentStatus.FAILED; - const intent = await this.prisma.paymentIntent.upsert({ - where: { bookingId: booking.id }, - update: { status, providerRef: result.providerRef }, - create: { - bookingId: booking.id, - amountMinor: booking.totalMinor, - method, - status, - providerRef: result.providerRef, - }, - }); - if (result.success) { - await this.finalizePaymentSuccess({ intentId: intent.id }); - const refreshed = await this.prisma.paymentIntent.findUniqueOrThrow({ - where: { id: intent.id }, - }); - return this.formatIntentResponse(refreshed); - } - return this.formatIntentResponse(intent); - } + private formatIntentResponse( intent: Prisma.PaymentIntentGetPayload>, diff --git a/apps/edr-passenger-api/src/modules/payments/providers/card.provider.ts b/apps/edr-passenger-api/src/modules/payments/providers/card.provider.ts new file mode 100644 index 000000000..6f444945b --- /dev/null +++ b/apps/edr-passenger-api/src/modules/payments/providers/card.provider.ts @@ -0,0 +1,218 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { HttpService } from '@nestjs/axios'; +import { PaymentIntentStatus, PaymentMethodType } from '@prisma/client'; +import { AxiosError, AxiosRequestConfig } from 'axios'; +import { firstValueFrom } from 'rxjs'; +import * as crypto from 'node:crypto'; +import { + PaymentProvider, + ProviderInitiationInput, + ProviderInitiationResult, + ProviderStatus, +} from '../payments.types'; + +interface CardInitiateRequest { + amount: number; + currency: string; + description: string; + metadata: { + merchantOrderId: string; + bookingRef: string; + }; + return_url: string; + webhook_url: string; +} + +interface CardInitiateResponse { + id: string; + status: string; + client_secret: string; + checkout_url: string; + expires_at: number; +} + +interface CardQueryResponse { + id: string; + status: string; + amount: number; + currency: string; + transaction_id?: string; + paid_at?: number; + failure_code?: string; + failure_message?: string; +} + +@Injectable() +export class CardProvider implements PaymentProvider { + readonly method = PaymentMethodType.CARD; + private readonly logger = new Logger(CardProvider.name); + + constructor( + private readonly config: ConfigService, + private readonly http: HttpService, + ) {} + + async initiate(input: ProviderInitiationInput): Promise { + const amount = input.amountMinor / 100; + + const requestBody: CardInitiateRequest = { + amount, + currency: input.currency, + description: `EDR Train Booking ${input.bookingRef}`, + metadata: { + merchantOrderId: input.merchantOrderId, + bookingRef: input.bookingRef, + }, + return_url: this.returnUrl, + webhook_url: this.webhookUrl, + }; + + const response = await this.postJson( + `${this.baseUrl}/v1/payment_intents`, + requestBody, + ); + + if (!response.id) { + throw new Error(`Card gateway initiate failed: ${JSON.stringify(response)}`); + } + + const expiresAt = new Date(response.expires_at * 1000); + + return { + providerOrderId: response.id, + clientAction: { type: 'REDIRECT', url: response.checkout_url }, + expiresAt, + rawInitiation: { + request: requestBody, + response, + }, + }; + } + + async queryStatus(merchantOrderId: string): Promise { + // For card payments, we need to find the payment intent by metadata + // In a real implementation, we'd store the provider order ID and use it directly + const response = await this.getJson( + `${this.baseUrl}/v1/payment_intents/search?metadata[merchantOrderId]=${merchantOrderId}`, + ); + + const mapped = this.mapStatus(response.status); + + return { + status: mapped, + providerTxnId: response.transaction_id, + failureCode: response.failure_code, + failureMessage: response.failure_message, + rawResponse: response as unknown as Record, + }; + } + + verifyWebhookSignature(payload: Record, signature: string): boolean { + const payloadString = JSON.stringify(payload); + const expectedSignature = crypto + .createHmac('sha256', this.webhookSecret) + .update(payloadString) + .digest('hex'); + + try { + return crypto.timingSafeEqual( + Buffer.from(signature), + Buffer.from(expectedSignature), + ); + } catch { + return false; + } + } + + mapWebhookStatus(status: string): PaymentIntentStatus { + return this.mapStatus(status); + } + + private mapStatus(status: string): PaymentIntentStatus { + switch (status?.toLowerCase()) { + case 'succeeded': + case 'paid': + return PaymentIntentStatus.SUCCEEDED; + case 'failed': + case 'canceled': + case 'expired': + return PaymentIntentStatus.FAILED; + case 'requires_payment_method': + case 'requires_confirmation': + case 'requires_action': + return PaymentIntentStatus.REQUIRES_ACTION; + case 'processing': + return PaymentIntentStatus.PROCESSING; + default: + return PaymentIntentStatus.PROCESSING; + } + } + + private async postJson(url: string, body: unknown): Promise { + const config: AxiosRequestConfig = { + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${this.apiKey}`, + }, + timeout: 10_000, + }; + + const started = Date.now(); + try { + const res = await firstValueFrom(this.http.post(url, body, config)); + this.logger.debug(`Card Gateway POST ${url} status=${res.status} latency=${Date.now() - started}ms`); + return res.data; + } catch (err) { + if (err instanceof AxiosError) { + this.logger.error( + `Card Gateway POST ${url} failed: status=${err.response?.status} body=${JSON.stringify(err.response?.data)}`, + ); + } else { + this.logger.error(`Card Gateway POST ${url} threw: ${err instanceof Error ? err.message : err}`); + } + throw err; + } + } + + private async getJson(url: string): Promise { + const config: AxiosRequestConfig = { + headers: { + 'Authorization': `Bearer ${this.apiKey}`, + }, + timeout: 10_000, + }; + + const started = Date.now(); + try { + const res = await firstValueFrom(this.http.get(url, config)); + this.logger.debug(`Card Gateway GET ${url} status=${res.status} latency=${Date.now() - started}ms`); + return res.data; + } catch (err) { + if (err instanceof AxiosError) { + this.logger.error( + `Card Gateway GET ${url} failed: status=${err.response?.status} body=${JSON.stringify(err.response?.data)}`, + ); + } else { + this.logger.error(`Card Gateway GET ${url} threw: ${err instanceof Error ? err.message : err}`); + } + throw err; + } + } + + private get baseUrl(): string { + return this.config.get('card.baseUrl') ?? ''; + } + private get apiKey(): string { + return this.config.get('card.apiKey') ?? ''; + } + private get webhookSecret(): string { + return this.config.get('card.webhookSecret') ?? ''; + } + private get webhookUrl(): string { + return this.config.get('card.webhookUrl') ?? ''; + } + private get returnUrl(): string { + return this.config.get('card.returnUrl') ?? ''; + } +} diff --git a/apps/edr-passenger-api/src/modules/payments/providers/cbe-birr.provider.ts b/apps/edr-passenger-api/src/modules/payments/providers/cbe-birr.provider.ts new file mode 100644 index 000000000..9f94a235a --- /dev/null +++ b/apps/edr-passenger-api/src/modules/payments/providers/cbe-birr.provider.ts @@ -0,0 +1,215 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { HttpService } from '@nestjs/axios'; +import { PaymentIntentStatus, PaymentMethodType } from '@prisma/client'; +import { AxiosError, AxiosRequestConfig } from 'axios'; +import { firstValueFrom } from 'rxjs'; +import * as crypto from 'node:crypto'; +import { + PaymentProvider, + ProviderInitiationInput, + ProviderInitiationResult, + ProviderStatus, +} from '../payments.types'; + +interface CbeBirrInitiateRequest { + merchantId: string; + merchantOrderId: string; + amount: string; + currency: string; + description: string; + returnUrl: string; + notifyUrl: string; + timestamp: string; + signature: string; +} + +interface CbeBirrInitiateResponse { + success: boolean; + orderId: string; + paymentUrl: string; + expiresIn: number; +} + +interface CbeBirrQueryResponse { + success: boolean; + orderId: string; + status: string; + transactionId?: string; + amount?: string; + paidAt?: string; +} + +@Injectable() +export class CbeBirrProvider implements PaymentProvider { + readonly method = PaymentMethodType.CBE_BIRR; + private readonly logger = new Logger(CbeBirrProvider.name); + + constructor( + private readonly config: ConfigService, + private readonly http: HttpService, + ) {} + + async initiate(input: ProviderInitiationInput): Promise { + const amount = (input.amountMinor / 100).toFixed(2); + const timestamp = new Date().toISOString(); + + const requestBody: CbeBirrInitiateRequest = { + merchantId: this.merchantId, + merchantOrderId: input.merchantOrderId, + amount, + currency: input.currency, + description: `EDR Booking ${input.bookingRef}`, + returnUrl: this.returnUrl, + notifyUrl: this.notifyUrl, + timestamp, + signature: this.signRequest({ + merchantId: this.merchantId, + merchantOrderId: input.merchantOrderId, + amount, + timestamp, + }), + }; + + const response = await this.postJson( + `${this.baseUrl}/api/v1/payment/initiate`, + requestBody, + ); + + if (!response.success || !response.orderId) { + throw new Error(`CBE Birr initiate failed: ${JSON.stringify(response)}`); + } + + const expiresAt = new Date(Date.now() + response.expiresIn * 1000); + + return { + providerOrderId: response.orderId, + clientAction: { type: 'REDIRECT', url: response.paymentUrl }, + expiresAt, + rawInitiation: { + request: this.sanitize(requestBody), + response, + }, + }; + } + + async queryStatus(merchantOrderId: string): Promise { + const timestamp = new Date().toISOString(); + const signature = this.signRequest({ + merchantId: this.merchantId, + merchantOrderId, + timestamp, + }); + + const response = await this.postJson( + `${this.baseUrl}/api/v1/payment/query`, + { + merchantId: this.merchantId, + merchantOrderId, + timestamp, + signature, + }, + ); + + const mapped = this.mapStatus(response.status); + + return { + status: mapped, + providerTxnId: response.transactionId, + failureCode: mapped === PaymentIntentStatus.FAILED ? response.status : undefined, + rawResponse: response as unknown as Record, + }; + } + + verifyWebhookSignature(payload: Record): boolean { + const { signature, ...data } = payload; + if (!signature || typeof signature !== 'string') return false; + + const expectedSignature = this.signRequest(data); + return crypto.timingSafeEqual( + Buffer.from(signature), + Buffer.from(expectedSignature), + ); + } + + mapWebhookStatus(status: string): PaymentIntentStatus { + return this.mapStatus(status); + } + + private mapStatus(status: string): PaymentIntentStatus { + switch (status?.toUpperCase()) { + case 'SUCCESS': + case 'COMPLETED': + return PaymentIntentStatus.SUCCEEDED; + case 'FAILED': + case 'REJECTED': + case 'EXPIRED': + return PaymentIntentStatus.FAILED; + case 'PENDING': + return PaymentIntentStatus.REQUIRES_ACTION; + case 'PROCESSING': + return PaymentIntentStatus.PROCESSING; + default: + return PaymentIntentStatus.PROCESSING; + } + } + + private signRequest(data: Record): string { + const sortedKeys = Object.keys(data).sort(); + const signString = sortedKeys + .map((key) => `${key}=${data[key]}`) + .join('&'); + + return crypto + .createHmac('sha256', this.secretKey) + .update(signString) + .digest('hex'); + } + + private async postJson(url: string, body: unknown): Promise { + const config: AxiosRequestConfig = { + headers: { + 'Content-Type': 'application/json', + 'X-Merchant-Id': this.merchantId, + }, + timeout: 10_000, + }; + + const started = Date.now(); + try { + const res = await firstValueFrom(this.http.post(url, body, config)); + this.logger.debug(`CBE Birr POST ${url} status=${res.status} latency=${Date.now() - started}ms`); + return res.data; + } catch (err) { + if (err instanceof AxiosError) { + this.logger.error( + `CBE Birr POST ${url} failed: status=${err.response?.status} body=${JSON.stringify(err.response?.data)}`, + ); + } else { + this.logger.error(`CBE Birr POST ${url} threw: ${err instanceof Error ? err.message : err}`); + } + throw err; + } + } + + private sanitize(body: CbeBirrInitiateRequest): Record { + const { signature: _signature, ...rest } = body; + return rest; + } + + private get baseUrl(): string { + return this.config.get('cbe.baseUrl') ?? ''; + } + private get merchantId(): string { + return this.config.get('cbe.merchantId') ?? ''; + } + private get secretKey(): string { + return this.config.get('cbe.secretKey') ?? ''; + } + private get notifyUrl(): string { + return this.config.get('cbe.notifyUrl') ?? ''; + } + private get returnUrl(): string { + return this.config.get('cbe.returnUrl') ?? ''; + } +} diff --git a/apps/edr-passenger-api/src/modules/payments/providers/ebirr.provider.ts b/apps/edr-passenger-api/src/modules/payments/providers/ebirr.provider.ts new file mode 100644 index 000000000..701d4b5fb --- /dev/null +++ b/apps/edr-passenger-api/src/modules/payments/providers/ebirr.provider.ts @@ -0,0 +1,228 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { HttpService } from '@nestjs/axios'; +import { PaymentIntentStatus, PaymentMethodType } from '@prisma/client'; +import { AxiosError, AxiosRequestConfig } from 'axios'; +import { firstValueFrom } from 'rxjs'; +import * as crypto from 'node:crypto'; +import { + PaymentProvider, + ProviderInitiationInput, + ProviderInitiationResult, + ProviderStatus, +} from '../payments.types'; + +interface EBirrInitiateRequest { + merchantCode: string; + orderNo: string; + amount: number; + currency: string; + subject: string; + body: string; + notifyUrl: string; + returnUrl: string; + timestamp: number; + sign: string; +} + +interface EBirrInitiateResponse { + code: string; + message: string; + data?: { + orderNo: string; + payUrl: string; + expireTime: number; + }; +} + +interface EBirrQueryResponse { + code: string; + message: string; + data?: { + orderNo: string; + tradeStatus: string; + tradeNo?: string; + totalAmount?: number; + payTime?: number; + }; +} + +@Injectable() +export class EBirrProvider implements PaymentProvider { + readonly method = PaymentMethodType.EBIRR; + private readonly logger = new Logger(EBirrProvider.name); + + constructor( + private readonly config: ConfigService, + private readonly http: HttpService, + ) {} + + async initiate(input: ProviderInitiationInput): Promise { + const amount = input.amountMinor / 100; + const timestamp = Date.now(); + + const requestBody: EBirrInitiateRequest = { + merchantCode: this.merchantCode, + orderNo: input.merchantOrderId, + amount, + currency: input.currency, + subject: `EDR Ticket`, + body: `Train booking ${input.bookingRef}`, + notifyUrl: this.notifyUrl, + returnUrl: this.returnUrl, + timestamp, + sign: this.signRequest({ + merchantCode: this.merchantCode, + orderNo: input.merchantOrderId, + amount, + timestamp, + }), + }; + + const response = await this.postJson( + `${this.baseUrl}/gateway/api/pay/create`, + requestBody, + ); + + if (response.code !== '0000' || !response.data?.orderNo) { + throw new Error(`eBirr initiate failed: ${response.message}`); + } + + const expiresAt = new Date(response.data.expireTime); + + return { + providerOrderId: response.data.orderNo, + clientAction: { type: 'REDIRECT', url: response.data.payUrl }, + expiresAt, + rawInitiation: { + request: this.sanitize(requestBody), + response, + }, + }; + } + + async queryStatus(merchantOrderId: string): Promise { + const timestamp = Date.now(); + const requestBody = { + merchantCode: this.merchantCode, + orderNo: merchantOrderId, + timestamp, + sign: this.signRequest({ + merchantCode: this.merchantCode, + orderNo: merchantOrderId, + timestamp, + }), + }; + + const response = await this.postJson( + `${this.baseUrl}/gateway/api/pay/query`, + requestBody, + ); + + if (response.code !== '0000' || !response.data) { + throw new Error(`eBirr query failed: ${response.message}`); + } + + const mapped = this.mapStatus(response.data.tradeStatus); + + return { + status: mapped, + providerTxnId: response.data.tradeNo, + failureCode: mapped === PaymentIntentStatus.FAILED ? response.data.tradeStatus : undefined, + rawResponse: response as unknown as Record, + }; + } + + verifyWebhookSignature(payload: Record): boolean { + const { sign, ...data } = payload; + if (!sign || typeof sign !== 'string') return false; + + const expectedSign = this.signRequest(data); + return crypto.timingSafeEqual( + Buffer.from(sign), + Buffer.from(expectedSign), + ); + } + + mapWebhookStatus(tradeStatus: string): PaymentIntentStatus { + return this.mapStatus(tradeStatus); + } + + private mapStatus(tradeStatus: string): PaymentIntentStatus { + switch (tradeStatus?.toUpperCase()) { + case 'TRADE_SUCCESS': + case 'SUCCESS': + return PaymentIntentStatus.SUCCEEDED; + case 'TRADE_CLOSED': + case 'TRADE_FAILED': + case 'FAILED': + return PaymentIntentStatus.FAILED; + case 'WAIT_BUYER_PAY': + case 'PENDING': + return PaymentIntentStatus.REQUIRES_ACTION; + case 'PROCESSING': + return PaymentIntentStatus.PROCESSING; + default: + return PaymentIntentStatus.PROCESSING; + } + } + + private signRequest(data: Record): string { + const sortedKeys = Object.keys(data).sort(); + const signString = sortedKeys + .map((key) => `${key}=${data[key]}`) + .join('&') + `&key=${this.secretKey}`; + + return crypto + .createHash('md5') + .update(signString) + .digest('hex') + .toUpperCase(); + } + + private async postJson(url: string, body: unknown): Promise { + const config: AxiosRequestConfig = { + headers: { + 'Content-Type': 'application/json', + }, + timeout: 10_000, + }; + + const started = Date.now(); + try { + const res = await firstValueFrom(this.http.post(url, body, config)); + this.logger.debug(`eBirr POST ${url} status=${res.status} latency=${Date.now() - started}ms`); + return res.data; + } catch (err) { + if (err instanceof AxiosError) { + this.logger.error( + `eBirr POST ${url} failed: status=${err.response?.status} body=${JSON.stringify(err.response?.data)}`, + ); + } else { + this.logger.error(`eBirr POST ${url} threw: ${err instanceof Error ? err.message : err}`); + } + throw err; + } + } + + private sanitize(body: EBirrInitiateRequest): Record { + const { sign: _sign, ...rest } = body; + return rest; + } + + private get baseUrl(): string { + return this.config.get('ebirr.baseUrl') ?? ''; + } + private get merchantCode(): string { + return this.config.get('ebirr.merchantCode') ?? ''; + } + private get secretKey(): string { + return this.config.get('ebirr.secretKey') ?? ''; + } + private get notifyUrl(): string { + return this.config.get('ebirr.notifyUrl') ?? ''; + } + private get returnUrl(): string { + return this.config.get('ebirr.returnUrl') ?? ''; + } +} diff --git a/apps/edr-passenger-api/src/modules/payments/webhooks/card-webhook.service.ts b/apps/edr-passenger-api/src/modules/payments/webhooks/card-webhook.service.ts new file mode 100644 index 000000000..5612ac77d --- /dev/null +++ b/apps/edr-passenger-api/src/modules/payments/webhooks/card-webhook.service.ts @@ -0,0 +1,147 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { Prisma, PaymentIntentStatus, PaymentMethodType } from '@prisma/client'; +import { PrismaService } from '../../../common/prisma.service'; +import { PaymentsService } from '../payments.service'; +import { CardProvider } from '../providers/card.provider'; + +export interface CardWebhookPayload { + id: string; + type: string; + data: { + object: { + id: string; + status: string; + amount: number; + currency: string; + metadata: { + merchantOrderId: string; + bookingRef: string; + }; + transaction_id?: string; + paid_at?: number; + failure_code?: string; + failure_message?: string; + }; + }; + created: number; +} + +@Injectable() +export class CardWebhookService { + private readonly logger = new Logger(CardWebhookService.name); + + constructor( + private readonly prisma: PrismaService, + private readonly provider: CardProvider, + private readonly payments: PaymentsService, + ) {} + + async handle(payload: CardWebhookPayload, signature: string): Promise { + const merchantOrderId = payload.data.object.metadata.merchantOrderId; + const externalEventId = `${payload.id}_${payload.type}`; + const signatureValid = this.provider.verifyWebhookSignature( + payload as unknown as Record, + signature, + ); + + const eventRow = await this.persistEvent({ + externalEventId, + merchantOrderId, + providerTxnId: payload.data.object.transaction_id, + signatureValid, + status: payload.data.object.status, + payload, + }); + + if (!eventRow) { + this.logger.log(`Card webhook duplicate: ${externalEventId} — short-circuit OK`); + return; + } + + if (!signatureValid) { + this.logger.warn(`Card webhook signature invalid for merchantOrderId=${merchantOrderId}`); + await this.markProcessed(eventRow.id, 'signature-invalid'); + return; + } + + const intent = await this.prisma.paymentIntent.findUnique({ + where: { merchantOrderId }, + }); + if (!intent) { + this.logger.warn(`Card webhook: no PaymentIntent for merchantOrderId=${merchantOrderId}`); + await this.markProcessed(eventRow.id, 'intent-not-found'); + return; + } + + const mapped = this.provider.mapWebhookStatus(payload.data.object.status); + + try { + if (mapped === PaymentIntentStatus.SUCCEEDED) { + await this.payments.finalizePaymentSuccess({ + intentId: intent.id, + providerTxnId: payload.data.object.transaction_id, + paidAt: payload.data.object.paid_at ? new Date(payload.data.object.paid_at * 1000) : undefined, + }); + } else if (mapped === PaymentIntentStatus.FAILED) { + await this.payments.markPaymentFailed({ + intentId: intent.id, + failureCode: payload.data.object.failure_code, + failureMessage: payload.data.object.failure_message, + }); + } else { + await this.prisma.paymentIntent.update({ + where: { id: intent.id }, + data: { + status: mapped, + providerTxnId: payload.data.object.transaction_id ?? undefined, + }, + }); + } + await this.markProcessed(eventRow.id); + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + this.logger.error(`Card webhook processing failed for ${merchantOrderId}: ${message}`); + await this.markProcessed(eventRow.id, `processing-error: ${message}`); + throw err; + } + } + + private async persistEvent(input: { + externalEventId: string; + merchantOrderId: string; + providerTxnId?: string; + signatureValid: boolean; + status: string; + payload: CardWebhookPayload; + }): Promise<{ id: string } | null> { + try { + return await this.prisma.paymentWebhookEvent.create({ + data: { + provider: PaymentMethodType.CARD, + externalEventId: input.externalEventId, + merchantOrderId: input.merchantOrderId, + providerTxnId: input.providerTxnId, + signatureValid: input.signatureValid, + status: input.status, + payload: input.payload as unknown as Prisma.InputJsonValue, + }, + select: { id: true }, + }); + } catch (err) { + if ( + err instanceof Prisma.PrismaClientKnownRequestError && + err.code === 'P2002' + ) { + return null; + } + throw err; + } + } + + private async markProcessed(eventId: string, processingError?: string): Promise { + await this.prisma.paymentWebhookEvent.update({ + where: { id: eventId }, + data: { processedAt: new Date(), processingError }, + }); + } +} diff --git a/apps/edr-passenger-api/src/modules/payments/webhooks/cbe-birr-webhook.service.ts b/apps/edr-passenger-api/src/modules/payments/webhooks/cbe-birr-webhook.service.ts new file mode 100644 index 000000000..2c34e85f6 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/payments/webhooks/cbe-birr-webhook.service.ts @@ -0,0 +1,133 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { Prisma, PaymentIntentStatus, PaymentMethodType } from '@prisma/client'; +import { PrismaService } from '../../../common/prisma.service'; +import { PaymentsService } from '../payments.service'; +import { CbeBirrProvider } from '../providers/cbe-birr.provider'; + +export interface CbeBirrWebhookPayload { + merchantId: string; + merchantOrderId: string; + orderId: string; + status: string; + transactionId?: string; + amount?: string; + currency?: string; + paidAt?: string; + signature: string; + [key: string]: unknown; +} + +@Injectable() +export class CbeBirrWebhookService { + private readonly logger = new Logger(CbeBirrWebhookService.name); + + constructor( + private readonly prisma: PrismaService, + private readonly provider: CbeBirrProvider, + private readonly payments: PaymentsService, + ) {} + + async handle(payload: CbeBirrWebhookPayload): Promise { + const merchantOrderId = payload.merchantOrderId; + const externalEventId = `${payload.orderId}_${payload.status}`; + const signatureValid = this.provider.verifyWebhookSignature( + payload as unknown as Record, + ); + + const eventRow = await this.persistEvent({ + externalEventId, + merchantOrderId, + providerTxnId: payload.transactionId ?? payload.orderId, + signatureValid, + status: payload.status, + payload, + }); + + if (!eventRow) { + this.logger.log(`CBE Birr webhook duplicate: ${externalEventId} — short-circuit OK`); + return; + } + + if (!signatureValid) { + this.logger.warn(`CBE Birr webhook signature invalid for merchantOrderId=${merchantOrderId}`); + await this.markProcessed(eventRow.id, 'signature-invalid'); + return; + } + + const intent = await this.prisma.paymentIntent.findUnique({ + where: { merchantOrderId }, + }); + if (!intent) { + this.logger.warn(`CBE Birr webhook: no PaymentIntent for merchantOrderId=${merchantOrderId}`); + await this.markProcessed(eventRow.id, 'intent-not-found'); + return; + } + + const mapped = this.provider.mapWebhookStatus(payload.status); + + try { + if (mapped === PaymentIntentStatus.SUCCEEDED) { + await this.payments.finalizePaymentSuccess({ + intentId: intent.id, + providerTxnId: payload.transactionId ?? payload.orderId, + paidAt: payload.paidAt ? new Date(payload.paidAt) : undefined, + }); + } else if (mapped === PaymentIntentStatus.FAILED) { + await this.payments.markPaymentFailed({ + intentId: intent.id, + failureCode: payload.status, + }); + } else { + await this.prisma.paymentIntent.update({ + where: { id: intent.id }, + data: { status: mapped, providerTxnId: payload.transactionId ?? undefined }, + }); + } + await this.markProcessed(eventRow.id); + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + this.logger.error(`CBE Birr webhook processing failed for ${merchantOrderId}: ${message}`); + await this.markProcessed(eventRow.id, `processing-error: ${message}`); + throw err; + } + } + + private async persistEvent(input: { + externalEventId: string; + merchantOrderId: string; + providerTxnId?: string; + signatureValid: boolean; + status: string; + payload: CbeBirrWebhookPayload; + }): Promise<{ id: string } | null> { + try { + return await this.prisma.paymentWebhookEvent.create({ + data: { + provider: PaymentMethodType.CBE_BIRR, + externalEventId: input.externalEventId, + merchantOrderId: input.merchantOrderId, + providerTxnId: input.providerTxnId, + signatureValid: input.signatureValid, + status: input.status, + payload: input.payload as unknown as Prisma.InputJsonValue, + }, + select: { id: true }, + }); + } catch (err) { + if ( + err instanceof Prisma.PrismaClientKnownRequestError && + err.code === 'P2002' + ) { + return null; + } + throw err; + } + } + + private async markProcessed(eventId: string, processingError?: string): Promise { + await this.prisma.paymentWebhookEvent.update({ + where: { id: eventId }, + data: { processedAt: new Date(), processingError }, + }); + } +} diff --git a/apps/edr-passenger-api/src/modules/payments/webhooks/ebirr-webhook.service.ts b/apps/edr-passenger-api/src/modules/payments/webhooks/ebirr-webhook.service.ts new file mode 100644 index 000000000..700078b79 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/payments/webhooks/ebirr-webhook.service.ts @@ -0,0 +1,133 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { Prisma, PaymentIntentStatus, PaymentMethodType } from '@prisma/client'; +import { PrismaService } from '../../../common/prisma.service'; +import { PaymentsService } from '../payments.service'; +import { EBirrProvider } from '../providers/ebirr.provider'; + +export interface EBirrWebhookPayload { + merchantCode: string; + orderNo: string; + tradeStatus: string; + tradeNo?: string; + totalAmount?: number; + currency?: string; + payTime?: number; + timestamp: number; + sign: string; + [key: string]: unknown; +} + +@Injectable() +export class EBirrWebhookService { + private readonly logger = new Logger(EBirrWebhookService.name); + + constructor( + private readonly prisma: PrismaService, + private readonly provider: EBirrProvider, + private readonly payments: PaymentsService, + ) {} + + async handle(payload: EBirrWebhookPayload): Promise { + const merchantOrderId = payload.orderNo; + const externalEventId = `${payload.orderNo}_${payload.tradeStatus}_${payload.timestamp}`; + const signatureValid = this.provider.verifyWebhookSignature( + payload as unknown as Record, + ); + + const eventRow = await this.persistEvent({ + externalEventId, + merchantOrderId, + providerTxnId: payload.tradeNo, + signatureValid, + status: payload.tradeStatus, + payload, + }); + + if (!eventRow) { + this.logger.log(`eBirr webhook duplicate: ${externalEventId} — short-circuit OK`); + return; + } + + if (!signatureValid) { + this.logger.warn(`eBirr webhook signature invalid for orderNo=${merchantOrderId}`); + await this.markProcessed(eventRow.id, 'signature-invalid'); + return; + } + + const intent = await this.prisma.paymentIntent.findUnique({ + where: { merchantOrderId }, + }); + if (!intent) { + this.logger.warn(`eBirr webhook: no PaymentIntent for orderNo=${merchantOrderId}`); + await this.markProcessed(eventRow.id, 'intent-not-found'); + return; + } + + const mapped = this.provider.mapWebhookStatus(payload.tradeStatus); + + try { + if (mapped === PaymentIntentStatus.SUCCEEDED) { + await this.payments.finalizePaymentSuccess({ + intentId: intent.id, + providerTxnId: payload.tradeNo, + paidAt: payload.payTime ? new Date(payload.payTime) : undefined, + }); + } else if (mapped === PaymentIntentStatus.FAILED) { + await this.payments.markPaymentFailed({ + intentId: intent.id, + failureCode: payload.tradeStatus, + }); + } else { + await this.prisma.paymentIntent.update({ + where: { id: intent.id }, + data: { status: mapped, providerTxnId: payload.tradeNo ?? undefined }, + }); + } + await this.markProcessed(eventRow.id); + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + this.logger.error(`eBirr webhook processing failed for ${merchantOrderId}: ${message}`); + await this.markProcessed(eventRow.id, `processing-error: ${message}`); + throw err; + } + } + + private async persistEvent(input: { + externalEventId: string; + merchantOrderId: string; + providerTxnId?: string; + signatureValid: boolean; + status: string; + payload: EBirrWebhookPayload; + }): Promise<{ id: string } | null> { + try { + return await this.prisma.paymentWebhookEvent.create({ + data: { + provider: PaymentMethodType.EBIRR, + externalEventId: input.externalEventId, + merchantOrderId: input.merchantOrderId, + providerTxnId: input.providerTxnId, + signatureValid: input.signatureValid, + status: input.status, + payload: input.payload as unknown as Prisma.InputJsonValue, + }, + select: { id: true }, + }); + } catch (err) { + if ( + err instanceof Prisma.PrismaClientKnownRequestError && + err.code === 'P2002' + ) { + return null; + } + throw err; + } + } + + private async markProcessed(eventId: string, processingError?: string): Promise { + await this.prisma.paymentWebhookEvent.update({ + where: { id: eventId }, + data: { processedAt: new Date(), processingError }, + }); + } +} diff --git a/apps/edr-passenger-api/src/modules/payments/webhooks/webhooks.controller.ts b/apps/edr-passenger-api/src/modules/payments/webhooks/webhooks.controller.ts index 3d5e0a3a0..4edbe58a8 100644 --- a/apps/edr-passenger-api/src/modules/payments/webhooks/webhooks.controller.ts +++ b/apps/edr-passenger-api/src/modules/payments/webhooks/webhooks.controller.ts @@ -1,16 +1,33 @@ -import { Body, Controller, HttpCode, HttpStatus, Logger, Post } from '@nestjs/common'; +import { Body, Controller, Headers, HttpCode, HttpStatus, Logger, Post } from '@nestjs/common'; import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { TelebirrWebhookPayload, TelebirrWebhookService, } from './telebirr-webhook.service'; +import { + CbeBirrWebhookPayload, + CbeBirrWebhookService, +} from './cbe-birr-webhook.service'; +import { + EBirrWebhookPayload, + EBirrWebhookService, +} from './ebirr-webhook.service'; +import { + CardWebhookPayload, + CardWebhookService, +} from './card-webhook.service'; @ApiTags('Payment Webhooks') @Controller('payments/webhooks') export class WebhooksController { private readonly logger = new Logger(WebhooksController.name); - constructor(private readonly telebirr: TelebirrWebhookService) {} + constructor( + private readonly telebirr: TelebirrWebhookService, + private readonly cbeBirr: CbeBirrWebhookService, + private readonly eBirr: EBirrWebhookService, + private readonly card: CardWebhookService, + ) {} @Post('telebirr') @HttpCode(HttpStatus.OK) @@ -24,4 +41,46 @@ export class WebhooksController { } return { code: '0', message: 'OK' }; } + + @Post('cbe-birr') + @HttpCode(HttpStatus.OK) + @ApiOperation({ summary: 'CBE Birr payment notification callback' }) + async receiveCbeBirr(@Body() payload: CbeBirrWebhookPayload) { + try { + await this.cbeBirr.handle(payload); + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + this.logger.error(`CBE Birr webhook handler threw: ${message}`); + } + return { success: true }; + } + + @Post('ebirr') + @HttpCode(HttpStatus.OK) + @ApiOperation({ summary: 'eBirr payment notification callback' }) + async receiveEBirr(@Body() payload: EBirrWebhookPayload) { + try { + await this.eBirr.handle(payload); + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + this.logger.error(`eBirr webhook handler threw: ${message}`); + } + return { code: '0000', message: 'success' }; + } + + @Post('card') + @HttpCode(HttpStatus.OK) + @ApiOperation({ summary: 'Card payment notification callback' }) + async receiveCard( + @Body() payload: CardWebhookPayload, + @Headers('stripe-signature') signature: string, + ) { + try { + await this.card.handle(payload, signature); + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + this.logger.error(`Card webhook handler threw: ${message}`); + } + return { received: true }; + } } diff --git a/apps/edr-passenger-api/src/modules/reports/reports.controller.ts b/apps/edr-passenger-api/src/modules/reports/reports.controller.ts new file mode 100644 index 000000000..772a1428c --- /dev/null +++ b/apps/edr-passenger-api/src/modules/reports/reports.controller.ts @@ -0,0 +1,35 @@ +import { Body, Controller, Get, Param, Post, Query, UseGuards } from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger'; +import { ReportsService } from './reports.service'; +import { GenerateReportDto } from './reports.dto'; +import { IamGuard, IamRoles } from '../../common/iam-adapter'; +import { UserRole } from '@prisma/client'; + +@ApiTags('Reports') +@Controller('reports') +@UseGuards(IamGuard) +@ApiBearerAuth('IAM-auth') +export class ReportsController { + constructor(private service: ReportsService) {} + + @Post('generate') + @IamRoles('ADMIN', 'SUPERVISOR') + @ApiOperation({ summary: 'Generate operational report' }) + generateReport(@Body() dto: GenerateReportDto) { + return this.service.generateReport(dto); + } + + @Get(':reportId') + @IamRoles('ADMIN', 'SUPERVISOR') + @ApiOperation({ summary: 'Get report by ID' }) + getReport(@Param('reportId') reportId: string) { + return this.service.getReport(reportId); + } + + @Get() + @IamRoles('ADMIN', 'SUPERVISOR') + @ApiOperation({ summary: 'List reports' }) + listReports(@Query('type') type?: string) { + return this.service.listReports(type); + } +} diff --git a/apps/edr-passenger-api/src/modules/reports/reports.dto.ts b/apps/edr-passenger-api/src/modules/reports/reports.dto.ts new file mode 100644 index 000000000..5fdb856ec --- /dev/null +++ b/apps/edr-passenger-api/src/modules/reports/reports.dto.ts @@ -0,0 +1,29 @@ +import { IsString, IsDateString, IsOptional, IsEnum } from 'class-validator'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; + +export enum ReportType { + REVENUE = 'REVENUE', + OCCUPANCY = 'OCCUPANCY', + AGENT_SALES = 'AGENT_SALES', + CANCELLATIONS = 'CANCELLATIONS', + PAYMENT_METHODS = 'PAYMENT_METHODS' +} + +export enum ExportFormat { + JSON = 'JSON', + CSV = 'CSV', + PDF = 'PDF' +} + +export class GenerateReportDto { + @ApiProperty({ enum: ReportType }) @IsEnum(ReportType) reportType: ReportType; + @ApiProperty({ example: '2026-01-01' }) @IsDateString() dateFrom: string; + @ApiProperty({ example: '2026-01-31' }) @IsDateString() dateTo: string; + @ApiPropertyOptional() @IsOptional() @IsString() routeId?: string; + @ApiPropertyOptional() @IsOptional() @IsString() agentId?: string; +} + +export class ExportReportDto { + @ApiProperty() @IsString() reportId: string; + @ApiProperty({ enum: ExportFormat }) @IsEnum(ExportFormat) format: ExportFormat; +} diff --git a/apps/edr-passenger-api/src/modules/reports/reports.module.ts b/apps/edr-passenger-api/src/modules/reports/reports.module.ts new file mode 100644 index 000000000..801120cbf --- /dev/null +++ b/apps/edr-passenger-api/src/modules/reports/reports.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; +import { HttpModule } from '@nestjs/axios'; +import { ReportsController } from './reports.controller'; +import { ReportsService } from './reports.service'; + +@Module({ + imports: [HttpModule], + controllers: [ReportsController], + providers: [ReportsService], + exports: [ReportsService] +}) +export class ReportsModule {} diff --git a/apps/edr-passenger-api/src/modules/reports/reports.service.ts b/apps/edr-passenger-api/src/modules/reports/reports.service.ts new file mode 100644 index 000000000..0d2699a99 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/reports/reports.service.ts @@ -0,0 +1,185 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../../common/prisma.service'; +import { GenerateReportDto, ReportType } from './reports.dto'; + +@Injectable() +export class ReportsService { + constructor(private prisma: PrismaService) {} + + async generateReport(dto: GenerateReportDto) { + const dateFrom = new Date(dto.dateFrom); + const dateTo = new Date(dto.dateTo); + + let data: any; + switch (dto.reportType) { + case ReportType.REVENUE: + data = await this.generateRevenueReport(dateFrom, dateTo); + break; + case ReportType.OCCUPANCY: + data = await this.generateOccupancyReport(dateFrom, dateTo); + break; + case ReportType.AGENT_SALES: + data = await this.generateAgentSalesReport(dateFrom, dateTo, dto.agentId); + break; + case ReportType.CANCELLATIONS: + data = await this.generateCancellationsReport(dateFrom, dateTo); + break; + case ReportType.PAYMENT_METHODS: + data = await this.generatePaymentMethodsReport(dateFrom, dateTo); + break; + default: + data = {}; + } + + const report = await this.prisma.operationalReport.create({ + data: { + reportType: dto.reportType, + dateFrom, + dateTo, + data + } + }); + + return { reportId: report.id, reportType: dto.reportType, data }; + } + + private async generateRevenueReport(dateFrom: Date, dateTo: Date) { + const bookings = await this.prisma.booking.findMany({ + where: { + createdAt: { gte: dateFrom, lte: dateTo }, + status: { in: ['CONFIRMED', 'COMPLETED'] } + }, + include: { paymentIntent: true } + }); + + const totalRevenue = bookings.reduce((sum, b) => sum + b.totalMinor, 0); + const byPaymentMethod = bookings.reduce((acc, b) => { + const method = b.paymentIntent?.method ?? 'UNKNOWN'; + acc[method] = (acc[method] || 0) + b.totalMinor; + return acc; + }, {} as Record); + + return { + totalBookings: bookings.length, + totalRevenueMinor: totalRevenue, + totalRevenue: totalRevenue / 100, + currency: 'ETB', + byPaymentMethod + }; + } + + private async generateOccupancyReport(dateFrom: Date, dateTo: Date) { + const trips = await this.prisma.trip.findMany({ + where: { departureAt: { gte: dateFrom, lte: dateTo } }, + include: { + coaches: { include: { seats: true } }, + bookings: { where: { status: { in: ['CONFIRMED', 'COMPLETED'] } }, include: { seats: true } } + } + }); + + const tripData = trips.map(trip => { + const totalSeats = trip.coaches.reduce((sum, c) => sum + c.seats.length, 0); + const bookedSeats = trip.bookings.reduce((sum, b) => sum + b.seats.length, 0); + const occupancyRate = totalSeats > 0 ? (bookedSeats / totalSeats) * 100 : 0; + + return { + tripId: trip.id, + departureAt: trip.departureAt, + totalSeats, + bookedSeats, + occupancyRate: +occupancyRate.toFixed(2) + }; + }); + + const avgOccupancy = tripData.length > 0 + ? tripData.reduce((sum, t) => sum + t.occupancyRate, 0) / tripData.length + : 0; + + return { + totalTrips: trips.length, + averageOccupancyRate: +avgOccupancy.toFixed(2), + trips: tripData + }; + } + + private async generateAgentSalesReport(dateFrom: Date, dateTo: Date, agentId?: string) { + const agentBookings = await this.prisma.agentBooking.findMany({ + where: { + createdAt: { gte: dateFrom, lte: dateTo }, + ...(agentId ? { agentId } : {}) + }, + include: { + agent: { include: { user: true } }, + booking: true + } + }); + + const byAgent = agentBookings.reduce((acc, ab) => { + const agentName = ab.agent.user.fullName; + if (!acc[agentName]) { + acc[agentName] = { bookings: 0, revenueMinor: 0, cashCollected: 0 }; + } + acc[agentName].bookings += 1; + acc[agentName].revenueMinor += ab.booking.totalMinor; + acc[agentName].cashCollected += ab.cashReceived ?? 0; + return acc; + }, {} as Record); + + return { + totalAgentBookings: agentBookings.length, + byAgent + }; + } + + private async generateCancellationsReport(dateFrom: Date, dateTo: Date) { + const cancellations = await this.prisma.bookingCancellation.findMany({ + where: { createdAt: { gte: dateFrom, lte: dateTo } }, + include: { booking: true } + }); + + const totalRefunded = cancellations.reduce((sum, c) => sum + c.refundAmount, 0); + + return { + totalCancellations: cancellations.length, + totalRefundedMinor: totalRefunded, + totalRefunded: totalRefunded / 100, + currency: 'ETB' + }; + } + + private async generatePaymentMethodsReport(dateFrom: Date, dateTo: Date) { + const payments = await this.prisma.paymentIntent.findMany({ + where: { + createdAt: { gte: dateFrom, lte: dateTo }, + status: 'SUCCEEDED' + } + }); + + const byMethod = payments.reduce((acc, p) => { + const method = p.method; + if (!acc[method]) { + acc[method] = { count: 0, totalMinor: 0 }; + } + acc[method].count += 1; + acc[method].totalMinor += p.amountMinor; + return acc; + }, {} as Record); + + return { + totalPayments: payments.length, + byMethod + }; + } + + async getReport(reportId: string) { + return this.prisma.operationalReport.findUnique({ where: { id: reportId } }); + } + + async listReports(reportType?: string) { + return this.prisma.operationalReport.findMany({ + where: reportType ? { reportType } : {}, + orderBy: { createdAt: 'desc' }, + take: 50 + }); + } +} diff --git a/apps/edr-passenger-api/src/modules/search/search.dto.ts b/apps/edr-passenger-api/src/modules/search/search.dto.ts index e4e3d2cae..3d8344218 100644 --- a/apps/edr-passenger-api/src/modules/search/search.dto.ts +++ b/apps/edr-passenger-api/src/modules/search/search.dto.ts @@ -11,7 +11,11 @@ export class SearchTripsDto { export class FareQuoteDto { @ApiProperty() @IsString() tripId: string; - @ApiProperty({ example: 'ECONOMY' }) @IsString() serviceClass: string; + @ApiProperty({ + example: 'ECONOMY_REGULAR', + enum: ['ECONOMY_REGULAR', 'ECONOMY_BED_LOWER', 'ECONOMY_BED_MIDDLE', 'ECONOMY_BED_UPPER', 'VIP_BED_LOWER', 'VIP_BED_UPPER'] + }) + @IsString() serviceClass: string; @ApiPropertyOptional({ example: 1 }) @IsOptional() @Type(() => Number) @IsInt() @Min(1) passengerCount?: number; @ApiPropertyOptional({ example: 'WEEKEND15' }) @IsOptional() @IsString() promoCode?: string; @ApiPropertyOptional({ example: 450 }) @IsOptional() @Type(() => Number) @IsInt() loyaltyRedemptionPoints?: number; diff --git a/apps/edr-passenger-api/src/modules/search/search.service.ts b/apps/edr-passenger-api/src/modules/search/search.service.ts index 046bdc70d..bf709b6d8 100644 --- a/apps/edr-passenger-api/src/modules/search/search.service.ts +++ b/apps/edr-passenger-api/src/modules/search/search.service.ts @@ -23,8 +23,22 @@ export class SearchService { origin: { id: trip.originStation.id, code: trip.originStation.code, name: trip.originStation.name, city: trip.originStation.city }, destination: { id: trip.destinationStation.id, code: trip.destinationStation.code, name: trip.destinationStation.name, city: trip.destinationStation.city }, departureAt: trip.departureAt, arrivalAt: trip.arrivalAt, status: trip.status, - availability: { ECONOMY: avail('ECONOMY'), BUSINESS: avail('BUSINESS'), FIRST: avail('FIRST') }, - fares: { ECONOMY: this.defaultFare('ECONOMY') / 100, BUSINESS: this.defaultFare('BUSINESS') / 100, FIRST: this.defaultFare('FIRST') / 100 }, + availability: { + ECONOMY_REGULAR: avail('ECONOMY_REGULAR'), + ECONOMY_BED_LOWER: avail('ECONOMY_BED_LOWER'), + ECONOMY_BED_MIDDLE: avail('ECONOMY_BED_MIDDLE'), + ECONOMY_BED_UPPER: avail('ECONOMY_BED_UPPER'), + VIP_BED_LOWER: avail('VIP_BED_LOWER'), + VIP_BED_UPPER: avail('VIP_BED_UPPER') + }, + fares: { + ECONOMY_REGULAR: this.defaultFare('ECONOMY_REGULAR') / 100, + ECONOMY_BED_LOWER: this.defaultFare('ECONOMY_BED_LOWER') / 100, + ECONOMY_BED_MIDDLE: this.defaultFare('ECONOMY_BED_MIDDLE') / 100, + ECONOMY_BED_UPPER: this.defaultFare('ECONOMY_BED_UPPER') / 100, + VIP_BED_LOWER: this.defaultFare('VIP_BED_LOWER') / 100, + VIP_BED_UPPER: this.defaultFare('VIP_BED_UPPER') / 100 + }, }; }); } @@ -45,6 +59,14 @@ export class SearchService { } private defaultFare(serviceClass: string): number { - return ({ ECONOMY: 45000, BUSINESS: 90000, FIRST: 135000 } as any)[serviceClass] ?? 45000; + const fares: Record = { + ECONOMY_REGULAR: 35000, // 350 ETB + ECONOMY_BED_LOWER: 55000, // 550 ETB + ECONOMY_BED_MIDDLE: 50000, // 500 ETB + ECONOMY_BED_UPPER: 45000, // 450 ETB + VIP_BED_LOWER: 85000, // 850 ETB + VIP_BED_UPPER: 80000 // 800 ETB + }; + return fares[serviceClass] ?? 35000; } } diff --git a/apps/edr-passenger-api/src/modules/seats/seats.controller.ts b/apps/edr-passenger-api/src/modules/seats/seats.controller.ts index a872f337d..a14a6a17f 100644 --- a/apps/edr-passenger-api/src/modules/seats/seats.controller.ts +++ b/apps/edr-passenger-api/src/modules/seats/seats.controller.ts @@ -14,4 +14,20 @@ export class SeatsController { holdSeats(@Body() dto: HoldSeatsDto) { return this.service.holdSeats(dto); } @Delete('hold/:holdId') @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') @ApiOperation({ summary: 'Release a seat hold' }) releaseHold(@Param('holdId') holdId: string) { return this.service.releaseHold(holdId); } + + @Get('export/csv/:tripId') @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') @ApiOperation({ summary: 'Export seats as CSV' }) + async exportCSV(@Param('tripId') tripId: string) { + const csv = await this.service.exportSeatsCSV(tripId); + return { csv, filename: `seats-${tripId}.csv` }; + } + + @Post('import/preview') @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') @ApiOperation({ summary: 'Preview CSV import' }) + previewCSV(@Body() body: { csv: string }) { + return this.service.previewSeatsCSV(body.csv); + } + + @Post('import/commit') @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') @ApiOperation({ summary: 'Commit CSV import' }) + importCSV(@Body() body: { tripId: string; csv: string; commit: boolean }) { + return this.service.importSeatsCSV(body.tripId, body.csv, body.commit); + } } diff --git a/apps/edr-passenger-api/src/modules/seats/seats.service.spec.ts b/apps/edr-passenger-api/src/modules/seats/seats.service.spec.ts new file mode 100644 index 000000000..2a3b84539 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/seats/seats.service.spec.ts @@ -0,0 +1,82 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { SeatsService } from './seats.service'; +import { PrismaService } from '../../common/prisma.service'; +import { ConflictException } from '@nestjs/common'; + +describe('SeatsService - Auto Assign', () => { + let service: SeatsService; + let prisma: PrismaService; + + const mockPrisma = { + seat: { + findMany: jest.fn(), + updateMany: jest.fn(), + }, + }; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + SeatsService, + { provide: PrismaService, useValue: mockPrisma }, + ], + }).compile(); + + service = module.get(SeatsService); + prisma = module.get(PrismaService); + jest.clearAllMocks(); + }); + + describe('autoAssignSeats', () => { + it('should assign contiguous seats in same row', async () => { + const mockSeats = [ + { id: 'seat-1', coachId: 'coach-1', row: 1, col: 'A' }, + { id: 'seat-2', coachId: 'coach-1', row: 1, col: 'B' }, + { id: 'seat-3', coachId: 'coach-1', row: 1, col: 'C' }, + { id: 'seat-4', coachId: 'coach-1', row: 2, col: 'A' }, + ]; + + mockPrisma.seat.findMany.mockResolvedValue(mockSeats); + + const result = await service.autoAssignSeats('trip-1', 2, 'ECONOMY_REGULAR'); + + expect(result).toHaveLength(2); + expect(result).toEqual(['seat-1', 'seat-2']); + }); + + it('should throw error if not enough seats available', async () => { + mockPrisma.seat.findMany.mockResolvedValue([ + { id: 'seat-1', coachId: 'coach-1', row: 1, col: 'A' }, + ]); + + await expect( + service.autoAssignSeats('trip-1', 3, 'ECONOMY_REGULAR'), + ).rejects.toThrow(ConflictException); + }); + + it('should respect eligibility filter', async () => { + const mockSeats = [ + { id: 'seat-1', coachId: 'coach-1', row: 1, col: 'A', eligibility: 'ACCESSIBLE' }, + { id: 'seat-2', coachId: 'coach-1', row: 1, col: 'B', eligibility: 'ACCESSIBLE' }, + ]; + + mockPrisma.seat.findMany.mockResolvedValue(mockSeats); + + const result = await service.autoAssignSeats('trip-1', 2, 'ECONOMY_REGULAR', 'ACCESSIBLE'); + + expect(result).toHaveLength(2); + }); + + it('should assign single seat', async () => { + const mockSeats = [ + { id: 'seat-1', coachId: 'coach-1', row: 1, col: 'A' }, + ]; + + mockPrisma.seat.findMany.mockResolvedValue(mockSeats); + + const result = await service.autoAssignSeats('trip-1', 1, 'ECONOMY_REGULAR'); + + expect(result).toEqual(['seat-1']); + }); + }); +}); diff --git a/apps/edr-passenger-api/src/modules/seats/seats.service.ts b/apps/edr-passenger-api/src/modules/seats/seats.service.ts index 90234b6f2..866d30cc3 100644 --- a/apps/edr-passenger-api/src/modules/seats/seats.service.ts +++ b/apps/edr-passenger-api/src/modules/seats/seats.service.ts @@ -42,6 +42,128 @@ export class SeatsService { async confirmSeats(seatIds: string[]) { await this.prisma.seat.updateMany({ where: { id: { in: seatIds } }, data: { status: 'BOOKED', heldUntil: null } }); } async releaseSeats(seatIds: string[]) { await this.prisma.seat.updateMany({ where: { id: { in: seatIds } }, data: { status: 'AVAILABLE', heldUntil: null } }); } + async autoAssignSeats(tripId: string, count: number, serviceClass: string, eligibility?: string): Promise { + const seats = await this.prisma.seat.findMany({ + where: { + coach: { tripId, serviceClass: serviceClass as any }, + status: 'AVAILABLE', + ...(eligibility ? { eligibility } : {}), + }, + orderBy: [{ coach: { label: 'asc' } }, { row: 'asc' }, { col: 'asc' }], + }); + + if (seats.length < count) { + throw new ConflictException(`Only ${seats.length} seats available, requested ${count}`); + } + + const assigned = this.findContiguousSeats(seats, count); + return assigned.map((s) => s.id); + } + + private findContiguousSeats(seats: any[], count: number): any[] { + if (count === 1) return [seats[0]]; + + const grouped = new Map(); + for (const seat of seats) { + const key = `${seat.coachId}-${seat.row}`; + if (!grouped.has(key)) grouped.set(key, []); + grouped.get(key)!.push(seat); + } + + for (const rowSeats of grouped.values()) { + if (rowSeats.length >= count) { + return rowSeats.slice(0, count); + } + } + + return seats.slice(0, count); + } + + async exportSeatsCSV(tripId: string): Promise { + const coaches = await this.prisma.coach.findMany({ + where: { tripId }, + include: { seats: { orderBy: [{ row: 'asc' }, { col: 'asc' }] } }, + }); + + const rows = ['coachId,coachLabel,row,col,label,kind,status,premiumFeeMinor,eligibility']; + for (const coach of coaches) { + for (const seat of coach.seats) { + rows.push( + `${coach.id},${coach.label},${seat.row},${seat.col},${seat.label},${seat.kind},${seat.status},${seat.premiumFeeMinor},${seat.eligibility || ''}`, + ); + } + } + return rows.join('\n'); + } + + async previewSeatsCSV(csvContent: string): Promise<{ valid: number; invalid: number; errors: string[] }> { + const lines = csvContent.trim().split('\n').slice(1); + const errors: string[] = []; + let valid = 0; + let invalid = 0; + + for (let i = 0; i < lines.length; i++) { + const parts = lines[i].split(','); + if (parts.length < 8) { + errors.push(`Line ${i + 2}: Invalid format`); + invalid++; + continue; + } + const [coachId, coachLabel, row, col, label, kind, status, premiumFeeMinor] = parts; + if (!coachId || !row || !col || !label) { + errors.push(`Line ${i + 2}: Missing required fields`); + invalid++; + continue; + } + valid++; + } + + return { valid, invalid, errors: errors.slice(0, 10) }; + } + + async importSeatsCSV(tripId: string, csvContent: string, commit: boolean): Promise<{ imported: number; errors: string[] }> { + const lines = csvContent.trim().split('\n').slice(1); + const errors: string[] = []; + let imported = 0; + + if (!commit) { + return { imported: 0, errors: ['Preview mode - use commit=true to apply changes'] }; + } + + for (let i = 0; i < lines.length; i++) { + try { + const parts = lines[i].split(','); + const [coachId, coachLabel, row, col, label, kind, status, premiumFeeMinor, eligibility] = parts; + + await this.prisma.seat.upsert({ + where: { coachId_row_col: { coachId, row: parseInt(row), col } }, + update: { + label, + kind: kind as any, + status: status as any, + premiumFeeMinor: parseInt(premiumFeeMinor) || 0, + eligibility: eligibility || null, + }, + create: { + coachId, + row: parseInt(row), + col, + label, + kind: kind as any, + status: status as any, + premiumFeeMinor: parseInt(premiumFeeMinor) || 0, + eligibility: eligibility || null, + }, + }); + imported++; + } catch (err) { + errors.push(`Line ${i + 2}: ${err instanceof Error ? err.message : String(err)}`); + } + } + + return { imported, errors: errors.slice(0, 10) }; + } + @Cron(CronExpression.EVERY_MINUTE) async expireHolds() { const expired = await this.prisma.seatHold.findMany({ where: { expiresAt: { lt: new Date() } } }); diff --git a/apps/edr-passenger-api/src/modules/tickets/tickets.controller.ts b/apps/edr-passenger-api/src/modules/tickets/tickets.controller.ts index 407af7234..c4f6a4d38 100644 --- a/apps/edr-passenger-api/src/modules/tickets/tickets.controller.ts +++ b/apps/edr-passenger-api/src/modules/tickets/tickets.controller.ts @@ -1,4 +1,4 @@ -import { Body, Controller, Get, Param, Post, UseGuards } from '@nestjs/common'; +import { Body, Controller, Get, Param, Post, Query, UseGuards } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger'; import { TicketsService } from './tickets.service'; import { JwtGuard } from '../../common/jwt.guard'; @@ -9,6 +9,38 @@ import { JwtGuard } from '../../common/jwt.guard'; @ApiBearerAuth('JWT-auth') export class TicketsController { constructor(private service: TicketsService) {} - @Get(':bookingRef') @ApiOperation({ summary: 'Get ticket by booking reference' }) getByRef(@Param('bookingRef') ref: string) { return this.service.getByRef(ref); } - @Post(':bookingRef/validate') @ApiOperation({ summary: 'Validate ticket at gate (staff)' }) validate(@Param('bookingRef') ref: string, @Body('validatorId') validatorId: string) { return this.service.validate(ref, validatorId); } + + @Get(':bookingRef') + @ApiOperation({ summary: 'Get ticket by booking reference' }) + getByRef(@Param('bookingRef') ref: string) { + return this.service.getByRef(ref); + } + + @Post(':bookingRef/validate') + @ApiOperation({ summary: 'Validate ticket at gate (staff)' }) + validate( + @Param('bookingRef') ref: string, + @Body('validatorId') validatorId: string, + @Body('gateId') gateId?: string + ) { + return this.service.validate(ref, validatorId, gateId); + } + + @Get(':ticketId/validation-logs') + @ApiOperation({ summary: 'Get validation logs for ticket' }) + getValidationLogs(@Param('ticketId') ticketId: string) { + return this.service.getValidationLogs(ticketId); + } + + @Get('offline/export') + @ApiOperation({ summary: 'Export tickets for offline validation' }) + exportOfflineData(@Query('tripId') tripId: string) { + return this.service.exportOfflineData(tripId); + } + + @Post('validate/offline') + @ApiOperation({ summary: 'Batch import offline validations' }) + validateOfflineBatch(@Body() body: { validations: any[] }) { + return this.service.validateOfflineBatch(body.validations); + } } diff --git a/apps/edr-passenger-api/src/modules/tickets/tickets.service.spec.ts b/apps/edr-passenger-api/src/modules/tickets/tickets.service.spec.ts new file mode 100644 index 000000000..7f6ad7f52 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/tickets/tickets.service.spec.ts @@ -0,0 +1,126 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { TicketsService } from './tickets.service'; +import { PrismaService } from '../../common/prisma.service'; + +describe('TicketsService - Offline Validation', () => { + let service: TicketsService; + let prisma: PrismaService; + + const mockPrisma = { + booking: { + findMany: jest.fn(), + findUnique: jest.fn(), + }, + ticket: { + findUnique: jest.fn(), + update: jest.fn(), + }, + gateValidationLog: { + create: jest.fn(), + }, + }; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + TicketsService, + { provide: PrismaService, useValue: mockPrisma }, + ], + }).compile(); + + service = module.get(TicketsService); + prisma = module.get(PrismaService); + jest.clearAllMocks(); + }); + + describe('exportOfflineData', () => { + it('should export tickets for offline validation', async () => { + const mockBookings = [ + { + bookingRef: 'ABC123', + ticket: { id: 'ticket-1', qrPayload: 'qr-data', validatedAt: null }, + seats: [{ passengerName: 'John Doe', seat: { label: '1A', coach: { label: 'A' } } }], + status: 'CONFIRMED', + }, + ]; + + mockPrisma.booking.findMany.mockResolvedValue(mockBookings); + + const result = await service.exportOfflineData('trip-1'); + + expect(result).toHaveLength(1); + expect(result[0].bookingRef).toBe('ABC123'); + expect(result[0].passengerName).toBe('John Doe'); + }); + }); + + describe('validateOfflineBatch', () => { + it('should process batch validations successfully', async () => { + const validations = [ + { + bookingRef: 'ABC123', + validatorId: 'validator-1', + gateId: 'gate-1', + validatedAt: new Date().toISOString(), + }, + ]; + + mockPrisma.booking.findUnique.mockResolvedValue({ id: 'booking-1' }); + mockPrisma.ticket.findUnique.mockResolvedValue({ id: 'ticket-1', validatedAt: null }); + mockPrisma.ticket.update.mockResolvedValue({}); + mockPrisma.gateValidationLog.create.mockResolvedValue({}); + + const result = await service.validateOfflineBatch(validations); + + expect(result.success).toBe(1); + expect(result.failed).toBe(0); + expect(result.duplicate).toBe(0); + }); + + it('should detect duplicate validations', async () => { + const validations = [ + { + bookingRef: 'ABC123', + validatorId: 'validator-1', + validatedAt: new Date().toISOString(), + }, + { + bookingRef: 'ABC123', + validatorId: 'validator-1', + validatedAt: new Date().toISOString(), + }, + ]; + + mockPrisma.booking.findUnique.mockResolvedValue({ id: 'booking-1' }); + mockPrisma.ticket.findUnique.mockResolvedValue({ id: 'ticket-1', validatedAt: null }); + mockPrisma.ticket.update.mockResolvedValue({}); + mockPrisma.gateValidationLog.create.mockResolvedValue({}); + + const result = await service.validateOfflineBatch(validations); + + expect(result.success).toBe(1); + expect(result.duplicate).toBe(1); + }); + + it('should handle already validated tickets', async () => { + const validations = [ + { + bookingRef: 'ABC123', + validatorId: 'validator-1', + validatedAt: new Date().toISOString(), + }, + ]; + + mockPrisma.booking.findUnique.mockResolvedValue({ id: 'booking-1' }); + mockPrisma.ticket.findUnique.mockResolvedValue({ + id: 'ticket-1', + validatedAt: new Date(), + }); + + const result = await service.validateOfflineBatch(validations); + + expect(result.duplicate).toBe(1); + expect(result.success).toBe(0); + }); + }); +}); diff --git a/apps/edr-passenger-api/src/modules/tickets/tickets.service.ts b/apps/edr-passenger-api/src/modules/tickets/tickets.service.ts index 1c9e05830..e2e2ff1f9 100644 --- a/apps/edr-passenger-api/src/modules/tickets/tickets.service.ts +++ b/apps/edr-passenger-api/src/modules/tickets/tickets.service.ts @@ -2,6 +2,13 @@ import { Injectable, NotFoundException, BadRequestException } from '@nestjs/comm import { PrismaService } from '../../common/prisma.service'; import * as QRCode from 'qrcode'; +interface OfflineValidation { + bookingRef: string; + validatorId: string; + gateId?: string; + validatedAt: string; +} + @Injectable() export class TicketsService { constructor(private prisma: PrismaService) {} @@ -13,7 +20,12 @@ export class TicketsService { }); if (!booking) throw new NotFoundException('Booking not found'); const qrPayload = await QRCode.toDataURL(`edr:tkt:${booking.id}:${booking.bookingRef}`); - return this.prisma.ticket.upsert({ where: { bookingId }, update: { qrPayload }, create: { bookingId, bookingRef: booking.bookingRef, qrPayload } }); + const barcodePayload = `EDR${booking.bookingRef}${booking.id.substring(0, 8).toUpperCase()}`; + return this.prisma.ticket.upsert({ + where: { bookingId }, + update: { qrPayload, barcodePayload }, + create: { bookingId, bookingRef: booking.bookingRef, qrPayload, barcodePayload } + }); } async getByRef(bookingRef: string) { @@ -29,15 +41,110 @@ export class TicketsService { departureAt: booking.trip.departureAt, trainName: booking.trip.service.name, coachLabel: seat?.seat.coach.label, seatLabel: seat?.seat.label, passengerName: seat?.passengerName, priceMinor: booking.totalMinor, currency: booking.currency, qrPayload: booking.ticket.qrPayload, + barcodePayload: booking.ticket.barcodePayload }; } - async validate(bookingRef: string, validatorId: string) { + async validate(bookingRef: string, validatorId: string, gateId?: string) { const booking = await this.prisma.booking.findUnique({ where: { bookingRef } }); if (!booking) throw new NotFoundException('Booking not found'); const ticket = await this.prisma.ticket.findUnique({ where: { bookingId: booking.id } }); if (!ticket) throw new NotFoundException('Ticket not found'); - if (ticket.validatedAt) throw new BadRequestException('Ticket already validated'); - return this.prisma.ticket.update({ where: { id: ticket.id }, data: { validatedAt: new Date(), validatorId } }); + if (ticket.validatedAt) { + await this.prisma.gateValidationLog.create({ + data: { ticketId: ticket.id, validatorId, gateId, status: 'REJECTED', reason: 'ALREADY_VALIDATED' } + }); + throw new BadRequestException('Ticket already validated'); + } + await this.prisma.ticket.update({ where: { id: ticket.id }, data: { validatedAt: new Date(), validatorId } }); + await this.prisma.gateValidationLog.create({ + data: { ticketId: ticket.id, validatorId, gateId, status: 'APPROVED' } + }); + return { validated: true, ticketId: ticket.id, validatedAt: new Date() }; + } + + async getValidationLogs(ticketId: string) { + return this.prisma.gateValidationLog.findMany({ + where: { ticketId }, + orderBy: { validatedAt: 'desc' } + }); + } + + async exportOfflineData(tripId: string) { + const bookings = await this.prisma.booking.findMany({ + where: { tripId, status: 'CONFIRMED' }, + include: { + ticket: true, + seats: { include: { seat: { include: { coach: true } } } }, + passenger: { include: { user: true } }, + }, + }); + + return bookings.map((b) => ({ + bookingRef: b.bookingRef, + ticketId: b.ticket?.id, + passengerName: b.seats[0]?.passengerName, + seatLabel: b.seats[0]?.seat.label, + coachLabel: b.seats[0]?.seat.coach.label, + qrPayload: b.ticket?.qrPayload, + status: b.status, + validatedAt: b.ticket?.validatedAt, + })); + } + + async validateOfflineBatch(validations: OfflineValidation[]) { + const results = { success: 0, failed: 0, duplicate: 0, errors: [] as string[] }; + const processedRefs = new Set(); + + for (const v of validations) { + if (processedRefs.has(v.bookingRef)) { + results.duplicate++; + continue; + } + processedRefs.add(v.bookingRef); + + try { + const booking = await this.prisma.booking.findUnique({ where: { bookingRef: v.bookingRef } }); + if (!booking) { + results.failed++; + results.errors.push(`Booking ${v.bookingRef} not found`); + continue; + } + + const ticket = await this.prisma.ticket.findUnique({ where: { bookingId: booking.id } }); + if (!ticket) { + results.failed++; + results.errors.push(`Ticket for ${v.bookingRef} not found`); + continue; + } + + if (ticket.validatedAt) { + results.duplicate++; + continue; + } + + await this.prisma.ticket.update({ + where: { id: ticket.id }, + data: { validatedAt: new Date(v.validatedAt), validatorId: v.validatorId }, + }); + + await this.prisma.gateValidationLog.create({ + data: { + ticketId: ticket.id, + validatorId: v.validatorId, + gateId: v.gateId, + status: 'APPROVED', + validatedAt: new Date(v.validatedAt), + }, + }); + + results.success++; + } catch (err) { + results.failed++; + results.errors.push(`Error processing ${v.bookingRef}: ${err instanceof Error ? err.message : String(err)}`); + } + } + + return results; } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bf0d892f0..d2519df19 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -36,251 +36,11 @@ importers: specifier: ^5.5.4 version: 5.9.3 - apps/edr-freight-api: - dependencies: - '@edr/api-common': - specifier: workspace:* - version: link:../../packages/api-common - '@edr/types': - specifier: workspace:* - version: link:../../packages/types - '@nestjs/common': - specifier: ^11.0.0 - version: 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/config': - specifier: ^4.0.0 - version: 4.0.4(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2) - '@nestjs/core': - specifier: ^11.0.0 - version: 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.19)(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/microservices': - specifier: ^11.0.0 - version: 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/platform-express': - specifier: ^11.0.0 - version: 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19) - '@nestjs/swagger': - specifier: ^11.4.2 - version: 11.4.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) - '@nestjs/typeorm': - specifier: ^11.0.1 - version: 11.0.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))) - '@tria-plc/api-common': - specifier: ^0.1.0 - version: 0.1.4(dlk6rffkpcjlebt3tne6hjqwx4) - '@tria-plc/iamapi-common': - specifier: ^0.1.0 - version: 0.1.6(nhzmwbpvzw5m5dv4mcbu7ilapi) - class-transformer: - specifier: ^0.5.1 - version: 0.5.1 - class-validator: - specifier: ^0.14.1 - version: 0.14.4 - pg: - specifier: ^8.13.0 - version: 8.20.0 - reflect-metadata: - specifier: ^0.2.2 - version: 0.2.2 - rxjs: - specifier: ^7.8.1 - version: 7.8.2 - typeorm: - specifier: ^0.3.20 - version: 0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) - devDependencies: - '@edr/eslint-config': - specifier: workspace:* - version: link:../../packages/config/eslint-config - '@edr/tsconfig': - specifier: workspace:* - version: link:../../packages/config/tsconfig - '@nestjs/cli': - specifier: ^11.0.0 - version: 11.0.21(@types/node@20.19.41)(prettier@3.8.3) - '@nestjs/schematics': - specifier: ^11.0.0 - version: 11.1.0(chokidar@4.0.3)(prettier@3.8.3)(typescript@5.9.3) - '@nestjs/testing': - specifier: ^11.0.0 - version: 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(@nestjs/microservices@11.1.19)(@nestjs/platform-express@11.1.19) - '@types/express': - specifier: ^5.0.0 - version: 5.0.6 - '@types/jest': - specifier: ^29.5.13 - version: 29.5.14 - '@types/node': - specifier: ^20.14.0 - version: 20.19.41 - '@types/supertest': - specifier: ^6.0.2 - version: 6.0.3 - jest: - specifier: ^29.7.0 - version: 29.7.0(@types/node@20.19.41)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) - supertest: - specifier: ^7.0.0 - version: 7.2.2 - ts-jest: - specifier: ^29.2.5 - version: 29.4.9(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.41)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)))(typescript@5.9.3) - ts-loader: - specifier: ^9.5.1 - version: 9.5.7(typescript@5.9.3)(webpack@5.106.0) - ts-node: - specifier: ^10.9.2 - version: 10.9.2(@types/node@20.19.41)(typescript@5.9.3) - tsconfig-paths: - specifier: ^4.2.0 - version: 4.2.0 - typescript: - specifier: ^5.5.4 - version: 5.9.3 - - apps/edr-freight-web/backoffice: - dependencies: - '@edr/types': - specifier: workspace:* - version: link:../../../packages/types - '@edr/ui-common': - specifier: workspace:* - version: link:../../../packages/ui-common - '@tanstack/react-query': - specifier: ^5.59.0 - version: 5.100.10(react@18.3.1) - '@tria-plc/iamui-common': - specifier: 1.0.3 - version: 1.0.3(iv2eyyfavqphryq7oznx6tfwre) - axios: - specifier: ^1.7.7 - version: 1.16.0 - clsx: - specifier: ^2.1.1 - version: 2.1.1 - react: - specifier: 18.3.1 - version: 18.3.1 - react-dom: - specifier: 18.3.1 - version: 18.3.1(react@18.3.1) - react-router-dom: - specifier: ^6.27.0 - version: 6.30.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - zustand: - specifier: ^5.0.0 - version: 5.0.13(@types/react@18.3.28)(immer@11.1.8)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) - devDependencies: - '@edr/eslint-config': - specifier: workspace:* - version: link:../../../packages/config/eslint-config - '@edr/tsconfig': - specifier: workspace:* - version: link:../../../packages/config/tsconfig - '@types/react': - specifier: ^18.3.11 - version: 18.3.28 - '@types/react-dom': - specifier: ^18.3.0 - version: 18.3.7(@types/react@18.3.28) - '@vitejs/plugin-react': - specifier: ^4.3.2 - version: 4.7.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1)) - autoprefixer: - specifier: ^10.4.20 - version: 10.5.0(postcss@8.5.14) - jsdom: - specifier: ^25.0.1 - version: 25.0.1(canvas@2.11.2) - postcss: - specifier: ^8.4.47 - version: 8.5.14 - tailwindcss: - specifier: ^3.4.13 - version: 3.4.19(yaml@2.9.0) - typescript: - specifier: ^5.5.4 - version: 5.9.3 - vite: - specifier: ^5.4.8 - version: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1) - vitest: - specifier: ^2.1.2 - version: 2.1.9(@types/node@24.12.4)(jsdom@25.0.1(canvas@2.11.2))(lightningcss@1.32.0)(terser@5.47.1) - - apps/edr-freight-web/portal: - dependencies: - '@edr/types': - specifier: workspace:* - version: link:../../../packages/types - '@edr/ui-common': - specifier: workspace:* - version: link:../../../packages/ui-common - '@tanstack/react-query': - specifier: ^5.59.0 - version: 5.100.10(react@18.3.1) - '@tria-plc/iamui-common': - specifier: 1.0.3 - version: 1.0.3(iv2eyyfavqphryq7oznx6tfwre) - axios: - specifier: ^1.7.7 - version: 1.16.0 - clsx: - specifier: ^2.1.1 - version: 2.1.1 - react: - specifier: 18.3.1 - version: 18.3.1 - react-dom: - specifier: 18.3.1 - version: 18.3.1(react@18.3.1) - react-router-dom: - specifier: ^6.27.0 - version: 6.30.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - zustand: - specifier: ^5.0.0 - version: 5.0.13(@types/react@18.3.28)(immer@11.1.8)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) - devDependencies: - '@edr/eslint-config': - specifier: workspace:* - version: link:../../../packages/config/eslint-config - '@edr/tsconfig': - specifier: workspace:* - version: link:../../../packages/config/tsconfig - '@types/react': - specifier: ^18.3.11 - version: 18.3.28 - '@types/react-dom': - specifier: ^18.3.0 - version: 18.3.7(@types/react@18.3.28) - '@vitejs/plugin-react': - specifier: ^4.3.2 - version: 4.7.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1)) - autoprefixer: - specifier: ^10.4.20 - version: 10.5.0(postcss@8.5.14) - jsdom: - specifier: ^25.0.1 - version: 25.0.1(canvas@2.11.2) - postcss: - specifier: ^8.4.47 - version: 8.5.14 - tailwindcss: - specifier: ^3.4.13 - version: 3.4.19(yaml@2.9.0) - typescript: - specifier: ^5.5.4 - version: 5.9.3 - vite: - specifier: ^5.4.8 - version: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1) - vitest: - specifier: ^2.1.2 - version: 2.1.9(@types/node@24.12.4)(jsdom@25.0.1(canvas@2.11.2))(lightningcss@1.32.0)(terser@5.47.1) - apps/edr-passenger-api: dependencies: + '@nestjs/axios': + specifier: ^4.0.1 + version: 4.0.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.16.0)(rxjs@7.8.2) '@nestjs/common': specifier: ^11.0.0 version: 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -308,12 +68,12 @@ importers: '@nestjs/swagger': specifier: ^7.4.0 version: 7.4.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) - '@prisma/client': - specifier: ^5.8.0 - version: 5.22.0(prisma@5.22.0) '@sendgrid/mail': specifier: ^8.1.0 version: 8.1.6 + axios: + specifier: ^1.7.7 + version: 1.16.0 bcrypt: specifier: ^5.1.1 version: 5.1.1 @@ -360,6 +120,9 @@ importers: '@nestjs/testing': specifier: ^11.1.19 version: 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(@nestjs/microservices@11.1.19)(@nestjs/platform-express@11.1.19) + '@prisma/client': + specifier: ^6.19.3 + version: 6.19.3(prisma@6.19.3(typescript@5.9.3))(typescript@5.9.3) '@types/bcrypt': specifier: ^5.0.2 version: 5.0.2 @@ -382,8 +145,8 @@ importers: specifier: ^29.7.0 version: 29.7.0(@types/node@20.19.41)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) prisma: - specifier: ^5.8.0 - version: 5.22.0 + specifier: ^6.19.3 + version: 6.19.3(typescript@5.9.3) supertest: specifier: ^7.0.0 version: 7.2.2 @@ -560,7 +323,7 @@ importers: version: 7.8.2 typeorm: specifier: ^0.3.20 - version: 0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) + version: 0.3.29(babel-plugin-macros@3.1.0)(mysql2@3.15.3)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) typescript: specifier: ^5.5.4 version: 5.9.3 @@ -663,12 +426,6 @@ packages: resolution: {integrity: sha512-lnw+ZM1Io+cJAkReC0NPDjqObL8NtKzKIkdgEEKC8CUmkhurYhedbicN8Y8NYHgG1uLd2GozW3+/QqPRZaN+Lw==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} - '@ark-ui/react@5.36.2': - resolution: {integrity: sha512-2lrZ7+Qtlj7hGx4qU2jZkE892JNrkULg/fUxqUuqmQfv9UGAXhdcw1Hr3N+zBgMDVz3aqip0Qa4v0Mox09MMvg==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - '@asamuzakjp/css-color@3.2.0': resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} @@ -856,13 +613,6 @@ packages: '@borewit/text-codec@0.2.2': resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==} - '@chakra-ui/react@3.35.0': - resolution: {integrity: sha512-qzfRNLwxKjxx2IXjBj6uz1nYI+pKsq6uwHxO619+hx1OzNNuwLIjEHJxnDfBzoynO7sPCBlubMwFWb1e1PrXzw==} - peerDependencies: - '@emotion/react': '>=11' - react: 18.3.1 - react-dom: 18.3.1 - '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} @@ -968,63 +718,6 @@ packages: resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} engines: {node: '>=18'} - '@date-fns/tz@1.4.1': - resolution: {integrity: sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==} - - '@emotion/babel-plugin@11.13.5': - resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} - - '@emotion/cache@11.14.0': - resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==} - - '@emotion/hash@0.9.2': - resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} - - '@emotion/is-prop-valid@1.4.0': - resolution: {integrity: sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==} - - '@emotion/memoize@0.9.0': - resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} - - '@emotion/react@11.14.0': - resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@emotion/serialize@1.3.3': - resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==} - - '@emotion/sheet@1.4.0': - resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==} - - '@emotion/styled@11.14.1': - resolution: {integrity: sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==} - peerDependencies: - '@emotion/react': ^11.0.0-rc.0 - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@emotion/unitless@0.10.0': - resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} - - '@emotion/use-insertion-effect-with-fallbacks@1.2.0': - resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==} - peerDependencies: - react: 18.3.1 - - '@emotion/utils@1.4.2': - resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==} - - '@emotion/weak-memoize@0.4.0': - resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} - '@esbuild/aix-ppc64@0.21.5': resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} engines: {node: '>=12'} @@ -1181,48 +874,6 @@ packages: resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@faker-js/faker@10.4.0': - resolution: {integrity: sha512-sDBWI3yLy8EcDzgobvJTWq1MJYzAkQdpjXuPukga9wXonhpMRvd1Izuo2Qgwey2OiEoRIBr35RMU9HJRoOHzpw==} - engines: {node: ^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0, npm: '>=10'} - - '@fast-csv/format@4.3.5': - resolution: {integrity: sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==} - - '@fast-csv/parse@4.3.6': - resolution: {integrity: sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==} - - '@floating-ui/core@1.7.5': - resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} - - '@floating-ui/dom@1.7.6': - resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} - - '@floating-ui/react-dom@2.1.8': - resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@floating-ui/react@0.27.19': - resolution: {integrity: sha512-31B8h5mm8YxotlE7/AU/PhNAl8eWxAmjL/v2QOxroDNkTFLk3Uu82u63N3b6TXa4EGJeeZLVcd/9AlNlVqzeog==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@floating-ui/utils@0.2.11': - resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} - - '@gilbarbara/deep-equal@0.1.2': - resolution: {integrity: sha512-jk+qzItoEb0D0xSSmrKDDzf9sheQj/BAPxlgNxgmOaA3mxpUa6ndJLYGZKsJnIVEQSD8zcTbyILz7I0HcnBCRA==} - - '@gilbarbara/deep-equal@0.3.1': - resolution: {integrity: sha512-I7xWjLs2YSVMc5gGx1Z3ZG1lgFpITPndpi8Ku55GeEIKpACCPQNS/OTqQbxgTCfq0Ncvcc+CrFov96itVh6Qvw==} - - '@hookform/resolvers@5.2.2': - resolution: {integrity: sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==} - peerDependencies: - react-hook-form: ^7.55.0 - '@humanwhocodes/config-array@0.13.0': resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} engines: {node: '>=10.10.0'} @@ -1379,12 +1030,6 @@ packages: '@types/node': optional: true - '@internationalized/date@3.12.0': - resolution: {integrity: sha512-/PyIMzK29jtXaGU23qTvNZxvBXRtKbNnGDFD+PY6CZw/Y8Ex8pFUzkuCJCG9aOqmShjqhS9mPqP6Dk5onQY8rQ==} - - '@internationalized/number@3.6.5': - resolution: {integrity: sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g==} - '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -1485,39 +1130,10 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@leichtgewicht/ip-codec@2.0.5': - resolution: {integrity: sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==} - - '@lottiefiles/react-lottie-player@3.6.0': - resolution: {integrity: sha512-WK5TriLJT93VF3w4IjSVyveiedraZCnDhKzCPhpbeLgQeMi6zufxa3dXNc4HmAFRXq+LULPAy+Idv1rAfkReMA==} - peerDependencies: - react: 18.3.1 - '@lukeed/csprng@1.1.0': resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} engines: {node: '>=8'} - '@mantine/core@8.3.18': - resolution: {integrity: sha512-9tph1lTVogKPjTx02eUxDUOdXacPzK62UuSqb4TdGliI54/Xgxftq0Dfqu6XuhCxn9J5MDJaNiLDvL/1KRkYqA==} - peerDependencies: - '@mantine/hooks': 8.3.18 - react: 18.3.1 - react-dom: 18.3.1 - - '@mantine/dates@8.3.18': - resolution: {integrity: sha512-FHx5teJOhupI0gO2o5evtVYQEdqOjayOkLRhEQfB5Nc5DvcysfPfmNILGkc1Nrp9ZQeQWKLT9qr+CkcCXwHOaw==} - peerDependencies: - '@mantine/core': 8.3.18 - '@mantine/hooks': 8.3.18 - dayjs: '>=1.0.0' - react: 18.3.1 - react-dom: 18.3.1 - - '@mantine/hooks@8.3.18': - resolution: {integrity: sha512-QoWr9+S8gg5050TQ06aTSxtlpGjYOpIllRbjYYXlRvZeTsUqiTbVfvQROLexu4rEaK+yy9Wwriwl9PMRgbLqPw==} - peerDependencies: - react: 18.3.1 - '@mapbox/node-pre-gyp@1.0.11': resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==} hasBin: true @@ -1525,156 +1141,6 @@ packages: '@microsoft/tsdoc@0.15.1': resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==} - '@microsoft/tsdoc@0.16.0': - resolution: {integrity: sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==} - - '@mui/base@5.0.0-beta.70': - resolution: {integrity: sha512-Tb/BIhJzb0pa5zv/wu7OdokY9ZKEDqcu1BDFnohyvGCoHuSXbEr90rPq1qeNW3XvTBIbNWHEF7gqge+xpUo6tQ==} - engines: {node: '>=14.0.0'} - deprecated: This package has been replaced by @base-ui/react - peerDependencies: - '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@mui/core-downloads-tracker@5.18.0': - resolution: {integrity: sha512-jbhwoQ1AY200PSSOrNXmrFCaSDSJWP7qk6urkTmIirvRXDROkqe+QwcLlUiw/PrREwsIF/vm3/dAXvjlMHF0RA==} - - '@mui/icons-material@5.18.0': - resolution: {integrity: sha512-1s0vEZj5XFXDMmz3Arl/R7IncFqJ+WQ95LDp1roHWGDE2oCO3IS4/hmiOv1/8SD9r6B7tv9GLiqVZYHo+6PkTg==} - engines: {node: '>=12.0.0'} - peerDependencies: - '@mui/material': ^5.0.0 - '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@mui/material@5.18.0': - resolution: {integrity: sha512-bbH/HaJZpFtXGvWg3TsBWG4eyt3gah3E7nCNU8GLyRjVoWcA91Vm/T+sjHfUcwgJSw9iLtucfHBoq+qW/T30aA==} - engines: {node: '>=12.0.0'} - peerDependencies: - '@emotion/react': ^11.5.0 - '@emotion/styled': ^11.3.0 - '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@emotion/react': - optional: true - '@emotion/styled': - optional: true - '@types/react': - optional: true - - '@mui/private-theming@5.17.1': - resolution: {integrity: sha512-XMxU0NTYcKqdsG8LRmSoxERPXwMbp16sIXPcLVgLGII/bVNagX0xaheWAwFv8+zDK7tI3ajllkuD3GZZE++ICQ==} - engines: {node: '>=12.0.0'} - peerDependencies: - '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@mui/styled-engine@5.18.0': - resolution: {integrity: sha512-BN/vKV/O6uaQh2z5rXV+MBlVrEkwoS/TK75rFQ2mjxA7+NBo8qtTAOA4UaM0XeJfn7kh2wZ+xQw2HAx0u+TiBg==} - engines: {node: '>=12.0.0'} - peerDependencies: - '@emotion/react': ^11.4.1 - '@emotion/styled': ^11.3.0 - react: 18.3.1 - peerDependenciesMeta: - '@emotion/react': - optional: true - '@emotion/styled': - optional: true - - '@mui/system@5.18.0': - resolution: {integrity: sha512-ojZGVcRWqWhu557cdO3pWHloIGJdzVtxs3rk0F9L+x55LsUjcMUVkEhiF7E4TMxZoF9MmIHGGs0ZX3FDLAf0Xw==} - engines: {node: '>=12.0.0'} - peerDependencies: - '@emotion/react': ^11.5.0 - '@emotion/styled': ^11.3.0 - '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 - react: 18.3.1 - peerDependenciesMeta: - '@emotion/react': - optional: true - '@emotion/styled': - optional: true - '@types/react': - optional: true - - '@mui/types@7.2.24': - resolution: {integrity: sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==} - peerDependencies: - '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - '@mui/utils@5.17.1': - resolution: {integrity: sha512-jEZ8FTqInt2WzxDV8bhImWBqeQRD99c/id/fq83H0ER9tFl+sfZlaAoCdznGvbSQQ9ividMxqSV2c7cC1vBcQg==} - engines: {node: '>=12.0.0'} - peerDependencies: - '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@mui/utils@6.4.9': - resolution: {integrity: sha512-Y12Q9hbK9g+ZY0T3Rxrx9m2m10gaphDuUMgWxyV5kNJevVxXYCLclYUCC9vXaIk1/NdNDTcW2Yfr2OGvNFNmHg==} - engines: {node: '>=14.0.0'} - peerDependencies: - '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@mui/x-date-pickers@6.20.2': - resolution: {integrity: sha512-x1jLg8R+WhvkmUETRfX2wC+xJreMii78EXKLl6r3G+ggcAZlPyt0myID1Amf6hvJb9CtR7CgUo8BwR+1Vx9Ggw==} - engines: {node: '>=14.0.0'} - peerDependencies: - '@emotion/react': ^11.9.0 - '@emotion/styled': ^11.8.1 - '@mui/material': ^5.8.6 - '@mui/system': ^5.8.0 - date-fns: ^3.6.0 - date-fns-jalali: ^2.13.0-0 - dayjs: ^1.10.7 - luxon: ^3.0.2 - moment: ^2.29.4 - moment-hijri: ^2.1.2 - moment-jalaali: ^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0 - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@emotion/react': - optional: true - '@emotion/styled': - optional: true - date-fns: - optional: true - date-fns-jalali: - optional: true - dayjs: - optional: true - luxon: - optional: true - moment: - optional: true - moment-hijri: - optional: true - moment-jalaali: - optional: true - '@nestjs/axios@4.0.1': resolution: {integrity: sha512-68pFJgu+/AZbWkGu65Z3r55bTsCPlgyKaV4BSG8yUAD72q1PPuyVRgUwFv6BxdnibTUHlyxm06FmYWNC+bjN7A==} peerDependencies: @@ -1743,11 +1209,6 @@ packages: peerDependencies: '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 - '@nestjs/jwt@11.0.2': - resolution: {integrity: sha512-rK8aE/3/Ma45gAWfCksAXUNbOoSOUudU0Kn3rT39htPF7wsYXtKfjALKeKKJbFrIWbLjsbqfXX5bIJNvgBugGA==} - peerDependencies: - '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 - '@nestjs/mapped-types@2.0.5': resolution: {integrity: sha512-bSJv4pd6EY99NX9CjBIyn4TVDoSit82DUZlL4I3bqNfy5Gt+gXTa86i3I/i0iIV9P4hntcGM5GyO+FhZAhxtyg==} peerDependencies: @@ -1761,19 +1222,6 @@ packages: class-validator: optional: true - '@nestjs/mapped-types@2.1.1': - resolution: {integrity: sha512-SCCoMEJ6jdeI5h/N+KCVF1+pmg/hmEkNA5nHTS8Gvww7T/LCl4o1gFLinw2iQ60w7slFkszHcGLKGdazVI4F8A==} - peerDependencies: - '@nestjs/common': ^10.0.0 || ^11.0.0 - class-transformer: ^0.4.0 || ^0.5.0 - class-validator: ^0.13.0 || ^0.14.0 || ^0.15.0 - reflect-metadata: ^0.1.12 || ^0.2.0 - peerDependenciesMeta: - class-transformer: - optional: true - class-validator: - optional: true - '@nestjs/microservices@11.1.19': resolution: {integrity: sha512-3Oja56ydTlSaui19/i7gYM0MMqz/w4UR2aqZeL4K8B+Fq0Ztg3zHb8et76atToJGpSCevJLEsoEMOMaGgzRwfg==} peerDependencies: @@ -1816,12 +1264,6 @@ packages: '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 passport: ^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0 - '@nestjs/passport@11.0.5': - resolution: {integrity: sha512-ulQX6mbjlws92PIM15Naes4F4p2JoxGnIJuUsdXQPT+Oo2sqQmENEZXM7eYuimocfHnKlcfZOuyzbA33LwUlOQ==} - peerDependencies: - '@nestjs/common': ^10.0.0 || ^11.0.0 - passport: ^0.5.0 || ^0.6.0 || ^0.7.0 - '@nestjs/platform-express@11.1.19': resolution: {integrity: sha512-Vpdv8jyCQdThfoTx+UTn+DRYr6H6X02YUqcpZ3qP6G3ZUwtVp7eS+hoQPGd4UuCnlnFG8Wqr2J9bGEzQdi1rIg==} peerDependencies: @@ -1843,23 +1285,6 @@ packages: prettier: optional: true - '@nestjs/swagger@11.4.2': - resolution: {integrity: sha512-aBihEogDMj/bLEcaqhkvyX/ZVWUw/bmnhKzR0zwUoyGJikvZyaq7rOPYl/H7Lxkkr3c90SJxyuv1AX2UT1WKlw==} - peerDependencies: - '@fastify/static': ^8.0.0 || ^9.0.0 - '@nestjs/common': ^11.0.1 - '@nestjs/core': ^11.0.1 - class-transformer: '*' - class-validator: '*' - reflect-metadata: ^0.1.12 || ^0.2.0 - peerDependenciesMeta: - '@fastify/static': - optional: true - class-transformer: - optional: true - class-validator: - optional: true - '@nestjs/swagger@7.4.2': resolution: {integrity: sha512-Mu6TEn1M/owIvAx2B4DUQObQXqo2028R2s9rSZ/hJEgBK95+doTwS0DjmVA2wTeZTyVtXOoN7CsoM5pONBzvKQ==} peerDependencies: @@ -1890,26 +1315,6 @@ packages: '@nestjs/platform-express': optional: true - '@nestjs/throttler@6.5.0': - resolution: {integrity: sha512-9j0ZRfH0QE1qyrj9JjIRDz5gQLPqq9yVC2nHsrosDVAfI5HHw08/aUAWx9DZLSdQf4HDkmhTTEGLrRFHENvchQ==} - peerDependencies: - '@nestjs/common': ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 - '@nestjs/core': ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 - reflect-metadata: ^0.1.13 || ^0.2.0 - - '@nestjs/typeorm@11.0.1': - resolution: {integrity: sha512-8rw/nKT0S+L+MkzgE9F2/mox7mAgsPlwfzmW9gsESN1lmQtIrVEfiiBwC2O8+guS1jBfQehJIdcdUj2OAp4VUQ==} - peerDependencies: - '@nestjs/common': ^10.0.0 || ^11.0.0 - '@nestjs/core': ^10.0.0 || ^11.0.0 - reflect-metadata: ^0.1.13 || ^0.2.0 - rxjs: ^7.2.0 - typeorm: ^0.3.0 || ^1.0.0-dev - - '@noble/ciphers@1.3.0': - resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} - engines: {node: ^14.21.3 || >=16} - '@noble/hashes@1.8.0': resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} @@ -1931,845 +1336,42 @@ packages: engines: {node: ^14.18.0 || >=16.10.0, npm: '>=5.10.0'} hasBin: true - '@onlyoffice/document-editor-react@2.1.1': - resolution: {integrity: sha512-b0SnFPmT+OEyJons18PPHpwtFABVCI4nr3gPtAAImar1PhN9tNc9703Yo5KPYsHhIgVq+FqHSWgunI9GJnKa5w==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@pandacss/is-valid-prop@1.11.1': - resolution: {integrity: sha512-tvfThJmSw88Lgk5qVYzVckZ2FY8T376mGvP1cWUC5SR58AYm82ZKEFciDbGOQKcyN70rF9qqJBB5JVWgJo3JmA==} - '@paralleldrive/cuid2@2.3.1': resolution: {integrity: sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==} - '@phc/format@1.0.0': - resolution: {integrity: sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==} - engines: {node: '>=10'} - '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@popperjs/core@2.11.8': - resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} - - '@prisma/client@5.22.0': - resolution: {integrity: sha512-M0SVXfyHnQREBKxCgyo7sffrKttwE6R8PMq330MIUF0pTwjUhLbW84pFDlf06B27XyCR++VtjugEnIHdr07SVA==} - engines: {node: '>=16.13'} + '@prisma/client@6.19.3': + resolution: {integrity: sha512-mKq3jQFhjvko5LTJFHGilsuQs+W+T3Gm451NzuTDGQxwCzwXHYnIu2zGkRoW+Exq3Rob7yp2MfzSrdIiZVhrBg==} + engines: {node: '>=18.18'} peerDependencies: prisma: '*' + typescript: '>=5.1.0' peerDependenciesMeta: prisma: optional: true - - '@prisma/debug@5.22.0': - resolution: {integrity: sha512-AUt44v3YJeggO2ZU5BkXI7M4hu9BF2zzH2iF2V5pyXT/lRTyWiElZ7It+bRH1EshoMRxHgpYg4VB6rCM+mG5jQ==} - - '@prisma/engines-version@5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2': - resolution: {integrity: sha512-2PTmxFR2yHW/eB3uqWtcgRcgAbG1rwG9ZriSvQw+nnb7c4uCr3RAcGMb6/zfE88SKlC1Nj2ziUvc96Z379mHgQ==} - - '@prisma/engines@5.22.0': - resolution: {integrity: sha512-UNjfslWhAt06kVL3CjkuYpHAWSO6L4kDCVPegV6itt7nD1kSJavd3vhgAEhjglLJJKEdJ7oIqDJ+yHk6qO8gPA==} - - '@prisma/fetch-engine@5.22.0': - resolution: {integrity: sha512-bkrD/Mc2fSvkQBV5EpoFcZ87AvOgDxbG99488a5cexp5Ccny+UM6MAe/UFkUC0wLYD9+9befNOqGiIJhhq+HbA==} - - '@prisma/get-platform@5.22.0': - resolution: {integrity: sha512-pHhpQdr1UPFpt+zFfnPazhulaZYCUqeIcPpJViYoq9R+D/yw4fjE+CtnsnKzPYm0ddUbeXUzjGVGIRVgPDCk4Q==} - - '@radix-ui/number@1.1.1': - resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} - - '@radix-ui/primitive@1.1.3': - resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} - - '@radix-ui/react-accordion@1.2.12': - resolution: {integrity: sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': + typescript: optional: true - '@radix-ui/react-alert-dialog@1.1.15': - resolution: {integrity: sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@prisma/config@6.19.3': + resolution: {integrity: sha512-CBPT44BjlQxEt8kiMEauji2WHTDoVBOKl7UlewXmUgBPnr/oPRZC3psci5chJnYmH0ivEIog2OU9PGWoki3DLQ==} - '@radix-ui/react-arrow@1.1.7': - resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@prisma/debug@6.19.3': + resolution: {integrity: sha512-ljkJ+SgpXNktLG0Q/n4JGYCkKf0f8oYLyjImS2I8e2q2WCfdRRtWER062ZV/ixaNP2M2VKlWXVJiGzZaUgbKZw==} - '@radix-ui/react-avatar@1.1.11': - resolution: {integrity: sha512-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@prisma/engines-version@7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7': + resolution: {integrity: sha512-03bgb1VD5gvuumNf+7fVGBzfpJPjmqV423l/WxsWk2cNQ42JD0/SsFBPhN6z8iAvdHs07/7ei77SKu7aZfq8bA==} - '@radix-ui/react-checkbox@1.3.3': - resolution: {integrity: sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@prisma/engines@6.19.3': + resolution: {integrity: sha512-RSYxtlYFl5pJ8ZePgMv0lZ9IzVCOdTPOegrs2qcbAEFrBI1G33h6wyC9kjQvo0DnYEhEVY0X4LsuFHXLKQk88g==} - '@radix-ui/react-collapsible@1.1.12': - resolution: {integrity: sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@prisma/fetch-engine@6.19.3': + resolution: {integrity: sha512-tKtl/qco9Nt7LU5iKhpultD8O4vMCZcU2CHjNTnRrL1QvSUr5W/GcyFPjNL87GtRrwBc7ubXXD9xy4EvLvt8JA==} - '@radix-ui/react-collection@1.1.7': - resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-compose-refs@1.1.2': - resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-context-menu@2.2.16': - resolution: {integrity: sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-context@1.1.2': - resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-context@1.1.3': - resolution: {integrity: sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-dialog@1.1.15': - resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-direction@1.1.1': - resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-dismissable-layer@1.1.11': - resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-dropdown-menu@2.1.16': - resolution: {integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-focus-guards@1.1.3': - resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-focus-scope@1.1.7': - resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-hover-card@1.1.15': - resolution: {integrity: sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-id@1.1.1': - resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-label@2.1.8': - resolution: {integrity: sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-menu@2.1.16': - resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-navigation-menu@1.2.14': - resolution: {integrity: sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-popover@1.1.15': - resolution: {integrity: sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-popper@1.2.8': - resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-portal@1.1.9': - resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-presence@1.1.5': - resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-primitive@2.1.3': - resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-primitive@2.1.4': - resolution: {integrity: sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-progress@1.1.8': - resolution: {integrity: sha512-+gISHcSPUJ7ktBy9RnTqbdKW78bcGke3t6taawyZ71pio1JewwGSJizycs7rLhGTvMJYCQB1DBK4KQsxs7U8dA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-radio-group@1.3.8': - resolution: {integrity: sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-roving-focus@1.1.11': - resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-scroll-area@1.2.10': - resolution: {integrity: sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-select@2.2.6': - resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-separator@1.1.8': - resolution: {integrity: sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-slider@1.3.6': - resolution: {integrity: sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-slot@1.2.3': - resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-slot@1.2.4': - resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-switch@1.2.6': - resolution: {integrity: sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-tabs@1.1.13': - resolution: {integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-toast@1.2.15': - resolution: {integrity: sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-toggle-group@1.1.11': - resolution: {integrity: sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-toggle@1.1.10': - resolution: {integrity: sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-tooltip@1.2.8': - resolution: {integrity: sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-use-callback-ref@1.1.1': - resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-controllable-state@1.2.2': - resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-effect-event@0.0.2': - resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-escape-keydown@1.1.1': - resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-is-hydrated@0.1.0': - resolution: {integrity: sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-layout-effect@1.1.1': - resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-previous@1.1.1': - resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-rect@1.1.1': - resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-size@1.1.1': - resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-visually-hidden@1.2.3': - resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/rect@1.1.1': - resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} - - '@react-pdf-viewer/attachment@3.12.0': - resolution: {integrity: sha512-mhwrYJSIpCvHdERpLUotqhMgSjhtF+BTY1Yb9Fnzpcq3gLZP+Twp5Rynq21tCrVdDizPaVY7SKu400GkgdMfZw==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@react-pdf-viewer/bookmark@3.12.0': - resolution: {integrity: sha512-i7nEit8vIFMAES8RFGwprZ9cXOOZb9ZStPW6E6yuObJEXcvBj/ctsbBJGZxqUZOGklM0JoB7sjHyxAriHfe92A==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@react-pdf-viewer/core@3.12.0': - resolution: {integrity: sha512-8MsdlQJ4jaw3GT+zpCHS33nwnvzpY0ED6DEahZg9WngG++A5RMhk8LSlxdHelwaFFHFiXBjmOaj2Kpxh50VQRg==} - peerDependencies: - pdfjs-dist: ^3.11.174 - react: 18.3.1 - react-dom: 18.3.1 - - '@react-pdf-viewer/default-layout@3.12.0': - resolution: {integrity: sha512-K2fS4+TJynHxxCBFuIDiFuAw3nqOh4bkBgtVZ/2pGvnFn9lLg46YGLMnTXCQqtyZzzXYh696jmlFViun3is4pA==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@react-pdf-viewer/full-screen@3.12.0': - resolution: {integrity: sha512-hQouJ26QUaRBCXNMU1aI1zpJn4l4PJRvlHhuE2dZYtLl37ycjl7vBCQYZW1FwnuxMWztZsY47R43DKaZORg0pg==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@react-pdf-viewer/get-file@3.12.0': - resolution: {integrity: sha512-Uhq45n2RWlZ7Ec/BtBJ0WQESRciaYIltveDXHNdWvXgFdOS8XsvB+mnTh/wzm7Cfl9hpPyzfeezifdU9AkQgQg==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@react-pdf-viewer/open@3.12.0': - resolution: {integrity: sha512-vhiDEYsiQLxvZkIKT9VPYHZ1BOnv46x9eCEmRWxO1DJ8fa/GRDTA9ivXmq/ap0dGEJs6t+epleCkCEfllLR/Yw==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@react-pdf-viewer/page-navigation@3.12.0': - resolution: {integrity: sha512-tVEJ48Dd5kajV1nKkrPWijglJRNBiKBTyYDKVexhiRdTHUP1f6QQXiSyDgCUb0IGSZeJzOJb1h7ApKHe8OTtuw==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@react-pdf-viewer/print@3.12.0': - resolution: {integrity: sha512-xJn76CgbU/M2iNaN7wLHTg+sdOekkRMfCakFLwPrE+SR7qD6NUF4vQQKJBSVCCK5bUijzb6cWfKGfo8VA72o4Q==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@react-pdf-viewer/properties@3.12.0': - resolution: {integrity: sha512-dYTCHtVwFNkpDo7QxL2qk/8zAKndLwdD1FFxBftl6jIlQbtvNdxkFfkv1HcQING9Ic+7DBryOiD7W0ze4IERYg==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@react-pdf-viewer/rotate@3.12.0': - resolution: {integrity: sha512-yaxaMYPChvNOjR8+AxRmj0kvojyJKPq4XHEcIB2lJJgBY1Zra3mliDUP3Nlb4yV8BS9+yBqWn9U9mtnopQD+tw==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@react-pdf-viewer/scroll-mode@3.12.0': - resolution: {integrity: sha512-okII7Xqhl6cMvl1izdEvlXNJ+vJVq/qdg53hJIDYVgBCWskLk/cpjUg/ZonBxseG9lIDP3w2VO1McT8Gn11OAg==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@react-pdf-viewer/search@3.12.0': - resolution: {integrity: sha512-jAkLpis49fsDDY/HrbUZIOIhzF5vynONQNA4INQKI38r/MjveblrkNv7qbr9j5lQ/WFic5+gD1e+Mtpf1/7DiA==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@react-pdf-viewer/selection-mode@3.12.0': - resolution: {integrity: sha512-yysWEu2aCtBvzSgbhgI9kT5cq2hf0FU6Z+3B7MMXz14Kxyc3y18wUqxtgbvpFEfWF0bNUUq16JtWRljtxvZ83w==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@react-pdf-viewer/theme@3.12.0': - resolution: {integrity: sha512-cdBi+wR1VOZ6URCcO9plmAZQu4ZGFcd7HJdBe7VIFiGyrvl9I/Of74ONLycnDImSuONt8D3uNjPBLieeaShVeg==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@react-pdf-viewer/thumbnail@3.12.0': - resolution: {integrity: sha512-Vc8j3bO6wumWZV4o6pAbktPWKDSC9tQAzOCJ3cof541u4i44C11ccYC4W9aNcsMMUSO3bNwAGWtP8OFthV5akQ==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@react-pdf-viewer/toolbar@3.12.0': - resolution: {integrity: sha512-qACTU3qXHgtNK8J+T13EWio+0liilj86SJ87BdapqXynhl720OKPlSKOQqskUGqg3oTUJAhrse9XG6SFdHJx+g==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@react-pdf-viewer/zoom@3.12.0': - resolution: {integrity: sha512-V0GUTyPM77+LzhoKX+T3XI10/HfGdqRTbgeP7ID60FCzcwu6kXWqJn5tzabjDKLTlFv8mJmn0aa/ppkIU97nfA==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@react-pdf/fns@3.1.3': - resolution: {integrity: sha512-0I7pApDr1/RLAKbizuLy/IHTEa93LSPy/bEwYniboC3Xqnp6Od8xFJKbKEzGw2wh/5zKFFwl00g4t9RwgIMc3w==} - - '@react-pdf/font@4.0.8': - resolution: {integrity: sha512-deNd+emtZAJho1IlzKL9bRoLAGv/6oXOIKO2oZfs4RuXUrK1onLHbJO7e2YoVLPFP/sQxisRTnzdJFtd35iKwA==} - - '@react-pdf/image@3.1.0': - resolution: {integrity: sha512-ks7Ry8v711r8NvKWSELehj0BXBNPRihSnWsM09nDD8Ur175zbWBCK217LLwQMKDNYDVpkZaipdoJPom1LGaE9g==} - - '@react-pdf/layout@4.6.1': - resolution: {integrity: sha512-gN6PmWoEffvlIkifLfEhMsVucRywVMyH3rnxdyOVOhGy0nWJKKGpHyPc4plbDdpP6EfZ0r8prHXujDSkIG2nSA==} - - '@react-pdf/pdfkit@5.1.1': - resolution: {integrity: sha512-wNcdSsNlNYyGHGAgIdt453egBF7fiF9UxpRlklUfVvu8OWCrUppG9xiUrPLVoKiqWet5tMi0w6LmuFUJuYqjEg==} - - '@react-pdf/primitives@4.3.0': - resolution: {integrity: sha512-nYXoZ36pvwNzbc54+DbL8RCn15jU7woJ9D/svnh5tpUXekJ+CbI4mZLo6boSv24CvJgychOu6h7gxX03B4ps0A==} - - '@react-pdf/reconciler@2.0.0': - resolution: {integrity: sha512-7zaPRujpbHSmCpIrZ+b9HSTJHthcVZzX0Wx7RzvQGsGBUbHP4p6s5itXrAIOuQuPvDepoHGNOvf6xUuMVvdoyw==} - peerDependencies: - react: 18.3.1 - - '@react-pdf/render@4.5.1': - resolution: {integrity: sha512-IW/N4HWJWtioBXCf7n02IR24VJJ8gbdS3jGypf+vW/rSErEx3/URRzh9UK6Ma8Fpog9+T/W6GE2NHJ5AAKHhVA==} - - '@react-pdf/renderer@4.5.1': - resolution: {integrity: sha512-5r1VQrE6FRLXX5wWUxwZzM24E2BJMo6g8AQWuS8WyPs9ugu5yMnb2g8/RpPYka/Z6J+RUEWc32wty2NoUJF42Q==} - peerDependencies: - react: 18.3.1 - - '@react-pdf/stylesheet@6.2.1': - resolution: {integrity: sha512-2+UEk+7e+z8baaWi2l5kPLWmwtJeOI+T5wW9GGeN3iDH7vd3kbTqOpN1yt9mmfNVZFxQsnDHpznFb5v5UF983A==} - - '@react-pdf/svg@1.1.0': - resolution: {integrity: sha512-cTIHXiz9x1HrbfqzfxfZP3FRdDwUXG77QWF6Fb5MP/lV3ONxR+g0Z3hwtBatCS9HeGBQCpxX/Lzb8wHE+co1PA==} - - '@react-pdf/textkit@6.3.0': - resolution: {integrity: sha512-v6+V8nAcVwm7s2s1jIG2MD3Iw//x/k+XrH1foWOELBE4b32pyDgKyPXN/6KJE0dnX7+fVy27uctLNCLNMvzKzQ==} - - '@react-pdf/types@2.11.1': - resolution: {integrity: sha512-i9xQgfaDU9QoeNnbp6rltXCWg1huEh195rpOuN8cE4BZ2FuLdQrsIcb2dhFF9aOxXf+XBA6LOSpIW051MDD/bw==} - - '@reduxjs/toolkit@2.11.2': - resolution: {integrity: sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==} - peerDependencies: - react: 18.3.1 - react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 - peerDependenciesMeta: - react: - optional: true - react-redux: - optional: true + '@prisma/get-platform@6.19.3': + resolution: {integrity: sha512-xFj1VcJ1N3MKooOQAGO0W5tsd0W2QzIvW7DD7c/8H14Zmp4jseeWAITm+w2LLoLrlhoHdPPh0NMZ8mfL6puoHA==} '@remix-run/router@1.23.2': resolution: {integrity: sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==} @@ -2930,335 +1532,20 @@ packages: '@sinonjs/fake-timers@10.3.0': resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} - '@socket.io/component-emitter@3.1.2': - resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} - '@sqltools/formatter@1.2.5': resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==} '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@standard-schema/utils@0.3.0': - resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} - - '@swc/helpers@0.5.21': - resolution: {integrity: sha512-jI/VAmtdjB/RnI8GTnokyX7Ug8c+g+ffD6QRLa6XQewtnGyukKkKSk3wLTM3b5cjt1jNh9x0jfVlagdN2gDKQg==} - - '@tabby_ai/hijri-converter@1.0.5': - resolution: {integrity: sha512-r5bClKrcIusDoo049dSL8CawnHR6mRdDwhlQuIgZRNty68q0x8k3Lf1BtPAMxRf/GgnHBnIO4ujd3+GQdLWzxQ==} - engines: {node: '>=16.0.0'} - - '@tabler/icons-react@3.44.0': - resolution: {integrity: sha512-8+rvzBbVm/1Z3sG3x7GUNAaxIKxwgz8xaMhRs23nrCnMTKRFAhEC+82zAIFeAA0seXdrAGX5HFCkaLpGK2rVHg==} - peerDependencies: - react: 18.3.1 - - '@tabler/icons@3.44.0': - resolution: {integrity: sha512-Wn0AOZG9sg0L+bjfMqq4eNhC6pQjIrk94LvvWYNYkY8KH8wC3YILRzQlrnVJc4FUeMxH/AK97QsYCX35H3LndA==} - - '@tailwindcss/node@4.3.0': - resolution: {integrity: sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==} - - '@tailwindcss/oxide-android-arm64@4.3.0': - resolution: {integrity: sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [android] - - '@tailwindcss/oxide-darwin-arm64@4.3.0': - resolution: {integrity: sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [darwin] - - '@tailwindcss/oxide-darwin-x64@4.3.0': - resolution: {integrity: sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==} - engines: {node: '>= 20'} - cpu: [x64] - os: [darwin] - - '@tailwindcss/oxide-freebsd-x64@4.3.0': - resolution: {integrity: sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==} - engines: {node: '>= 20'} - cpu: [x64] - os: [freebsd] - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': - resolution: {integrity: sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==} - engines: {node: '>= 20'} - cpu: [arm] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': - resolution: {integrity: sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-musl@4.3.0': - resolution: {integrity: sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [linux] - - '@tailwindcss/oxide-linux-x64-gnu@4.3.0': - resolution: {integrity: sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==} - engines: {node: '>= 20'} - cpu: [x64] - os: [linux] - - '@tailwindcss/oxide-linux-x64-musl@4.3.0': - resolution: {integrity: sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==} - engines: {node: '>= 20'} - cpu: [x64] - os: [linux] - - '@tailwindcss/oxide-wasm32-wasi@4.3.0': - resolution: {integrity: sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - bundledDependencies: - - '@napi-rs/wasm-runtime' - - '@emnapi/core' - - '@emnapi/runtime' - - '@tybys/wasm-util' - - '@emnapi/wasi-threads' - - tslib - - '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': - resolution: {integrity: sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [win32] - - '@tailwindcss/oxide-win32-x64-msvc@4.3.0': - resolution: {integrity: sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==} - engines: {node: '>= 20'} - cpu: [x64] - os: [win32] - - '@tailwindcss/oxide@4.3.0': - resolution: {integrity: sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==} - engines: {node: '>= 20'} - - '@tailwindcss/vite@4.3.0': - resolution: {integrity: sha512-t6J3OrB5Fc0ExuhohouH0fWUGMYL6PTLhW+E7zIk/pdbnJARZDCwjBznFnkh5ynRnIRSI4YjtTH0t6USjJISrw==} - peerDependencies: - vite: ^5.2.0 || ^6 || ^7 || ^8 - '@tanstack/query-core@5.100.10': resolution: {integrity: sha512-8UR0yJR+GiQ40m3lPhUr0xbfAupe6GSQiksSBSa9SM2NjezFyxXCIA69/lz8cSoNKZLrw1/PktIyQBJcVeMi3w==} - '@tanstack/query-devtools@5.100.10': - resolution: {integrity: sha512-3DmJf25hDPus5IpVvp6ujXv6bKV2zPzI9vpbAmpJigsL/H6DPvPjmf7/Q9yVKEke//8fgeQ45abjgnLuyYxAiw==} - - '@tanstack/react-query-devtools@5.100.10': - resolution: {integrity: sha512-zes0+o9ef5rAZXJ9f/SeaLs2nufJaeVkZkl/Or9NGrWVF41kL9Od9ED9nCwtQlgiF2VGtrzhEw5AU/igAO+aAg==} - peerDependencies: - '@tanstack/react-query': ^5.100.10 - react: 18.3.1 - '@tanstack/react-query@5.100.10': resolution: {integrity: sha512-FLaZf2RCrA/Zgp4aiu5tG3TyasTRO7aZ99skxQpr3Hg/zXOhu6yq5FZCYQ/tRaJtM9ylnoK8tFK7PolXQadv6Q==} peerDependencies: react: 18.3.1 - '@tanstack/react-table@8.21.3': - resolution: {integrity: sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==} - engines: {node: '>=12'} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@tanstack/table-core@8.21.3': - resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==} - engines: {node: '>=12'} - - '@tinymce/tinymce-react@6.3.0': - resolution: {integrity: sha512-E++xnn0XzDzpKr40jno2Kj7umfAE6XfINZULEBBeNjTMvbACWzA6CjiR6V8eTDc9yVmdVhIPqVzV4PqD5TZ/4g==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - tinymce: ^8.0.0 || ^7.0.0 || ^6.0.0 || ^5.5.1 - peerDependenciesMeta: - tinymce: - optional: true - - '@tiptap/core@3.23.1': - resolution: {integrity: sha512-8YvSGiJTeU5wPuGiYIIYgyiyaaT1CAx+kJL0bju0w871OvbJJj0T/ywhcmxGXW6pOal2T8X2xt9ZqE+vib0VJw==} - peerDependencies: - '@tiptap/pm': 3.23.1 - - '@tiptap/extension-blockquote@3.23.1': - resolution: {integrity: sha512-FdVZLZOkL06j3WLXOC2UeX7++Cj3qI2vfohruMJiz4vk1Q5UUH7G4+AykFzjzBJHrdEpkiRUkRpU1KZIWdbluw==} - peerDependencies: - '@tiptap/core': 3.23.1 - - '@tiptap/extension-bold@3.23.1': - resolution: {integrity: sha512-EAYdNzyOjlQh2VBY1EhdxtiTjVMaOAD6P0ezms60dKRjd4oj/8grfXfUqwgo4NVdFb11Ks85vXoHuXJSylfR4A==} - peerDependencies: - '@tiptap/core': 3.23.1 - - '@tiptap/extension-bubble-menu@3.23.1': - resolution: {integrity: sha512-1advMCpPkHD/3ucZhYmNau8B4tF0L6iRAFhUOglp5bBZDuq13+rYujh3cm4vFmjH9KqThzpcUDn+ZU2c+mTMyw==} - peerDependencies: - '@tiptap/core': 3.23.1 - '@tiptap/pm': 3.23.1 - - '@tiptap/extension-bullet-list@3.23.1': - resolution: {integrity: sha512-owWnBBI4t+jqVDY0naDjhsAmrNGldh4czouef2K+mEf032B7uGsDVCwKp1qaX1JZesyYDfvXOaIwT22hNID2mw==} - peerDependencies: - '@tiptap/extension-list': 3.23.1 - - '@tiptap/extension-code-block@3.23.1': - resolution: {integrity: sha512-BdJGqM57CsKgYrQUZz78vIG8Yn7EpsE2pA7iKn5tYoSXpYtt0IaU4qB1heH7lwWD/vVCAm0YQVD7/0F+0++yhA==} - peerDependencies: - '@tiptap/core': 3.23.1 - '@tiptap/pm': 3.23.1 - - '@tiptap/extension-code@3.23.1': - resolution: {integrity: sha512-nGuhb4YghgTfkejwWHrD9GSpwcC5kkVmm2sN/UY4yceDw+PkyysYKJWZehRLTOC8GNgSAhq/EeQeq14Xwk6dyg==} - peerDependencies: - '@tiptap/core': 3.23.1 - - '@tiptap/extension-color@3.23.1': - resolution: {integrity: sha512-OYk/fT3h8Bz4B6GUVTQDvKGpPnpI5d6QHkuqjVhdFsgH3oo58PdLE1TdIGgeavuYPLaFxgBtEXmm3oTY9jPWxw==} - peerDependencies: - '@tiptap/extension-text-style': 3.23.1 - - '@tiptap/extension-document@3.23.1': - resolution: {integrity: sha512-NA5Rx59HRwG6Hb6LwLpC5lE7z6vCj6f90S7RNNsnE+CyiXNR/OhY2BcjuxiGnascHvsnsAbvxGU3ymKMDgvDVg==} - peerDependencies: - '@tiptap/core': 3.23.1 - - '@tiptap/extension-dropcursor@3.23.1': - resolution: {integrity: sha512-WRN7e/h9m3uI5j9/+L6jcPhHbTL6aKxfFfQWZHNf5M8TqSL1P+/2h034td0XMj3n48i4fWyzjVUV9+sz6t2fDw==} - peerDependencies: - '@tiptap/extensions': 3.23.1 - - '@tiptap/extension-floating-menu@3.23.1': - resolution: {integrity: sha512-XrYHpLn1DpLFSGTko9F9xgbNamL6fGpWkK4wqgwPVbg/SJwQCDO/9p5D3DtJTwD+xgw4sQ9as4O6rt6jx8JT+Q==} - peerDependencies: - '@floating-ui/dom': ^1.0.0 - '@tiptap/core': 3.23.1 - '@tiptap/pm': 3.23.1 - - '@tiptap/extension-gapcursor@3.23.1': - resolution: {integrity: sha512-E4hB0xquUpEXy7kboLBazrFyRCsN0j0fsTFR8udgQf5xetAVPhOexSTKuzOcU/n0kxsKJin7laYYEag/Fd2KNw==} - peerDependencies: - '@tiptap/extensions': 3.23.1 - - '@tiptap/extension-hard-break@3.23.1': - resolution: {integrity: sha512-XYkCKC5RVqMmmBk+nd22/6IDDx1OC54sdStH5VEHtfOrarriO0JztK8Mr0TijPPk9N4rKXsmndYZM2xyWZZytQ==} - peerDependencies: - '@tiptap/core': 3.23.1 - - '@tiptap/extension-heading@3.23.1': - resolution: {integrity: sha512-1z9yCSp8fevgX3r/4kWXO3of0WFCQWfYjWfHANvoJ4JQTYBkARjXlj1tbk5rrAJBFDDfKRkUpZOurXKgGo+h+g==} - peerDependencies: - '@tiptap/core': 3.23.1 - - '@tiptap/extension-highlight@3.23.1': - resolution: {integrity: sha512-Bf5u5KBb6SLveKzPgUEbHoU5uWTUcEvSSZr/mpQZpvCpE6MlXZbvengmFj1OkKnrNZWg0Um2p9e6zKnZHH07sA==} - peerDependencies: - '@tiptap/core': 3.23.1 - - '@tiptap/extension-horizontal-rule@3.23.1': - resolution: {integrity: sha512-30XUHXdEZxcz1FCWjz9HW2EEq06NQcAye6rXGnvHo6Y60iJ6MRsrX5byvceFNF9DTVtOIcUFBQ/psIiRcoi0KA==} - peerDependencies: - '@tiptap/core': 3.23.1 - '@tiptap/pm': 3.23.1 - - '@tiptap/extension-image@3.23.1': - resolution: {integrity: sha512-rAyfh8HS0PfXS8PKl1VQUiDFzXtF5SlrILpOPmz+4Oc4pmI+/vN+ain4z8k6HRxWM03YVpvLvyeQ0OFwi/fq3A==} - peerDependencies: - '@tiptap/core': 3.23.1 - - '@tiptap/extension-italic@3.23.1': - resolution: {integrity: sha512-lZB9YCjoVNDoPMguya66nBvaS/2YpGN5iAcjAGx/JQkCAZeOAtl9+ALMzbWPKH6tQP6m98YtkY1T7RXr++T0bA==} - peerDependencies: - '@tiptap/core': 3.23.1 - - '@tiptap/extension-link@3.23.1': - resolution: {integrity: sha512-uOeyLqYQI0WG62agpFG24kVHSn3Z48gD8Y0uLLJbtzh/nDFC3d9So2sQGWlSVyMzsgkJ4k/9jNnxxsVO8qgJOg==} - peerDependencies: - '@tiptap/core': 3.23.1 - '@tiptap/pm': 3.23.1 - - '@tiptap/extension-list-item@3.23.1': - resolution: {integrity: sha512-Fk/884un5OSLCFxe2TbOmfp3sLMB5b76CnMjaSrvgfiaZnsV2WlJZGPXxCAPbxNIATTykNlSBsVuMBO7we64Vg==} - peerDependencies: - '@tiptap/extension-list': 3.23.1 - - '@tiptap/extension-list-keymap@3.23.1': - resolution: {integrity: sha512-sHbE5sxiJzhgGn94GUAzD4qKM9SyImBrOlAGS/EIe+pausjqQE7xi+YW0gRo2jG+gXhSYl4/oAGXQXzmSInSUQ==} - peerDependencies: - '@tiptap/extension-list': 3.23.1 - - '@tiptap/extension-list@3.23.1': - resolution: {integrity: sha512-v1AeXPpagslgRZdOp7WdjCoO4TjjNP8RM2R6Gqx0/inGaNXnM8zCMshOxZlAb03Ad7kq/4RGJmkpM/Jjsi6dEQ==} - peerDependencies: - '@tiptap/core': 3.23.1 - '@tiptap/pm': 3.23.1 - - '@tiptap/extension-ordered-list@3.23.1': - resolution: {integrity: sha512-3GG7YFhVJWw/HWmRxvMMUC296x7TPBQRLsH4ryEC1SMAmVJnbTIvetyvIcLqLEXGW7Rj41S7SO8qjOXVceSOTA==} - peerDependencies: - '@tiptap/extension-list': 3.23.1 - - '@tiptap/extension-paragraph@3.23.1': - resolution: {integrity: sha512-GC7b6yAjASl1q9sNkPmukZmVYMfxx03EEhpMMrLYJY9GBz82Ald927yYQsOqf2aKA/Rjo/aZMYCGtjXkGk6aBA==} - peerDependencies: - '@tiptap/core': 3.23.1 - - '@tiptap/extension-strike@3.23.1': - resolution: {integrity: sha512-+R5LG0ZW9SDZc4weA79uq6uUduVsCEph9tRcoQCRA82IVIiPYSTxTLew9odalmk/Mc7vdZvOK5jjtO5jUVw/rg==} - peerDependencies: - '@tiptap/core': 3.23.1 - - '@tiptap/extension-text-align@3.23.1': - resolution: {integrity: sha512-ap4ZN31v57mVX2P+0OoW5iO+ehsUNe0C5MgF/Ta2F/HRmTCc1M1mFqYUCk8zJYX1TFRV18vqK2j6STRBk0R8ng==} - peerDependencies: - '@tiptap/core': 3.23.1 - - '@tiptap/extension-text-style@3.23.1': - resolution: {integrity: sha512-q3GQQo+lBhrtNkqdbhYWnv/byG/RYAxVnNhYPQMubRzavGdXBU8NhpJ/47YYjPimG1sahzcs2aqy7amVd8ri/A==} - peerDependencies: - '@tiptap/core': 3.23.1 - - '@tiptap/extension-text@3.23.1': - resolution: {integrity: sha512-k1Ki9bBV6mLz1mFP+Laqh1YHJ2MY0P8XzaMqpkgMndEBIJQ3XcpWQc5bfAlRnYcOI9ZXDbAgQ8CwgArxHmQWCQ==} - peerDependencies: - '@tiptap/core': 3.23.1 - - '@tiptap/extension-underline@3.23.1': - resolution: {integrity: sha512-+PvHyVozHyxJ9oWCIQx5JHBZ7LAa/sFJUOFaKyfmel4gL9AbP52MmvrciXARlZHd1WCULJtdbLan0+x5/D/9hQ==} - peerDependencies: - '@tiptap/core': 3.23.1 - - '@tiptap/extensions@3.23.1': - resolution: {integrity: sha512-7UIn+idaVTVhdlP0KmgzBh8Csmwck357Dq4te5DuAxhSkN1gsXHlq39mpx907UYKJdSOgd+GMFeyOziPwSmbOQ==} - peerDependencies: - '@tiptap/core': 3.23.1 - '@tiptap/pm': 3.23.1 - - '@tiptap/pm@3.23.1': - resolution: {integrity: sha512-8G+TkNsUHHAAJYREpA6fw+Dw/m2Y3Go4/QMQM8RYepid+wTeE1wSv7sBA/CBrphhYmJSWeTyCPtgQIxnTJXMCA==} - - '@tiptap/react@3.23.1': - resolution: {integrity: sha512-43zUwKOcsxRIcgiDbcEUagojhPIez2OIryaNG/uiDcRzkrUteiTu2wSJndkQqwouwh3wJEm+KOw8xybNYvU+qA==} - peerDependencies: - '@tiptap/core': 3.23.1 - '@tiptap/pm': 3.23.1 - '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 - '@types/react-dom': ^17.0.0 || ^18.0.0 || ^19.0.0 - react: 18.3.1 - react-dom: 18.3.1 - - '@tiptap/starter-kit@3.23.1': - resolution: {integrity: sha512-CURePHQagBaZIDJrHH3of4Nmi0VYGpZ6yBlkdFxFHBxY9aeG2/h5kn+oHo8GbzkSFsRV+9olzRgDTOULVgs8pQ==} - '@tokenizer/inflate@0.4.1': resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} engines: {node: '>=18'} @@ -3266,46 +1553,6 @@ packages: '@tokenizer/token@0.3.0': resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} - '@tria-plc/api-common@0.1.4': - resolution: {integrity: sha512-lm9esp5PDxUyggqxYXbx2CQhZKwtcAaAcGFuuUURw3u5DlzGUNwMOFkQkDLM/fbgN+33+s1RKC7UynnG9NZFww==, tarball: https://npm.pkg.github.com/download/@tria-plc/api-common/0.1.4/de160e4bb61a882efd9c877b4614028f1ffd7cb8} - peerDependencies: - '@nestjs/common': ^11.0.0 - '@nestjs/core': ^11.0.0 - '@nestjs/jwt': ^11.0.0 - '@nestjs/microservices': ^11.0.0 - '@nestjs/passport': ^11.0.0 - '@nestjs/swagger': ^11.0.0 - '@nestjs/throttler': ^6.0.0 - '@nestjs/typeorm': ^11.0.0 - '@tria-plc/iamapi-common': '*' - reflect-metadata: ^0.2.0 - rxjs: ^7.8.0 - typeorm: ^0.3.0 - - '@tria-plc/iamapi-common@0.1.6': - resolution: {integrity: sha512-qaCLZ1TgbcQ5XciRuA/aZjRCM/GmGYgcmsyDDIlhiMNw3FL3DCiR/QiFuQpERvV4FqgQNBJg66+S/jXO3I2jbw==, tarball: https://npm.pkg.github.com/download/@tria-plc/iamapi-common/0.1.6/e2a8f3357b650bb9477facae4aaa7044382acebf} - engines: {node: '>=20'} - peerDependencies: - '@nestjs/axios': ^4.0.0 - '@nestjs/common': ^11.0.0 - '@nestjs/core': ^11.0.0 - '@nestjs/jwt': ^11.0.0 - '@nestjs/microservices': ^11.0.0 - '@nestjs/passport': ^11.0.0 - '@nestjs/swagger': ^11.0.0 - '@nestjs/throttler': ^6.0.0 - '@nestjs/typeorm': ^11.0.0 - '@tria-plc/api-common': ^0.1.0 - axios: ^1.9.0 - class-transformer: ^0.5.1 - class-validator: ^0.14.1 - reflect-metadata: ^0.2.0 - rxjs: ^7.8.0 - typeorm: ^0.3.0 - - '@tria-plc/iamui-common@1.0.3': - resolution: {integrity: sha512-RebVPhbHpV4VtaUlBi/sqJlGf0vXrDO6iVq/VvSFgxd10YlEVR7lGvkXC1ManVOK+Aq3d+mBKdDUAVgI5ATZJA==, tarball: https://npm.pkg.github.com/download/@tria-plc/iamui-common/1.0.3/61c1cb36a5737a5c1f2d8595dec8aeca055a3a62} - '@tsconfig/node10@1.0.12': resolution: {integrity: sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==} @@ -3375,33 +1622,6 @@ packages: '@types/cookiejar@2.1.5': resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==} - '@types/d3-array@3.2.2': - resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} - - '@types/d3-color@3.1.3': - resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} - - '@types/d3-ease@3.0.2': - resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} - - '@types/d3-interpolate@3.0.4': - resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} - - '@types/d3-path@3.1.1': - resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} - - '@types/d3-scale@4.0.9': - resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} - - '@types/d3-shape@3.1.8': - resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==} - - '@types/d3-time@3.0.4': - resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} - - '@types/d3-timer@3.0.2': - resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} - '@types/eslint-scope@3.7.7': resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} @@ -3423,11 +1643,6 @@ packages: '@types/graceful-fs@4.1.9': resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} - '@types/hoist-non-react-statics@3.3.7': - resolution: {integrity: sha512-PQTyIulDkIDro8P+IHbKCsw7U2xxBYflVzW/FgWdCAePD9xGSidgA76/GeJ6lBKoblyhf9pBY763gbrN+1dI8g==} - peerDependencies: - '@types/react': '*' - '@types/http-errors@2.0.5': resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} @@ -3443,9 +1658,6 @@ packages: '@types/jest@29.5.14': resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} - '@types/jquery@4.0.0': - resolution: {integrity: sha512-Z+to+A2VkaHq1DfI2oSwsoCdhCHMpTSgjWzNcbNlRGYzksDBpPUgEcAL+RQjOBJRaLoEAOHXxqDGBVP+BblBwg==} - '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -3467,18 +1679,12 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@14.18.63': - resolution: {integrity: sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==} - '@types/node@20.19.41': resolution: {integrity: sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ==} '@types/node@24.12.4': resolution: {integrity: sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==} - '@types/pako@2.0.4': - resolution: {integrity: sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==} - '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} @@ -3500,9 +1706,6 @@ packages: '@types/qs@6.15.1': resolution: {integrity: sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==} - '@types/raf@3.4.3': - resolution: {integrity: sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==} - '@types/range-parser@1.2.7': resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} @@ -3511,11 +1714,6 @@ packages: peerDependencies: '@types/react': ^18.0.0 - '@types/react-transition-group@4.4.12': - resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==} - peerDependencies: - '@types/react': '*' - '@types/react@18.3.28': resolution: {integrity: sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==} @@ -3525,9 +1723,6 @@ packages: '@types/serve-static@2.2.0': resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} - '@types/signature_pad@2.3.6': - resolution: {integrity: sha512-v3j92gCQJoxomHhd+yaG4Vsf8tRS/XbzWKqDv85UsqjMGy4zhokuwKe4b6vhbgncKkh+thF+gpz6+fypTtnFqQ==} - '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} @@ -3537,15 +1732,6 @@ packages: '@types/supertest@6.0.3': resolution: {integrity: sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==} - '@types/tinymce@4.6.9': - resolution: {integrity: sha512-pDxBUlV4v1jgJ97SlnVOSyf3KUy3OQ3s5Ddpfh1L9M5lXlBmX7TJ2OLSozx1WBxp91acHvYPWDwz2U/kMM1oxQ==} - - '@types/trusted-types@2.0.7': - resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - - '@types/use-sync-external-store@0.0.6': - resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} - '@types/validator@13.15.10': resolution: {integrity: sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==} @@ -3703,243 +1889,6 @@ packages: '@xtuc/long@4.2.2': resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} - '@zag-js/accordion@1.40.0': - resolution: {integrity: sha512-YDdyvZJ6fr92RZazyXQq+juT3ZA0ubjDISptb5YPgMoTPdnjKNiICPpMeCeVj1ncYRDkHXrOdChS/5CtuX/K6g==} - - '@zag-js/anatomy@1.40.0': - resolution: {integrity: sha512-oiB4uAaV//L38JluLVPtOHO3xvqambrfrXVOoq4kmNrBv1LLlCmFvrXA2HOR9lakn4ExK27XSUrKhUN7YlKjfQ==} - - '@zag-js/angle-slider@1.40.0': - resolution: {integrity: sha512-6X6bOBoCyYG0/lFY0Y+AXJZZG6CeYQiWkcMXvegxCC2zxthodqOVzkVOASW+6rzLjn2bru+V5O9RMjNgmCumKg==} - - '@zag-js/aria-hidden@1.40.0': - resolution: {integrity: sha512-lNWujEIlfGKwMQIcgfXuOZSsJD2avrgPsQHrXNVF9mkXygjLFcIRKz2pEexTSCqFh/HuUZJ6rG4pM/hJ/BiVCw==} - - '@zag-js/async-list@1.40.0': - resolution: {integrity: sha512-hLGUTtwRFl6FIdYxSIYSeLQjJeG4isKpdmGCUvtWNnKr7ayf1yAkkSwX10SdBMWOCldbtvKCZXumKvP6dDwNvw==} - - '@zag-js/auto-resize@1.40.0': - resolution: {integrity: sha512-eZC+AGKUip7UMu41/ApeT1wCIgn2fmo63FJeGAdMMD8E9M8M7QLsfISMIoieNNGBAYWhSyqELQ3jPgkUf6xReA==} - - '@zag-js/avatar@1.40.0': - resolution: {integrity: sha512-DayZDsNXbipT+1GUkX29tVhO4hZonDnidwE3SjEQv9Ic9vCdnwP95+B0FPEuaca03F5ZXFqVXjnPmRVbRMyDYQ==} - - '@zag-js/carousel@1.40.0': - resolution: {integrity: sha512-9svWc2jjvUP8iQ0afuu/ZAI75PuPLm4qB7h+10rmDrAgUPn7fwUBVzyATKubJPdtmaYQQvTTIiZU2B8mV88oGg==} - - '@zag-js/cascade-select@1.40.0': - resolution: {integrity: sha512-0fkE0Fd2VQ4QsaWXHdgQxHWiaef3UWW0l6Jd47frtMNnrvg5t5Xfqowa7c2S23hcduOUfz2WC0xEuGXnO4UVDQ==} - - '@zag-js/checkbox@1.40.0': - resolution: {integrity: sha512-oFCgnkOjrUDejB1wEp5s3cyJ+uFe/GoI3+wqNyckqOtcdKL1MBxy193GYVdj0LDfuCNrk8V0aIJGTdusCD2b4A==} - - '@zag-js/clipboard@1.40.0': - resolution: {integrity: sha512-QbFhJMwwUxTKcbWyb9ZrKgAp13U4+IzfHSLhPxbDVSQ15mIrjIkjW68gS6ElzhRDwGr1qawkZVApsqcToUqSaQ==} - - '@zag-js/collapsible@1.40.0': - resolution: {integrity: sha512-xDLY4j9D3gdoTirkwzMaCtelfCjnMhBzPyY6c/mh4oPvD3RB6dr3V3kI80i3yxHaUUeDCIUm/XAxK0InPsRBug==} - - '@zag-js/collection@1.40.0': - resolution: {integrity: sha512-+3o1nvbcA9Kz2hDDFf8Kngpd+of33S4TS5Tb9KvrHlU5ieQdvEUtc7/pWG2aCTkGpmgda+j91akB6ZB8+oVkvA==} - - '@zag-js/color-picker@1.40.0': - resolution: {integrity: sha512-lT93xd1BlNBbitl2RxST8ARYE6q/HZD5a0QhMIT1RbndB8F4e9j/NxkStgE9f0QqgpC/rO+nKHLoR+H1xs/EkA==} - - '@zag-js/color-utils@1.40.0': - resolution: {integrity: sha512-PZihcGheb5bn0/cEUwozjJjPoKkEwlJNpTA5mUxj/+sOElLaZM+zY2AnGYeMl6w5zIyZZUDoJMIT5rcb5sN87g==} - - '@zag-js/combobox@1.40.0': - resolution: {integrity: sha512-5IVCDrB8m7XrKBu28j7bIRE5KiyKJLPDZB3AJ+PLJyL69D+9z1anhLDmkUYcPseyCasszLKzIejby+kYQJgHlA==} - - '@zag-js/core@1.40.0': - resolution: {integrity: sha512-0YcqCh7TmhSonkbKM/7NWolxlaQgvvXgqedocW9oeRYiDJIpBZyRqnHPoGAS2XwbBPkCnrqSosxSF5yBjhZpgw==} - - '@zag-js/date-input@1.40.0': - resolution: {integrity: sha512-/VU8g3dugggC5xW2OJW1KONWzPkEbK/yLA0lPxymW/Uo0ixh2mKJUVTOTqDFWf1b0vzLX2XlYoLL+I2ryUyPvA==} - peerDependencies: - '@internationalized/date': '>=3.0.0' - - '@zag-js/date-picker@1.40.0': - resolution: {integrity: sha512-Nm3aSKn/5tGOZk8rIddLyBk+oeE0zr/ZsJuuTc3rysd04owVy1UhmUh6X9CqfTJtwTDpUZe+orHaIvKlE3Rd0w==} - peerDependencies: - '@internationalized/date': '>=3.0.0' - - '@zag-js/date-utils@1.40.0': - resolution: {integrity: sha512-nuB1QM3X7yY0k2JiZbHHm6wigY+Cl1QK6sRlh+C7mOyzEKnNEqNSVIqgSionCtWO6zAZh1R8Znp5ZeCdbbc27w==} - peerDependencies: - '@internationalized/date': '>=3.0.0' - - '@zag-js/dialog@1.40.0': - resolution: {integrity: sha512-1FHxR7/Kuu+9K2dxH7dKlSckCZ26n5ec79qWr0aMSSs2DF+ypQf5GUlaS6z2UqroZvIoJCvABVMm9OMko/qxlA==} - - '@zag-js/dismissable@1.40.0': - resolution: {integrity: sha512-bBkFvPg/zbYn31ZgEfx8not6s2Ekx7zU2sO8tGXb8rYPnHBfGDYEzVQansUStJn0Atzw+y7XR7B3G3u5AFQJKw==} - - '@zag-js/dom-query@1.40.0': - resolution: {integrity: sha512-4J3EO2gHpZ1VZiGLuMlH6G1Tsp4gKB8PPt2yKeNQWYGEXyrHUXrvMhRUzv7Z4/2I1s1tnxlFG4F8ovB3kTpz/Q==} - - '@zag-js/drawer@1.40.0': - resolution: {integrity: sha512-N2OR5ZYuTsWkYYmwsNgmL+wfuM3qUxB8GAfo53AWvOh07QUVz1Dvh1WP4km5L6Tkz4UBQZACu8T/ZLyeZ+PdWg==} - - '@zag-js/editable@1.40.0': - resolution: {integrity: sha512-X23wOg42BPvFWfJQi3yd8HiL8xtisrpL5ouFEzba56SQIxWZHDRpeWoqXqyLODq2/z2+SsZ0wV3laRD3ZH0C2g==} - - '@zag-js/file-upload@1.40.0': - resolution: {integrity: sha512-hUZlJYjSGk7SAflTmQIjZv6M+icujaHS6I+dik2LM48rLWwNa/GYTNx+uY4zJLd9oW1eEj+6NcCYZpPWzKku4Q==} - - '@zag-js/file-utils@1.40.0': - resolution: {integrity: sha512-BGny4rafiBQ5TPCBXfzbH7lSyFdnoix7brq/+FllKpDqpWPQz0tIsgSZueF/Z8GPTrAkwMKOFI99P7OVhAhRig==} - - '@zag-js/floating-panel@1.40.0': - resolution: {integrity: sha512-e2QXwapCbjLJnU+MAz06CoByj4XJ3sdSBgWF+PSe2X2T8dd/FkZUnaDPaX0yyfyTWKzBbyRRNyon2LMAs8ndHw==} - - '@zag-js/focus-trap@1.40.0': - resolution: {integrity: sha512-Q6W+DU7pix5rtRwoDnYzTYMkUV2kMWrFV0/EdNN3spFSvnUSkDWRmcNpzf+56AuCNeqsAZxaLJpsHLZkcT2xrw==} - - '@zag-js/focus-visible@1.40.0': - resolution: {integrity: sha512-63byl/kLVzDYlnHFma4HKEKrqB1Vx2zg0sBmUSENPyh+Ia1xhEVVC5vu6GX7nu4t/8QRy3Jn0q7T5og81FGb1A==} - - '@zag-js/highlight-word@1.40.0': - resolution: {integrity: sha512-+aeVn3S5NPG6Tk4Sanl0VZk/0atjnF7Xy7POPs1HD5SBui29/6i3vn3bUBNXJXrnhUoNrUhuySVYVhgkffcQ7w==} - - '@zag-js/hover-card@1.40.0': - resolution: {integrity: sha512-lkuLaikPLBIOnR0X75kSXdDYgv3ritAsn4TF1eGs12iYnZVX4PTL3J39tVNm9QrEXZ+iKcA1D2cUXNhEteCTyA==} - - '@zag-js/i18n-utils@1.40.0': - resolution: {integrity: sha512-8D3ki9V81gMKZvtRfNVoHCBDVYjr+WJLBvdfSv3cdOsVM2/E8//xAfYbYzl5Fdmeny3H71fxBNqOX05GN4K6OA==} - - '@zag-js/image-cropper@1.40.0': - resolution: {integrity: sha512-bpTCaiUXM0Mh6ddoJ1fA1B/YXp5Fc8LA0hg8CuEByDwGRVKPJ0KotL6QXMF6cEJZ1fcHF3Lcmpbj5Xotfkr4mA==} - - '@zag-js/interact-outside@1.40.0': - resolution: {integrity: sha512-Fws+O4uD9vS0I5KVcf3U2tNjLKvqlv+RExFbTywckDLOCJ145M/pMQWTr1FHil04jk5PFyM1iGfsbom8tozHpQ==} - - '@zag-js/json-tree-utils@1.40.0': - resolution: {integrity: sha512-7zEzU59Gz76nV7n3l70uMB5yAOOQMmt1PTAni6S97uw7/6KzPktsEWBcw7ocC4IIA42PKdT7akpq721H0vthbA==} - - '@zag-js/listbox@1.40.0': - resolution: {integrity: sha512-zB33y+dk6/e0ZTs3wun2KsuPaH/wygOuD8scnH2a2Y/W9a2P1rq503Kgm5d5kVXBKQLxOBwievWJ8Blajv8LnA==} - - '@zag-js/live-region@1.40.0': - resolution: {integrity: sha512-i1Dx02KGcQOAZGNhkFe8kz26gYJcn7KsT/M1UovjS9RTbl9diY8ShiyfIAhqruoaHQyqsHMRh/f7Idu45HdiDA==} - - '@zag-js/marquee@1.40.0': - resolution: {integrity: sha512-XfvAwSNYXV3fEIRc44a9sAsoJoLKt+CWbpSPgQBpiFPpWh0rZ8frUZCslevTzBB3ifIWoSg+svDHQOGsDa8wGA==} - - '@zag-js/menu@1.40.0': - resolution: {integrity: sha512-FRBqwsOjxBi0eSwqwrOw2td1rd0Xxl0f41J2lGc8E7z+2PabbBcJ/poqSiEn8YoaCT4mAWNjt4QQU/Pe1bRJ/g==} - - '@zag-js/navigation-menu@1.40.0': - resolution: {integrity: sha512-aJkEGYH8P9NfsQOjxMzxuF4YrrV2N1GQj6Y5Ow19MKuLh42o35bUhwoGsYjFbxgEcImabINtZJqtAPAkOdJXmQ==} - - '@zag-js/number-input@1.40.0': - resolution: {integrity: sha512-WffdeqSOpsKmgPzBkNZl9nAolQPlyl9dIabaPguGgXdYtZW/OGCGj8jCYqyEu4VL3kDPPVVQRWEqC/XzwzVCRg==} - - '@zag-js/pagination@1.40.0': - resolution: {integrity: sha512-Ykotky0A/7rswb6BfOD9aXL1EssKwUYfBRbdWGe52uhVc7dGagMSTUDRVeNhVsP/MEdtwqys7urvDbAlEqq+GA==} - - '@zag-js/password-input@1.40.0': - resolution: {integrity: sha512-mD4tbA4m82oV+0NbJ+P00Q4Gwz+zf1kZEZ3Z48ohICfK/WO1KhCgviY7vu/7bCMnRiD3dbi+nEeym8Kb29wRHw==} - - '@zag-js/pin-input@1.40.0': - resolution: {integrity: sha512-iJIXDJC+9DUx+A3sRdTmHV7vPZXCw9O6le3R0lKf/8kQOgj7FKjbVw2SkUMAoOZ0u5J7Zwg2oZc7ddt1pwUk9w==} - - '@zag-js/popover@1.40.0': - resolution: {integrity: sha512-bjvOep1YNlsvIYGh/rPsFCHjH2cCt2aKsVLyRvzTT1jhGZJvBdQKQBJjSuG5Nh4y1PUqtrrz69ZMWRrJGQ3rNg==} - - '@zag-js/popper@1.40.0': - resolution: {integrity: sha512-rCkgqgwlpgMwcnuSVrZK2xXl1Mvptpuw3cZy6rC2C5F3yE1GmWohdts5VkeQNro+sd/xHTdVovOqY6cU9Htj1w==} - - '@zag-js/presence@1.40.0': - resolution: {integrity: sha512-P0bAuzEIDuMglE1xfmW5xTuSBlWjNZ8nOGXoIksKOKb+b+jy2Vys6WjZjKipV/jop4u85wfzKchcPc3C+cXuog==} - - '@zag-js/progress@1.40.0': - resolution: {integrity: sha512-V61a5CHEs8suevQVS+/1ENj1RDVYNOUUTawK6uriCA6Ol59xe30DmF+eV6Y9miM7L/pN3YjZRq9uEDJMXXK32g==} - - '@zag-js/qr-code@1.40.0': - resolution: {integrity: sha512-xD37tVrQ46CeqVLqkSm61kURoJ4Z/uOFcB8z7Hu3UX+1OFTfkhgrns6iLUneoRjO3hsqQaTaVkxVOQeLYWb+wA==} - - '@zag-js/radio-group@1.40.0': - resolution: {integrity: sha512-sFJCdyOKzQC9hylSP19R71yv44by/C78D9EHfsxQJtvOgDv9E+h13NNX4n9wWyubC20xftlxkja8sNT5NfJKUw==} - - '@zag-js/rating-group@1.40.0': - resolution: {integrity: sha512-UMBI3xAMcm7otpAczMGPEA7jC1hvV8NhnZ4mN3oftJB0bc1winoXxJdCkrXN58TTNWrGNSRzjtm048G+HPCdpw==} - - '@zag-js/react@1.40.0': - resolution: {integrity: sha512-2TFS1HYABYGc0lurC+4WEXvKkpxsVv6vKm+t8QAL7wfoeZnw6HDQWLc91kINp89vln+A2kwCfYqIq8HSm+9EeA==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - '@zag-js/rect-utils@1.40.0': - resolution: {integrity: sha512-ikgLuE4rLlACm4mGLp6Ga8sJA44uFwohA1nVmb95sQ+VIyx2naf91CEF7SMrZVEwFKHaHpxdKVQSZLRjJqO/dw==} - - '@zag-js/remove-scroll@1.40.0': - resolution: {integrity: sha512-f6EgODnJMRtkbgdJCgyllND8jui+RtPrCZy6JYhhOg7KQ+bFfV36KzWQMty38ZdOyrh23UUO7MJ3WGcFXPvk3g==} - - '@zag-js/scroll-area@1.40.0': - resolution: {integrity: sha512-7EtWETRIn8dY7xqAeMOlnEuzhOrtc65mN/0YvT3XYcBz/CzmHzyZTmos3UXBJGnKHSGj61aEpP9g3RK+x/w63A==} - - '@zag-js/scroll-snap@1.40.0': - resolution: {integrity: sha512-XtjeOd+pwGX0+K7NvsQncrKwV8CTSzHfVVJrdQ+MweiWBpGNeAh43ySN4L+KSTgtnUiZbuwBIxlKK0tX+WupgQ==} - - '@zag-js/select@1.40.0': - resolution: {integrity: sha512-auMI9SvocVvKHNWF2DobyQN6+1k3OO6UsQTdkofvbHxX7maosy8ZXA6k1r9Ndt4qLUu7CbdAAQ+qJ4VkgJyvxA==} - - '@zag-js/signature-pad@1.40.0': - resolution: {integrity: sha512-L0LTxcpdckaGdDDXcQCr4AG+J9xUHH+lsenH7NG4ZI7rSr4nRmHMdDH0GR7nBa6MMdPIIimjWIE/TwZ1OuHzCQ==} - - '@zag-js/slider@1.40.0': - resolution: {integrity: sha512-xZGycm+ghGFG3kTYq8g0t1Av1moxg45WiFz5E3bRgP7YU9beSTaFZI8h6f65NiC5P3YuwA0RoYxA46GH22qoZg==} - - '@zag-js/splitter@1.40.0': - resolution: {integrity: sha512-64KNKwlIjyUIjp7i/whDCpREiSFrNI/cF7MpBJvBGRPUWq8NpNxMGKWD+vBCV+JC61QF9xg/NgNoigFycS9sYw==} - - '@zag-js/steps@1.40.0': - resolution: {integrity: sha512-5sVFzcIYubCn1nJSQIx9WWNlJuFoOJMpkD/ZMwNp0LzpnmnspsCOmdnQUWEftMQ1KdwZ+qNgfo/+kHclb9cBjg==} - - '@zag-js/store@1.40.0': - resolution: {integrity: sha512-EmgYIdbNZ4TN4Qht/jugY4UVkaWx69l8P1qiX23U4YwqNLq10tyOJmcXWbvsrprU1dGb24B+xq0WBm/RIjw4WA==} - - '@zag-js/switch@1.40.0': - resolution: {integrity: sha512-hUH3AF79ndSFZxt7Plw7mVZV0QlM0kFqKwrAGBEOE77P3rKpOsMJ3wWgMb3w6nwlxGQsbwmMgAFvYUslLpM4Lg==} - - '@zag-js/tabs@1.40.0': - resolution: {integrity: sha512-xqfPC2nQ6Bn4nqy1L+1CVcQcg/Z7K2q753OvsX2C8Wtu+7tF//HyMbOpF6fGikqlLkUzCkvjkqDjdOXcfWN9ZQ==} - - '@zag-js/tags-input@1.40.0': - resolution: {integrity: sha512-3cB7nPlUvzZNZwQw5AaTuxwcRn1n2qkDCjLEb2NEwtmI+YxHbK3k1MtXjTccjcYjU8cAkv+jaeyZPs6KFKQcHA==} - - '@zag-js/timer@1.40.0': - resolution: {integrity: sha512-Rvet226fhUtZnItjHpUYV7MH0uEFZfXT9PSRrX5jdiU4/P0eWKbirwi//AVeqcWFexXvw6ajYSfQN7EVyr2x4w==} - - '@zag-js/toast@1.40.0': - resolution: {integrity: sha512-EDH43zdiH4Bz30cE6YI9g//qXGOOfWObM3dFLG8I0q/cJRf7/6jO82rwZAHPwfOSfKhUDxStirD8F6eoY6BWXA==} - - '@zag-js/toggle-group@1.40.0': - resolution: {integrity: sha512-+JKcnfEbdQnr5p7uRvYLdivhUsM6iio71UC10tK74nXYRnYm0/Uvxg3oQzvbNTq9WdcU/DIh3gZVZ2Vex9nBnQ==} - - '@zag-js/toggle@1.40.0': - resolution: {integrity: sha512-DW7682lzTP2eDlMvrS7tUX3zAm7ufrrKr7VDiX8BB6oXBRETXrVIxCYNuoIdqjwXebdjAoxaCiUZEreRVucYQg==} - - '@zag-js/tooltip@1.40.0': - resolution: {integrity: sha512-pyrvit+nB8dIwVNTGBRlHPsh7yMJGAxxM1zfY7HOTJqF+n6+6xYTQ4gQ/Ocy1Q7I5kO88+m16naEh0qLFiTZww==} - - '@zag-js/tour@1.40.0': - resolution: {integrity: sha512-VczYGFQM9xsSbfy5N0NP91GdKxbYvfPCDAguD+WQSs1umEIgAAozSKPUdV3NNCX5Pq6B1F3dBxi6gYPdNqrAHg==} - - '@zag-js/tree-view@1.40.0': - resolution: {integrity: sha512-v/20ekjbM+HXDEkpHAz6k8WpoZRmZmdCApDIkIgXVHPRQk+kwAiiIPY20ZDG+DjRu7Lh0MUdQavdZtGj6Ihwkw==} - - '@zag-js/types@1.40.0': - resolution: {integrity: sha512-LVvxEyqFv/u9SEe5xdivvG2vYb9cCmbkD+5r6s+IGljpDLaRgv4BYyxEh40ri1ai070tL08ZKmoLfx2/xfvY/A==} - - '@zag-js/utils@1.40.0': - resolution: {integrity: sha512-XUpqDtXfHe7CySjOhLPLj9H8rxbiFUJAGgmBzNdpsGPP4wx12cpOXrpSjRXZ2kMwooMPz/P7RPDBteto8sqhAQ==} - - '@zxing/text-encoding@0.9.0': - resolution: {integrity: sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==} - JSONStream@1.3.5: resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} hasBin: true @@ -3947,25 +1896,10 @@ packages: abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} - abort-controller@3.0.0: - resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} - engines: {node: '>=6.5'} - - abs-svg-path@0.1.1: - resolution: {integrity: sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA==} - - accepts@1.3.8: - resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} - engines: {node: '>= 0.6'} - accepts@2.0.0: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} - acorn-dynamic-import@2.0.2: - resolution: {integrity: sha512-GKp5tQ8h0KMPWIYGRHHXI1s5tUpZixZ3IHF2jAu42wSCf6In/G873s6/y4DdKdhWvzhu1T6mE1JgvnhAKqyYYQ==} - deprecated: This is probably built in to whatever tool you're using. If you still need it... idk - acorn-import-phases@1.0.4: resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} engines: {node: '>=10.13.0'} @@ -3981,25 +1915,11 @@ packages: resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==} engines: {node: '>=0.4.0'} - acorn@4.0.13: - resolution: {integrity: sha512-fu2ygVGuMmlzG8ZeRJ0bvR41nsAkxxhbyk8bZ1SS521Z7vmgJFTQQlfz/Mp/nJexGBz+v8sC9bM6+lNgskt4Ug==} - engines: {node: '>=0.4.0'} - hasBin: true - - acorn@5.7.4: - resolution: {integrity: sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==} - engines: {node: '>=0.4.0'} - hasBin: true - acorn@8.16.0: resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} hasBin: true - adler-32@1.3.1: - resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==} - engines: {node: '>=0.8'} - agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} @@ -4043,70 +1963,10 @@ packages: ajv@8.20.0: resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} - align-text@0.1.4: - resolution: {integrity: sha512-GrTZLRpmp6wIC2ztrWW9MjjTgSKccffgFagbNDOX95/dcjEcYZibYTeaOntySQLcdw1ztBoFkviiUvTMbb9MYg==} - engines: {node: '>=0.10.0'} - - ansi-bgblack@0.1.1: - resolution: {integrity: sha512-tp8M/NCmSr6/skdteeo9UgJ2G1rG88X3ZVNZWXUxFw4Wh0PAGaAAWQS61sfBt/1QNcwMTY3EBKOMPujwioJLaw==} - engines: {node: '>=0.10.0'} - - ansi-bgblue@0.1.1: - resolution: {integrity: sha512-R8JmX2Xv3+ichUQE99oL+LvjsyK+CDWo/BtVb4QUz3hOfmf2bdEmiDot3fQcpn2WAHW3toSRdjSLm6bgtWRDlA==} - engines: {node: '>=0.10.0'} - - ansi-bgcyan@0.1.1: - resolution: {integrity: sha512-6SByK9q2H978bmqzuzA5NPT1lRDXl3ODLz/DjC4URO5f/HqK7dnRKfoO/xQLx/makOz7zWIbRf6+Uf7bmaPSkQ==} - engines: {node: '>=0.10.0'} - - ansi-bggreen@0.1.1: - resolution: {integrity: sha512-8TRtOKmIPOuxjpklrkhUbqD2NnVb4WZQuIjXrT+TGKFKzl7NrL7wuNvEap3leMt2kQaCngIN1ZzazSbJNzF+Aw==} - engines: {node: '>=0.10.0'} - - ansi-bgmagenta@0.1.1: - resolution: {integrity: sha512-UZYhobiGAlV4NiwOlKAKbkCyxOl1PPZNvdIdl/Ce5by45vwiyNdBetwHk/AjIpo1Ji9z+eE29PUBAjjfVmz5SA==} - engines: {node: '>=0.10.0'} - - ansi-bgred@0.1.1: - resolution: {integrity: sha512-BpPHMnYmRBhcjY5knRWKjQmPDPvYU7wrgBSW34xj7JCH9+a/SEIV7+oSYVOgMFopRIadOz9Qm4zIy+mEBvUOPA==} - engines: {node: '>=0.10.0'} - - ansi-bgwhite@0.1.1: - resolution: {integrity: sha512-KIF19t+HOYOorUnHTOhZpeZ3bJsjzStBG2hSGM0WZ8YQQe4c7lj9CtwnucscJDPrNwfdz6GBF+pFkVfvHBq6uw==} - engines: {node: '>=0.10.0'} - - ansi-bgyellow@0.1.1: - resolution: {integrity: sha512-WyRoOFSIvOeM7e7YdlSjfAV82Z6K1+VUVbygIQ7C/VGzWYuO/d30F0PG7oXeo4uSvSywR0ozixDQvtXJEorq4Q==} - engines: {node: '>=0.10.0'} - - ansi-black@0.1.1: - resolution: {integrity: sha512-hl7re02lWus7lFOUG6zexhoF5gssAfG5whyr/fOWK9hxNjUFLTjhbU/b4UHWOh2dbJu9/STSUv+80uWYzYkbTQ==} - engines: {node: '>=0.10.0'} - - ansi-blue@0.1.1: - resolution: {integrity: sha512-8Um59dYNDdQyoczlf49RgWLzYgC2H/28W3JAIyOAU/+WkMcfZmaznm+0i1ikrE0jME6Ypk9CJ9CY2+vxbPs7Fg==} - engines: {node: '>=0.10.0'} - - ansi-bold@0.1.1: - resolution: {integrity: sha512-wWKwcViX1E28U6FohtWOP4sHFyArELHJ2p7+3BzbibqJiuISeskq6t7JnrLisUngMF5zMhgmXVw8Equjzz9OlA==} - engines: {node: '>=0.10.0'} - - ansi-colors@0.2.0: - resolution: {integrity: sha512-ScRNUT0TovnYw6+Xo3iKh6G+VXDw2Ds7ZRnMIuKBgHY02DgvT2T2K22/tc/916Fi0W/5Z1RzDaHQwnp75hqdbA==} - engines: {node: '>=0.10.0'} - ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} - ansi-cyan@0.1.1: - resolution: {integrity: sha512-eCjan3AVo/SxZ0/MyIYRtkpxIu/H3xZN7URr1vXVrISxeyz8fUFz0FJziamK4sS8I+t35y4rHg1b2PklyBe/7A==} - engines: {node: '>=0.10.0'} - - ansi-dim@0.1.1: - resolution: {integrity: sha512-zAfb1fokXsq4BoZBkL0eK+6MfFctbzX3R4UMcoWrL1n2WHewFKentTvOZv2P11u6P4NtW/V47hVjaN7fJiefOg==} - engines: {node: '>=0.10.0'} - ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} @@ -4115,51 +1975,6 @@ packages: resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} engines: {node: '>=18'} - ansi-gray@0.1.1: - resolution: {integrity: sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==} - engines: {node: '>=0.10.0'} - - ansi-green@0.1.1: - resolution: {integrity: sha512-WJ70OI4jCaMy52vGa/ypFSKFb/TrYNPaQ2xco5nUwE0C5H8piume/uAZNNdXXiMQ6DbRmiE7l8oNBHu05ZKkrw==} - engines: {node: '>=0.10.0'} - - ansi-grey@0.1.1: - resolution: {integrity: sha512-+J1nM4lC+whSvf3T4jsp1KR+C63lypb+VkkwtLQMc1Dlt+nOvdZpFT0wwFTYoSlSwCcLUAaOpHF6kPkYpSa24A==} - engines: {node: '>=0.10.0'} - - ansi-hidden@0.1.1: - resolution: {integrity: sha512-8gB1bo9ym9qZ/Obvrse1flRsfp2RE+40B23DhQcKxY+GSeaOJblLnzBOxzvmLTWbi5jNON3as7wd9rC0fNK73Q==} - engines: {node: '>=0.10.0'} - - ansi-html@0.0.7: - resolution: {integrity: sha512-JoAxEa1DfP9m2xfB/y2r/aKcwXNlltr4+0QSBC4TrLfcxyvepX2Pv0t/xpgGV5bGsDzCYV8SzjWgyCW0T9yYbA==} - engines: {'0': node >= 0.8.0} - hasBin: true - - ansi-inverse@0.1.1: - resolution: {integrity: sha512-Kq8Z0dBRhQhDMN/Rso1Nu9niwiTsRkJncfJZXiyj7ApbfJrGrrubHXqXI37feJZkYcIx6SlTBdNCeK0OQ6X6ag==} - engines: {node: '>=0.10.0'} - - ansi-italic@0.1.1: - resolution: {integrity: sha512-jreCxifSAqbaBvcibeQxcwhQDbEj7gF69XnpA6x83qbECEBaRBD1epqskrmov1z4B+zzQuEdwbWxgzvhKa+PkA==} - engines: {node: '>=0.10.0'} - - ansi-magenta@0.1.1: - resolution: {integrity: sha512-A1Giu+HRwyWuiXKyXPw2AhG1yWZjNHWO+5mpt+P+VWYkmGRpLPry0O5gmlJQEvpjNpl4RjFV7DJQ4iozWOmkbQ==} - engines: {node: '>=0.10.0'} - - ansi-red@0.1.1: - resolution: {integrity: sha512-ewaIr5y+9CUTGFwZfpECUbFlGcC0GCw1oqR9RI6h1gQCd9Aj2GxSckCnPsVJnmfMZbwFYE+leZGASgkWl06Jow==} - engines: {node: '>=0.10.0'} - - ansi-regex@2.1.1: - resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} - engines: {node: '>=0.10.0'} - - ansi-regex@3.0.1: - resolution: {integrity: sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==} - engines: {node: '>=4'} - ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -4168,14 +1983,6 @@ packages: resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} - ansi-reset@0.1.1: - resolution: {integrity: sha512-n+D0qD3B+h/lP0dSwXX1SZMoXufdUVotLMwUuvXa50LtBAh3f+WV8b5nFMfLL/hgoPBUt+rG/pqqzF8krlZKcw==} - engines: {node: '>=0.10.0'} - - ansi-strikethrough@0.1.1: - resolution: {integrity: sha512-gWkLPDvHH2pC9YEKqp8dIl0mg3sRglMPvioqGDIOXiwxjxUwIJ1gF86E2o4R5yLNh8IAkwHbaMtASkJfkQ2hIA==} - engines: {node: '>=0.10.0'} - ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -4188,22 +1995,6 @@ packages: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} - ansi-underline@0.1.1: - resolution: {integrity: sha512-D+Bzwio/0/a0Fu5vJzrIT6bFk43TW46vXfSvzysOTEHcXOAUJTVMHWDbELIzGU4AVxVw2rCTb7YyWS4my2cSKQ==} - engines: {node: '>=0.10.0'} - - ansi-white@0.1.1: - resolution: {integrity: sha512-DJHaF2SRzBb9wZBgqIJNjjTa7JUJTO98sHeTS1sDopyKKRopL1KpaJ20R6W2f/ZGras8bYyIZDtNwYOVXNgNFg==} - engines: {node: '>=0.10.0'} - - ansi-wrap@0.1.0: - resolution: {integrity: sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==} - engines: {node: '>=0.10.0'} - - ansi-yellow@0.1.1: - resolution: {integrity: sha512-6E3D4BQLXHLl3c/NwirWVZ+BCkMq2qsYxdeAGGOijKrx09FaqU+HktFL6QwAwNvgJiMLnv6AQ2C1gFZx0h1CBg==} - engines: {node: '>=0.10.0'} - ansis@4.2.0: resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} engines: {node: '>=14'} @@ -4215,9 +2006,6 @@ packages: any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - anymatch@2.0.0: - resolution: {integrity: sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==} - anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -4232,18 +2020,6 @@ packages: aproba@2.1.0: resolution: {integrity: sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==} - archiver-utils@2.1.0: - resolution: {integrity: sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==} - engines: {node: '>= 6'} - - archiver-utils@3.0.4: - resolution: {integrity: sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==} - engines: {node: '>= 10'} - - archiver@5.3.2: - resolution: {integrity: sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==} - engines: {node: '>= 10'} - are-we-there-yet@2.0.0: resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} engines: {node: '>=10'} @@ -4255,46 +2031,16 @@ packages: arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} - argon2@0.43.1: - resolution: {integrity: sha512-TfOzvDWUaQPurCT1hOwIeFNkgrAJDpbBGBGWDgzDsm11nNhImc13WhdGdCU6K7brkp8VpeY07oGtSex0Wmhg8w==} - engines: {node: '>=16.17.0'} - argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - aria-hidden@1.2.6: - resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} - engines: {node: '>=10'} - - arr-diff@4.0.0: - resolution: {integrity: sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==} - engines: {node: '>=0.10.0'} - - arr-flatten@1.1.0: - resolution: {integrity: sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==} - engines: {node: '>=0.10.0'} - - arr-union@3.1.0: - resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==} - engines: {node: '>=0.10.0'} - array-buffer-byte-length@1.0.2: resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} engines: {node: '>= 0.4'} - array-find-index@1.0.2: - resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==} - engines: {node: '>=0.10.0'} - - array-flatten@1.1.1: - resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - - array-flatten@2.1.2: - resolution: {integrity: sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==} - array-ify@1.0.0: resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} @@ -4302,25 +2048,9 @@ packages: resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} engines: {node: '>= 0.4'} - array-sort@0.1.4: - resolution: {integrity: sha512-BNcM+RXxndPxiZ2rd76k6nyQLRZr2/B/sdi8pQ+Joafr5AH279L40dfokSUTp8O+AaqYjXWhblBWa2st2nc4fQ==} - engines: {node: '>=0.10.0'} - array-timsort@1.0.3: resolution: {integrity: sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==} - array-union@1.0.2: - resolution: {integrity: sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==} - engines: {node: '>=0.10.0'} - - array-uniq@1.0.3: - resolution: {integrity: sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==} - engines: {node: '>=0.10.0'} - - array-unique@0.3.2: - resolution: {integrity: sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==} - engines: {node: '>=0.10.0'} - array.prototype.findlast@1.2.5: resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} engines: {node: '>= 0.4'} @@ -4348,55 +2078,17 @@ packages: asap@2.0.6: resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} - asn1.js@4.10.1: - resolution: {integrity: sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==} - - asn1@0.2.6: - resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} - - assert-plus@1.0.0: - resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} - engines: {node: '>=0.8'} - - assert@1.5.1: - resolution: {integrity: sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==} - assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - assign-symbols@1.0.0: - resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==} - engines: {node: '>=0.10.0'} - - async-each@1.0.6: - resolution: {integrity: sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==} - async-function@1.0.0: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} - async@2.6.4: - resolution: {integrity: sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==} - - async@3.2.6: - resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} - asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - atob@2.1.2: - resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} - engines: {node: '>= 4.5.0'} - hasBin: true - - attr-accept@2.2.5: - resolution: {integrity: sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==} - engines: {node: '>=4'} - - autolinker@0.28.1: - resolution: {integrity: sha512-zQAFO1Dlsn69eXaO6+7YZc+v84aquQKbwpzCE3L0stj56ERn9hutFxPopViLjo9G+rWwjozRhgS5KJ25Xy19cQ==} - autoprefixer@10.5.0: resolution: {integrity: sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==} engines: {node: ^10 || ^12 || >=14} @@ -4408,11 +2100,9 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - aws-sign2@0.7.0: - resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} - - aws4@1.13.2: - resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} + aws-ssl-profiles@1.1.2: + resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} + engines: {node: '>= 6.0.0'} axios@1.16.0: resolution: {integrity: sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==} @@ -4453,92 +2143,29 @@ packages: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} - base64-arraybuffer@1.0.2: - resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==} - engines: {node: '>= 0.6.0'} - - base64-js@0.0.8: - resolution: {integrity: sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==} - engines: {node: '>= 0.4'} - base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - base@0.11.2: - resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==} - engines: {node: '>=0.10.0'} - baseline-browser-mapping@2.10.29: resolution: {integrity: sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ==} engines: {node: '>=6.0.0'} hasBin: true - batch@0.6.1: - resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} - - bcrypt-pbkdf@1.0.2: - resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} - bcrypt@5.1.1: resolution: {integrity: sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==} engines: {node: '>= 10.0.0'} - bidi-js@1.0.3: - resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} - - big-integer@1.6.52: - resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} - engines: {node: '>=0.6'} - - big.js@5.2.2: - resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} - - binary-extensions@1.13.1: - resolution: {integrity: sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==} - engines: {node: '>=0.10.0'} - binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} - binary@0.3.0: - resolution: {integrity: sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==} - - bindings@1.5.0: - resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - block-stream2@2.1.0: - resolution: {integrity: sha512-suhjmLI57Ewpmq00qaygS8UgEq2ly2PCItenIyhMqVjo4t4pGzqMvfgJuX8iWTeSDdfSSqS6j38fL4ToNL7Pfg==} - - bluebird@3.4.7: - resolution: {integrity: sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==} - - bmp-js@0.1.0: - resolution: {integrity: sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==} - - bn.js@4.12.3: - resolution: {integrity: sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==} - - bn.js@5.2.3: - resolution: {integrity: sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==} - - body-parser@1.20.5: - resolution: {integrity: sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - body-parser@2.2.2: resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} engines: {node: '>=18'} - bonjour@3.5.1: - resolution: {integrity: sha512-xONzj4PfpPJw6xSqCcT2SmQkBOXpUINUz3o3qXcWJwYlXbkZNcNaUae0o5lle7tKt4HHV6dTgkIRhAXZ3nBMsQ==} - - boolbase@1.0.0: - resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - brace-expansion@1.1.14: resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} @@ -4549,43 +2176,10 @@ packages: resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} engines: {node: 18 || 20 || >=22} - braces@2.3.2: - resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==} - engines: {node: '>=0.10.0'} - braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - brorand@1.1.0: - resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} - - brotli@1.3.3: - resolution: {integrity: sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==} - - browser-or-node@2.1.1: - resolution: {integrity: sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg==} - - browserify-aes@1.2.0: - resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} - - browserify-cipher@1.0.1: - resolution: {integrity: sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==} - - browserify-des@1.0.2: - resolution: {integrity: sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==} - - browserify-rsa@4.1.1: - resolution: {integrity: sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==} - engines: {node: '>= 0.10'} - - browserify-sign@4.2.5: - resolution: {integrity: sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==} - engines: {node: '>= 0.10'} - - browserify-zlib@0.2.0: - resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==} - browserslist@4.28.2: resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -4598,41 +2192,18 @@ packages: bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} - buffer-crc32@0.2.13: - resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} - buffer-equal-constant-time@1.0.1: resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - buffer-indexof-polyfill@1.0.2: - resolution: {integrity: sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==} - engines: {node: '>=0.10'} - - buffer-indexof@1.1.1: - resolution: {integrity: sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==} - - buffer-xor@1.0.3: - resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} - - buffer@4.9.2: - resolution: {integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==} - buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - buffers@0.1.1: - resolution: {integrity: sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==} - engines: {node: '>=0.2.0'} - - builtin-status-codes@3.0.0: - resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} - busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} @@ -4641,14 +2212,18 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} + c12@3.1.0: + resolution: {integrity: sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==} + peerDependencies: + magicast: ^0.3.5 + peerDependenciesMeta: + magicast: + optional: true + cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} - cache-base@1.0.1: - resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} - engines: {node: '>=0.10.0'} - call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -4669,26 +2244,6 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - camelcase-keys@2.1.0: - resolution: {integrity: sha512-bA/Z/DERHKqoEOrp+qeGKw1QlvEQkGZSc0XaY6VnTxZr+Kv1G5zFwttpjv8qxZ/sBPT4nthwZaAcsAZTJlSKXQ==} - engines: {node: '>=0.10.0'} - - camelcase@1.2.1: - resolution: {integrity: sha512-wzLkDa4K/mzI1OSITC+DUyjgIl/ETNHE9QvYgy6J6Jvqyyz4C0Xfd+lQhb19sX2jMpZV4IssUn0VDVmglV+s4g==} - engines: {node: '>=0.10.0'} - - camelcase@2.1.1: - resolution: {integrity: sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==} - engines: {node: '>=0.10.0'} - - camelcase@3.0.0: - resolution: {integrity: sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==} - engines: {node: '>=0.10.0'} - - camelcase@4.1.0: - resolution: {integrity: sha512-FxAv7HpHrXbh3aPo4o2qxHay2lkLY3x5Mw3KeE4KQE8ysVfziWeRZDwcjauvwBSGEC/nXUPzZy8zeh4HokqOnw==} - engines: {node: '>=4'} - camelcase@5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} @@ -4704,28 +2259,10 @@ packages: resolution: {integrity: sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==} engines: {node: '>=6'} - canvg@3.0.11: - resolution: {integrity: sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==} - engines: {node: '>=10.0.0'} - - caseless@0.12.0: - resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} - - center-align@0.1.3: - resolution: {integrity: sha512-Baz3aNe2gd2LP2qk5U+sDk/m4oSuwSDcBfayTCTBoWpfIGO5XFxPmjILQII4NGiZjD6DoDI6kf7gKaxkf7s3VQ==} - engines: {node: '>=0.10.0'} - - cfb@1.2.2: - resolution: {integrity: sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==} - engines: {node: '>=0.8'} - chai@5.3.3: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} engines: {node: '>=18'} - chainsaw@0.1.0: - resolution: {integrity: sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==} - chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -4734,9 +2271,6 @@ packages: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - change-case@5.4.4: - resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} - char-regex@1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} @@ -4748,9 +2282,6 @@ packages: resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} engines: {node: '>= 16'} - chokidar@2.1.8: - resolution: {integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==} - chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -4771,9 +2302,11 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} - cipher-base@1.0.7: - resolution: {integrity: sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==} - engines: {node: '>= 0.10'} + citty@0.1.6: + resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + + citty@0.2.2: + resolution: {integrity: sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==} cjs-module-lexer@1.4.3: resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} @@ -4781,16 +2314,9 @@ packages: class-transformer@0.5.1: resolution: {integrity: sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==} - class-utils@0.3.6: - resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==} - engines: {node: '>=0.10.0'} - class-validator@0.14.4: resolution: {integrity: sha512-AwNusCCam51q703dW82x95tOqQp6oC9HNUl724KxJJOfnKscI8dOloXFgyez7LbTTKWuRBA37FScqVbJEoq8Yw==} - class-variance-authority@0.7.1: - resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} - cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -4815,12 +2341,6 @@ packages: resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} engines: {node: '>= 12'} - cliui@2.1.0: - resolution: {integrity: sha512-GIOYRizG+TGoc7Wgc1LiOTLare95R3mzKgoln+Q/lE4ceiYH19gUpl0l0Ffq4lJDEf3FxujMe6IBfOCs7pfqNA==} - - cliui@3.2.0: - resolution: {integrity: sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==} - cliui@6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} @@ -4828,47 +2348,21 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} - cliui@9.0.1: - resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} - engines: {node: '>=20'} - clone@1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} - clone@2.1.2: - resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} - engines: {node: '>=0.8'} - clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} - cmdk@1.1.1: - resolution: {integrity: sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - co@4.6.0: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} - code-point-at@1.1.0: - resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==} - engines: {node: '>=0.10.0'} - - codepage@1.15.0: - resolution: {integrity: sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==} - engines: {node: '>=0.8'} - collect-v8-coverage@1.0.3: resolution: {integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==} - collection-visit@1.0.0: - resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==} - engines: {node: '>=0.10.0'} - color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -4876,14 +2370,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color-name@2.1.0: - resolution: {integrity: sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==} - engines: {node: '>=12.20'} - - color-string@2.1.4: - resolution: {integrity: sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==} - engines: {node: '>=18'} - color-support@1.1.3: resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} hasBin: true @@ -4916,18 +2402,6 @@ packages: component-emitter@1.3.1: resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} - compress-commons@4.1.2: - resolution: {integrity: sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==} - engines: {node: '>= 10'} - - compressible@2.0.18: - resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} - engines: {node: '>= 0.6'} - - compression@1.8.1: - resolution: {integrity: sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==} - engines: {node: '>= 0.8.0'} - concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -4935,30 +2409,16 @@ packages: resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} engines: {'0': node >= 6.0} - concat-with-sourcemaps@1.1.0: - resolution: {integrity: sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==} - - connect-history-api-fallback@1.6.0: - resolution: {integrity: sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==} - engines: {node: '>=0.8'} + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} consola@3.4.2: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} - console-browserify@1.2.0: - resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==} - console-control-strings@1.1.0: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} - constants-browserify@1.0.0: - resolution: {integrity: sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==} - - content-disposition@0.5.4: - resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} - engines: {node: '>= 0.6'} - content-disposition@1.1.0: resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} engines: {node: '>=18'} @@ -4980,15 +2440,9 @@ packages: engines: {node: '>=16'} hasBin: true - convert-source-map@1.9.0: - resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} - convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - cookie-signature@1.0.7: - resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==} - cookie-signature@1.2.2: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} engines: {node: '>=6.6.0'} @@ -4997,26 +2451,9 @@ packages: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} - cookie@1.1.1: - resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} - engines: {node: '>=18'} - cookiejar@2.1.4: resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==} - copy-descriptor@0.1.1: - resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==} - engines: {node: '>=0.10.0'} - - core-js@3.49.0: - resolution: {integrity: sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==} - - core-util-is@1.0.2: - resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} - - core-util-is@1.0.3: - resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - cors@2.8.6: resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} engines: {node: '>= 0.10'} @@ -5051,28 +2488,6 @@ packages: typescript: optional: true - crc-32@1.2.2: - resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} - engines: {node: '>=0.8'} - hasBin: true - - crc32-stream@4.0.3: - resolution: {integrity: sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==} - engines: {node: '>= 10'} - - create-ecdh@4.0.4: - resolution: {integrity: sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==} - - create-frame@1.0.0: - resolution: {integrity: sha512-SnJYqAwa5Jon3cP8e3LMFBoRG2m/hX20vtOnC3ynhyAa6jmy+BqrPoicBtmKUutnJuphXPj7C54yOXF58Tl71Q==} - engines: {node: '>=0.10.0'} - - create-hash@1.2.0: - resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} - - create-hmac@1.1.7: - resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} - create-jest@29.7.0: resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -5085,31 +2500,10 @@ packages: resolution: {integrity: sha512-fkdfq+b+AHI4cKdhZlppHveI/mgz2qpiYxcm+t5E5TsxX7QrLS1VE0+7GENEk9z0EeGPcpSciGv6ez24duWhwQ==} engines: {node: '>=18.x'} - cross-spawn@5.1.0: - resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==} - cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - crypto-browserify@3.12.1: - resolution: {integrity: sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==} - engines: {node: '>= 0.10'} - - css-line-break@2.1.0: - resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==} - - css-select@5.2.2: - resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} - - css-tree@1.1.3: - resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==} - engines: {node: '>=8.0.0'} - - css-what@6.2.2: - resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} - engines: {node: '>= 6'} - cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} @@ -5122,66 +2516,10 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - currently-unhandled@0.4.1: - resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} - engines: {node: '>=0.10.0'} - - d3-array@3.2.4: - resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} - engines: {node: '>=12'} - - d3-color@3.1.0: - resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} - engines: {node: '>=12'} - - d3-ease@3.0.1: - resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} - engines: {node: '>=12'} - - d3-format@3.1.2: - resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} - engines: {node: '>=12'} - - d3-interpolate@3.0.1: - resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} - engines: {node: '>=12'} - - d3-path@3.1.0: - resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} - engines: {node: '>=12'} - - d3-scale@4.0.2: - resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} - engines: {node: '>=12'} - - d3-shape@3.2.0: - resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} - engines: {node: '>=12'} - - d3-time-format@4.1.0: - resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} - engines: {node: '>=12'} - - d3-time@3.1.0: - resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} - engines: {node: '>=12'} - - d3-timer@3.0.1: - resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} - engines: {node: '>=12'} - - d@1.0.2: - resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==} - engines: {node: '>=0.12'} - dargs@8.1.0: resolution: {integrity: sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==} engines: {node: '>=12'} - dashdash@1.14.1: - resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} - engines: {node: '>=0.10'} - data-urls@5.0.0: resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} engines: {node: '>=18'} @@ -5198,34 +2536,9 @@ packages: resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} - date-fns-jalali@4.1.0-0: - resolution: {integrity: sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==} - - date-fns@3.6.0: - resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==} - - date.js@0.3.3: - resolution: {integrity: sha512-HgigOS3h3k6HnW011nAb43c5xx5rBXk8P2v/WIT9Zv4koIaVXiH2BURguI78VVp+5Qc076T7OR378JViCnZtBw==} - dayjs@1.11.20: resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} - debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - debug@3.1.0: - resolution: {integrity: sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: @@ -5247,16 +2560,9 @@ packages: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} - decimal.js-light@2.5.1: - resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} - decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - decode-uri-component@0.2.2: - resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} - engines: {node: '>=0.10'} - decompress-response@4.2.1: resolution: {integrity: sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==} engines: {node: '>=8'} @@ -5269,29 +2575,21 @@ packages: babel-plugin-macros: optional: true - deep-diff@1.0.2: - resolution: {integrity: sha512-aWS3UIVH+NPGCD1kki+DCU9Dua032iSsO43LqQpcs4R3+dVv7tX0qBGjiVHJHjplsoUM2XRO/KB92glqc68awg==} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - deep-eql@5.0.2: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} - deep-equal@1.1.2: - resolution: {integrity: sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==} - engines: {node: '>= 0.4'} - deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + deepmerge-ts@7.1.5: + resolution: {integrity: sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==} + engines: {node: '>=16.0.0'} + deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} - default-compare@1.0.0: - resolution: {integrity: sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==} - engines: {node: '>=0.10.0'} - defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} @@ -5303,21 +2601,8 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} - define-property@0.2.5: - resolution: {integrity: sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==} - engines: {node: '>=0.10.0'} - - define-property@1.0.0: - resolution: {integrity: sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==} - engines: {node: '>=0.10.0'} - - define-property@2.0.2: - resolution: {integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==} - engines: {node: '>=0.10.0'} - - del@3.0.0: - resolution: {integrity: sha512-7yjqSoVSlJzA4t/VUwazuEagGeANEKB3f/aNI//06pfKgwoCb7f6Q1gETN1sZzYaj6chTQ0AhIwDiPdfOjko4A==} - engines: {node: '>=4'} + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} @@ -5326,28 +2611,17 @@ packages: delegates@1.0.0: resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} - depd@1.1.2: - resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} - engines: {node: '>= 0.6'} + denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} - dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} - - des.js@1.1.0: - resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} - destr@2.0.5: resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} - destroy@1.2.0: - resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -5356,18 +2630,9 @@ packages: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} - detect-node-es@1.1.0: - resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} - - detect-node@2.1.0: - resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} - dezalgo@1.0.4: resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} - dfa@1.2.0: - resolution: {integrity: sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==} - didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} @@ -5379,25 +2644,12 @@ packages: resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} engines: {node: '>=0.3.1'} - diffie-hellman@5.0.3: - resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} - dijkstrajs@1.0.3: resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - dns-equal@1.0.0: - resolution: {integrity: sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==} - - dns-packet@5.6.1: - resolution: {integrity: sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==} - engines: {node: '>=6'} - - dns-txt@2.0.2: - resolution: {integrity: sha512-Ix5PrWjphuSoUXV/Zv5gaFHjnaJtb02F2+Si3Ht9dyJ87+Z/lMmy+dpNHtTGraNK958ndXq2i+GLkWsWHcKaBQ==} - doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -5406,29 +2658,6 @@ packages: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} - dom-helpers@5.2.1: - resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} - - dom-serializer@2.0.0: - resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} - - domain-browser@1.2.0: - resolution: {integrity: sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==} - engines: {node: '>=0.4', npm: '>=1.2'} - - domelementtype@2.3.0: - resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} - - domhandler@5.0.3: - resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} - engines: {node: '>= 4'} - - dompurify@3.4.2: - resolution: {integrity: sha512-lHeS9SA/IKeIFFyYciHBr2n0v1VMPlSj843HdLOwjb2OxNwdq9Xykxqhk+FE42MzAdHvInbAolSE4mhahPpjXA==} - - domutils@3.2.2: - resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} - dot-prop@5.3.0: resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} engines: {node: '>=8'} @@ -5449,40 +2678,25 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - duplexer2@0.1.4: - resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} - eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - ebec@1.1.1: - resolution: {integrity: sha512-JZ1vcvPQtR+8LGbZmbjG21IxLQq/v47iheJqn2F6yB2CgnGfn8ZVg3myHrf3buIZS8UCwQK0jOSIb3oHX7aH8g==} - - ebec@2.3.0: - resolution: {integrity: sha512-bt+0tSL7223VU3PSVi0vtNLZ8pO1AfWolcPPMk2a/a5H+o/ZU9ky0n3A0zhrR4qzJTN61uPsGIO4ShhOukdzxA==} - - ecc-jsbn@0.1.2: - resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} - ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + effect@3.21.0: + resolution: {integrity: sha512-PPN80qRokCd1f015IANNhrwOnLO7GrrMQfk4/lnZRE/8j7UPWrNNjPV0uBrZutI/nHzernbW+J0hdqQysHiSnQ==} + electron-to-chromium@1.5.353: resolution: {integrity: sha512-kOrWphBi8TOZyiJZqsgqIle0lw+tzmnQK83pV9dZUd01Nm2POECSyFQMAuarzZdYqQW7FH9RaYOuaRo3h+bQ3w==} - elliptic@6.6.1: - resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} - emittery@0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} engines: {node: '>=12'} - emoji-regex-xs@1.0.0: - resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} - emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} @@ -5492,40 +2706,18 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - emojis-list@3.0.0: - resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} - engines: {node: '>= 4'} + empathic@2.0.0: + resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} + engines: {node: '>=14'} encodeurl@2.0.0: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} - end-of-stream@1.4.5: - resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} - - engine.io-client@6.6.4: - resolution: {integrity: sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw==} - - engine.io-parser@5.2.3: - resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} - engines: {node: '>=10.0.0'} - - enhanced-resolve@3.4.1: - resolution: {integrity: sha512-ZaAux1rigq1e2nQrztHn4h2ugvpzZxs64qneNah+8Mh/K0CRqJFJc+UoXnUsq+1yX+DmQFPPdVqboKAJ89e0Iw==} - engines: {node: '>=4.3.0 <5.0.0 || >=5.10'} - enhanced-resolve@5.21.3: resolution: {integrity: sha512-QyL119InA+XXEkNLNTPCXPugSvOfhwv0JOlGNzvxs0hZaiHLNvXSpudUWsOlsXGWJh8G6ckCScEkVHfX3kw/2Q==} engines: {node: '>=10.13.0'} - ent@2.2.2: - resolution: {integrity: sha512-kKvD1tO6BM+oK9HzCPpUdRb4vKFQY/FPTFmurMvh6LlN68VMrdj77w8yp51/kDbpkFOS9J8w5W6zIzgM2H8/hw==} - engines: {node: '>= 0.4'} - - entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} - entities@6.0.1: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} @@ -5538,21 +2730,9 @@ packages: resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} engines: {node: '>=18'} - envix@1.5.0: - resolution: {integrity: sha512-IOxTKT+tffjxgvX2O5nq6enbkv6kBQ/QdMy18bZWo0P0rKPvsRp2/EypIPwTvJfnmk3VdOlq/KcRSZCswefM/w==} - engines: {node: '>=18.0.0'} - - errno@0.1.8: - resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} - hasBin: true - error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} - error-symbol@0.1.0: - resolution: {integrity: sha512-VyjaKxUmeDX/m2lxm/aknsJ1GWDWUO2Ze2Ad8S1Pb9dykAm9TjSKp5CjrNyltYqZ5W/PO6TInAmO2/BfwMyT1g==} - engines: {node: '>=0.10.0'} - es-abstract@1.24.2: resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==} engines: {node: '>= 0.4'} @@ -5591,30 +2771,6 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - es-toolkit@1.46.1: - resolution: {integrity: sha512-5eNtXOs3tbfxXOj04tjjseeWkRWaoCjdEI+96DgwzZoe6c9juL49pXlzAFTI72aWC9Y8p7168g6XIKjh7k6pyQ==} - - es5-ext@0.10.64: - resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} - engines: {node: '>=0.10'} - - es6-iterator@2.0.3: - resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} - - es6-map@0.1.5: - resolution: {integrity: sha512-mz3UqCh0uPCIqsw1SSAkB/p0rOzF/M0V++vyN7JqlPtSW/VsYgQBvVvqMLmfBuyMzTpLnNqi6JmcSizs4jy19A==} - - es6-set@0.1.6: - resolution: {integrity: sha512-TE3LgGLDIBX332jq3ypv6bcOpkLO0AslAQo7p2VqX/1N46YNsvIWgvjojjSEnWEGWMhr1qUbYeTSir5J6mFHOw==} - engines: {node: '>=0.12'} - - es6-symbol@3.1.4: - resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==} - engines: {node: '>=0.12'} - - es6-weak-map@2.0.3: - resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==} - esbuild@0.21.5: resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} @@ -5635,10 +2791,6 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - escope@3.6.0: - resolution: {integrity: sha512-75IUQsusDdalQEW/G/2esa87J7raqdJF+Ca0/Xm5C3Q58Nr4yVYjZGp/P1+2xiEVgXRrA39dpRb8LcshajbqDQ==} - engines: {node: '>=0.4.0'} - eslint-config-prettier@9.1.2: resolution: {integrity: sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==} hasBin: true @@ -5718,10 +2870,6 @@ packages: deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true - esniff@2.0.1: - resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==} - engines: {node: '>=0.10'} - espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -5758,29 +2906,9 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} - ethiopian-calendar-date-converter@2.1.6: - resolution: {integrity: sha512-qqOPkFQlMfLXF4gP70+2z6DrJNvKKcj+VIC37e72A5qs/LXCYQVt8egahDUfGkI0s92FyV7lfSUtGrX4rdM+3w==} - - ethiopian-calendar-new@1.1.0: - resolution: {integrity: sha512-5M0vB1Jb2lmK/l6s1mSykn4+/R4dElF89WXUp4HBdnwLYgHAnZ2nShebY5mgc/Noc5b9Sg8gTF+MYbmNUk+qSA==} - engines: {node: '>=16.0.0'} - - ethiopian-date@0.0.6: - resolution: {integrity: sha512-O+8hYimosZVn85MWcHtq9HQLR2HdELZPbv1zk3Xc6nm1cYvBl3V1fezrcMkqWKt8tin9dr3/vk0JkQAEWQZzXA==} - - event-emitter@0.3.5: - resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==} - - event-target-shim@5.0.1: - resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} - engines: {node: '>=6'} - eventemitter2@6.4.9: resolution: {integrity: sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==} - eventemitter3@4.0.7: - resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} - eventemitter3@5.0.4: resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} @@ -5788,21 +2916,6 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} - eventsource@0.1.6: - resolution: {integrity: sha512-bbB5tEuvC+SuRUG64X8ghvjgiRniuA4WlehWbFnoN4z6TxDXpyX+BMHF7rMgZAqoe+EbyNRUbHN0uuP9phy5jQ==} - engines: {node: '>=0.8.0'} - - evp_bytestokey@1.0.3: - resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} - - exceljs@4.4.0: - resolution: {integrity: sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg==} - engines: {node: '>=8.3.0'} - - execa@0.7.0: - resolution: {integrity: sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==} - engines: {node: '>=4'} - execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -5815,10 +2928,6 @@ packages: resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} engines: {node: '>= 0.8.0'} - expand-brackets@2.1.4: - resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==} - engines: {node: '>=0.10.0'} - expect-type@1.3.0: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} @@ -5827,51 +2936,20 @@ packages: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - express@4.22.2: - resolution: {integrity: sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==} - engines: {node: '>= 0.10.0'} - express@5.2.1: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} - ext@1.7.0: - resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} - extend-shallow@2.0.1: - resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} - engines: {node: '>=0.10.0'} - - extend-shallow@3.0.2: - resolution: {integrity: sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==} - engines: {node: '>=0.10.0'} - - extend@3.0.2: - resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - - extglob@2.0.4: - resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==} - engines: {node: '>=0.10.0'} - - extsprintf@1.3.0: - resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} - engines: {'0': node >=0.6.0} - - falsey@0.3.2: - resolution: {integrity: sha512-lxEuefF5MBIVDmE6XeqCdM4BWk1+vYmGZtkbKZ/VFcg6uBBw6fXNEbWmxCjDdQlFc9hy450nkiWwM3VAW6G1qg==} - engines: {node: '>=0.10.0'} - - fast-csv@4.3.6: - resolution: {integrity: sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==} - engines: {node: '>=10.0.0'} + fast-check@3.23.2: + resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} + engines: {node: '>=8.0.0'} fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-equals@5.4.0: - resolution: {integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==} - engines: {node: '>=6.0.0'} - fast-glob@3.3.3: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} @@ -5882,34 +2960,15 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-png@6.4.0: - resolution: {integrity: sha512-kAqZq1TlgBjZcLr5mcN6NP5Rv4V2f22z00c3g8vRrwkcqjerx7BEhPbOnWCPqaHUl2XWQBJQvOT/FQhdMT7X/Q==} - fast-safe-stringify@2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} fast-uri@3.1.2: resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} - fast-xml-parser@4.5.6: - resolution: {integrity: sha512-Yd4vkROfJf8AuJrDIVMVmYfULKmIJszVsMv7Vo71aocsKgFxpdlpSHXSaInvyYfgw2PRuObQSW2GFpVMUjxu9A==} - hasBin: true - fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} - faye-websocket@0.10.0: - resolution: {integrity: sha512-Xhj93RXbMSq8urNCUq4p9l0P6hnySJ/7YNRhYNug0bLOuii7pKO7xQFb5mx9xZXWCar88pLPb805PvUkwrLZpQ==} - engines: {node: '>=0.4.0'} - - faye-websocket@0.11.4: - resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} - engines: {node: '>=0.8.0'} - - faye@0.8.11: - resolution: {integrity: sha512-d2SXlWy+wR8D2AgYjCnJrA8v4RvwKeRQeTB2aLUetyhrNKTU28mAvSMezSZDNyOONVrsF0IY1s4625QgggM2XA==} - engines: {node: '>=0.1.96'} - fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} @@ -5922,59 +2981,22 @@ packages: picomatch: optional: true - fflate@0.8.2: - resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} - file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} - file-selector@2.1.2: - resolution: {integrity: sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==} - engines: {node: '>= 12'} - - file-type@18.7.0: - resolution: {integrity: sha512-ihHtXRzXEziMrQ56VSgU7wkxh55iNchFkosu7Y9/S+tXHdKyrGjVK0ujbqNnsxzea+78MaLhN6PGmfYSAv1ACw==} - engines: {node: '>=14.16'} - file-type@21.3.4: resolution: {integrity: sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==} engines: {node: '>=20'} - file-uri-to-path@1.0.0: - resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - - fill-range@4.0.0: - resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==} - engines: {node: '>=0.10.0'} - fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - filter-obj@1.1.0: - resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==} - engines: {node: '>=0.10.0'} - - finalhandler@1.3.2: - resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} - engines: {node: '>= 0.8'} - finalhandler@2.1.1: resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} engines: {node: '>= 18.0.0'} - find-root@1.1.0: - resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} - - find-up@1.1.2: - resolution: {integrity: sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==} - engines: {node: '>=0.10.0'} - - find-up@2.1.0: - resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} - engines: {node: '>=4'} - find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -5991,10 +3013,6 @@ packages: resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} engines: {node: ^10.12.0 || >=12.0.0} - flat@5.0.2: - resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} - hasBin: true - flatted@3.4.2: resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} @@ -6007,31 +3025,14 @@ packages: debug: optional: true - fontkit@2.0.4: - resolution: {integrity: sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==} - for-each@0.3.5: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} - for-in@1.0.2: - resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==} - engines: {node: '>=0.10.0'} - - for-own@1.0.0: - resolution: {integrity: sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==} - engines: {node: '>=0.10.0'} - - force@0.0.3: - resolution: {integrity: sha512-B/4gl3/7o8Q4jYfXNKSvTHlAPxB1ruYCkxVkiVUUuHziYbDa2NsURljSgpm+Q+d4cGmN1EaAD5QXhLodGN44zA==} - foreground-child@3.3.1: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} - forever-agent@0.6.1: - resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} - fork-ts-checker-webpack-plugin@9.1.0: resolution: {integrity: sha512-mpafl89VFPJmhnJ1ssH+8wmM2b50n+Rew5x42NeI2U78aRWgtkEtGmctp7iT16UjquJTjorEmIfESj3DxdW84Q==} engines: {node: '>=14.21.3'} @@ -6039,10 +3040,6 @@ packages: typescript: '>3.6.0' webpack: ^5.11.0 - form-data@2.3.3: - resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} - engines: {node: '>= 0.12'} - form-data@4.0.5: resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} @@ -6055,46 +3052,13 @@ packages: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} - frac@1.1.2: - resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==} - engines: {node: '>=0.8'} - fraction.js@5.3.4: resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} - fragment-cache@0.2.1: - resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==} - engines: {node: '>=0.10.0'} - - framer-motion@12.38.0: - resolution: {integrity: sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g==} - peerDependencies: - '@emotion/is-prop-valid': '*' - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@emotion/is-prop-valid': - optional: true - react: - optional: true - react-dom: - optional: true - - fresh@0.5.2: - resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} - engines: {node: '>= 0.6'} - fresh@2.0.0: resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} engines: {node: '>= 0.8'} - fs-constants@1.0.0: - resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - - fs-exists-sync@0.1.0: - resolution: {integrity: sha512-cR/vflFyPZtrN6b38ZyWxpWdhlXrzZEBawlpBQMq7033xVY7/kg0GDMBK5jg8lDYQckdJ5x/YC88lM3C7VMsLg==} - engines: {node: '>=0.10.0'} - fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} @@ -6109,22 +3073,11 @@ packages: fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - fsevents@1.2.13: - resolution: {integrity: sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==} - engines: {node: '>= 4.0'} - os: [darwin] - deprecated: Upgrade to fsevents v2 to mitigate potential security issues - fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - fstream@1.0.12: - resolution: {integrity: sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==} - engines: {node: '>=0.6'} - deprecated: This package is no longer supported. - function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} @@ -6140,6 +3093,9 @@ packages: engines: {node: '>=10'} deprecated: This package is no longer supported. + generate-function@2.3.1: + resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} + generator-function@2.0.1: resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} engines: {node: '>= 0.4'} @@ -6148,9 +3104,6 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} - get-caller-file@1.0.3: - resolution: {integrity: sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==} - get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -6163,14 +3116,6 @@ packages: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} - get-nonce@1.0.1: - resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} - engines: {node: '>=6'} - - get-object@0.2.0: - resolution: {integrity: sha512-7P6y6k6EzEFmO/XyUyFlXm1YLJy9xeA1x/grNV8276abX5GuwUtYgKFkRFkLixw4hf4Pz9q2vgv/8Ar42R0HuQ==} - engines: {node: '>=0.10.0'} - get-package-type@0.1.0: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} @@ -6179,14 +3124,6 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} - get-stdin@4.0.1: - resolution: {integrity: sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==} - engines: {node: '>=0.10.0'} - - get-stream@3.0.0: - resolution: {integrity: sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==} - engines: {node: '>=4'} - get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -6199,12 +3136,9 @@ packages: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} - get-value@2.0.6: - resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==} - engines: {node: '>=0.10.0'} - - getpass@0.1.7: - resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} + giget@2.0.0: + resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} + hasBin: true git-raw-commits@4.0.0: resolution: {integrity: sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==} @@ -6212,9 +3146,6 @@ packages: deprecated: This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead. hasBin: true - glob-parent@3.1.0: - resolution: {integrity: sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==} - glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -6251,10 +3182,6 @@ packages: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} - globby@6.1.0: - resolution: {integrity: sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==} - engines: {node: '>=0.10.0'} - gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -6265,51 +3192,15 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - gulp-header@1.8.12: - resolution: {integrity: sha512-lh9HLdb53sC7XIZOYzTXM4lFuXElv3EVkSDhsd7DoJBj7hm+Ni7D3qYbb+Rr8DuM8nRanBvkVO9d7askreXGnQ==} - deprecated: Removed event-stream from gulp-header - - handle-thing@2.0.1: - resolution: {integrity: sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==} - - handlebars-helper-create-frame@0.1.0: - resolution: {integrity: sha512-yR99Rh8JYcWSsARw/unaOUUICqG0M+SV3U4vBl3Psn78r0qXjU+cT9+IGXglNuuI3RfahvFDyEQ0l1KWthavRQ==} - engines: {node: '>=4'} - - handlebars-helpers@0.10.0: - resolution: {integrity: sha512-QiyhQz58u/DbuV41VnfpE0nhy6YCH4vB514ajysV8SoKmP+DxU+pR+fahVyNECHj+jiwEN2VrvxD/34/yHaLUg==} - engines: {node: '>=0.12.0'} - - handlebars-utils@1.0.6: - resolution: {integrity: sha512-d5mmoQXdeEqSKMtQQZ9WkiUcO1E3tPbWxluCK9hVgIDPzQa9WsKo3Lbe/sGflTe7TomHEeZaOgwIkyIr1kfzkw==} - engines: {node: '>=0.10.0'} - handlebars@4.7.9: resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==} engines: {node: '>=0.4.7'} hasBin: true - har-schema@2.0.0: - resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==} - engines: {node: '>=4'} - - har-validator@5.1.5: - resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==} - engines: {node: '>=6'} - deprecated: this library is no longer supported - has-bigints@1.1.0: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} - has-flag@2.0.0: - resolution: {integrity: sha512-P+1n3MnwjR/Epg9BBo1KT8qbye2g2Ou4sFumihwt6I4tsUX7jnLcX4BTOSKg/B1ZrIYMN9FcEnG4x5a7NB8Eng==} - engines: {node: '>=0.10.0'} - - has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -6332,129 +3223,25 @@ packages: has-unicode@2.0.1: resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} - has-value@0.3.1: - resolution: {integrity: sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==} - engines: {node: '>=0.10.0'} - - has-value@1.0.0: - resolution: {integrity: sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==} - engines: {node: '>=0.10.0'} - - has-values@0.1.4: - resolution: {integrity: sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==} - engines: {node: '>=0.10.0'} - - has-values@1.0.0: - resolution: {integrity: sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==} - engines: {node: '>=0.10.0'} - - hash-base@3.0.5: - resolution: {integrity: sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==} - engines: {node: '>= 0.10'} - - hash-base@3.1.2: - resolution: {integrity: sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==} - engines: {node: '>= 0.8'} - - hash.js@1.1.7: - resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} - hasown@2.0.3: resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} engines: {node: '>= 0.4'} - he@1.2.0: - resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} - hasBin: true - - helper-date@1.0.1: - resolution: {integrity: sha512-wU3VOwwTJvGr/w5rZr3cprPHO+hIhlblTJHD6aFBrKLuNbf4lAmkawd2iK3c6NbJEvY7HAmDpqjOFSI5/+Ey2w==} - engines: {node: '>=4.0'} - - helper-markdown@1.0.0: - resolution: {integrity: sha512-AnDqMS4ejkQK0MXze7pA9TM3pu01ZY+XXsES6gEE0RmCGk5/NIfvTn0NmItfyDOjRAzyo9z6X7YHbHX4PzIvOA==} - engines: {node: '>=0.10.0'} - - helper-md@0.2.2: - resolution: {integrity: sha512-49TaQzK+Ic7ZVTq4i1UZxRUJEmAilTk8hz7q4I0WNUaTclLR8ArJV5B3A1fe1xF2HtsDTr2gYKLaVTof/Lt84Q==} - engines: {node: '>=0.10.0'} - - highlight.js@9.18.5: - resolution: {integrity: sha512-a5bFyofd/BHCX52/8i8uJkjr9DYwXIPnM/plwI6W7ezItLGqzt7X2G2nXuYSfsIJdkwwj/g9DG1LkcGJI/dDoA==} - deprecated: Support has ended for 9.x series. Upgrade to @latest - - hmac-drbg@1.0.1: - resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} - - hoist-non-react-statics@3.3.2: - resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} - - hosted-git-info@2.8.9: - resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} - - hpack.js@2.1.6: - resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==} - - hsl-to-hex@1.0.0: - resolution: {integrity: sha512-K6GVpucS5wFf44X0h2bLVRDsycgJmf9FF2elg+CrqD8GcFU8c6vYhgXn8NjUkFCwj+xDFb70qgLbTUm6sxwPmA==} - - hsl-to-rgb-for-reals@1.1.1: - resolution: {integrity: sha512-LgOWAkrN0rFaQpfdWBQlv/VhkOxb5AsBjk6NQVx4yEzWS923T07X0M1Y0VNko2H52HeSpZrZNNMJ0aFqsdVzQg==} - html-encoding-sniffer@4.0.0: resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} engines: {node: '>=18'} - html-entities@1.4.0: - resolution: {integrity: sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==} - html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - html-parse-stringify@3.0.1: - resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} - - html-tag@2.0.0: - resolution: {integrity: sha512-XxzooSo6oBoxBEUazgjdXj7VwTn/iSTSZzTYKzYY6I916tkaYzypHxy+pbVU1h+0UQ9JlVf5XkNQyxOAiiQO1g==} - engines: {node: '>=0.10.0'} - - html2canvas@1.4.1: - resolution: {integrity: sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==} - engines: {node: '>=8.0.0'} - - http-deceiver@1.2.7: - resolution: {integrity: sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==} - - http-errors@1.8.1: - resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==} - engines: {node: '>= 0.6'} - http-errors@2.0.1: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} - http-parser-js@0.5.10: - resolution: {integrity: sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==} - http-proxy-agent@7.0.2: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} - http-proxy-middleware@0.19.2: - resolution: {integrity: sha512-aYk1rTKqLTus23X3L96LGNCGNgWpG4cG0XoZIT1GUPhhulEHX/QalnO6Vbo+WmKWi4AL2IidjuC0wZtbpg0yhQ==} - engines: {node: '>=4.0.0'} - - http-proxy@1.18.1: - resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==} - engines: {node: '>=8.0.0'} - - http-signature@1.2.0: - resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==} - engines: {node: '>=0.8', npm: '>=1.3.7'} - - https-browserify@1.0.0: - resolution: {integrity: sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==} - https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} @@ -6476,24 +3263,6 @@ packages: engines: {node: '>=18'} hasBin: true - hyphen@1.14.1: - resolution: {integrity: sha512-kvL8xYl5QMTh+LwohVN72ciOxC0OEV79IPdJSTwEXok9y9QHebXGdFgrED4sWfiax/ODx++CAMk3hMy4XPJPOw==} - - i18next-browser-languagedetector@8.2.1: - resolution: {integrity: sha512-bZg8+4bdmaOiApD7N7BPT9W8MLZG+nPTOFlLiJiT8uzKXFjhxw4v2ierCXOwB5sFDMtuA5G4kgYZ0AznZxQ/cw==} - - i18next@25.10.10: - resolution: {integrity: sha512-cqUW2Z3EkRx7NqSyywjkgCLK7KLCL6IFVFcONG7nVYIJ3ekZ1/N5jUsihHV6Bq37NfhgtczxJcxduELtjTwkuQ==} - peerDependencies: - typescript: ^5 || ^6 - peerDependenciesMeta: - typescript: - optional: true - - iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} - iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} @@ -6502,9 +3271,6 @@ packages: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} - idb-keyval@6.2.2: - resolution: {integrity: sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==} - ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -6516,12 +3282,6 @@ packages: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} - immediate@3.0.6: - resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} - - immer@10.2.0: - resolution: {integrity: sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==} - immer@11.1.8: resolution: {integrity: sha512-/tbkHMW7y10Lx6i1crLjD4/OhNkRG+Fo7byZHtah0547nIeXYcpIXaUh0IAQY6gO5459qpGGYapcEOHtFXkIuA==} @@ -6529,11 +3289,6 @@ packages: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} - import-local@1.0.0: - resolution: {integrity: sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ==} - engines: {node: '>=4'} - hasBin: true - import-local@3.2.0: resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} engines: {node: '>=8'} @@ -6546,21 +3301,10 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - indent-string@2.1.0: - resolution: {integrity: sha512-aqwDFWSgSgfRaEwao5lg5KEcVd/2a+D1rvoG7NdilmYz0NwRk6StWpWdz/Hpk34MKPpx7s8XxUqimfcQK6gGlg==} - engines: {node: '>=0.10.0'} - inflight@1.0.6: resolution: {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. - info-symbol@0.1.0: - resolution: {integrity: sha512-qkc9wjLDQ+dYYZnY5uJXGNNHyZ0UOMDUnhvy0SEZGVVYmQ5s4i8cPAin2MbU6OxJgi8dfj/AnwqPx0CJE6+Lsw==} - engines: {node: '>=0.10.0'} - - inherits@2.0.3: - resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} - inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -6568,49 +3312,14 @@ packages: resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - internal-ip@1.2.0: - resolution: {integrity: sha512-DzGfTasXPmwizQP4XV2rR6r2vp8TjlOpMnJqG9Iy2i1pl1lkZdZj5rSpIc7YFGX2nS46PPgAGEyT+Q5hE2FB2g==} - engines: {node: '>=0.10.0'} - hasBin: true - internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} - internmap@2.0.3: - resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} - engines: {node: '>=12'} - - interpret@1.4.0: - resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} - engines: {node: '>= 0.10'} - - invert-kv@1.0.0: - resolution: {integrity: sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==} - engines: {node: '>=0.10.0'} - - iobuffer@5.4.0: - resolution: {integrity: sha512-DRebOWuqDvxunfkNJAlc3IzWIPD5xVxwUNbHr7xKB8E6aLJxIPfNX3CoMJghcFjpv6RWQsrcJbghtEwSPoJqMA==} - - ip@1.1.9: - resolution: {integrity: sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==} - ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} - ipaddr.js@2.4.0: - resolution: {integrity: sha512-9VGk3HGanVE6JoZXHiCpnGy5X0jYDnN4EA4lntFPj+1vIWlFhIylq2CrrCOJH9EAhc5CYhq18F2Av2tgoAPsYQ==} - engines: {node: '>= 10'} - - is-accessor-descriptor@1.0.2: - resolution: {integrity: sha512-AIbwAcazqP3R65dGvqk1V+a+vE5Fg1yu/ZKMOiBWSUIXXiwQkYmXQcVa2O0nh0tSDKDFKxG2mY7dB1Sr4hEP1g==} - engines: {node: '>= 0.4'} - - is-arguments@1.2.0: - resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} - engines: {node: '>= 0.4'} - is-array-buffer@3.0.5: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} @@ -6626,10 +3335,6 @@ packages: resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} engines: {node: '>= 0.4'} - is-binary-path@1.0.1: - resolution: {integrity: sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==} - engines: {node: '>=0.10.0'} - is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -6638,9 +3343,6 @@ packages: resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} engines: {node: '>= 0.4'} - is-buffer@1.1.6: - resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} - is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} @@ -6649,10 +3351,6 @@ packages: resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} engines: {node: '>= 0.4'} - is-data-descriptor@1.0.1: - resolution: {integrity: sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==} - engines: {node: '>= 0.4'} - is-data-view@1.0.2: resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} engines: {node: '>= 0.4'} @@ -6661,26 +3359,6 @@ packages: resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} - is-descriptor@0.1.8: - resolution: {integrity: sha512-SceYGWXvdqlWa/OnQ5FQuV+NxvNmMRhMw/w9AHkH71hTzveND4BTYgvp16g+oITK47qbOl/3D0bl0iygehWAWQ==} - engines: {node: '>= 0.4'} - - is-descriptor@1.0.4: - resolution: {integrity: sha512-bv5z95W0dDtLfKwDfkTNxaRxmISBD3eQBKJeVxv2AQ7MjuUnDNG7cIQqvFtMOUYhsILWHhMayWdoGqNqYYYjww==} - engines: {node: '>= 0.4'} - - is-even@1.0.0: - resolution: {integrity: sha512-LEhnkAdJqic4Dbqn58A0y52IXoHWlsueqQkKfMfdEnIYG8A1sm/GHidKkS6yvXlMoRrkM34csHnXQtOqcb+Jzg==} - engines: {node: '>=0.10.0'} - - is-extendable@0.1.1: - resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} - engines: {node: '>=0.10.0'} - - is-extendable@1.0.1: - resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==} - engines: {node: '>=0.10.0'} - is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -6689,18 +3367,6 @@ packages: resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} engines: {node: '>= 0.4'} - is-finite@1.1.0: - resolution: {integrity: sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==} - engines: {node: '>=0.10.0'} - - is-fullwidth-code-point@1.0.0: - resolution: {integrity: sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==} - engines: {node: '>=0.10.0'} - - is-fullwidth-code-point@2.0.0: - resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} - engines: {node: '>=4'} - is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -6721,10 +3387,6 @@ packages: resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} engines: {node: '>= 0.4'} - is-glob@3.1.0: - resolution: {integrity: sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==} - engines: {node: '>=0.10.0'} - is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -6733,12 +3395,6 @@ packages: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} - is-lite@0.8.2: - resolution: {integrity: sha512-JZfH47qTsslwaAsqbMI3Q6HNNjUuq6Cmzzww50TdP5Esb6e1y2sK2UAaZZuzfAzpoI2AkxoPQapZdlDuP6Vlsw==} - - is-lite@1.2.1: - resolution: {integrity: sha512-pgF+L5bxC+10hLBgf6R2P4ZZUBOQIIacbdo8YvuCP8/JvsWxG7aZ9p10DYuLtifFci4l3VITphhMlMV4Y+urPw==} - is-map@2.0.3: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} engines: {node: '>= 0.4'} @@ -6751,18 +3407,6 @@ packages: resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} engines: {node: '>= 0.4'} - is-number@2.1.0: - resolution: {integrity: sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg==} - engines: {node: '>=0.10.0'} - - is-number@3.0.0: - resolution: {integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==} - engines: {node: '>=0.10.0'} - - is-number@4.0.0: - resolution: {integrity: sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==} - engines: {node: '>=0.10.0'} - is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -6771,44 +3415,23 @@ packages: resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} engines: {node: '>=8'} - is-odd@0.1.2: - resolution: {integrity: sha512-Ri7C2K7o5IrUU9UEI8losXJCCD/UtsaIrkR5sxIcFg4xQ9cRJXlWA5DQvTE0yDc0krvSNLsRGXN11UPS6KyfBw==} - engines: {node: '>=0.10.0'} - - is-path-cwd@1.0.0: - resolution: {integrity: sha512-cnS56eR9SPAscL77ik76ATVqoPARTqPIVkMDVxRaWH06zT+6+CzIroYRJ0VVvm0Z1zfAvxvz9i/D3Ppjaqt5Nw==} - engines: {node: '>=0.10.0'} - - is-path-in-cwd@1.0.1: - resolution: {integrity: sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==} - engines: {node: '>=0.10.0'} - - is-path-inside@1.0.1: - resolution: {integrity: sha512-qhsCR/Esx4U4hg/9I19OVUAJkGWtjRYHMRgUMZE2TDdj+Ag+kttZanLupfddNyglzz50cUlmWzUaI37GDfNx/g==} - engines: {node: '>=0.10.0'} - is-path-inside@3.0.3: resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} engines: {node: '>=8'} - is-plain-object@2.0.4: - resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} - engines: {node: '>=0.10.0'} - is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-property@1.0.2: + resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} + is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} - is-self-closing@1.0.1: - resolution: {integrity: sha512-E+60FomW7Blv5GXTlYee2KDrnG6srxF7Xt1SjrhWUGUEsTFIqY/nq2y3DaftCsgUMdh89V07IVfhY9KIJhLezg==} - engines: {node: '>=0.12.0'} - is-set@2.0.3: resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} engines: {node: '>= 0.4'} @@ -6817,10 +3440,6 @@ packages: resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} engines: {node: '>= 0.4'} - is-stream@1.1.0: - resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} - engines: {node: '>=0.10.0'} - is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} @@ -6845,19 +3464,10 @@ packages: resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} - is-typedarray@1.0.0: - resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} - is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} - is-url@1.2.4: - resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==} - - is-utf8@0.2.1: - resolution: {integrity: sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==} - is-weakmap@2.0.2: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} @@ -6870,38 +3480,12 @@ packages: resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} engines: {node: '>= 0.4'} - is-windows@1.0.2: - resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} - engines: {node: '>=0.10.0'} - - is-wsl@1.1.0: - resolution: {integrity: sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==} - engines: {node: '>=4'} - - isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - isobject@0.2.0: - resolution: {integrity: sha512-VaWq6XYAsbvM0wf4dyBO7WH9D7GosB7ZZlqrawI9BBiTMINBeCyqSKBa35m870MY3O4aM31pYyZi9DfGrYMJrQ==} - engines: {node: '>=0.10.0'} - - isobject@2.1.0: - resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==} - engines: {node: '>=0.10.0'} - - isobject@3.0.1: - resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} - engines: {node: '>=0.10.0'} - - isstream@0.1.2: - resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} - istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} @@ -6937,9 +3521,6 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jay-peg@1.1.1: - resolution: {integrity: sha512-D62KEuBxz/ip2gQKOEhk/mx14o7eiFRaU+VNNSP4MOiIkwb/D6B3G1Mfas7C/Fit8EsSV2/IWjZElx/Gs6A4ww==} - jest-changed-files@29.7.0: resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -7081,27 +3662,6 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true - jiti@2.7.0: - resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} - hasBin: true - - jmespath@0.16.0: - resolution: {integrity: sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==} - engines: {node: '>= 0.6.0'} - - jose@5.10.0: - resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} - - jquery@3.7.1: - resolution: {integrity: sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==} - - js-cookie@3.0.5: - resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} - engines: {node: '>=14'} - - js-md5@0.8.3: - resolution: {integrity: sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ==} - js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -7117,9 +3677,6 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true - jsbn@0.1.1: - resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} - jsdom@25.0.1: resolution: {integrity: sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==} engines: {node: '>=18'} @@ -7137,9 +3694,6 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - json-loader@0.5.7: - resolution: {integrity: sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==} - json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} @@ -7149,25 +3703,9 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - json-schema@0.4.0: - resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} - json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - json-stream@1.0.0: - resolution: {integrity: sha512-H/ZGY0nIAg3QcOwE1QN/rK/Fa7gJn7Ii5obwp6zyPO4xiPNwpIMjqy2gwjBEGqzkF/vSWEIBQCBuN19hYiL6Qg==} - - json-stringify-safe@5.0.1: - resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} - - json3@3.3.3: - resolution: {integrity: sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==} - - json5@0.5.1: - resolution: {integrity: sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==} - hasBin: true - json5@1.0.2: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true @@ -7195,20 +3733,10 @@ packages: resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} engines: {node: '>=12', npm: '>=6'} - jspdf@3.0.4: - resolution: {integrity: sha512-dc6oQ8y37rRcHn316s4ngz/nOjayLF/FFxBF4V9zamQKRqXxyiH1zagkCdktdWhtoQId5K20xt1lB90XzkB+hQ==} - - jsprim@1.4.2: - resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==} - engines: {node: '>=0.6.0'} - jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} - jszip@3.10.1: - resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} - jwa@1.4.2: resolution: {integrity: sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==} @@ -7224,45 +3752,10 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - killable@1.0.1: - resolution: {integrity: sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==} - - kind-of@3.2.2: - resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} - engines: {node: '>=0.10.0'} - - kind-of@4.0.0: - resolution: {integrity: sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==} - engines: {node: '>=0.10.0'} - - kind-of@5.1.0: - resolution: {integrity: sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==} - engines: {node: '>=0.10.0'} - - kind-of@6.0.3: - resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} - engines: {node: '>=0.10.0'} - kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} - lazy-cache@1.0.4: - resolution: {integrity: sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==} - engines: {node: '>=0.10.0'} - - lazy-cache@2.0.2: - resolution: {integrity: sha512-7vp2Acd2+Kz4XkzxGxaB1FWOi8KjWIWsgdfD5MCb86DWvlLqhRPM+d6Pro3iNEL5VT9mstz5hKAlcd+QR6H3aA==} - engines: {node: '>=0.10.0'} - - lazystream@1.0.1: - resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} - engines: {node: '>= 0.6.3'} - - lcid@1.0.0: - resolution: {integrity: sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==} - engines: {node: '>=0.10.0'} - leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -7274,13 +3767,6 @@ packages: libphonenumber-js@1.13.1: resolution: {integrity: sha512-GEw0GLL7YUUA6nv21IsCvVjtI5Ejn84sjbdfQ9KxdbqEVOk1PZh7xejn01EEiniKw+dBeCfim+8MGeuvVuE2BA==} - libreoffice-convert@1.8.1: - resolution: {integrity: sha512-iZ1DD/EMTlPvol8G++QQ/0w4pVecSwRuhMLXRm7nRim/gcaSscSXuTO9Tgbkieyw5UdJg7UXD+lkFT8SCi51Dw==} - engines: {node: '>=6'} - - lie@3.3.0: - resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} - lightningcss-android-arm64@1.32.0: resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} engines: {node: '>= 12.0.0'} @@ -7355,23 +3841,14 @@ packages: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} - linebreak@1.1.0: - resolution: {integrity: sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==} - lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - linkifyjs@4.3.2: - resolution: {integrity: sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==} - lint-staged@15.5.2: resolution: {integrity: sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==} engines: {node: '>=18.12.0'} hasBin: true - listenercount@1.0.1: - resolution: {integrity: sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==} - listr2@8.3.3: resolution: {integrity: sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==} engines: {node: '>=18.0.0'} @@ -7380,34 +3857,10 @@ packages: resolution: {integrity: sha512-v5xlu8eHD1+6r8EHTg6hfmO97LN8ugKtiXcy5e6oN72iD2r6u0RPfLl6fxM+7Wnh2ZRq15o0russMst44WauPA==} engines: {node: '>=13.2.0'} - load-json-file@1.1.0: - resolution: {integrity: sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==} - engines: {node: '>=0.10.0'} - - load-json-file@2.0.0: - resolution: {integrity: sha512-3p6ZOGNbiX4CdvEd1VcE6yi78UrGNpjHO33noGwHCnT/o2fyllJDepsm8+mFFv/DvtwFHht5HIHSyOy5a+ChVQ==} - engines: {node: '>=4'} - - loadash@1.0.0: - resolution: {integrity: sha512-xlX5HBsXB3KG0FJbJJG/3kYWCfsCyCSus3T+uHVu6QL6YxAdggmm3QeyLgn54N2yi5/UE6xxL5ZWJAAiHzHYEg==} - deprecated: Package is unsupport. Please use the lodash package instead. - - loader-runner@2.4.0: - resolution: {integrity: sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==} - engines: {node: '>=4.3.0 <5.0.0 || >=5.10'} - loader-runner@4.3.2: resolution: {integrity: sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==} engines: {node: '>=6.11.5'} - loader-utils@1.4.2: - resolution: {integrity: sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==} - engines: {node: '>=4.0.0'} - - locate-path@2.0.0: - resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} - engines: {node: '>=4'} - locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -7420,50 +3873,18 @@ packages: resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - locter@2.2.1: - resolution: {integrity: sha512-Cc7mowptFl7ug5he6Iuos7aGRd9xbwTfnx1ng4AX/7F4iqemPaXAIJDi13IBwQZrKgli9OPEYXm6uCKr7ynxUQ==} - engines: {node: '>=22.0.0'} - - lodash._reinterpolate@3.0.0: - resolution: {integrity: sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==} - lodash.camelcase@4.3.0: resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} - lodash.defaults@4.2.0: - resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} - - lodash.difference@4.5.0: - resolution: {integrity: sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==} - - lodash.escaperegexp@4.1.2: - resolution: {integrity: sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==} - - lodash.flatten@4.4.0: - resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} - - lodash.groupby@4.6.0: - resolution: {integrity: sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==} - lodash.includes@4.3.0: resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} lodash.isboolean@3.0.3: resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} - lodash.isequal@4.5.0: - resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} - deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. - - lodash.isfunction@3.0.9: - resolution: {integrity: sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==} - lodash.isinteger@4.0.4: resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} - lodash.isnil@4.0.0: - resolution: {integrity: sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==} - lodash.isnumber@3.0.3: resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} @@ -7473,9 +3894,6 @@ packages: lodash.isstring@4.0.1: resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} - lodash.isundefined@3.0.1: - resolution: {integrity: sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==} - lodash.kebabcase@4.1.1: resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==} @@ -7497,16 +3915,6 @@ packages: lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} - lodash.template@4.18.1: - resolution: {integrity: sha512-5urZrLnV/VD6zHK5KsVtZgt7H19v51mIzoS0aBNH8yp3I8tbswrEjOABOPY8m8uB7NuibubLrMX+Y0PXsU9X+w==} - deprecated: This package is deprecated. Use https://socket.dev/npm/package/eta instead. - - lodash.templatesettings@4.2.0: - resolution: {integrity: sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==} - - lodash.union@4.6.0: - resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==} - lodash.uniq@4.5.0: resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} @@ -7519,10 +3927,6 @@ packages: lodash@4.18.1: resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} - log-ok@0.1.1: - resolution: {integrity: sha512-cc8VrkS6C+9TFuYAwuHpshrcrGRAv7d0tUJ0GdM72ZBlKXtlgjUZF84O+OhQUdiVHoF7U/nVxwpjOdwUJ8d3Vg==} - engines: {node: '>=0.10.0'} - log-symbols@4.1.0: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} @@ -7531,39 +3935,16 @@ packages: resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} engines: {node: '>=18'} - log-utils@0.2.1: - resolution: {integrity: sha512-udyegKoMz9eGfpKAX//Khy7sVAZ8b1F7oLDnepZv/1/y8xTvsyPgqQrM94eG8V0vcc2BieYI2kVW4+aa6m+8Qw==} - engines: {node: '>=0.10.0'} - - logging-helpers@1.0.0: - resolution: {integrity: sha512-qyIh2goLt1sOgQQrrIWuwkRjUx4NUcEqEGAcYqD8VOnOC6ItwkrVE8/tA4smGpjzyp4Svhc6RodDp9IO5ghpyA==} - engines: {node: '>=0.10.0'} - - loglevel@1.9.2: - resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} - engines: {node: '>= 0.6.0'} - - longest@1.0.1: - resolution: {integrity: sha512-k+yt5n3l48JU4k8ftnKG6V7u32wyH2NfKzeMto9F/QRE0amxy/LayxwlvjjkZEIzqR+19IrtFO8p5kB9QaYUFg==} - engines: {node: '>=0.10.0'} + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true - lottie-web@5.13.0: - resolution: {integrity: sha512-+gfBXl6sxXMPe8tKQm7qzLnUy5DUPJPKIyRHwtpCpyUEYjHYRJC/5gjUvdkuO2c3JllrPtHXH5UJJK8LRYl5yQ==} - - loud-rejection@1.6.0: - resolution: {integrity: sha512-RPNliZOFkqFumDhvYqOaNY4Uz9oJM2K9tC6JWsJJsNdhuONW4LQHRBpb0qf4pJApVffI5N39SwzWZJuEhfd7eQ==} - engines: {node: '>=0.10.0'} - loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} - lower-case@2.0.2: - resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} - lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -7571,16 +3952,12 @@ packages: resolution: {integrity: sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==} engines: {node: 20 || >=22} - lru-cache@4.1.5: - resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} - lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lucide-react@0.513.0: - resolution: {integrity: sha512-CJZKq2g8Y8yN4Aq002GahSXbG2JpFv9kXwyiOAMvUBv7pxeOFHUWKB0mO7MiY4ZVFCV4aNjv2BJFq/z3DgKPQg==} - peerDependencies: - react: 18.3.1 + lru.min@1.1.4: + resolution: {integrity: sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==} + engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} luxon@3.7.2: resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==} @@ -7592,9 +3969,6 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - make-cancellable-promise@2.0.0: - resolution: {integrity: sha512-3SEQqTpV9oqVsIWqAcmDuaNeo7yBO3tqPtqGRcKkEo0lrzD3wqbKG9mkxO65KoOgXqj+zH2phJ2LiAsdzlogSw==} - make-dir@3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} @@ -7606,37 +3980,13 @@ packages: make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - make-event-props@2.0.0: - resolution: {integrity: sha512-G/hncXrl4Qt7mauJEXSg3AcdYzmpkIITTNl5I+rH9sog5Yw0kK6vseJjCaPfOXqOqQuPUP89Rkhfz5kPS8ijtw==} - makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} - map-cache@0.2.2: - resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} - engines: {node: '>=0.10.0'} - - map-obj@1.0.1: - resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} - engines: {node: '>=0.10.0'} - - map-visit@1.0.0: - resolution: {integrity: sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==} - engines: {node: '>=0.10.0'} - math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - md5.js@1.3.5: - resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} - - mdn-data@2.0.14: - resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==} - - media-engine@1.0.3: - resolution: {integrity: sha512-aa5tG6sDoK+k70B9iEX1NeyfT8ObCKhNDs6lJVpwF6r8vhUfuKMslIcirq6HIUYuuUYLefcEQOn9bSBOvawtwg==} - media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} @@ -7645,40 +3995,18 @@ packages: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} - mem@1.1.0: - resolution: {integrity: sha512-nOBDrc/wgpkd3X/JOhMqYR+/eLqlfLP4oQfoBA6QExIxEl+GU01oyEkwWyueyO8110pUKijtiHGhEmYoOn88oQ==} - engines: {node: '>=4'} - memfs@3.5.3: resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==} engines: {node: '>= 4.0.0'} - memory-fs@0.4.1: - resolution: {integrity: sha512-cda4JKCxReDXFXRqOHPQscuIYg1PvxbE2S2GP45rnwfEK+vZaXC8C1OFvdHIbgw0DLzowXGVoxLaAmlgRy14GQ==} - meow@12.1.1: resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} engines: {node: '>=16.10'} - meow@3.7.0: - resolution: {integrity: sha512-TNdwZs0skRlpPpCUK25StC4VH+tP5GgeY1HQOOGP+lQ2xtdkN2VtT/5tiX9k3IWpkBPV9b3LsAWXn4GGi/PrSA==} - engines: {node: '>=0.10.0'} - - merge-descriptors@1.0.3: - resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} - merge-descriptors@2.0.0: resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} engines: {node: '>=18'} - merge-refs@2.0.0: - resolution: {integrity: sha512-3+B21mYK2IqUWnd2EivABLT7ueDhb0b8/dGK8LoFQPrU61YITeCMn14F7y7qZafWNZhUEKb24cJdiT5Wxs3prg==} - peerDependencies: - '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -7690,18 +4018,10 @@ packages: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} - micromatch@3.1.10: - resolution: {integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==} - engines: {node: '>=0.10.0'} - micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} - miller-rabin@4.0.1: - resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} - hasBin: true - mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -7718,23 +4038,11 @@ packages: resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} engines: {node: '>=18'} - mime@1.2.11: - resolution: {integrity: sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==} - - mime@1.6.0: - resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} - engines: {node: '>=4'} - hasBin: true - mime@2.6.0: resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} engines: {node: '>=4.0.0'} hasBin: true - mimic-fn@1.2.0: - resolution: {integrity: sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==} - engines: {node: '>=4'} - mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -7751,12 +4059,6 @@ packages: resolution: {integrity: sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==} engines: {node: '>=8'} - minimalistic-assert@1.0.1: - resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - - minimalistic-crypto-utils@1.0.1: - resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} - minimatch@10.2.5: resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} @@ -7764,10 +4066,6 @@ packages: minimatch@3.1.5: resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - minimatch@5.1.9: - resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} - engines: {node: '>=10'} - minimatch@9.0.9: resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} @@ -7775,10 +4073,6 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - minio@7.1.3: - resolution: {integrity: sha512-xPrLjWkTT5E7H7VnzOjF//xBp9I40jYB4aWhb2xTFopXXfw+Wo82DDWngdUju7Doy3Wk7R8C4LAgwhLHHnf0wA==} - engines: {node: ^16 || ^18 || >=20} - minipass@3.3.6: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} engines: {node: '>=8'} @@ -7795,64 +4089,33 @@ packages: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} engines: {node: '>= 8'} - mixin-deep@1.3.2: - resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==} - engines: {node: '>=0.10.0'} - - mkdirp@0.5.6: - resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} - hasBin: true - mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} hasBin: true - moment@2.30.1: - resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} - - motion-dom@12.38.0: - resolution: {integrity: sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA==} - - motion-utils@12.36.0: - resolution: {integrity: sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg==} - - ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - mui-ethiopian-datepicker@0.3.2: - resolution: {integrity: sha512-I8TZ8lvloAxhFNl8tDl7NmgT7RPJslfnArNMpT2Sd9GbpfsdRrOwH/JBMcOhLQyaNUee9due0W6J85io1WLjlg==} - peerDependencies: - '@emotion/react': ^11.11.0 - '@emotion/styled': ^11.11.0 - '@mui/icons-material': ^5.11.16 - '@mui/material': ^5.13.3 - '@mui/x-date-pickers': ^6.7.0 - date-fns: ^3.6.0 - react: 18.3.1 - react-dom: 18.3.1 - multer@2.1.1: resolution: {integrity: sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==} engines: {node: '>= 10.16.0'} - multicast-dns-service-types@1.1.0: - resolution: {integrity: sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==} - - multicast-dns@7.2.5: - resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==} - hasBin: true - mute-stream@2.0.0: resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} engines: {node: ^18.17.0 || >=20.5.0} + mysql2@3.15.3: + resolution: {integrity: sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==} + engines: {node: '>= 8.0'} + mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + named-placeholders@1.1.6: + resolution: {integrity: sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==} + engines: {node: '>=8.0.0'} + nan@2.26.2: resolution: {integrity: sha512-0tTvBTYkt3tdGw22nrAy50x7gpbGCCFH3AFcyS5WiUu7Eu4vWlri1woE6qHBSfy11vksDqkiwjOnlR7WV8G1Hw==} @@ -7861,21 +4124,9 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - nanomatch@1.2.13: - resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==} - engines: {node: '>=0.10.0'} - natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - negotiator@0.6.3: - resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} - engines: {node: '>= 0.6'} - - negotiator@0.6.4: - resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} - engines: {node: '>= 0.6'} - negotiator@1.0.0: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} @@ -7883,34 +4134,12 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - nestjs-minio-client@2.2.0: - resolution: {integrity: sha512-mz1vfJq/7YfSyVCIeZwOCfIfBz+msI9QynHS2QGO9GB+tVNnQOYta8PxFsH9tMxN7gNrjrf5jXsEIpgBB1oTeA==} - peerDependencies: - '@nestjs/common': '>=9.0.0' - '@nestjs/core': '>=9.0.0' - - next-themes@0.4.6: - resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - next-tick@1.1.0: - resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} - - no-case@3.0.4: - resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} - node-abort-controller@3.1.1: resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} node-addon-api@5.1.0: resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==} - node-addon-api@8.7.0: - resolution: {integrity: sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==} - engines: {node: ^18 || ^20 || >= 21} - node-emoji@1.11.0: resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} @@ -7918,6 +4147,9 @@ packages: resolution: {integrity: sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==} engines: {node: '>= 0.4'} + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -7927,23 +4159,9 @@ packages: encoding: optional: true - node-forge@0.10.0: - resolution: {integrity: sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==} - engines: {node: '>= 6.0.0'} - - node-gyp-build@4.8.4: - resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} - hasBin: true - - node-html-parser@6.1.13: - resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==} - node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - node-libs-browser@2.2.1: - resolution: {integrity: sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==} - node-releases@2.0.44: resolution: {integrity: sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==} @@ -7952,24 +4170,10 @@ packages: engines: {node: '>=6'} hasBin: true - normalize-package-data@2.5.0: - resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} - - normalize-path@2.1.1: - resolution: {integrity: sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==} - engines: {node: '>=0.10.0'} - normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - normalize-svg-path@1.1.0: - resolution: {integrity: sha512-r9KHKG2UUeB5LoTouwDzBy2VxXlHsiM6fyLQvnJa0S5hrhzqElH/CH7TUGhT1fVvIYBIKf3OpY4YJ4CK+iaqHg==} - - npm-run-path@2.0.2: - resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==} - engines: {node: '>=4'} - npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} @@ -7982,27 +4186,18 @@ packages: resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} deprecated: This package is no longer supported. - nth-check@2.1.1: - resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - - number-is-nan@1.0.1: - resolution: {integrity: sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==} - engines: {node: '>=0.10.0'} - nwsapi@2.2.23: resolution: {integrity: sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==} - oauth-sign@0.9.0: - resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==} + nypm@0.6.6: + resolution: {integrity: sha512-vRyr0r4cbBapw07Xw8xrj9Teq3o7MUD35rSaTcanDbW+aK2XHDgJFiU6ZTj2GBw7Q12ysdsyFss+Vdz4hQ0Y6Q==} + engines: {node: '>=18'} + hasBin: true object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} - object-copy@0.1.0: - resolution: {integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==} - engines: {node: '>=0.10.0'} - object-hash@3.0.0: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} @@ -8011,18 +4206,10 @@ packages: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} - object-is@1.1.6: - resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} - engines: {node: '>= 0.4'} - object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} - object-visit@1.0.1: - resolution: {integrity: sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==} - engines: {node: '>=0.10.0'} - object.assign@4.1.7: resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} engines: {node: '>= 0.4'} @@ -8039,25 +4226,17 @@ packages: resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} engines: {node: '>= 0.4'} - object.pick@1.3.0: - resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==} - engines: {node: '>=0.10.0'} - object.values@1.2.1: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} - obuf@1.1.2: - resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} - on-headers@1.1.0: - resolution: {integrity: sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==} - engines: {node: '>= 0.8'} - once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -8073,14 +4252,6 @@ packages: resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} engines: {node: '>=18'} - opencollective-postinstall@2.0.3: - resolution: {integrity: sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==} - hasBin: true - - opn@5.5.0: - resolution: {integrity: sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==} - engines: {node: '>=4'} - optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -8089,35 +4260,10 @@ packages: resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} engines: {node: '>=10'} - orderedmap@2.1.1: - resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==} - - original@1.0.2: - resolution: {integrity: sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==} - - os-browserify@0.3.0: - resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==} - - os-locale@1.4.0: - resolution: {integrity: sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==} - engines: {node: '>=0.10.0'} - - os-locale@2.1.0: - resolution: {integrity: sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==} - engines: {node: '>=4'} - own-keys@1.0.1: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} - p-finally@1.0.0: - resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} - engines: {node: '>=4'} - - p-limit@1.3.0: - resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} - engines: {node: '>=4'} - p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -8130,10 +4276,6 @@ packages: resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - p-locate@2.0.0: - resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} - engines: {node: '>=4'} - p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} @@ -8146,14 +4288,6 @@ packages: resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - p-map@1.2.0: - resolution: {integrity: sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==} - engines: {node: '>=4'} - - p-try@1.0.0: - resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} - engines: {node: '>=4'} - p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -8161,34 +4295,14 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - pako@0.2.9: - resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} - - pako@1.0.11: - resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} - - pako@2.1.0: - resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} - parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} - parse-asn1@5.1.9: - resolution: {integrity: sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==} - engines: {node: '>= 0.10'} - - parse-json@2.2.0: - resolution: {integrity: sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==} - engines: {node: '>=0.10.0'} - parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} - parse-svg-path@0.1.2: - resolution: {integrity: sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==} - parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} @@ -8196,13 +4310,6 @@ packages: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} - pascal-case@3.1.2: - resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} - - pascalcase@0.1.1: - resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==} - engines: {node: '>=0.10.0'} - passport-jwt@4.0.1: resolution: {integrity: sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==} @@ -8214,20 +4321,6 @@ packages: resolution: {integrity: sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==} engines: {node: '>= 0.4.0'} - path-browserify@0.0.1: - resolution: {integrity: sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==} - - path-dirname@1.0.2: - resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==} - - path-exists@2.1.0: - resolution: {integrity: sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==} - engines: {node: '>=0.10.0'} - - path-exists@3.0.0: - resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} - engines: {node: '>=4'} - path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -8240,13 +4333,6 @@ packages: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} - path-is-inside@1.0.2: - resolution: {integrity: sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==} - - path-key@2.0.1: - resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==} - engines: {node: '>=4'} - path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -8266,37 +4352,22 @@ packages: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} - path-to-regexp@0.1.13: - resolution: {integrity: sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==} - path-to-regexp@3.3.0: resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==} path-to-regexp@8.4.2: resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} - path-type@1.1.0: - resolution: {integrity: sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==} - engines: {node: '>=0.10.0'} - - path-type@2.0.0: - resolution: {integrity: sha512-dUnb5dXUf+kzhC/W/F4e5/SkluXIFf5VUHolW1Eg1irn1hGWjPGdsRcvYJ1nD6lhk8Ir7VM0bHJKsYTx8Jx9OQ==} - engines: {node: '>=4'} - path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - path2d-polyfill@2.0.1: - resolution: {integrity: sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==} - engines: {node: '>=8'} - - path@0.12.7: - resolution: {integrity: sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==} - pathe@1.1.2: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + pathval@2.0.1: resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} engines: {node: '>= 14.16'} @@ -8304,23 +4375,8 @@ packages: pause@0.0.1: resolution: {integrity: sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==} - pbkdf2@3.1.5: - resolution: {integrity: sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==} - engines: {node: '>= 0.10'} - - pdfjs-dist@3.11.174: - resolution: {integrity: sha512-TdTZPf1trZ8/UFu5Cx/GXB7GZM30LT+wWUNfsi6Bq8ePLnb+woNKtDymI2mxZYBpMbonNFqKmiz684DIfnd8dA==} - engines: {node: '>=18'} - - peek-readable@5.4.2: - resolution: {integrity: sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg==} - engines: {node: '>=14.16'} - - perfect-freehand@1.2.3: - resolution: {integrity: sha512-bHZSfqDHGNlPpgH2yxXgPHlQSPpEbo+qg7li0M78J9vNAi2yjwLeA4x79BEQhX44lEWpCLSFCeRZwpw0niiXPA==} - - performance-now@2.1.0: - resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} pg-cloudflare@1.3.0: resolution: {integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==} @@ -8376,53 +4432,25 @@ packages: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} - pify@3.0.0: - resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} - engines: {node: '>=4'} - - pinkie-promise@2.0.1: - resolution: {integrity: sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==} - engines: {node: '>=0.10.0'} - - pinkie@2.0.4: - resolution: {integrity: sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==} - engines: {node: '>=0.10.0'} - pirates@4.0.7: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} - pkg-dir@2.0.0: - resolution: {integrity: sha512-ojakdnUgL5pzJYWw2AIDEupaQCX5OPbM688ZevubICjdIX01PRSYKqm33fJoCOJBRseYCTUlQRnBNX+Pchaejw==} - engines: {node: '>=4'} - pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} + pkg-types@2.3.1: + resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} + pluralize@8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} - png-js@2.0.0: - resolution: {integrity: sha512-GdzJuUMc6ZSpxFJWVxtOH1bzYHym+TOnveqUjb+VJIbZWbZzyiRGFiKhbiielfpYbgMlhHVhsJ0FTazfuRFkMA==} - pngjs@5.0.0: resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} engines: {node: '>=10.13.0'} - popper.js@1.16.1: - resolution: {integrity: sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==} - deprecated: You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1 - - portfinder@1.0.38: - resolution: {integrity: sha512-rEwq/ZHlJIKw++XtLAO8PPuOQA/zaPJOZJ37BVuN97nLpMJeuDVLVGRwbFoBgLudgdTMP2hdRJP++H+8QOA3vg==} - engines: {node: '>= 10.12'} - - posix-character-classes@0.1.1: - resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} - engines: {node: '>=0.10.0'} - possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} @@ -8503,17 +4531,15 @@ packages: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - prisma@5.22.0: - resolution: {integrity: sha512-vtpjW3XuYCSnMsNVBjLMNkTj6OZbudcPPTPYHqX0CJfpcdWciI1dM8uHETwmDxxiqEwCIE6WvXucWUetJgfu/A==} - engines: {node: '>=16.13'} + prisma@6.19.3: + resolution: {integrity: sha512-++ZJ0ijLrDJF6hNB4t4uxg2br3fC4H9Yc9tcbjr2fcNFP3rh/SBNrAgjhsqBU4Ght8JPrVofG/ZkXfnSfnYsFg==} + engines: {node: '>=18.18'} hasBin: true - - process-nextick-args@2.0.1: - resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - - process@0.11.10: - resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} - engines: {node: '>= 0.6.0'} + peerDependencies: + typescript: '>=5.1.0' + peerDependenciesMeta: + typescript: + optional: true prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} @@ -8522,71 +4548,14 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - prosemirror-changeset@2.4.1: - resolution: {integrity: sha512-96WBLhOaYhJ+kPhLg3uW359Tz6I/MfcrQfL4EGv4SrcqKEMC1gmoGrXHecPE8eOwTVCJ4IwgfzM8fFad25wNfw==} - - prosemirror-commands@1.7.1: - resolution: {integrity: sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==} - - prosemirror-dropcursor@1.8.2: - resolution: {integrity: sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==} - - prosemirror-gapcursor@1.4.1: - resolution: {integrity: sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==} - - prosemirror-history@1.5.0: - resolution: {integrity: sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==} - - prosemirror-keymap@1.2.3: - resolution: {integrity: sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==} - - prosemirror-model@1.25.4: - resolution: {integrity: sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==} - - prosemirror-schema-list@1.5.1: - resolution: {integrity: sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==} - - prosemirror-state@1.4.4: - resolution: {integrity: sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==} - - prosemirror-tables@1.8.5: - resolution: {integrity: sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==} - - prosemirror-transform@1.12.0: - resolution: {integrity: sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w==} - - prosemirror-view@1.41.8: - resolution: {integrity: sha512-TnKDdohEatgyZNGCDWIdccOHXhYloJwbwU+phw/a23KBvJIR9lWQWW7WHHK3vBdOLDNuF7TaX98GObUZOWkOnA==} - proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} - proxy-compare@3.0.1: - resolution: {integrity: sha512-V9plBAt3qjMlS1+nC8771KNf6oJ12gExvaxnNzN/9yVRLdTv/lc+oJlnSzrdYDAvBfTStPCoiaCOTmTs0adv7Q==} - proxy-from-env@2.1.0: resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} engines: {node: '>=10'} - proxy-memoize@3.0.1: - resolution: {integrity: sha512-VDdG/VYtOgdGkWJx7y0o7p+zArSf2383Isci8C+BP3YXgMYDoPd3cCBjw0JdWb6YBb9sFiOPbAADDVTPJnh+9g==} - - prr@1.0.1: - resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} - - pseudomap@1.0.2: - resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} - - psl@1.15.0: - resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} - - public-encrypt@4.0.3: - resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} - - punycode@1.4.1: - resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} - punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -8603,215 +4572,35 @@ packages: resolution: {integrity: sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==} engines: {node: '>=0.6'} - qs@6.5.5: - resolution: {integrity: sha512-mzR4sElr1bfCaPJe7m8ilJ6ZXdDaGoObcYR0ZHSsktM/Lt21MVHj5De30GQH2eiZ1qGRTO7LCAzQsUeXTNexWQ==} - engines: {node: '>=0.6'} - - query-string@7.1.3: - resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} - engines: {node: '>=6'} - - querystring-es3@0.2.1: - resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} - engines: {node: '>=0.4.x'} - - querystringify@2.2.0: - resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} - queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - queue@6.0.2: - resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} - - raf@3.4.1: - resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==} - - randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - - randomfill@1.0.4: - resolution: {integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==} - range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} - rapiq@0.9.0: - resolution: {integrity: sha512-k4oT4RarFBrlLMJ49xUTeQpa/us0uU4I70D/UEnK3FWQ4GENzei01rEQAmvPKAIzACo4NMW+YcYJ7EVfSa7EFg==} - - raw-body@2.5.3: - resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==} - engines: {node: '>= 0.8'} - raw-body@3.0.2: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} - react-cookie@8.1.2: - resolution: {integrity: sha512-S45Z1y1dHyYfLEI4bFKQICuP+SwJqTPWbdc2ZpE6aQSdjSVJAjUDfwTPq8B7BWieIsgyyEWMb/QOrudtwJMjXA==} - peerDependencies: - react: 18.3.1 - - react-datepicker@8.10.0: - resolution: {integrity: sha512-JIXuA+g+qP3c4MVJpx24o7n1gnv3WV/8A/D6964HucY1FlSEc30+ITPNUfbKZXYHl5rruCtxYCwi2lzn7gaz7g==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - react-day-picker@9.14.0: - resolution: {integrity: sha512-tBaoDWjPwe0M5pGrum4H0SR6Lyk+BO9oHnp9JbKpGKW2mlraNPgP9BMfsg5pWpwrssARmeqk7YBl2oXutZTaHA==} - engines: {node: '>=18'} - peerDependencies: - react: 18.3.1 + rc9@2.1.2: + resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} react-dom@18.3.1: resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} peerDependencies: react: 18.3.1 - react-dropzone@14.4.1: - resolution: {integrity: sha512-QDuV76v3uKbHiH34SpwifZ+gOLi1+RdsCO1kl5vxMT4wW8R82+sthjvBw4th3NHF/XX6FBsqDYZVNN+pnhaw0g==} - engines: {node: '>= 10.13'} - peerDependencies: - react: 18.3.1 - - react-floater@0.7.9: - resolution: {integrity: sha512-NXqyp9o8FAXOATOEo0ZpyaQ2KPb4cmPMXGWkx377QtJkIXHlHRAGer7ai0r0C1kG5gf+KJ6Gy+gdNIiosvSicg==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - react-hook-form@7.75.0: - resolution: {integrity: sha512-Ovv94H+0p3sJ7B9B5QxPuCP1u8V/cHuVGyH55cSwodYDtoJwK+fqk3vjfIgSX59I2U/bU4z0nRJ9HMLpNiWEmw==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: 18.3.1 - - react-i18next@15.7.4: - resolution: {integrity: sha512-nyU8iKNrI5uDJch0z9+Y5XEr34b0wkyYj3Rp+tfbahxtlswxSCjcUL9H0nqXo9IR3/t5Y5PKIA3fx3MfUyR9Xw==} - peerDependencies: - i18next: '>= 23.4.0' - react: 18.3.1 - react-dom: '*' - react-native: '*' - typescript: ^5 - peerDependenciesMeta: - react-dom: - optional: true - react-native: - optional: true - typescript: - optional: true - - react-icons@5.6.0: - resolution: {integrity: sha512-RH93p5ki6LfOiIt0UtDyNg/cee+HLVR6cHHtW3wALfo+eOHTp8RnU2kRkI6E+H19zMIs03DyxUG/GfZMOGvmiA==} - peerDependencies: - react: 18.3.1 - - react-image-crop@11.0.10: - resolution: {integrity: sha512-+5FfDXUgYLLqBh1Y/uQhIycpHCbXkI50a+nbfkB1C0xXXUTwkisHDo2QCB1SQJyHCqIuia4FeyReqXuMDKWQTQ==} - peerDependencies: - react: 18.3.1 - - react-innertext@1.1.5: - resolution: {integrity: sha512-PWAqdqhxhHIv80dT9znP2KvS+hfkbRovFp4zFYHFFlOoQLRiawIic81gKb3U1wEyJZgMwgs3JoLtwryASRWP3Q==} - peerDependencies: - '@types/react': '>=0.0.0 <=99' - react: 18.3.1 - - react-intersection-observer@9.16.0: - resolution: {integrity: sha512-w9nJSEp+DrW9KmQmeWHQyfaP6b03v+TdXynaoA964Wxt7mdR3An11z4NNCQgL4gKSK7y1ver2Fq+JKH6CWEzUA==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - react-dom: - optional: true - react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react-is@19.2.6: - resolution: {integrity: sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==} - - react-joyride@2.9.3: - resolution: {integrity: sha512-1+Mg34XK5zaqJ63eeBhqdbk7dlGCFp36FXwsEvgpjqrtyywX2C6h9vr3jgxP0bGHCw8Ilsp/nRDzNVq6HJ3rNw==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - react-number-format@5.4.5: - resolution: {integrity: sha512-y8O2yHHj3w0aE9XO8d2BCcUOOdQTRSVq+WIuMlLVucAm5XNjJAy+BoOJiuQMldVYVOKTMyvVNfnbl2Oqp+YxGw==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - react-pdf-html@2.1.5: - resolution: {integrity: sha512-KhmiTUcnUNbLVdZbxMcV/+Rp+PyBt+eVJHu425eNwjSsDUtytvcwS/SBdBbbpM0c4+MnnOQBOs3AiColUesM8A==} - engines: {node: '>=16.0.0'} - peerDependencies: - '@react-pdf/renderer': '>=3.4.4' - react: 18.3.1 - - react-pdf-viewer@0.1.0: - resolution: {integrity: sha512-JO0bZEA6EMtljhTrLNyn9T03nIOXY6/tzK8guOdwfYpImdOpYfACy47G9AKXrVrtob9bEW2d1jR3MkC0NEGajw==} - - react-pdf@10.4.1: - resolution: {integrity: sha512-kS/35staVCBqS29verTQJQZXw7RfsRCPO3fdJoW1KXylcv7A9dw6DZ3vJXC2w+bIBgLw5FN4pOFvKSQtkQhPfA==} - peerDependencies: - '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - react-redux@9.2.0: - resolution: {integrity: sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==} - peerDependencies: - '@types/react': ^18.2.25 || ^19 - react: 18.3.1 - redux: ^5.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - redux: - optional: true - react-refresh@0.17.0: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} - react-remove-scroll-bar@2.3.8: - resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - react-remove-scroll@2.7.2: - resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - react-resizable-panels@3.0.6: - resolution: {integrity: sha512-b3qKHQ3MLqOgSS+FRYKapNkJZf5EQzuf6+RLiq1/IlTHw99YrZ2NJZLk4hQIzTnnIkRg2LUqyVinu6YWWpUYew==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - react-router-dom@6.30.3: resolution: {integrity: sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==} engines: {node: '>=14.0.0'} @@ -8819,65 +4608,12 @@ packages: react: 18.3.1 react-dom: 18.3.1 - react-router-dom@7.15.0: - resolution: {integrity: sha512-VcrVg64Fo8nwBvDscajG8gRTLIuTC6N50nb22l2HOOV4PTOHgoGp8mUjy9wLiHYoYTSYI36tUnXZgasSRFZorQ==} - engines: {node: '>=20.0.0'} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - react-router@6.30.3: resolution: {integrity: sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==} engines: {node: '>=14.0.0'} peerDependencies: react: 18.3.1 - react-router@7.15.0: - resolution: {integrity: sha512-HW9vYwuM8f4yx66Izy8xfrzCM+SBJluoZcCbww9A1TySax11S5Vgw6fi3ZjMONw9J4gQwngL7PzkyIpJJpJ7RQ==} - engines: {node: '>=20.0.0'} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - react-dom: - optional: true - - react-signature-canvas@1.1.0-alpha.2: - resolution: {integrity: sha512-tKUNk3Gmh04Ug4K8p5g8Is08BFUKvbXxi0PyetQ/f8OgCBzcx4vqNf9+OArY/TdNdfHtswXQNRwZD6tyELjkjQ==} - peerDependencies: - '@types/prop-types': ^15.7.3 - '@types/react': 0.14 - 19 - prop-types: ^15.5.8 - react: 18.3.1 - react-dom: 18.3.1 - peerDependenciesMeta: - '@types/prop-types': - optional: true - '@types/react': - optional: true - - react-style-singleton@2.2.3: - resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - react-textarea-autosize@8.5.9: - resolution: {integrity: sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A==} - engines: {node: '>=10'} - peerDependencies: - react: 18.3.1 - - react-transition-group@4.4.5: - resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -8885,44 +4621,10 @@ packages: read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} - read-pkg-up@1.0.1: - resolution: {integrity: sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==} - engines: {node: '>=0.10.0'} - - read-pkg-up@2.0.0: - resolution: {integrity: sha512-1orxQfbWGUiTn9XsPlChs6rLie/AV9jwZTGmu2NZw/CUDJQchXJFYE0Fq5j7+n558T1JhDWLdhyd1Zj+wLY//w==} - engines: {node: '>=4'} - - read-pkg@1.1.0: - resolution: {integrity: sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==} - engines: {node: '>=0.10.0'} - - read-pkg@2.0.0: - resolution: {integrity: sha512-eFIBOPW7FGjzBuk3hdXEuNSiTZS/xEMlH49HxMyzb0hyPfu4EhVjT2DH32K1hSSmVq4sebAWnZuuY5auISUTGA==} - engines: {node: '>=4'} - - readable-stream@2.3.8: - resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} - readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} - readable-stream@4.7.0: - resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - readable-web-to-node-stream@3.0.4: - resolution: {integrity: sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw==} - engines: {node: '>=8'} - - readdir-glob@1.1.3: - resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} - - readdirp@2.2.1: - resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==} - engines: {node: '>=0.10'} - readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -8931,29 +4633,6 @@ packages: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} - recharts@3.8.1: - resolution: {integrity: sha512-mwzmO1s9sFL0TduUpwndxCUNoXsBw3u3E/0+A+cLcrSfQitSG62L32N69GhqUrrT5qKcAE3pCGVINC6pqkBBQg==} - engines: {node: '>=18'} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - react-is: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - redent@1.0.0: - resolution: {integrity: sha512-qtW5hKzGQZqKoh6JNSD+4lfitfPKGz42e6QwiRmPM5mmKtR0N41AbJRYu0xJi7nhOJ4WDgRkKvAk6tw4WIwR4g==} - engines: {node: '>=0.10.0'} - - redux-thunk@3.1.0: - resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==} - peerDependencies: - redux: ^5.0.0 - - redux@5.0.1: - resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} - - reflect-metadata@0.1.14: - resolution: {integrity: sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==} - reflect-metadata@0.2.2: resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} @@ -8961,46 +4640,10 @@ packages: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} - regenerator-runtime@0.13.11: - resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} - - regex-not@1.0.2: - resolution: {integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==} - engines: {node: '>=0.10.0'} - regexp.prototype.flags@1.5.4: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} - relative@3.0.2: - resolution: {integrity: sha512-Q5W2qeYtY9GbiR8z1yHNZ1DGhyjb4AnLEjt8iE6XfcC1QIu+FAtj3HQaO0wH28H1mX6cqNLvAqWhP402dxJGyA==} - engines: {node: '>= 0.8.0'} - - remarkable@1.7.4: - resolution: {integrity: sha512-e6NKUXgX95whv7IgddywbeN/ItCkWbISmc2DiqHJb0wTrqZIexqdco5b8Z3XZoo/48IdNVKM9ZCvTPJ4F5uvhg==} - engines: {node: '>= 0.10.0'} - hasBin: true - - remove-trailing-separator@1.1.0: - resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} - - repeat-element@1.1.4: - resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==} - engines: {node: '>=0.10.0'} - - repeat-string@1.6.1: - resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} - engines: {node: '>=0.10'} - - repeating@2.0.1: - resolution: {integrity: sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A==} - engines: {node: '>=0.10.0'} - - request@2.88.2: - resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==} - engines: {node: '>= 6'} - deprecated: request has been deprecated, see https://github.com/request/request/issues/3142 - require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -9009,30 +4652,13 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - require-main-filename@1.0.1: - resolution: {integrity: sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==} - require-main-filename@2.0.0: resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} - requires-port@1.0.0: - resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} - - reselect@5.1.1: - resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==} - - resolve-cwd@2.0.0: - resolution: {integrity: sha512-ccu8zQTrzVr954472aUVPLEcB3YpKSYR3cg/3lo1okzobPBM+1INXBbBZlDbnI/hbEocnf8j0QVo43hQKrbchg==} - engines: {node: '>=4'} - resolve-cwd@3.0.0: resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} engines: {node: '>=8'} - resolve-from@3.0.0: - resolution: {integrity: sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==} - engines: {node: '>=4'} - resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -9041,10 +4667,6 @@ packages: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} - resolve-url@0.2.1: - resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==} - deprecated: https://github.com/lydell/resolve-url#deprecated - resolve.exports@2.0.3: resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} engines: {node: '>=10'} @@ -9067,13 +4689,6 @@ packages: resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} engines: {node: '>=18'} - restructure@3.0.2: - resolution: {integrity: sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==} - - ret@0.1.15: - resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==} - engines: {node: '>=0.12'} - reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -9081,36 +4696,16 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rgbcolor@1.0.1: - resolution: {integrity: sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==} - engines: {node: '>= 0.8.15'} - - right-align@0.1.3: - resolution: {integrity: sha512-yqINtL/G7vs2v+dFIZmFUDbnVyFUJFKd6gK22Kgo6R4jfJGFtisKyncWDDULgjfqf4ASQuIQyjJ7XZ+3aWpsAg==} - engines: {node: '>=0.10.0'} - - rimraf@2.7.1: - resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - ripemd160@2.0.3: - resolution: {integrity: sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==} - engines: {node: '>= 0.8'} - rollup@4.60.3: resolution: {integrity: sha512-pAQK9HalE84QSm4Po3EmWIZPd3FnjkShVkiMlz1iligWYkWQ7wHYd1PF/T7QZ5TVSD6uSTon5gBVMSM4JfBV+A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - rope-sequence@1.3.4: - resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} - router@2.2.0: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} @@ -9134,9 +4729,6 @@ packages: resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} engines: {node: '>=0.4'} - safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -9148,20 +4740,9 @@ packages: resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} engines: {node: '>= 0.4'} - safe-regex@1.1.0: - resolution: {integrity: sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==} - safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sax@1.6.0: - resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==} - engines: {node: '>=11.0.0'} - - saxes@5.0.1: - resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==} - engines: {node: '>=10'} - saxes@6.0.0: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} @@ -9169,9 +4750,6 @@ packages: scheduler@0.23.2: resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} - scheduler@0.25.0-rc-603e6108-20241029: - resolution: {integrity: sha512-pFwF6H1XrSdYYNLfOcGlM28/j8CGLu8IvdrxqhjWULe2bPcKiKW4CV+OWqR/9fT52mywx65l7ysNkjLKBda7eA==} - schema-utils@3.3.0: resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} engines: {node: '>= 10.13.0'} @@ -9180,26 +4758,6 @@ packages: resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} engines: {node: '>= 10.13.0'} - scroll@3.0.1: - resolution: {integrity: sha512-pz7y517OVls1maEzlirKO5nPYle9AXsFzTMNJrRGmT951mzpIBy7sNHOg5o/0MQd/NqliCiWnAi0kZneMPFLcg==} - - scrollparent@2.1.0: - resolution: {integrity: sha512-bnnvJL28/Rtz/kz2+4wpBjHzWoEzXhVg/TE8BeVGJHUqE8THNIRnDxDWMktwM+qahvlRdvlLdsQfYe+cuqfZeA==} - - select-hose@2.0.0: - resolution: {integrity: sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==} - - self-closing-tags@1.0.1: - resolution: {integrity: sha512-7t6hNbYMxM+VHXTgJmxwgZgLGktuXtVVD5AivWzNTdJBM4DBjnDKDzkf2SrNjihaArpeJYNjxkELBu1evI4lQA==} - engines: {node: '>=0.12.0'} - - selfsigned@1.10.14: - resolution: {integrity: sha512-lkjaiAye+wBZDCBsu5BGi0XiLRxeUlsGod5ZP924CRSEoGuZAw/f7y9RKu28rwTfiHVhdavhB0qH0INV6P1lEA==} - - semver@5.7.2: - resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} - hasBin: true - semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -9209,21 +4767,12 @@ packages: engines: {node: '>=10'} hasBin: true - send@0.19.2: - resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} - engines: {node: '>= 0.8.0'} - send@1.2.1: resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} engines: {node: '>= 18'} - serve-index@1.9.2: - resolution: {integrity: sha512-KDj11HScOaLmrPxl70KYNW1PksP4Nb/CLL2yvC+Qd2kHMPEEpfc4Re2e4FOay+bC/+XQl/7zAcWON3JVo5v3KQ==} - engines: {node: '>= 0.8.0'} - - serve-static@1.16.3: - resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} - engines: {node: '>= 0.8.0'} + seq-queue@0.0.5: + resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} serve-static@2.2.1: resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} @@ -9232,9 +4781,6 @@ packages: set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - set-cookie-parser@2.7.2: - resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} - set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -9243,21 +4789,10 @@ packages: resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} - set-getter@0.1.1: - resolution: {integrity: sha512-9sVWOy+gthr+0G9DzqqLaYNA7+5OKkSmcqjL9cBpDEaZrr3ShQlyX2cZ/O/ozE41oxn/Tt0LGEM/w4Rub3A3gw==} - engines: {node: '>=0.10.0'} - set-proto@1.0.0: resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} engines: {node: '>= 0.4'} - set-value@2.0.1: - resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==} - engines: {node: '>=0.10.0'} - - setimmediate@1.0.5: - resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} - setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} @@ -9266,18 +4801,10 @@ packages: engines: {node: '>= 0.10'} hasBin: true - shebang-command@1.2.0: - resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} - engines: {node: '>=0.10.0'} - shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} - shebang-regex@1.0.0: - resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} - engines: {node: '>=0.10.0'} - shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} @@ -9308,9 +4835,6 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - signature_pad@2.3.2: - resolution: {integrity: sha512-peYXLxOsIY6MES2TrRLDiNg2T++8gGbpP2yaC+6Ohtxr+a2dzoaqWosWDY9sWqTAAk6E/TyQO+LJw9zQwyu5kA==} - simple-concat@1.0.1: resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} @@ -9332,67 +4856,16 @@ packages: resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} engines: {node: '>=18'} - smob@1.6.1: - resolution: {integrity: sha512-KAkBqZl3c2GvNgNhcoyJae1aKldDW0LO279wF9bk1PnluRTETKBq0WyzRXxEhoQLk56yHaOY4JCBEKDuJIET5g==} - engines: {node: '>=20.0.0'} - - snapdragon-node@2.1.1: - resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==} - engines: {node: '>=0.10.0'} - - snapdragon-util@3.0.1: - resolution: {integrity: sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==} - engines: {node: '>=0.10.0'} - - snapdragon@0.8.2: - resolution: {integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==} - engines: {node: '>=0.10.0'} - - socket.io-client@4.8.3: - resolution: {integrity: sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==} - engines: {node: '>=10.0.0'} - - socket.io-parser@4.2.6: - resolution: {integrity: sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg==} - engines: {node: '>=10.0.0'} - - sockjs-client@1.1.5: - resolution: {integrity: sha512-PmPRkAYIeuRgX+ZSieViT4Z3Q23bLS2Itm/ck1tSf5P0/yVuFDiI5q9mcnpXoMdToaPSRS9MEyUx/aaBxrFzyw==} - - sockjs@0.3.19: - resolution: {integrity: sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==} - - sonner@2.0.7: - resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - source-list-map@2.0.1: - resolution: {integrity: sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==} - source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} - source-map-resolve@0.5.3: - resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==} - deprecated: See https://github.com/lydell/source-map-resolve#deprecated - source-map-support@0.5.13: resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - source-map-url@0.4.1: - resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==} - deprecated: See https://github.com/lydell/source-map-url#deprecated - - source-map@0.5.7: - resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} - engines: {node: '>=0.10.0'} - source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} @@ -9401,37 +4874,6 @@ packages: resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} engines: {node: '>= 8'} - source-map@0.7.6: - resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} - engines: {node: '>= 12'} - - spdx-correct@3.2.0: - resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} - - spdx-exceptions@2.5.0: - resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} - - spdx-expression-parse@3.0.1: - resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - - spdx-license-ids@3.0.23: - resolution: {integrity: sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==} - - spdy-transport@3.0.0: - resolution: {integrity: sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==} - - spdy@4.0.2: - resolution: {integrity: sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==} - engines: {node: '>=6.0.0'} - - split-on-first@1.1.0: - resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==} - engines: {node: '>=6'} - - split-string@3.1.0: - resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==} - engines: {node: '>=0.10.0'} - split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} @@ -9443,14 +4885,9 @@ packages: resolution: {integrity: sha512-ed7OK4e9ywpE7pgRMkMQmZDPKSVdm0oX5IEtZiKnFucSF0zu6c80GZBe38UqHuVhTWJ9xsKgSMjCG2bml86KvA==} engines: {node: '>=14'} - ssf@0.11.2: - resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==} - engines: {node: '>=0.8'} - - sshpk@1.18.0: - resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==} - engines: {node: '>=0.10.0'} - hasBin: true + sqlstring@2.3.3: + resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} + engines: {node: '>= 0.6'} stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} @@ -9459,18 +4896,6 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - stackblur-canvas@2.7.0: - resolution: {integrity: sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==} - engines: {node: '>=0.1.14'} - - static-extend@0.1.2: - resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==} - engines: {node: '>=0.10.0'} - - statuses@1.5.0: - resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} - engines: {node: '>= 0.6'} - statuses@2.0.2: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} @@ -9482,20 +4907,10 @@ packages: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} - stream-browserify@2.0.2: - resolution: {integrity: sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==} - - stream-http@2.8.3: - resolution: {integrity: sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==} - streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} - strict-uri-encode@2.0.0: - resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} - engines: {node: '>=4'} - string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} @@ -9504,14 +4919,6 @@ packages: resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} engines: {node: '>=10'} - string-width@1.0.2: - resolution: {integrity: sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==} - engines: {node: '>=0.10.0'} - - string-width@2.1.1: - resolution: {integrity: sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==} - engines: {node: '>=4'} - string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -9543,20 +4950,9 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} - string_decoder@1.1.1: - resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} - string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - strip-ansi@3.0.1: - resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} - engines: {node: '>=0.10.0'} - - strip-ansi@4.0.0: - resolution: {integrity: sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==} - engines: {node: '>=4'} - strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -9565,10 +4961,6 @@ packages: resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} - strip-bom@2.0.0: - resolution: {integrity: sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==} - engines: {node: '>=0.10.0'} - strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} @@ -9577,10 +4969,6 @@ packages: resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} engines: {node: '>=8'} - strip-eof@1.0.0: - resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==} - engines: {node: '>=0.10.0'} - strip-final-newline@2.0.0: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} @@ -9589,39 +4977,14 @@ packages: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} engines: {node: '>=12'} - strip-indent@1.0.1: - resolution: {integrity: sha512-I5iQq6aFMM62fBEAIB/hXzwJD6EEZ0xEGCX2t7oXqaKPIRgt4WruAQ285BISgdkP+HLGWyeGmNJcpIwFeRYRUA==} - engines: {node: '>=0.10.0'} - hasBin: true - strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - striptags@3.2.0: - resolution: {integrity: sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw==} - - strnum@1.1.2: - resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==} - strtok3@10.3.5: resolution: {integrity: sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==} engines: {node: '>=18'} - strtok3@7.1.1: - resolution: {integrity: sha512-mKX8HA/cdBqMKUr0MMZAFssCkIGoZeSCMXgnt79yKxNFguMLVFgRe6wB+fsL0NmoHDbeyZXczy7vEPSoo3rkzg==} - engines: {node: '>=16'} - - style-object-to-css-string@1.1.3: - resolution: {integrity: sha512-bISQoUsir/qGfo7vY8rw00ia9nnyE1jvYt3zZ2jhdkcXZ6dAEi74inMzQ6On57vFI+I4Fck6wOv5UI9BEwJDgw==} - - stylis@4.2.0: - resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} - - success-symbol@0.1.0: - resolution: {integrity: sha512-7S6uOTxPklNGxOSbDIg4KlVLBQw1UiGVyfCUYgYxrZUKRblUkmGj7r8xlfQoFudvqLv6Ap5gd76/IIFfI9JG2A==} - engines: {node: '>=0.10.0'} - sucrase@3.35.1: resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} engines: {node: '>=16 || 14 >=14.17'} @@ -9635,14 +4998,6 @@ packages: resolution: {integrity: sha512-oK8WG9diS3DlhdUkcFn4tkNIiIbBx9lI2ClF8K+b2/m8Eyv47LSawxUzZQSNKUrVb2KsqeTDCcjAAVPYaSLVTA==} engines: {node: '>=14.18.0'} - supports-color@4.5.0: - resolution: {integrity: sha512-ycQR/UbvI9xIlEdQT1TQqwoXtEldExbCEAJgRo5YXlmSKjv6ThHnP9/vwGa1gr19Gfw+LkFd7KqYMhzrRC5JYw==} - engines: {node: '>=4'} - - supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} - supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -9655,13 +5010,6 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - svg-arc-to-cubic-bezier@3.2.0: - resolution: {integrity: sha512-djbJ/vZKZO+gPoSDThGNpKDO+o+bAeA4XQKovvkNCqnIS2t+S4qnLAGQhyyrulhCFRl1WWzAp0wUDV8PpTVU3g==} - - svg-pathdata@6.0.3: - resolution: {integrity: sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==} - engines: {node: '>=12.0.0'} - swagger-ui-dist@5.17.14: resolution: {integrity: sha512-CVbSfaLpstV65OnSjbXfVd6Sta3q3F7Cj/yYuvHMp1P90LztOLs6PfUnKEVAeiIVQt9u2SaPwv0LiH/OyMjHRw==} @@ -9681,42 +5029,15 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - tabbable@6.4.0: - resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} - - tailwind-merge@3.6.0: - resolution: {integrity: sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==} - - tailwind-scrollbar-hide@4.0.0: - resolution: {integrity: sha512-gobtvVcThB2Dxhy0EeYSS1RKQJ5baDFkamkhwBvzvevwX6L4XQfpZ3me9s25Ss1ecFVT5jPYJ50n+7xTBJG9WQ==} - peerDependencies: - tailwindcss: '>=3.0.0 || >= 4.0.0 || >= 4.0.0-beta.8 || >= 4.0.0-alpha.20' - - tailwindcss-animate@1.0.7: - resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} - peerDependencies: - tailwindcss: '>=3.0.0 || insiders' - tailwindcss@3.4.19: resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==} engines: {node: '>=14.0.0'} hasBin: true - tailwindcss@4.3.0: - resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==} - - tapable@0.2.9: - resolution: {integrity: sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==} - engines: {node: '>=0.6'} - tapable@2.3.3: resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} - tar-stream@2.2.0: - resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} - engines: {node: '>=6'} - tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} @@ -9770,12 +5091,6 @@ packages: engines: {node: '>=10'} hasBin: true - tesseract.js-core@7.0.0: - resolution: {integrity: sha512-WnNH518NzmbSq9zgTPeoF8c+xmilS8rFIl1YKbk/ptuuc7p6cLNELNuPAzcmsYw450ca6bLa8j3t0VAtq435Vw==} - - tesseract.js@7.0.0: - resolution: {integrity: sha512-exPBkd+z+wM1BuMkx/Bjv43OeLBxhL5kKWsz/9JY+DXcXdiBjiAch0V49QR3oAJqCaL5qURE0vx9Eo+G5YE7mA==} - test-exclude@6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} @@ -9784,9 +5099,6 @@ packages: resolution: {integrity: sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==} engines: {node: '>=8'} - text-segmentation@1.0.3: - resolution: {integrity: sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==} - text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -9797,36 +5109,9 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - through2@2.0.5: - resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} - - through2@4.0.2: - resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} - through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - thunky@1.1.0: - resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==} - - time-stamp@1.1.0: - resolution: {integrity: sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==} - engines: {node: '>=0.10.0'} - - time-stamp@2.2.0: - resolution: {integrity: sha512-zxke8goJQpBeEgD82CXABeMh0LSJcj7CXEd0OHOg45HgcofF7pxNwZm9+RknpxpDhwN4gFpySkApKfFYfRQnUA==} - engines: {node: '>=0.10.0'} - - timers-browserify@2.0.12: - resolution: {integrity: sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==} - engines: {node: '>=0.6.0'} - - tiny-inflate@1.0.3: - resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} - - tiny-invariant@1.3.3: - resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} - tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -9841,9 +5126,6 @@ packages: resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} - tinymce@7.9.2: - resolution: {integrity: sha512-zS2gn2CPQmZhUqLzkhwYH+WGsx/DIRY/mS18RVzsIcuQg2lN2uzaqoHSJU6DdMUpvXBtBFnLNpumC3QrDwLBzA==} - tinypool@1.1.1: resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} engines: {node: ^18.0.0 || >=20.0.0} @@ -9863,56 +5145,25 @@ packages: resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} hasBin: true - tmp@0.2.5: - resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} - engines: {node: '>=14.14'} - tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - to-arraybuffer@1.0.1: - resolution: {integrity: sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==} - to-buffer@1.2.2: resolution: {integrity: sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==} engines: {node: '>= 0.4'} - to-gfm-code-block@0.1.1: - resolution: {integrity: sha512-LQRZWyn8d5amUKnfR9A9Uu7x9ss7Re8peuWR2gkh1E+ildOfv2aF26JpuDg8JtvCduu5+hOrMIH+XstZtnagqg==} - engines: {node: '>=0.10.0'} - - to-object-path@0.3.0: - resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==} - engines: {node: '>=0.10.0'} - - to-regex-range@2.1.1: - resolution: {integrity: sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==} - engines: {node: '>=0.10.0'} - to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - to-regex@3.0.2: - resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==} - engines: {node: '>=0.10.0'} - toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} - token-types@5.0.1: - resolution: {integrity: sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==} - engines: {node: '>=14.16'} - token-types@6.1.2: resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} engines: {node: '>=14.16'} - tough-cookie@2.5.0: - resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==} - engines: {node: '>=0.8'} - tough-cookie@5.1.2: resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} engines: {node: '>=16'} @@ -9924,22 +5175,6 @@ packages: resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} engines: {node: '>=18'} - traverse@0.3.9: - resolution: {integrity: sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==} - - tree-changes@0.11.3: - resolution: {integrity: sha512-r14mvDZ6tqz8PRQmlFKjhUVngu4VZ9d92ON3tp0EGpFBE6PAHOq8Bx8m8ahbNoGE3uI/npjYcJiqVydyOiYXag==} - - tree-changes@0.9.3: - resolution: {integrity: sha512-vvvS+O6kEeGRzMglTKbc19ltLWNtmNt1cpBoSYLj/iEcPVvpJasemKOlxBrmZaCtDJoF+4bwv3m01UKYi8mukQ==} - - trim-canvas@0.1.2: - resolution: {integrity: sha512-nd4Ga3iLFV94mdhW9JFMLpQbHUyCQuhFOD71PEAt1NjtMD5wbZctzhX8c3agHNybMR5zXD1XTGoIEWk995E6pQ==} - - trim-newlines@1.0.0: - resolution: {integrity: sha512-Nm4cF79FhSTzrLKGDMi3I4utBtFv8qKy4sq1enftf2gMdpqI8oVQTAfySkTz5r49giVzDj88SVZXP4CeYQwjaw==} - engines: {node: '>=0.10.0'} - ts-api-utils@2.5.0: resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} @@ -9976,13 +5211,6 @@ packages: jest-util: optional: true - ts-loader@9.5.7: - resolution: {integrity: sha512-/ZNrKgA3K3PtpMYOC71EeMWIloGw3IYEa5/t1cyz2r5/PyUwTXGzYJvcD3kfUvmhlfpz1rhV8B2O6IVTQ0avsg==} - engines: {node: '>=12.0.0'} - peerDependencies: - typescript: '*' - webpack: ^5.0.0 - ts-node@10.9.2: resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true @@ -10011,19 +5239,10 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tty-browserify@0.0.0: - resolution: {integrity: sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==} - - tunnel-agent@0.6.0: - resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - turbo@2.9.12: resolution: {integrity: sha512-lCPgus1NuTiBdaITWqzSH/Ff6HVL8HHGBtOXHg1dHRfcshN79XkygSdh0M6g8b0td91ILLG5MTkLOkp5UvyPJw==} hasBin: true - tweetnacl@0.14.5: - resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} - type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -10052,9 +5271,6 @@ packages: resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} engines: {node: '>= 0.6'} - type@2.7.3: - resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==} - typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -10074,18 +5290,6 @@ packages: typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - typeof-article@0.1.1: - resolution: {integrity: sha512-Vn42zdX3FhmUrzEmitX3iYyLb+Umwpmv8fkZRIknYh84lmdrwqZA5xYaoKiIj2Rc5i/5wcDrpUmZcbk1U51vTw==} - engines: {node: '>=4'} - - typeorm-extension@3.9.0: - resolution: {integrity: sha512-LCVo/7zEh59/+Ig+WsXFbuu1gvU7EilIOH1vwxTG2eAiKmteaTQlID9c1x/PQH2IyZ+Lk4htbWf1d9QieKrpPQ==} - engines: {node: ^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0} - hasBin: true - peerDependencies: - '@faker-js/faker': '>=8.4.1' - typeorm: ~0.3.0 - typeorm@0.3.29: resolution: {integrity: sha512-wwPEX/df4l72gCmOsrs0otJZYLGA9lLQkUZCkukbsymEycV4zXv2KM7wU7v2r8L01TaCgY9ApSSqHQWBOUhEoQ==} engines: {node: '>=16.13.0'} @@ -10146,25 +5350,11 @@ packages: engines: {node: '>=14.17'} hasBin: true - uglify-js@2.8.29: - resolution: {integrity: sha512-qLq/4y2pjcU3vhlhseXGGJ7VbFO4pBANu0kwl8VCa9KEI0V8VfZIx2Fy3w01iSTA/pGwKZSmu/+I4etLNDdt5w==} - engines: {node: '>=0.8.0'} - hasBin: true - uglify-js@3.19.3: resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} engines: {node: '>=0.8.0'} hasBin: true - uglify-to-browserify@1.0.2: - resolution: {integrity: sha512-vb2s1lYx2xBtUgy+ta+b2J/GLVUR+wmpINwHePmPRhOsIVCG2wDzKJ0n14GslH1BifsqVzSOwQhRaCAsZ/nI4Q==} - - uglifyjs-webpack-plugin@0.4.6: - resolution: {integrity: sha512-TNM20HMW67kxHRNCZdvLyiwE1ST6WyY5Ae+TG55V81NpvNwJ9+V4/po4LHA1R9afV/WrqzfedG2UJCk2+swirw==} - engines: {node: '>=4.3.0 <5.0.0 || >=5.10'} - peerDependencies: - webpack: ^1.9 || ^2 || ^2.1.0-beta || ^2.2.0-rc || ^3.0.0 - uid@2.0.2: resolution: {integrity: sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==} engines: {node: '>=8'} @@ -10183,23 +5373,10 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - unicode-properties@1.4.1: - resolution: {integrity: sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==} - - unicode-trie@2.0.0: - resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==} - unicorn-magic@0.1.0: resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} engines: {node: '>=18'} - union-value@1.0.1: - resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} - engines: {node: '>=0.10.0'} - - universal-cookie@8.1.2: - resolution: {integrity: sha512-kcKzTGNsxVytujrYOvQbvh//QyFrA53HrzCGyzh6i9ujCww5gfPrLK0tG+jJD40SIIldiEjBNPPSR8fBMS21GA==} - universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -10208,129 +5385,31 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - unset-value@1.0.0: - resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==} - engines: {node: '>=0.10.0'} - - unzipper@0.10.14: - resolution: {integrity: sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==} - - upath@1.2.0: - resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} - engines: {node: '>=4'} - update-browserslist-db@1.2.3: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' - uqr@0.1.2: - resolution: {integrity: sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==} - uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - urix@0.1.0: - resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==} - deprecated: Please see https://github.com/lydell/urix#deprecated - - url-parse@1.5.10: - resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - - url@0.11.4: - resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==} - engines: {node: '>= 0.4'} - - use-callback-ref@1.3.3: - resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - use-composed-ref@1.4.0: - resolution: {integrity: sha512-djviaxuOOh7wkj0paeO1Q/4wMZ8Zrnag5H6yBvzN7AKKe8beOaED9SF5/ByLqsku8NP4zQqsvM2u3ew/tJK8/w==} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - use-isomorphic-layout-effect@1.2.1: - resolution: {integrity: sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - use-latest@1.3.0: - resolution: {integrity: sha512-mhg3xdm9NaM8q+gLT8KryJPnRFOz1/5XPBhmDEVZK1webPzDjrPk7f/mbpeLqTgB9msytYWANxgALOCJKnLvcQ==} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - - use-sidecar@1.1.3: - resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: 18.3.1 - peerDependenciesMeta: - '@types/react': - optional: true - use-sync-external-store@1.6.0: resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} peerDependencies: react: 18.3.1 - use@3.1.1: - resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} - engines: {node: '>=0.10.0'} - util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - util@0.10.4: - resolution: {integrity: sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==} - - util@0.11.1: - resolution: {integrity: sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==} - - util@0.12.5: - resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} - utils-merge@1.0.1: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} - utrie@1.0.2: - resolution: {integrity: sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==} - uuid@11.1.1: resolution: {integrity: sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==} hasBin: true - uuid@3.4.0: - resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} - deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). - hasBin: true - - uuid@8.3.2: - resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} - deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). - hasBin: true - v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} @@ -10338,9 +5417,6 @@ packages: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} - validate-npm-package-license@3.0.4: - resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - validator@13.15.35: resolution: {integrity: sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==} engines: {node: '>= 0.10'} @@ -10349,23 +5425,6 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - vaul@1.1.2: - resolution: {integrity: sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - verror@1.10.0: - resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} - engines: {'0': node >=0.6.0} - - victory-vendor@37.3.6: - resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==} - - vite-compatible-readable-stream@3.6.1: - resolution: {integrity: sha512-t20zYkrSf868+j/p31cRIGN28Phrjm3nRSLR2fyc2tiWi4cZGVdv68yNlwnIINTkMTmPoMiSlc0OadaO7DXZaQ==} - engines: {node: '>= 6'} - vite-node@2.1.9: resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -10427,16 +5486,6 @@ packages: jsdom: optional: true - vm-browserify@1.1.2: - resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==} - - void-elements@3.1.0: - resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} - engines: {node: '>=0.10.0'} - - w3c-keyname@2.2.8: - resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} - w3c-xmlserializer@5.0.0: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} @@ -10444,35 +5493,13 @@ packages: walker@1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} - warning-symbol@0.1.0: - resolution: {integrity: sha512-1S0lwbHo3kNUKA4VomBAhqn4DPjQkIKSdbOin5K7EFUQNwyIKx+wZMGXKI53RUjla8V2B8ouQduUlgtx8LoSMw==} - engines: {node: '>=0.10.0'} - - warning@4.0.3: - resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} - - wasm-feature-detect@1.8.0: - resolution: {integrity: sha512-zksaLKM2fVlnB5jQQDqKXXwYHLQUVH9es+5TOOHwGOVJOCeRBCiPjwSg+3tN2AdTCzjgli4jijCH290kXb/zWQ==} - - watchpack-chokidar2@2.0.1: - resolution: {integrity: sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==} - - watchpack@1.7.5: - resolution: {integrity: sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==} - watchpack@2.5.1: resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} engines: {node: '>=10.13.0'} - wbuf@1.7.3: - resolution: {integrity: sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==} - wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} - web-encoding@1.1.5: - resolution: {integrity: sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==} - webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -10480,47 +5507,14 @@ packages: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} - webpack-dev-middleware@1.12.2: - resolution: {integrity: sha512-FCrqPy1yy/sN6U/SaEZcHKRXGlqU0DUaEBL45jkUYoB8foVb6wCnbIJ1HKIx+qUFTW+3JpVcCJCxZ8VATL4e+A==} - engines: {node: '>=0.6'} - peerDependencies: - webpack: ^1.0.0 || ^2.0.0 || ^3.0.0 - - webpack-dev-server@2.11.5: - resolution: {integrity: sha512-7TdOKKt7G3sWEhPKV0zP+nD0c4V9YKUJ3wDdBwQsZNo58oZIRoVIu66pg7PYkBW8A74msP9C2kLwmxGHndz/pw==} - engines: {node: '>=4.7'} - hasBin: true - peerDependencies: - webpack: ^2.2.0 || ^3.0.0 - webpack-cli: '*' - peerDependenciesMeta: - webpack-cli: - optional: true - webpack-node-externals@3.0.0: resolution: {integrity: sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==} engines: {node: '>=6'} - webpack-sources@1.4.3: - resolution: {integrity: sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==} - webpack-sources@3.4.1: resolution: {integrity: sha512-eACpxRN02yaawnt+uUNIF7Qje6A9zArxBbcAJjK1PK3S9Ycg5jIuJ8pW4q8EMnwNZCEGltcjkRx1QzOxOkKD8A==} engines: {node: '>=10.13.0'} - webpack@3.12.0: - resolution: {integrity: sha512-Sw7MdIIOv/nkzPzee4o0EdvCuPmxT98+vVpIvwtcwcF1Q4SDSNp92vwcKc4REe7NItH9f1S4ra9FuQ7yuYZ8bQ==} - engines: {node: '>=4.3.0 <5.0.0 || >=5.10'} - hasBin: true - peerDependencies: - webpack-cli: '*' - webpack-command: '*' - peerDependenciesMeta: - webpack-cli: - optional: true - webpack-command: - optional: true - webpack@5.106.0: resolution: {integrity: sha512-Pkx5joZ9RrdgO5LBkyX1L2ZAJeK/Taz3vqZ9CbcP0wS5LEMx5QkKsEwLl29QJfihZ+DKRBFldzy1O30pJ1MDpA==} engines: {node: '>=10.13.0'} @@ -10531,14 +5525,6 @@ packages: webpack-cli: optional: true - websocket-driver@0.7.4: - resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==} - engines: {node: '>=0.8.0'} - - websocket-extensions@0.1.4: - resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==} - engines: {node: '>=0.8.0'} - whatwg-encoding@3.1.1: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} @@ -10567,9 +5553,6 @@ packages: resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} engines: {node: '>= 0.4'} - which-module@1.0.0: - resolution: {integrity: sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==} - which-module@2.0.1: resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} @@ -10577,10 +5560,6 @@ packages: resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} engines: {node: '>= 0.4'} - which@1.3.1: - resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} - hasBin: true - which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -10594,33 +5573,13 @@ packages: wide-align@1.1.5: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} - window-size@0.1.0: - resolution: {integrity: sha512-1pTPQDKTdd61ozlKGNCjhNRd+KPmgLSGa3mZTHoOliaGcESD8G1PXhh7c1fgiPjVbNVfgy2Faw4BI8/m0cC8Mg==} - engines: {node: '>= 0.8.0'} - - wmf@1.0.2: - resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==} - engines: {node: '>=0.8'} - word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - word@0.3.0: - resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==} - engines: {node: '>=0.8'} - - wordwrap@0.0.2: - resolution: {integrity: sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q==} - engines: {node: '>=0.4.0'} - wordwrap@1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - wrap-ansi@2.1.0: - resolution: {integrity: sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==} - engines: {node: '>=0.10.0'} - wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} @@ -10644,18 +5603,6 @@ packages: resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - ws@8.18.3: - resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} - 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 - ws@8.20.0: resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} engines: {node: '>=10.0.0'} @@ -10668,40 +5615,17 @@ packages: utf-8-validate: optional: true - xlsx@0.18.5: - resolution: {integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==} - engines: {node: '>=0.8'} - hasBin: true - xml-name-validator@5.0.0: resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} engines: {node: '>=18'} - xml2js@0.5.0: - resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} - engines: {node: '>=4.0.0'} - - xml@1.0.1: - resolution: {integrity: sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==} - - xmlbuilder@11.0.1: - resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} - engines: {node: '>=4.0'} - xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - xmlhttprequest-ssl@2.1.2: - resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==} - engines: {node: '>=0.4.0'} - xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} - y18n@3.2.2: - resolution: {integrity: sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==} - y18n@4.0.3: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} @@ -10709,9 +5633,6 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - yallist@2.1.2: - resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} - yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -10735,16 +5656,6 @@ packages: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} - yargs-parser@22.0.0: - resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} - engines: {node: ^20.19.0 || ^22.12.0 || >=23} - - yargs-parser@4.2.1: - resolution: {integrity: sha512-+QQWqC2xeL0N5/TE+TY6OGEqyNRM+g2/r712PDNYgiCdXYCApXf1vzfmDSLBxfGRwV+moTq/V8FnMI24JCm2Yg==} - - yargs-parser@7.0.0: - resolution: {integrity: sha512-WhzC+xgstid9MbVUktco/bf+KJG+Uu6vMX0LN1sLJvwmbCQVxb4D8LzogobonKycNasCZLdOzTAk1SK7+K7swg==} - yargs@15.4.1: resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} engines: {node: '>=8'} @@ -10753,23 +5664,6 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} - yargs@18.0.0: - resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=23} - - yargs@3.10.0: - resolution: {integrity: sha512-QFzUah88GAGy9lyDKGBqZdkYApt63rCXYBGYnEP4xDJPXNqXXnBDACnbrXnViV6jRSqAePwrATi2i8mfYm4L1A==} - - yargs@6.6.0: - resolution: {integrity: sha512-6/QWTdisjnu5UHUzQGst+UOEuEVwIzFVGBjq3jMTFNs5WJQsH/X6nMURSaScIdF5txylr1Ao9bvbWiKi2yXbwA==} - - yargs@8.0.2: - resolution: {integrity: sha512-3RiZrpLpjrzIAKgGdPktBcMP/eG5bDFlkI+PHle1qwzyVXyDQL+pD/eZaMoOOO0Y7LLBfjpucObuUm/icvbpKQ==} - - year@0.2.1: - resolution: {integrity: sha512-9GnJUZ0QM4OgXuOzsKNzTJ5EOkums1Xc+3YQXp+Q+UxFjf7zLucp9dQ8QMIft0Szs1E1hUiXFim1OYfEKFq97w==} - engines: {node: '>=0.8'} - yn@3.1.1: resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} engines: {node: '>=6'} @@ -10786,19 +5680,6 @@ packages: resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} engines: {node: '>=18'} - yoga-layout@3.2.1: - resolution: {integrity: sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==} - - zip-stream@4.1.1: - resolution: {integrity: sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==} - engines: {node: '>= 10'} - - zlibjs@0.3.1: - resolution: {integrity: sha512-+J9RrgTKOmlxFSDHo0pI1xM6BLVUv+o0ZT9ANtCxGkjIVCCUdx9alUF8Gm+dGLKbkkkidWIHFDZHDMpfITt4+w==} - - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - zustand@5.0.13: resolution: {integrity: sha512-efI2tVaVQPqtOh114loML/Z80Y4NP3yc+Ff0fYiZJPauNeWZeIp/bRFD7I9bfmCOYBh/PHxlglQ9+wvlwnPikQ==} engines: {node: '>=12.20.0'} @@ -10854,78 +5735,6 @@ snapshots: transitivePeerDependencies: - chokidar - '@ark-ui/react@5.36.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@internationalized/date': 3.12.0 - '@zag-js/accordion': 1.40.0 - '@zag-js/anatomy': 1.40.0 - '@zag-js/angle-slider': 1.40.0 - '@zag-js/async-list': 1.40.0 - '@zag-js/auto-resize': 1.40.0 - '@zag-js/avatar': 1.40.0 - '@zag-js/carousel': 1.40.0 - '@zag-js/cascade-select': 1.40.0 - '@zag-js/checkbox': 1.40.0 - '@zag-js/clipboard': 1.40.0 - '@zag-js/collapsible': 1.40.0 - '@zag-js/collection': 1.40.0 - '@zag-js/color-picker': 1.40.0 - '@zag-js/color-utils': 1.40.0 - '@zag-js/combobox': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/date-input': 1.40.0(@internationalized/date@3.12.0) - '@zag-js/date-picker': 1.40.0(@internationalized/date@3.12.0) - '@zag-js/date-utils': 1.40.0(@internationalized/date@3.12.0) - '@zag-js/dialog': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/drawer': 1.40.0 - '@zag-js/editable': 1.40.0 - '@zag-js/file-upload': 1.40.0 - '@zag-js/file-utils': 1.40.0 - '@zag-js/floating-panel': 1.40.0 - '@zag-js/focus-trap': 1.40.0 - '@zag-js/focus-visible': 1.40.0 - '@zag-js/highlight-word': 1.40.0 - '@zag-js/hover-card': 1.40.0 - '@zag-js/i18n-utils': 1.40.0 - '@zag-js/image-cropper': 1.40.0 - '@zag-js/json-tree-utils': 1.40.0 - '@zag-js/listbox': 1.40.0 - '@zag-js/marquee': 1.40.0 - '@zag-js/menu': 1.40.0 - '@zag-js/navigation-menu': 1.40.0 - '@zag-js/number-input': 1.40.0 - '@zag-js/pagination': 1.40.0 - '@zag-js/password-input': 1.40.0 - '@zag-js/pin-input': 1.40.0 - '@zag-js/popover': 1.40.0 - '@zag-js/presence': 1.40.0 - '@zag-js/progress': 1.40.0 - '@zag-js/qr-code': 1.40.0 - '@zag-js/radio-group': 1.40.0 - '@zag-js/rating-group': 1.40.0 - '@zag-js/react': 1.40.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@zag-js/scroll-area': 1.40.0 - '@zag-js/select': 1.40.0 - '@zag-js/signature-pad': 1.40.0 - '@zag-js/slider': 1.40.0 - '@zag-js/splitter': 1.40.0 - '@zag-js/steps': 1.40.0 - '@zag-js/switch': 1.40.0 - '@zag-js/tabs': 1.40.0 - '@zag-js/tags-input': 1.40.0 - '@zag-js/timer': 1.40.0 - '@zag-js/toast': 1.40.0 - '@zag-js/toggle': 1.40.0 - '@zag-js/toggle-group': 1.40.0 - '@zag-js/tooltip': 1.40.0 - '@zag-js/tour': 1.40.0 - '@zag-js/tree-view': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - '@asamuzakjp/css-color@3.2.0': dependencies: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) @@ -11108,7 +5917,8 @@ snapshots: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@babel/runtime@7.29.2': {} + '@babel/runtime@7.29.2': + optional: true '@babel/template@7.28.6': dependencies: @@ -11137,19 +5947,6 @@ snapshots: '@borewit/text-codec@0.2.2': {} - '@chakra-ui/react@3.35.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@ark-ui/react': 5.36.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@emotion/is-prop-valid': 1.4.0 - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@18.3.1) - '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@18.3.1) - '@emotion/utils': 1.4.2 - '@pandacss/is-valid-prop': 1.11.1 - csstype: 3.2.3 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - '@colors/colors@1.5.0': optional: true @@ -11287,91 +6084,6 @@ snapshots: '@csstools/css-tokenizer@3.0.4': {} - '@date-fns/tz@1.4.1': {} - - '@emotion/babel-plugin@11.13.5': - dependencies: - '@babel/helper-module-imports': 7.28.6 - '@babel/runtime': 7.29.2 - '@emotion/hash': 0.9.2 - '@emotion/memoize': 0.9.0 - '@emotion/serialize': 1.3.3 - babel-plugin-macros: 3.1.0 - convert-source-map: 1.9.0 - escape-string-regexp: 4.0.0 - find-root: 1.1.0 - source-map: 0.5.7 - stylis: 4.2.0 - transitivePeerDependencies: - - supports-color - - '@emotion/cache@11.14.0': - dependencies: - '@emotion/memoize': 0.9.0 - '@emotion/sheet': 1.4.0 - '@emotion/utils': 1.4.2 - '@emotion/weak-memoize': 0.4.0 - stylis: 4.2.0 - - '@emotion/hash@0.9.2': {} - - '@emotion/is-prop-valid@1.4.0': - dependencies: - '@emotion/memoize': 0.9.0 - - '@emotion/memoize@0.9.0': {} - - '@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@babel/runtime': 7.29.2 - '@emotion/babel-plugin': 11.13.5 - '@emotion/cache': 11.14.0 - '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@18.3.1) - '@emotion/utils': 1.4.2 - '@emotion/weak-memoize': 0.4.0 - hoist-non-react-statics: 3.3.2 - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - transitivePeerDependencies: - - supports-color - - '@emotion/serialize@1.3.3': - dependencies: - '@emotion/hash': 0.9.2 - '@emotion/memoize': 0.9.0 - '@emotion/unitless': 0.10.0 - '@emotion/utils': 1.4.2 - csstype: 3.2.3 - - '@emotion/sheet@1.4.0': {} - - '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@babel/runtime': 7.29.2 - '@emotion/babel-plugin': 11.13.5 - '@emotion/is-prop-valid': 1.4.0 - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@18.3.1) - '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@18.3.1) - '@emotion/utils': 1.4.2 - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - transitivePeerDependencies: - - supports-color - - '@emotion/unitless@0.10.0': {} - - '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@18.3.1)': - dependencies: - react: 18.3.1 - - '@emotion/utils@1.4.2': {} - - '@emotion/weak-memoize@0.4.0': {} - '@esbuild/aix-ppc64@0.21.5': optional: true @@ -11464,61 +6176,6 @@ snapshots: '@eslint/js@8.57.1': {} - '@faker-js/faker@10.4.0': {} - - '@fast-csv/format@4.3.5': - dependencies: - '@types/node': 14.18.63 - lodash.escaperegexp: 4.1.2 - lodash.isboolean: 3.0.3 - lodash.isequal: 4.5.0 - lodash.isfunction: 3.0.9 - lodash.isnil: 4.0.0 - - '@fast-csv/parse@4.3.6': - dependencies: - '@types/node': 14.18.63 - lodash.escaperegexp: 4.1.2 - lodash.groupby: 4.6.0 - lodash.isfunction: 3.0.9 - lodash.isnil: 4.0.0 - lodash.isundefined: 3.0.1 - lodash.uniq: 4.5.0 - - '@floating-ui/core@1.7.5': - dependencies: - '@floating-ui/utils': 0.2.11 - - '@floating-ui/dom@1.7.6': - dependencies: - '@floating-ui/core': 1.7.5 - '@floating-ui/utils': 0.2.11 - - '@floating-ui/react-dom@2.1.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@floating-ui/dom': 1.7.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - - '@floating-ui/react@0.27.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@floating-ui/react-dom': 2.1.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@floating-ui/utils': 0.2.11 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - tabbable: 6.4.0 - - '@floating-ui/utils@0.2.11': {} - - '@gilbarbara/deep-equal@0.1.2': {} - - '@gilbarbara/deep-equal@0.3.1': {} - - '@hookform/resolvers@5.2.2(react-hook-form@7.75.0(react@18.3.1))': - dependencies: - '@standard-schema/utils': 0.3.0 - react-hook-form: 7.75.0(react@18.3.1) - '@humanwhocodes/config-array@0.13.0': dependencies: '@humanwhocodes/object-schema': 2.0.3 @@ -11671,14 +6328,6 @@ snapshots: optionalDependencies: '@types/node': 20.19.41 - '@internationalized/date@3.12.0': - dependencies: - '@swc/helpers': 0.5.21 - - '@internationalized/number@3.6.5': - dependencies: - '@swc/helpers': 0.5.21 - '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -11889,42 +6538,8 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@leichtgewicht/ip-codec@2.0.5': {} - - '@lottiefiles/react-lottie-player@3.6.0(react@18.3.1)': - dependencies: - lottie-web: 5.13.0 - react: 18.3.1 - '@lukeed/csprng@1.1.0': {} - '@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@floating-ui/react': 0.27.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mantine/hooks': 8.3.18(react@18.3.1) - clsx: 2.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-number-format: 5.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@18.3.1) - react-textarea-autosize: 8.5.9(@types/react@18.3.28)(react@18.3.1) - type-fest: 4.41.0 - transitivePeerDependencies: - - '@types/react' - - '@mantine/dates@8.3.18(@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@8.3.18(react@18.3.1))(dayjs@1.11.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@mantine/core': 8.3.18(@mantine/hooks@8.3.18(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mantine/hooks': 8.3.18(react@18.3.1) - clsx: 2.1.1 - dayjs: 1.11.20 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - - '@mantine/hooks@8.3.18(react@18.3.1)': - dependencies: - react: 18.3.1 - '@mapbox/node-pre-gyp@1.0.11': dependencies: detect-libc: 2.1.2 @@ -11942,140 +6557,6 @@ snapshots: '@microsoft/tsdoc@0.15.1': {} - '@microsoft/tsdoc@0.16.0': {} - - '@mui/base@5.0.0-beta.70(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@babel/runtime': 7.29.2 - '@floating-ui/react-dom': 2.1.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/types': 7.2.24(@types/react@18.3.28) - '@mui/utils': 6.4.9(@types/react@18.3.28)(react@18.3.1) - '@popperjs/core': 2.11.8 - clsx: 2.1.1 - prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - - '@mui/core-downloads-tracker@5.18.0': {} - - '@mui/icons-material@5.18.0(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@babel/runtime': 7.29.2 - '@mui/material': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - '@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@babel/runtime': 7.29.2 - '@mui/core-downloads-tracker': 5.18.0 - '@mui/system': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) - '@mui/types': 7.2.24(@types/react@18.3.28) - '@mui/utils': 5.17.1(@types/react@18.3.28)(react@18.3.1) - '@popperjs/core': 2.11.8 - '@types/react-transition-group': 4.4.12(@types/react@18.3.28) - clsx: 2.1.1 - csstype: 3.2.3 - prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-is: 19.2.6 - react-transition-group: 4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - optionalDependencies: - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@18.3.1) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) - '@types/react': 18.3.28 - - '@mui/private-theming@5.17.1(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@babel/runtime': 7.29.2 - '@mui/utils': 5.17.1(@types/react@18.3.28)(react@18.3.1) - prop-types: 15.8.1 - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - '@mui/styled-engine@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(react@18.3.1)': - dependencies: - '@babel/runtime': 7.29.2 - '@emotion/cache': 11.14.0 - '@emotion/serialize': 1.3.3 - csstype: 3.2.3 - prop-types: 15.8.1 - react: 18.3.1 - optionalDependencies: - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@18.3.1) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) - - '@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@babel/runtime': 7.29.2 - '@mui/private-theming': 5.17.1(@types/react@18.3.28)(react@18.3.1) - '@mui/styled-engine': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(react@18.3.1) - '@mui/types': 7.2.24(@types/react@18.3.28) - '@mui/utils': 5.17.1(@types/react@18.3.28)(react@18.3.1) - clsx: 2.1.1 - csstype: 3.2.3 - prop-types: 15.8.1 - react: 18.3.1 - optionalDependencies: - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@18.3.1) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) - '@types/react': 18.3.28 - - '@mui/types@7.2.24(@types/react@18.3.28)': - optionalDependencies: - '@types/react': 18.3.28 - - '@mui/utils@5.17.1(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@babel/runtime': 7.29.2 - '@mui/types': 7.2.24(@types/react@18.3.28) - '@types/prop-types': 15.7.15 - clsx: 2.1.1 - prop-types: 15.8.1 - react: 18.3.1 - react-is: 19.2.6 - optionalDependencies: - '@types/react': 18.3.28 - - '@mui/utils@6.4.9(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@babel/runtime': 7.29.2 - '@mui/types': 7.2.24(@types/react@18.3.28) - '@types/prop-types': 15.7.15 - clsx: 2.1.1 - prop-types: 15.8.1 - react: 18.3.1 - react-is: 19.2.6 - optionalDependencies: - '@types/react': 18.3.28 - - '@mui/x-date-pickers@6.20.2(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(date-fns@3.6.0)(dayjs@1.11.20)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@babel/runtime': 7.29.2 - '@mui/base': 5.0.0-beta.70(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/material': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/system': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) - '@mui/utils': 5.17.1(@types/react@18.3.28)(react@18.3.1) - '@types/react-transition-group': 4.4.12(@types/react@18.3.28) - clsx: 2.1.1 - prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-transition-group: 4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - optionalDependencies: - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@18.3.1) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) - date-fns: 3.6.0 - dayjs: 1.11.20 - moment: 2.30.1 - transitivePeerDependencies: - - '@types/react' - '@nestjs/axios@4.0.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.16.0)(rxjs@7.8.2)': dependencies: '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -12168,12 +6649,6 @@ snapshots: '@types/jsonwebtoken': 9.0.5 jsonwebtoken: 9.0.2 - '@nestjs/jwt@11.0.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))': - dependencies: - '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@types/jsonwebtoken': 9.0.10 - jsonwebtoken: 9.0.3 - '@nestjs/mapped-types@2.0.5(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)': dependencies: '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -12182,14 +6657,6 @@ snapshots: class-transformer: 0.5.1 class-validator: 0.14.4 - '@nestjs/mapped-types@2.1.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)': - dependencies: - '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - reflect-metadata: 0.2.2 - optionalDependencies: - class-transformer: 0.5.1 - class-validator: 0.14.4 - '@nestjs/microservices@11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -12198,17 +6665,13 @@ snapshots: reflect-metadata: 0.2.2 rxjs: 7.8.2 tslib: 2.8.1 + optional: true '@nestjs/passport@10.0.3(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0)': dependencies: '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) passport: 0.7.0 - '@nestjs/passport@11.0.5(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0)': - dependencies: - '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - passport: 0.7.0 - '@nestjs/platform-express@11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)': dependencies: '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -12240,21 +6703,6 @@ snapshots: transitivePeerDependencies: - chokidar - '@nestjs/swagger@11.4.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)': - dependencies: - '@microsoft/tsdoc': 0.16.0 - '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.19)(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/mapped-types': 2.1.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) - js-yaml: 4.1.1 - lodash: 4.18.1 - path-to-regexp: 8.4.2 - reflect-metadata: 0.2.2 - swagger-ui-dist: 5.32.4 - optionalDependencies: - class-transformer: 0.5.1 - class-validator: 0.14.4 - '@nestjs/swagger@7.4.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)': dependencies: '@microsoft/tsdoc': 0.15.1 @@ -12279,22 +6727,6 @@ snapshots: '@nestjs/microservices': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/platform-express': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19) - '@nestjs/throttler@6.5.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)': - dependencies: - '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.19)(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) - reflect-metadata: 0.2.2 - - '@nestjs/typeorm@11.0.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)))': - dependencies: - '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.19)(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) - reflect-metadata: 0.2.2 - rxjs: 7.8.2 - typeorm: 0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) - - '@noble/ciphers@1.3.0': {} - '@noble/hashes@1.8.0': {} '@nodelib/fs.scandir@2.1.5': @@ -12313,991 +6745,47 @@ snapshots: dependencies: consola: 3.4.2 - '@onlyoffice/document-editor-react@2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - lodash: 4.17.21 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - - '@pandacss/is-valid-prop@1.11.1': {} - '@paralleldrive/cuid2@2.3.1': dependencies: '@noble/hashes': 1.8.0 - '@phc/format@1.0.0': {} - '@pkgjs/parseargs@0.11.0': optional: true - '@popperjs/core@2.11.8': {} - - '@prisma/client@5.22.0(prisma@5.22.0)': + '@prisma/client@6.19.3(prisma@6.19.3(typescript@5.9.3))(typescript@5.9.3)': optionalDependencies: - prisma: 5.22.0 + prisma: 6.19.3(typescript@5.9.3) + typescript: 5.9.3 - '@prisma/debug@5.22.0': {} - - '@prisma/engines-version@5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2': {} - - '@prisma/engines@5.22.0': + '@prisma/config@6.19.3': dependencies: - '@prisma/debug': 5.22.0 - '@prisma/engines-version': 5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2 - '@prisma/fetch-engine': 5.22.0 - '@prisma/get-platform': 5.22.0 - - '@prisma/fetch-engine@5.22.0': - dependencies: - '@prisma/debug': 5.22.0 - '@prisma/engines-version': 5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2 - '@prisma/get-platform': 5.22.0 - - '@prisma/get-platform@5.22.0': - dependencies: - '@prisma/debug': 5.22.0 - - '@radix-ui/number@1.1.1': {} - - '@radix-ui/primitive@1.1.3': {} - - '@radix-ui/react-accordion@1.2.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-arrow@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-avatar@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-context': 1.1.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-checkbox@1.3.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-collapsible@1.1.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-collection@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-compose-refs@1.1.2(@types/react@18.3.28)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - '@radix-ui/react-context-menu@2.2.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-context@1.1.2(@types/react@18.3.28)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - '@radix-ui/react-context@1.1.3(@types/react@18.3.28)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - '@radix-ui/react-dialog@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - aria-hidden: 1.2.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-direction@1.1.1(@types/react@18.3.28)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-focus-guards@1.1.3(@types/react@18.3.28)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-hover-card@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-id@1.1.1(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - '@radix-ui/react-label@2.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-menu@2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - aria-hidden: 1.2.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-navigation-menu@1.2.14(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-popover@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - aria-hidden: 1.2.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-popper@1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@floating-ui/react-dom': 2.1.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-rect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/rect': 1.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-portal@1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-presence@1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-primitive@2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-primitive@2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-slot': 1.2.4(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-progress@1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-context': 1.1.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-radio-group@1.3.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-select@2.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - aria-hidden: 1.2.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-separator@1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-slider@1.3.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-slot@1.2.3(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - '@radix-ui/react-slot@1.2.4(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - '@radix-ui/react-switch@1.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-tabs@1.1.13(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-toast@1.2.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-toggle-group@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-toggle': 1.1.10(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-toggle@1.1.10(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-tooltip@1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@18.3.28)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - '@radix-ui/react-use-effect-event@0.0.2(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@18.3.28)(react@18.3.1)': - dependencies: - react: 18.3.1 - use-sync-external-store: 1.6.0(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@18.3.28)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - '@radix-ui/react-use-previous@1.1.1(@types/react@18.3.28)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - '@radix-ui/react-use-rect@1.1.1(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@radix-ui/rect': 1.1.1 - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - '@radix-ui/react-use-size@1.1.1(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - - '@radix-ui/rect@1.1.1': {} - - '@react-pdf-viewer/attachment@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + c12: 3.1.0 + deepmerge-ts: 7.1.5 + effect: 3.21.0 + empathic: 2.0.0 transitivePeerDependencies: - - pdfjs-dist + - magicast - '@react-pdf-viewer/bookmark@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@prisma/debug@6.19.3': {} + + '@prisma/engines-version@7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7': {} + + '@prisma/engines@6.19.3': dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - pdfjs-dist + '@prisma/debug': 6.19.3 + '@prisma/engines-version': 7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7 + '@prisma/fetch-engine': 6.19.3 + '@prisma/get-platform': 6.19.3 - '@react-pdf-viewer/core@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@prisma/fetch-engine@6.19.3': dependencies: - pdfjs-dist: 3.11.174 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@prisma/debug': 6.19.3 + '@prisma/engines-version': 7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7 + '@prisma/get-platform': 6.19.3 - '@react-pdf-viewer/default-layout@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@prisma/get-platform@6.19.3': dependencies: - '@react-pdf-viewer/attachment': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/bookmark': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/thumbnail': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/toolbar': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - pdfjs-dist - - '@react-pdf-viewer/full-screen@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - pdfjs-dist - - '@react-pdf-viewer/get-file@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - pdfjs-dist - - '@react-pdf-viewer/open@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - pdfjs-dist - - '@react-pdf-viewer/page-navigation@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - pdfjs-dist - - '@react-pdf-viewer/print@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - pdfjs-dist - - '@react-pdf-viewer/properties@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - pdfjs-dist - - '@react-pdf-viewer/rotate@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - pdfjs-dist - - '@react-pdf-viewer/scroll-mode@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - pdfjs-dist - - '@react-pdf-viewer/search@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - pdfjs-dist - - '@react-pdf-viewer/selection-mode@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - pdfjs-dist - - '@react-pdf-viewer/theme@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - pdfjs-dist - - '@react-pdf-viewer/thumbnail@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - pdfjs-dist - - '@react-pdf-viewer/toolbar@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/full-screen': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/get-file': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/open': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/page-navigation': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/print': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/properties': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/rotate': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/scroll-mode': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/search': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/selection-mode': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/theme': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/zoom': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - pdfjs-dist - - '@react-pdf-viewer/zoom@3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - pdfjs-dist - - '@react-pdf/fns@3.1.3': {} - - '@react-pdf/font@4.0.8': - dependencies: - '@react-pdf/pdfkit': 5.1.1 - '@react-pdf/types': 2.11.1 - fontkit: 2.0.4 - is-url: 1.2.4 - - '@react-pdf/image@3.1.0': - dependencies: - '@react-pdf/svg': 1.1.0 - jay-peg: 1.1.1 - png-js: 2.0.0 - - '@react-pdf/layout@4.6.1': - dependencies: - '@react-pdf/fns': 3.1.3 - '@react-pdf/image': 3.1.0 - '@react-pdf/primitives': 4.3.0 - '@react-pdf/stylesheet': 6.2.1 - '@react-pdf/textkit': 6.3.0 - '@react-pdf/types': 2.11.1 - emoji-regex-xs: 1.0.0 - queue: 6.0.2 - yoga-layout: 3.2.1 - - '@react-pdf/pdfkit@5.1.1': - dependencies: - '@babel/runtime': 7.29.2 - '@noble/ciphers': 1.3.0 - '@noble/hashes': 1.8.0 - browserify-zlib: 0.2.0 - fontkit: 2.0.4 - jay-peg: 1.1.1 - js-md5: 0.8.3 - linebreak: 1.1.0 - png-js: 2.0.0 - vite-compatible-readable-stream: 3.6.1 - - '@react-pdf/primitives@4.3.0': {} - - '@react-pdf/reconciler@2.0.0(react@18.3.1)': - dependencies: - object-assign: 4.1.1 - react: 18.3.1 - scheduler: 0.25.0-rc-603e6108-20241029 - - '@react-pdf/render@4.5.1': - dependencies: - '@babel/runtime': 7.29.2 - '@react-pdf/fns': 3.1.3 - '@react-pdf/primitives': 4.3.0 - '@react-pdf/textkit': 6.3.0 - '@react-pdf/types': 2.11.1 - abs-svg-path: 0.1.1 - color-string: 2.1.4 - normalize-svg-path: 1.1.0 - parse-svg-path: 0.1.2 - svg-arc-to-cubic-bezier: 3.2.0 - - '@react-pdf/renderer@4.5.1(react@18.3.1)': - dependencies: - '@babel/runtime': 7.29.2 - '@react-pdf/fns': 3.1.3 - '@react-pdf/font': 4.0.8 - '@react-pdf/layout': 4.6.1 - '@react-pdf/pdfkit': 5.1.1 - '@react-pdf/primitives': 4.3.0 - '@react-pdf/reconciler': 2.0.0(react@18.3.1) - '@react-pdf/render': 4.5.1 - '@react-pdf/types': 2.11.1 - events: 3.3.0 - object-assign: 4.1.1 - prop-types: 15.8.1 - queue: 6.0.2 - react: 18.3.1 - - '@react-pdf/stylesheet@6.2.1': - dependencies: - '@react-pdf/fns': 3.1.3 - '@react-pdf/types': 2.11.1 - color-string: 2.1.4 - hsl-to-hex: 1.0.0 - media-engine: 1.0.3 - postcss-value-parser: 4.2.0 - - '@react-pdf/svg@1.1.0': - dependencies: - '@react-pdf/primitives': 4.3.0 - - '@react-pdf/textkit@6.3.0': - dependencies: - '@react-pdf/fns': 3.1.3 - bidi-js: 1.0.3 - hyphen: 1.14.1 - unicode-properties: 1.4.1 - - '@react-pdf/types@2.11.1': - dependencies: - '@react-pdf/font': 4.0.8 - '@react-pdf/primitives': 4.3.0 - '@react-pdf/stylesheet': 6.2.1 - - '@reduxjs/toolkit@2.11.2(react-redux@9.2.0(@types/react@18.3.28)(react@18.3.1)(redux@5.0.1))(react@18.3.1)': - dependencies: - '@standard-schema/spec': 1.1.0 - '@standard-schema/utils': 0.3.0 - immer: 11.1.8 - redux: 5.0.1 - redux-thunk: 3.1.0(redux@5.0.1) - reselect: 5.1.1 - optionalDependencies: - react: 18.3.1 - react-redux: 9.2.0(@types/react@18.3.28)(react@18.3.1)(redux@5.0.1) + '@prisma/debug': 6.19.3 '@remix-run/router@1.23.2': {} @@ -13410,317 +6898,17 @@ snapshots: dependencies: '@sinonjs/commons': 3.0.1 - '@socket.io/component-emitter@3.1.2': {} - '@sqltools/formatter@1.2.5': {} '@standard-schema/spec@1.1.0': {} - '@standard-schema/utils@0.3.0': {} - - '@swc/helpers@0.5.21': - dependencies: - tslib: 2.8.1 - - '@tabby_ai/hijri-converter@1.0.5': {} - - '@tabler/icons-react@3.44.0(react@18.3.1)': - dependencies: - '@tabler/icons': 3.44.0 - react: 18.3.1 - - '@tabler/icons@3.44.0': {} - - '@tailwindcss/node@4.3.0': - dependencies: - '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.21.3 - jiti: 2.7.0 - lightningcss: 1.32.0 - magic-string: 0.30.21 - source-map-js: 1.2.1 - tailwindcss: 4.3.0 - - '@tailwindcss/oxide-android-arm64@4.3.0': - optional: true - - '@tailwindcss/oxide-darwin-arm64@4.3.0': - optional: true - - '@tailwindcss/oxide-darwin-x64@4.3.0': - optional: true - - '@tailwindcss/oxide-freebsd-x64@4.3.0': - optional: true - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': - optional: true - - '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': - optional: true - - '@tailwindcss/oxide-linux-arm64-musl@4.3.0': - optional: true - - '@tailwindcss/oxide-linux-x64-gnu@4.3.0': - optional: true - - '@tailwindcss/oxide-linux-x64-musl@4.3.0': - optional: true - - '@tailwindcss/oxide-wasm32-wasi@4.3.0': - optional: true - - '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': - optional: true - - '@tailwindcss/oxide-win32-x64-msvc@4.3.0': - optional: true - - '@tailwindcss/oxide@4.3.0': - optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.3.0 - '@tailwindcss/oxide-darwin-arm64': 4.3.0 - '@tailwindcss/oxide-darwin-x64': 4.3.0 - '@tailwindcss/oxide-freebsd-x64': 4.3.0 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.0 - '@tailwindcss/oxide-linux-arm64-gnu': 4.3.0 - '@tailwindcss/oxide-linux-arm64-musl': 4.3.0 - '@tailwindcss/oxide-linux-x64-gnu': 4.3.0 - '@tailwindcss/oxide-linux-x64-musl': 4.3.0 - '@tailwindcss/oxide-wasm32-wasi': 4.3.0 - '@tailwindcss/oxide-win32-arm64-msvc': 4.3.0 - '@tailwindcss/oxide-win32-x64-msvc': 4.3.0 - - '@tailwindcss/vite@4.3.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1))': - dependencies: - '@tailwindcss/node': 4.3.0 - '@tailwindcss/oxide': 4.3.0 - tailwindcss: 4.3.0 - vite: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1) - '@tanstack/query-core@5.100.10': {} - '@tanstack/query-devtools@5.100.10': {} - - '@tanstack/react-query-devtools@5.100.10(@tanstack/react-query@5.100.10(react@18.3.1))(react@18.3.1)': - dependencies: - '@tanstack/query-devtools': 5.100.10 - '@tanstack/react-query': 5.100.10(react@18.3.1) - react: 18.3.1 - '@tanstack/react-query@5.100.10(react@18.3.1)': dependencies: '@tanstack/query-core': 5.100.10 react: 18.3.1 - '@tanstack/react-table@8.21.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@tanstack/table-core': 8.21.3 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - - '@tanstack/table-core@8.21.3': {} - - '@tinymce/tinymce-react@6.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tinymce@7.9.2)': - dependencies: - prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - tinymce: 7.9.2 - - '@tiptap/core@3.23.1(@tiptap/pm@3.23.1)': - dependencies: - '@tiptap/pm': 3.23.1 - - '@tiptap/extension-blockquote@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - - '@tiptap/extension-bold@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - - '@tiptap/extension-bubble-menu@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)': - dependencies: - '@floating-ui/dom': 1.7.6 - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - '@tiptap/pm': 3.23.1 - optional: true - - '@tiptap/extension-bullet-list@3.23.1(@tiptap/extension-list@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1))': - dependencies: - '@tiptap/extension-list': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - - '@tiptap/extension-code-block@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - '@tiptap/pm': 3.23.1 - - '@tiptap/extension-code@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - - '@tiptap/extension-color@3.23.1(@tiptap/extension-text-style@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)))': - dependencies: - '@tiptap/extension-text-style': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - - '@tiptap/extension-document@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - - '@tiptap/extension-dropcursor@3.23.1(@tiptap/extensions@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1))': - dependencies: - '@tiptap/extensions': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - - '@tiptap/extension-floating-menu@3.23.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)': - dependencies: - '@floating-ui/dom': 1.7.6 - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - '@tiptap/pm': 3.23.1 - optional: true - - '@tiptap/extension-gapcursor@3.23.1(@tiptap/extensions@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1))': - dependencies: - '@tiptap/extensions': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - - '@tiptap/extension-hard-break@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - - '@tiptap/extension-heading@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - - '@tiptap/extension-highlight@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - - '@tiptap/extension-horizontal-rule@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - '@tiptap/pm': 3.23.1 - - '@tiptap/extension-image@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - - '@tiptap/extension-italic@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - - '@tiptap/extension-link@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - '@tiptap/pm': 3.23.1 - linkifyjs: 4.3.2 - - '@tiptap/extension-list-item@3.23.1(@tiptap/extension-list@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1))': - dependencies: - '@tiptap/extension-list': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - - '@tiptap/extension-list-keymap@3.23.1(@tiptap/extension-list@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1))': - dependencies: - '@tiptap/extension-list': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - - '@tiptap/extension-list@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - '@tiptap/pm': 3.23.1 - - '@tiptap/extension-ordered-list@3.23.1(@tiptap/extension-list@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1))': - dependencies: - '@tiptap/extension-list': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - - '@tiptap/extension-paragraph@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - - '@tiptap/extension-strike@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - - '@tiptap/extension-text-align@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - - '@tiptap/extension-text-style@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - - '@tiptap/extension-text@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - - '@tiptap/extension-underline@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - - '@tiptap/extensions@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - '@tiptap/pm': 3.23.1 - - '@tiptap/pm@3.23.1': - dependencies: - prosemirror-changeset: 2.4.1 - prosemirror-commands: 1.7.1 - prosemirror-dropcursor: 1.8.2 - prosemirror-gapcursor: 1.4.1 - prosemirror-history: 1.5.0 - prosemirror-keymap: 1.2.3 - prosemirror-model: 1.25.4 - prosemirror-schema-list: 1.5.1 - prosemirror-state: 1.4.4 - prosemirror-tables: 1.8.5 - prosemirror-transform: 1.12.0 - prosemirror-view: 1.41.8 - - '@tiptap/react@3.23.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - '@tiptap/pm': 3.23.1 - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) - '@types/use-sync-external-store': 0.0.6 - fast-equals: 5.4.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - use-sync-external-store: 1.6.0(react@18.3.1) - optionalDependencies: - '@tiptap/extension-bubble-menu': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - '@tiptap/extension-floating-menu': 3.23.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - transitivePeerDependencies: - - '@floating-ui/dom' - - '@tiptap/starter-kit@3.23.1': - dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - '@tiptap/extension-blockquote': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-bold': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-bullet-list': 3.23.1(@tiptap/extension-list@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)) - '@tiptap/extension-code': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-code-block': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - '@tiptap/extension-document': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-dropcursor': 3.23.1(@tiptap/extensions@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)) - '@tiptap/extension-gapcursor': 3.23.1(@tiptap/extensions@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)) - '@tiptap/extension-hard-break': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-heading': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-horizontal-rule': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - '@tiptap/extension-italic': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-link': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - '@tiptap/extension-list': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - '@tiptap/extension-list-item': 3.23.1(@tiptap/extension-list@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)) - '@tiptap/extension-list-keymap': 3.23.1(@tiptap/extension-list@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)) - '@tiptap/extension-ordered-list': 3.23.1(@tiptap/extension-list@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)) - '@tiptap/extension-paragraph': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-strike': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-text': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-underline': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extensions': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - '@tiptap/pm': 3.23.1 - '@tokenizer/inflate@0.4.1': dependencies: debug: 4.4.3 @@ -13730,221 +6918,6 @@ snapshots: '@tokenizer/token@0.3.0': {} - '@tria-plc/api-common@0.1.4(dlk6rffkpcjlebt3tne6hjqwx4)': - dependencies: - '@nestjs/axios': 4.0.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.16.0)(rxjs@7.8.2) - '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.19)(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/jwt': 11.0.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)) - '@nestjs/microservices': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/passport': 11.0.5(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0) - '@nestjs/swagger': 11.4.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) - '@nestjs/throttler': 6.5.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2) - '@nestjs/typeorm': 11.0.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))) - '@tria-plc/iamapi-common': 0.1.6(nhzmwbpvzw5m5dv4mcbu7ilapi) - argon2: 0.43.1 - axios: 1.16.0 - change-case: 5.4.4 - class-transformer: 0.5.1 - class-validator: 0.14.4 - dotenv: 16.6.1 - ethiopian-calendar-date-converter: 2.1.6 - ethiopian-date: 0.0.6 - exceljs: 4.4.0 - file-type: 21.3.4 - handlebars: 4.7.9 - handlebars-helpers: 0.10.0 - jmespath: 0.16.0 - jose: 5.10.0 - jsonwebtoken: 9.0.3 - libphonenumber-js: 1.13.1 - libreoffice-convert: 1.8.1 - nestjs-minio-client: 2.2.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19) - passport-jwt: 4.0.1 - qrcode: 1.5.4 - reflect-metadata: 0.2.2 - rxjs: 7.8.2 - style-object-to-css-string: 1.1.3 - typeorm: 0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) - typeorm-extension: 3.9.0(@faker-js/faker@10.4.0)(typeorm@0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))) - uuid: 11.1.1 - xlsx: 0.18.5 - transitivePeerDependencies: - - '@faker-js/faker' - - debug - - supports-color - - '@tria-plc/iamapi-common@0.1.6(nhzmwbpvzw5m5dv4mcbu7ilapi)': - dependencies: - '@nestjs/axios': 4.0.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.16.0)(rxjs@7.8.2) - '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.19)(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/jwt': 11.0.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)) - '@nestjs/microservices': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/passport': 11.0.5(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0) - '@nestjs/swagger': 11.4.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) - '@nestjs/throttler': 6.5.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2) - '@nestjs/typeorm': 11.0.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))) - '@tria-plc/api-common': 0.1.4(dlk6rffkpcjlebt3tne6hjqwx4) - argon2: 0.43.1 - axios: 1.16.0 - class-transformer: 0.5.1 - class-validator: 0.14.4 - ethiopian-date: 0.0.6 - file-type: 21.3.4 - jose: 5.10.0 - jsonwebtoken: 9.0.3 - libphonenumber-js: 1.13.1 - nestjs-minio-client: 2.2.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19) - passport-jwt: 4.0.1 - qrcode: 1.5.4 - reflect-metadata: 0.2.2 - rxjs: 7.8.2 - typeorm: 0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) - typeorm-extension: 3.9.0(@faker-js/faker@10.4.0)(typeorm@0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))) - uuid: 11.1.1 - transitivePeerDependencies: - - '@faker-js/faker' - - supports-color - - '@tria-plc/iamui-common@1.0.3(iv2eyyfavqphryq7oznx6tfwre)': - dependencies: - '@chakra-ui/react': 3.35.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@18.3.1) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) - '@hookform/resolvers': 5.2.2(react-hook-form@7.75.0(react@18.3.1)) - '@lottiefiles/react-lottie-player': 3.6.0(react@18.3.1) - '@mantine/core': 8.3.18(@mantine/hooks@8.3.18(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mantine/dates': 8.3.18(@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mantine/hooks@8.3.18(react@18.3.1))(dayjs@1.11.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mantine/hooks': 8.3.18(react@18.3.1) - '@onlyoffice/document-editor-react': 2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-accordion': 1.2.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-alert-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-avatar': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-checkbox': 1.3.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-context-menu': 2.2.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-hover-card': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-label': 2.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-popover': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-progress': 1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-radio-group': 1.3.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-scroll-area': 1.2.10(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-select': 2.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-separator': 1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slider': 1.3.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.4(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-switch': 1.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-tabs': 1.1.13(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-toast': 1.2.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-tooltip': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf-viewer/default-layout': 3.12.0(pdfjs-dist@3.11.174)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-pdf/renderer': 4.5.1(react@18.3.1) - '@reduxjs/toolkit': 2.11.2(react-redux@9.2.0(@types/react@18.3.28)(react@18.3.1)(redux@5.0.1))(react@18.3.1) - '@tabler/icons-react': 3.44.0(react@18.3.1) - '@tailwindcss/vite': 4.3.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1)) - '@tanstack/react-query': 5.100.10(react@18.3.1) - '@tanstack/react-query-devtools': 5.100.10(@tanstack/react-query@5.100.10(react@18.3.1))(react@18.3.1) - '@tanstack/react-table': 8.21.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@tinymce/tinymce-react': 6.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tinymce@7.9.2) - '@tiptap/extension-color': 3.23.1(@tiptap/extension-text-style@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))) - '@tiptap/extension-highlight': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-image': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-link': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - '@tiptap/extension-text-align': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-text-style': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-underline': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/react': 3.23.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@tiptap/starter-kit': 3.23.1 - '@types/node': 24.12.4 - '@types/tinymce': 4.6.9 - axios: 1.16.0 - class-variance-authority: 0.7.1 - clsx: 2.1.1 - cmdk: 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - date-fns: 3.6.0 - dayjs: 1.11.20 - ethiopian-calendar-date-converter: 2.1.6 - ethiopian-calendar-new: 1.1.0 - file-type: 18.7.0 - force: 0.0.3 - framer-motion: 12.38.0(@emotion/is-prop-valid@1.4.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - html2canvas: 1.4.1 - i18next: 25.10.10(typescript@5.9.3) - i18next-browser-languagedetector: 8.2.1 - jquery: 3.7.1 - js-cookie: 3.0.5 - jspdf: 3.0.4 - loadash: 1.0.0 - lodash: 4.18.1 - lucide-react: 0.513.0(react@18.3.1) - mui-ethiopian-datepicker: 0.3.2(hjxdxgubdlhng5uhyvidfkiyo4) - next-themes: 0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - path: 0.12.7 - qs: 6.15.1 - react: 18.3.1 - react-cookie: 8.1.2(@types/react@18.3.28)(react@18.3.1) - react-datepicker: 8.10.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-day-picker: 9.14.0(react@18.3.1) - react-dom: 18.3.1(react@18.3.1) - react-dropzone: 14.4.1(react@18.3.1) - react-hook-form: 7.75.0(react@18.3.1) - react-i18next: 15.7.4(i18next@25.10.10(typescript@5.9.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3) - react-icons: 5.6.0(react@18.3.1) - react-image-crop: 11.0.10(react@18.3.1) - react-intersection-observer: 9.16.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-is: 19.2.6 - react-joyride: 2.9.3(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-pdf: 10.4.1(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-pdf-html: 2.1.5(@react-pdf/renderer@4.5.1(react@18.3.1))(react@18.3.1) - react-pdf-viewer: 0.1.0 - react-redux: 9.2.0(@types/react@18.3.28)(react@18.3.1)(redux@5.0.1) - react-resizable-panels: 3.0.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-router-dom: 7.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-signature-canvas: 1.1.0-alpha.2(@types/prop-types@15.7.15)(@types/react@18.3.28)(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - recharts: 3.8.1(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react-is@19.2.6)(react@18.3.1)(redux@5.0.1) - socket.io-client: 4.8.3 - sonner: 2.0.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - tailwind-merge: 3.6.0 - tailwind-scrollbar-hide: 4.0.0(tailwindcss@4.3.0) - tailwindcss: 4.3.0 - tailwindcss-animate: 1.0.7(tailwindcss@4.3.0) - tesseract.js: 7.0.0 - tinymce: 7.9.2 - url: 0.11.4 - vaul: 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - xlsx: 0.18.5 - zod: 3.25.76 - transitivePeerDependencies: - - '@emotion/is-prop-valid' - - '@floating-ui/dom' - - '@mui/icons-material' - - '@mui/material' - - '@mui/x-date-pickers' - - '@tiptap/core' - - '@tiptap/pm' - - '@types/prop-types' - - '@types/react' - - '@types/react-dom' - - bufferutil - - debug - - encoding - - pdfjs-dist - - prop-types - - react-native - - redux - - supports-color - - typescript - - utf-8-validate - - vite - - webpack-cli - - webpack-command - '@tsconfig/node10@1.0.12': {} '@tsconfig/node12@1.0.11': {} @@ -14011,30 +6984,6 @@ snapshots: '@types/cookiejar@2.1.5': {} - '@types/d3-array@3.2.2': {} - - '@types/d3-color@3.1.3': {} - - '@types/d3-ease@3.0.2': {} - - '@types/d3-interpolate@3.0.4': - dependencies: - '@types/d3-color': 3.1.3 - - '@types/d3-path@3.1.1': {} - - '@types/d3-scale@4.0.9': - dependencies: - '@types/d3-time': 3.0.4 - - '@types/d3-shape@3.1.8': - dependencies: - '@types/d3-path': 3.1.1 - - '@types/d3-time@3.0.4': {} - - '@types/d3-timer@3.0.2': {} - '@types/eslint-scope@3.7.7': dependencies: '@types/eslint': 9.6.1 @@ -14066,11 +7015,6 @@ snapshots: dependencies: '@types/node': 20.19.41 - '@types/hoist-non-react-statics@3.3.7(@types/react@18.3.28)': - dependencies: - '@types/react': 18.3.28 - hoist-non-react-statics: 3.3.2 - '@types/http-errors@2.0.5': {} '@types/istanbul-lib-coverage@2.0.6': {} @@ -14088,8 +7032,6 @@ snapshots: expect: 29.7.0 pretty-format: 29.7.0 - '@types/jquery@4.0.0': {} - '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} @@ -14109,8 +7051,6 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node@14.18.63': {} - '@types/node@20.19.41': dependencies: undici-types: 6.21.0 @@ -14119,9 +7059,8 @@ snapshots: dependencies: undici-types: 7.16.0 - '@types/pako@2.0.4': {} - - '@types/parse-json@4.0.2': {} + '@types/parse-json@4.0.2': + optional: true '@types/passport-jwt@4.0.1': dependencies: @@ -14145,19 +7084,12 @@ snapshots: '@types/qs@6.15.1': {} - '@types/raf@3.4.3': - optional: true - '@types/range-parser@1.2.7': {} '@types/react-dom@18.3.7(@types/react@18.3.28)': dependencies: '@types/react': 18.3.28 - '@types/react-transition-group@4.4.12(@types/react@18.3.28)': - dependencies: - '@types/react': 18.3.28 - '@types/react@18.3.28': dependencies: '@types/prop-types': 15.7.15 @@ -14172,8 +7104,6 @@ snapshots: '@types/http-errors': 2.0.5 '@types/node': 20.19.41 - '@types/signature_pad@2.3.6': {} - '@types/stack-utils@2.0.3': {} '@types/superagent@8.1.9': @@ -14188,15 +7118,6 @@ snapshots: '@types/methods': 1.1.4 '@types/superagent': 8.1.9 - '@types/tinymce@4.6.9': - dependencies: - '@types/jquery': 4.0.0 - - '@types/trusted-types@2.0.7': - optional: true - - '@types/use-sync-external-store@0.0.6': {} - '@types/validator@13.15.10': {} '@types/yargs-parser@21.0.3': {} @@ -14430,576 +7351,6 @@ snapshots: '@xtuc/long@4.2.2': {} - '@zag-js/accordion@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/anatomy@1.40.0': {} - - '@zag-js/angle-slider@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/rect-utils': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/aria-hidden@1.40.0': - dependencies: - '@zag-js/dom-query': 1.40.0 - - '@zag-js/async-list@1.40.0': - dependencies: - '@zag-js/core': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/auto-resize@1.40.0': - dependencies: - '@zag-js/dom-query': 1.40.0 - - '@zag-js/avatar@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/carousel@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/scroll-snap': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/cascade-select@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/collection': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dismissable': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/focus-visible': 1.40.0 - '@zag-js/popper': 1.40.0 - '@zag-js/rect-utils': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/checkbox@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/focus-visible': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/clipboard@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/collapsible@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/collection@1.40.0': - dependencies: - '@zag-js/utils': 1.40.0 - - '@zag-js/color-picker@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/color-utils': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dismissable': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/popper': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/color-utils@1.40.0': - dependencies: - '@zag-js/utils': 1.40.0 - - '@zag-js/combobox@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/collection': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dismissable': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/focus-visible': 1.40.0 - '@zag-js/live-region': 1.40.0 - '@zag-js/popper': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/core@1.40.0': - dependencies: - '@zag-js/dom-query': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/date-input@1.40.0(@internationalized/date@3.12.0)': - dependencies: - '@internationalized/date': 3.12.0 - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/date-utils': 1.40.0(@internationalized/date@3.12.0) - '@zag-js/dom-query': 1.40.0 - '@zag-js/live-region': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/date-picker@1.40.0(@internationalized/date@3.12.0)': - dependencies: - '@internationalized/date': 3.12.0 - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/date-utils': 1.40.0(@internationalized/date@3.12.0) - '@zag-js/dismissable': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/live-region': 1.40.0 - '@zag-js/popper': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/date-utils@1.40.0(@internationalized/date@3.12.0)': - dependencies: - '@internationalized/date': 3.12.0 - - '@zag-js/dialog@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/aria-hidden': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dismissable': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/focus-trap': 1.40.0 - '@zag-js/remove-scroll': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/dismissable@1.40.0': - dependencies: - '@zag-js/dom-query': 1.40.0 - '@zag-js/interact-outside': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/dom-query@1.40.0': - dependencies: - '@zag-js/types': 1.40.0 - - '@zag-js/drawer@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/aria-hidden': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dismissable': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/focus-trap': 1.40.0 - '@zag-js/remove-scroll': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/editable@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/interact-outside': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/file-upload@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/file-utils': 1.40.0 - '@zag-js/i18n-utils': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/file-utils@1.40.0': - dependencies: - '@zag-js/i18n-utils': 1.40.0 - - '@zag-js/floating-panel@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/popper': 1.40.0 - '@zag-js/rect-utils': 1.40.0 - '@zag-js/store': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/focus-trap@1.40.0': - dependencies: - '@zag-js/dom-query': 1.40.0 - - '@zag-js/focus-visible@1.40.0': - dependencies: - '@zag-js/dom-query': 1.40.0 - - '@zag-js/highlight-word@1.40.0': {} - - '@zag-js/hover-card@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dismissable': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/popper': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/i18n-utils@1.40.0': - dependencies: - '@zag-js/dom-query': 1.40.0 - - '@zag-js/image-cropper@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/interact-outside@1.40.0': - dependencies: - '@zag-js/dom-query': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/json-tree-utils@1.40.0': {} - - '@zag-js/listbox@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/collection': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/focus-visible': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/live-region@1.40.0': {} - - '@zag-js/marquee@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/menu@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dismissable': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/focus-visible': 1.40.0 - '@zag-js/popper': 1.40.0 - '@zag-js/rect-utils': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/navigation-menu@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dismissable': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/number-input@1.40.0': - dependencies: - '@internationalized/number': 3.6.5 - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/pagination@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/password-input@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/pin-input@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/popover@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/aria-hidden': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dismissable': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/focus-trap': 1.40.0 - '@zag-js/popper': 1.40.0 - '@zag-js/remove-scroll': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/popper@1.40.0': - dependencies: - '@floating-ui/dom': 1.7.6 - '@zag-js/dom-query': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/presence@1.40.0': - dependencies: - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - - '@zag-js/progress@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/qr-code@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - proxy-memoize: 3.0.1 - uqr: 0.1.2 - - '@zag-js/radio-group@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/focus-visible': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/rating-group@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/react@1.40.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@zag-js/core': 1.40.0 - '@zag-js/store': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - - '@zag-js/rect-utils@1.40.0': {} - - '@zag-js/remove-scroll@1.40.0': - dependencies: - '@zag-js/dom-query': 1.40.0 - - '@zag-js/scroll-area@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/scroll-snap@1.40.0': - dependencies: - '@zag-js/dom-query': 1.40.0 - - '@zag-js/select@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/collection': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dismissable': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/focus-visible': 1.40.0 - '@zag-js/popper': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/signature-pad@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - perfect-freehand: 1.2.3 - - '@zag-js/slider@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/splitter@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/steps@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/store@1.40.0': - dependencies: - proxy-compare: 3.0.1 - - '@zag-js/switch@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/focus-visible': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/tabs@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/tags-input@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/auto-resize': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/interact-outside': 1.40.0 - '@zag-js/live-region': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/timer@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/toast@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dismissable': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/toggle-group@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/toggle@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/tooltip@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/focus-visible': 1.40.0 - '@zag-js/popper': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/tour@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dismissable': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/focus-trap': 1.40.0 - '@zag-js/interact-outside': 1.40.0 - '@zag-js/popper': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/tree-view@1.40.0': - dependencies: - '@zag-js/anatomy': 1.40.0 - '@zag-js/collection': 1.40.0 - '@zag-js/core': 1.40.0 - '@zag-js/dom-query': 1.40.0 - '@zag-js/types': 1.40.0 - '@zag-js/utils': 1.40.0 - - '@zag-js/types@1.40.0': - dependencies: - csstype: 3.2.3 - - '@zag-js/utils@1.40.0': {} - - '@zxing/text-encoding@0.9.0': - optional: true - JSONStream@1.3.5: dependencies: jsonparse: 1.3.1 @@ -15007,26 +7358,11 @@ snapshots: abbrev@1.1.1: {} - abort-controller@3.0.0: - dependencies: - event-target-shim: 5.0.1 - - abs-svg-path@0.1.1: {} - - accepts@1.3.8: - dependencies: - mime-types: 2.1.35 - negotiator: 0.6.3 - accepts@2.0.0: dependencies: mime-types: 3.0.2 negotiator: 1.0.0 - acorn-dynamic-import@2.0.2: - dependencies: - acorn: 4.0.13 - acorn-import-phases@1.0.4(acorn@8.16.0): dependencies: acorn: 8.16.0 @@ -15039,14 +7375,8 @@ snapshots: dependencies: acorn: 8.16.0 - acorn@4.0.13: {} - - acorn@5.7.4: {} - acorn@8.16.0: {} - adler-32@1.3.1: {} - agent-base@6.0.2: dependencies: debug: 4.4.3 @@ -15093,96 +7423,8 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - align-text@0.1.4: - dependencies: - kind-of: 3.2.2 - longest: 1.0.1 - repeat-string: 1.6.1 - - ansi-bgblack@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-bgblue@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-bgcyan@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-bggreen@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-bgmagenta@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-bgred@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-bgwhite@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-bgyellow@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-black@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-blue@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-bold@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-colors@0.2.0: - dependencies: - ansi-bgblack: 0.1.1 - ansi-bgblue: 0.1.1 - ansi-bgcyan: 0.1.1 - ansi-bggreen: 0.1.1 - ansi-bgmagenta: 0.1.1 - ansi-bgred: 0.1.1 - ansi-bgwhite: 0.1.1 - ansi-bgyellow: 0.1.1 - ansi-black: 0.1.1 - ansi-blue: 0.1.1 - ansi-bold: 0.1.1 - ansi-cyan: 0.1.1 - ansi-dim: 0.1.1 - ansi-gray: 0.1.1 - ansi-green: 0.1.1 - ansi-grey: 0.1.1 - ansi-hidden: 0.1.1 - ansi-inverse: 0.1.1 - ansi-italic: 0.1.1 - ansi-magenta: 0.1.1 - ansi-red: 0.1.1 - ansi-reset: 0.1.1 - ansi-strikethrough: 0.1.1 - ansi-underline: 0.1.1 - ansi-white: 0.1.1 - ansi-yellow: 0.1.1 - lazy-cache: 2.0.2 - ansi-colors@4.1.3: {} - ansi-cyan@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-dim@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 @@ -15191,56 +7433,10 @@ snapshots: dependencies: environment: 1.1.0 - ansi-gray@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-green@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-grey@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-hidden@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-html@0.0.7: {} - - ansi-inverse@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-italic@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-magenta@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-red@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-regex@2.1.1: {} - - ansi-regex@3.0.1: {} - ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} - ansi-reset@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-strikethrough@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 @@ -15249,41 +7445,12 @@ snapshots: ansi-styles@6.2.3: {} - ansi-underline@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-white@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - - ansi-wrap@0.1.0: {} - - ansi-yellow@0.1.1: - dependencies: - ansi-wrap: 0.1.0 - ansis@4.2.0: {} ansis@4.3.0: {} any-promise@1.3.0: {} - anymatch@2.0.0(supports-color@4.5.0): - dependencies: - micromatch: 3.1.10(supports-color@4.5.0) - normalize-path: 2.1.1 - transitivePeerDependencies: - - supports-color - optional: true - - anymatch@2.0.0(supports-color@5.5.0): - dependencies: - micromatch: 3.1.10(supports-color@5.5.0) - normalize-path: 2.1.1 - transitivePeerDependencies: - - supports-color - anymatch@3.1.3: dependencies: normalize-path: 3.0.0 @@ -15295,42 +7462,6 @@ snapshots: aproba@2.1.0: {} - archiver-utils@2.1.0: - dependencies: - glob: 7.2.3 - graceful-fs: 4.2.11 - lazystream: 1.0.1 - lodash.defaults: 4.2.0 - lodash.difference: 4.5.0 - lodash.flatten: 4.4.0 - lodash.isplainobject: 4.0.6 - lodash.union: 4.6.0 - normalize-path: 3.0.0 - readable-stream: 2.3.8 - - archiver-utils@3.0.4: - dependencies: - glob: 7.2.3 - graceful-fs: 4.2.11 - lazystream: 1.0.1 - lodash.defaults: 4.2.0 - lodash.difference: 4.5.0 - lodash.flatten: 4.4.0 - lodash.isplainobject: 4.0.6 - lodash.union: 4.6.0 - normalize-path: 3.0.0 - readable-stream: 3.6.2 - - archiver@5.3.2: - dependencies: - archiver-utils: 2.1.0 - async: 3.2.6 - buffer-crc32: 0.2.13 - readable-stream: 3.6.2 - readdir-glob: 1.1.3 - tar-stream: 2.2.0 - zip-stream: 4.1.1 - are-we-there-yet@2.0.0: dependencies: delegates: 1.0.0 @@ -15340,39 +7471,17 @@ snapshots: arg@5.0.2: {} - argon2@0.43.1: - dependencies: - '@phc/format': 1.0.0 - node-addon-api: 8.7.0 - node-gyp-build: 4.8.4 - argparse@1.0.10: dependencies: sprintf-js: 1.0.3 argparse@2.0.1: {} - aria-hidden@1.2.6: - dependencies: - tslib: 2.8.1 - - arr-diff@4.0.0: {} - - arr-flatten@1.1.0: {} - - arr-union@3.1.0: {} - array-buffer-byte-length@1.0.2: dependencies: call-bound: 1.0.4 is-array-buffer: 3.0.5 - array-find-index@1.0.2: {} - - array-flatten@1.1.1: {} - - array-flatten@2.1.2: {} - array-ify@1.0.0: {} array-includes@3.1.9: @@ -15386,22 +7495,8 @@ snapshots: is-string: 1.1.1 math-intrinsics: 1.1.0 - array-sort@0.1.4: - dependencies: - default-compare: 1.0.0 - get-value: 2.0.6 - kind-of: 5.1.0 - array-timsort@1.0.3: {} - array-union@1.0.2: - dependencies: - array-uniq: 1.0.3 - - array-uniq@1.0.3: {} - - array-unique@0.3.2: {} - array.prototype.findlast@1.2.5: dependencies: call-bind: 1.0.9 @@ -15455,47 +7550,12 @@ snapshots: asap@2.0.6: {} - asn1.js@4.10.1: - dependencies: - bn.js: 4.12.3 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - - asn1@0.2.6: - dependencies: - safer-buffer: 2.1.2 - - assert-plus@1.0.0: {} - - assert@1.5.1: - dependencies: - object.assign: 4.1.7 - util: 0.10.4 - assertion-error@2.0.1: {} - assign-symbols@1.0.0: {} - - async-each@1.0.6: {} - async-function@1.0.0: {} - async@2.6.4: - dependencies: - lodash: 4.18.1 - - async@3.2.6: {} - asynckit@0.4.0: {} - atob@2.1.2: {} - - attr-accept@2.2.5: {} - - autolinker@0.28.1: - dependencies: - gulp-header: 1.8.12 - autoprefixer@10.5.0(postcss@8.5.14): dependencies: browserslist: 4.28.2 @@ -15509,9 +7569,8 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 - aws-sign2@0.7.0: {} - - aws4@1.13.2: {} + aws-ssl-profiles@1.1.2: + optional: true axios@1.16.0: dependencies: @@ -15556,6 +7615,7 @@ snapshots: '@babel/runtime': 7.29.2 cosmiconfig: 7.1.0 resolve: 1.22.12 + optional: true babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.0): dependencies: @@ -15586,30 +7646,10 @@ snapshots: balanced-match@4.0.4: {} - base64-arraybuffer@1.0.2: {} - - base64-js@0.0.8: {} - base64-js@1.5.1: {} - base@0.11.2: - dependencies: - cache-base: 1.0.1 - class-utils: 0.3.6 - component-emitter: 1.3.1 - define-property: 1.0.0 - isobject: 3.0.1 - mixin-deep: 1.3.2 - pascalcase: 0.1.1 - baseline-browser-mapping@2.10.29: {} - batch@0.6.1: {} - - bcrypt-pbkdf@1.0.2: - dependencies: - tweetnacl: 0.14.5 - bcrypt@5.1.1: dependencies: '@mapbox/node-pre-gyp': 1.0.11 @@ -15618,63 +7658,14 @@ snapshots: - encoding - supports-color - bidi-js@1.0.3: - dependencies: - require-from-string: 2.0.2 - - big-integer@1.6.52: {} - - big.js@5.2.2: {} - - binary-extensions@1.13.1: {} - binary-extensions@2.3.0: {} - binary@0.3.0: - dependencies: - buffers: 0.1.1 - chainsaw: 0.1.0 - - bindings@1.5.0: - dependencies: - file-uri-to-path: 1.0.0 - optional: true - bl@4.1.0: dependencies: buffer: 5.7.1 inherits: 2.0.4 readable-stream: 3.6.2 - block-stream2@2.1.0: - dependencies: - readable-stream: 3.6.2 - - bluebird@3.4.7: {} - - bmp-js@0.1.0: {} - - bn.js@4.12.3: {} - - bn.js@5.2.3: {} - - body-parser@1.20.5(supports-color@5.5.0): - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 2.6.9(supports-color@5.5.0) - depd: 2.0.0 - destroy: 1.2.0 - http-errors: 2.0.1 - iconv-lite: 0.4.24 - on-finished: 2.4.1 - qs: 6.15.1 - raw-body: 2.5.3 - type-is: 1.6.18 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - body-parser@2.2.2: dependencies: bytes: 3.1.2 @@ -15689,17 +7680,6 @@ snapshots: transitivePeerDependencies: - supports-color - bonjour@3.5.1: - dependencies: - array-flatten: 2.1.2 - deep-equal: 1.1.2 - dns-equal: 1.0.0 - dns-txt: 2.0.2 - multicast-dns: 7.2.5 - multicast-dns-service-types: 1.1.0 - - boolbase@1.0.0: {} - brace-expansion@1.1.14: dependencies: balanced-match: 1.0.2 @@ -15713,108 +7693,10 @@ snapshots: dependencies: balanced-match: 4.0.4 - braces@2.3.2: - dependencies: - arr-flatten: 1.1.0 - array-unique: 0.3.2 - extend-shallow: 2.0.1 - fill-range: 4.0.0 - isobject: 3.0.1 - repeat-element: 1.1.4 - snapdragon: 0.8.2 - snapdragon-node: 2.1.1 - split-string: 3.1.0 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - - braces@2.3.2(supports-color@4.5.0): - dependencies: - arr-flatten: 1.1.0 - array-unique: 0.3.2 - extend-shallow: 2.0.1 - fill-range: 4.0.0 - isobject: 3.0.1 - repeat-element: 1.1.4 - snapdragon: 0.8.2(supports-color@4.5.0) - snapdragon-node: 2.1.1 - split-string: 3.1.0 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - optional: true - - braces@2.3.2(supports-color@5.5.0): - dependencies: - arr-flatten: 1.1.0 - array-unique: 0.3.2 - extend-shallow: 2.0.1 - fill-range: 4.0.0 - isobject: 3.0.1 - repeat-element: 1.1.4 - snapdragon: 0.8.2(supports-color@5.5.0) - snapdragon-node: 2.1.1 - split-string: 3.1.0 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - braces@3.0.3: dependencies: fill-range: 7.1.1 - brorand@1.1.0: {} - - brotli@1.3.3: - dependencies: - base64-js: 1.5.1 - - browser-or-node@2.1.1: {} - - browserify-aes@1.2.0: - dependencies: - buffer-xor: 1.0.3 - cipher-base: 1.0.7 - create-hash: 1.2.0 - evp_bytestokey: 1.0.3 - inherits: 2.0.4 - safe-buffer: 5.2.1 - - browserify-cipher@1.0.1: - dependencies: - browserify-aes: 1.2.0 - browserify-des: 1.0.2 - evp_bytestokey: 1.0.3 - - browserify-des@1.0.2: - dependencies: - cipher-base: 1.0.7 - des.js: 1.1.0 - inherits: 2.0.4 - safe-buffer: 5.2.1 - - browserify-rsa@4.1.1: - dependencies: - bn.js: 5.2.3 - randombytes: 2.1.0 - safe-buffer: 5.2.1 - - browserify-sign@4.2.5: - dependencies: - bn.js: 5.2.3 - browserify-rsa: 4.1.1 - create-hash: 1.2.0 - create-hmac: 1.1.7 - elliptic: 6.6.1 - inherits: 2.0.4 - parse-asn1: 5.1.9 - readable-stream: 2.3.8 - safe-buffer: 5.2.1 - - browserify-zlib@0.2.0: - dependencies: - pako: 1.0.11 - browserslist@4.28.2: dependencies: baseline-browser-mapping: 2.10.29 @@ -15831,24 +7713,10 @@ snapshots: dependencies: node-int64: 0.4.0 - buffer-crc32@0.2.13: {} - buffer-equal-constant-time@1.0.1: {} buffer-from@1.1.2: {} - buffer-indexof-polyfill@1.0.2: {} - - buffer-indexof@1.1.1: {} - - buffer-xor@1.0.3: {} - - buffer@4.9.2: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - isarray: 1.0.0 - buffer@5.7.1: dependencies: base64-js: 1.5.1 @@ -15859,29 +7727,28 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 - buffers@0.1.1: {} - - builtin-status-codes@3.0.0: {} - busboy@1.6.0: dependencies: streamsearch: 1.1.0 bytes@3.1.2: {} - cac@6.7.14: {} - - cache-base@1.0.1: + c12@3.1.0: dependencies: - collection-visit: 1.0.0 - component-emitter: 1.3.1 - get-value: 2.0.6 - has-value: 1.0.0 - isobject: 3.0.1 - set-value: 2.0.1 - to-object-path: 0.3.0 - union-value: 1.0.1 - unset-value: 1.0.0 + chokidar: 4.0.3 + confbox: 0.2.4 + defu: 6.1.7 + dotenv: 16.6.1 + exsolve: 1.0.8 + giget: 2.0.0 + jiti: 2.6.1 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 1.0.0 + pkg-types: 2.3.1 + rc9: 2.1.2 + + cac@6.7.14: {} call-bind-apply-helpers@1.0.2: dependencies: @@ -15904,19 +7771,6 @@ snapshots: camelcase-css@2.0.1: {} - camelcase-keys@2.1.0: - dependencies: - camelcase: 2.1.1 - map-obj: 1.0.1 - - camelcase@1.2.1: {} - - camelcase@2.1.1: {} - - camelcase@3.0.0: {} - - camelcase@4.1.0: {} - camelcase@5.3.1: {} camelcase@6.3.0: {} @@ -15933,30 +7787,6 @@ snapshots: - supports-color optional: true - canvg@3.0.11: - dependencies: - '@babel/runtime': 7.29.2 - '@types/raf': 3.4.3 - core-js: 3.49.0 - raf: 3.4.1 - regenerator-runtime: 0.13.11 - rgbcolor: 1.0.1 - stackblur-canvas: 2.7.0 - svg-pathdata: 6.0.3 - optional: true - - caseless@0.12.0: {} - - center-align@0.1.3: - dependencies: - align-text: 0.1.4 - lazy-cache: 1.0.4 - - cfb@1.2.2: - dependencies: - adler-32: 1.3.1 - crc-32: 1.2.2 - chai@5.3.3: dependencies: assertion-error: 2.0.1 @@ -15965,10 +7795,6 @@ snapshots: loupe: 3.2.1 pathval: 2.0.1 - chainsaw@0.1.0: - dependencies: - traverse: 0.3.9 - chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -15976,51 +7802,12 @@ snapshots: chalk@5.6.2: {} - change-case@5.4.4: {} - char-regex@1.0.2: {} chardet@2.1.1: {} check-error@2.1.3: {} - chokidar@2.1.8(supports-color@4.5.0): - dependencies: - anymatch: 2.0.0(supports-color@4.5.0) - async-each: 1.0.6 - braces: 2.3.2(supports-color@4.5.0) - glob-parent: 3.1.0 - inherits: 2.0.4 - is-binary-path: 1.0.1 - is-glob: 4.0.3 - normalize-path: 3.0.0 - path-is-absolute: 1.0.1 - readdirp: 2.2.1(supports-color@4.5.0) - upath: 1.2.0 - optionalDependencies: - fsevents: 1.2.13 - transitivePeerDependencies: - - supports-color - optional: true - - chokidar@2.1.8(supports-color@5.5.0): - dependencies: - anymatch: 2.0.0(supports-color@5.5.0) - async-each: 1.0.6 - braces: 2.3.2(supports-color@5.5.0) - glob-parent: 3.1.0 - inherits: 2.0.4 - is-binary-path: 1.0.1 - is-glob: 4.0.3 - normalize-path: 3.0.0 - path-is-absolute: 1.0.1 - readdirp: 2.2.1(supports-color@5.5.0) - upath: 1.2.0 - optionalDependencies: - fsevents: 1.2.13 - transitivePeerDependencies: - - supports-color - chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -16043,33 +7830,22 @@ snapshots: ci-info@3.9.0: {} - cipher-base@1.0.7: + citty@0.1.6: dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - to-buffer: 1.2.2 + consola: 3.4.2 + + citty@0.2.2: {} cjs-module-lexer@1.4.3: {} class-transformer@0.5.1: {} - class-utils@0.3.6: - dependencies: - arr-union: 3.1.0 - define-property: 0.2.5 - isobject: 3.0.1 - static-extend: 0.1.2 - class-validator@0.14.4: dependencies: '@types/validator': 13.15.10 libphonenumber-js: 1.13.1 validator: 13.15.35 - class-variance-authority@0.7.1: - dependencies: - clsx: 2.1.1 - cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 @@ -16093,18 +7869,6 @@ snapshots: cli-width@4.1.0: {} - cliui@2.1.0: - dependencies: - center-align: 0.1.3 - right-align: 0.1.3 - wordwrap: 0.0.2 - - cliui@3.2.0: - dependencies: - string-width: 1.0.2 - strip-ansi: 3.0.1 - wrap-ansi: 2.1.0 - cliui@6.0.0: dependencies: string-width: 4.2.3 @@ -16117,55 +7881,20 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - cliui@9.0.1: - dependencies: - string-width: 7.2.0 - strip-ansi: 7.2.0 - wrap-ansi: 9.0.2 - clone@1.0.4: {} - clone@2.1.2: {} - clsx@2.1.1: {} - cmdk@1.1.1(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - '@types/react' - - '@types/react-dom' - co@4.6.0: {} - code-point-at@1.1.0: {} - - codepage@1.15.0: {} - collect-v8-coverage@1.0.3: {} - collection-visit@1.0.0: - dependencies: - map-visit: 1.0.0 - object-visit: 1.0.1 - color-convert@2.0.1: dependencies: color-name: 1.1.4 color-name@1.1.4: {} - color-name@2.1.0: {} - - color-string@2.1.4: - dependencies: - color-name: 2.1.0 - color-support@1.1.3: {} colorette@2.0.20: {} @@ -16192,29 +7921,6 @@ snapshots: component-emitter@1.3.1: {} - compress-commons@4.1.2: - dependencies: - buffer-crc32: 0.2.13 - crc32-stream: 4.0.3 - normalize-path: 3.0.0 - readable-stream: 3.6.2 - - compressible@2.0.18: - dependencies: - mime-db: 1.54.0 - - compression@1.8.1(supports-color@5.5.0): - dependencies: - bytes: 3.1.2 - compressible: 2.0.18 - debug: 2.6.9(supports-color@5.5.0) - negotiator: 0.6.4 - on-headers: 1.1.0 - safe-buffer: 5.2.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - concat-map@0.0.1: {} concat-stream@2.0.0: @@ -16224,24 +7930,12 @@ snapshots: readable-stream: 3.6.2 typedarray: 0.0.6 - concat-with-sourcemaps@1.1.0: - dependencies: - source-map: 0.6.1 - - connect-history-api-fallback@1.6.0: {} + confbox@0.2.4: {} consola@3.4.2: {} - console-browserify@1.2.0: {} - console-control-strings@1.1.0: {} - constants-browserify@1.0.0: {} - - content-disposition@0.5.4: - dependencies: - safe-buffer: 5.2.1 - content-disposition@1.1.0: {} content-type@1.0.5: {} @@ -16261,29 +7955,14 @@ snapshots: meow: 12.1.1 split2: 4.2.0 - convert-source-map@1.9.0: {} - convert-source-map@2.0.0: {} - cookie-signature@1.0.7: {} - cookie-signature@1.2.2: {} cookie@0.7.2: {} - cookie@1.1.1: {} - cookiejar@2.1.4: {} - copy-descriptor@0.1.1: {} - - core-js@3.49.0: - optional: true - - core-util-is@1.0.2: {} - - core-util-is@1.0.3: {} - cors@2.8.6: dependencies: object-assign: 4.1.1 @@ -16303,6 +7982,7 @@ snapshots: parse-json: 5.2.0 path-type: 4.0.0 yaml: 1.10.3 + optional: true cosmiconfig@8.3.6(typescript@5.9.3): dependencies: @@ -16322,42 +8002,6 @@ snapshots: optionalDependencies: typescript: 5.9.3 - crc-32@1.2.2: {} - - crc32-stream@4.0.3: - dependencies: - crc-32: 1.2.2 - readable-stream: 3.6.2 - - create-ecdh@4.0.4: - dependencies: - bn.js: 4.12.3 - elliptic: 6.6.1 - - create-frame@1.0.0: - dependencies: - define-property: 0.2.5 - extend-shallow: 2.0.1 - isobject: 3.0.1 - lazy-cache: 2.0.2 - - create-hash@1.2.0: - dependencies: - cipher-base: 1.0.7 - inherits: 2.0.4 - md5.js: 1.3.5 - ripemd160: 2.0.3 - sha.js: 2.4.12 - - create-hmac@1.1.7: - dependencies: - cipher-base: 1.0.7 - create-hash: 1.2.0 - inherits: 2.0.4 - ripemd160: 2.0.3 - safe-buffer: 5.2.1 - sha.js: 2.4.12 - create-jest@29.7.0(@types/node@20.19.41)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)): dependencies: '@jest/types': 29.6.3 @@ -16380,52 +8024,12 @@ snapshots: '@types/luxon': 3.7.1 luxon: 3.7.2 - cross-spawn@5.1.0: - dependencies: - lru-cache: 4.1.5 - shebang-command: 1.2.0 - which: 1.3.1 - cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - crypto-browserify@3.12.1: - dependencies: - browserify-cipher: 1.0.1 - browserify-sign: 4.2.5 - create-ecdh: 4.0.4 - create-hash: 1.2.0 - create-hmac: 1.1.7 - diffie-hellman: 5.0.3 - hash-base: 3.0.5 - inherits: 2.0.4 - pbkdf2: 3.1.5 - public-encrypt: 4.0.3 - randombytes: 2.1.0 - randomfill: 1.0.4 - - css-line-break@2.1.0: - dependencies: - utrie: 1.0.2 - - css-select@5.2.2: - dependencies: - boolbase: 1.0.0 - css-what: 6.2.2 - domhandler: 5.0.3 - domutils: 3.2.2 - nth-check: 2.1.1 - - css-tree@1.1.3: - dependencies: - mdn-data: 2.0.14 - source-map: 0.6.1 - - css-what@6.2.2: {} - cssesc@3.0.0: {} cssstyle@4.6.0: @@ -16435,59 +8039,8 @@ snapshots: csstype@3.2.3: {} - currently-unhandled@0.4.1: - dependencies: - array-find-index: 1.0.2 - - d3-array@3.2.4: - dependencies: - internmap: 2.0.3 - - d3-color@3.1.0: {} - - d3-ease@3.0.1: {} - - d3-format@3.1.2: {} - - d3-interpolate@3.0.1: - dependencies: - d3-color: 3.1.0 - - d3-path@3.1.0: {} - - d3-scale@4.0.2: - dependencies: - d3-array: 3.2.4 - d3-format: 3.1.2 - d3-interpolate: 3.0.1 - d3-time: 3.1.0 - d3-time-format: 4.1.0 - - d3-shape@3.2.0: - dependencies: - d3-path: 3.1.0 - - d3-time-format@4.1.0: - dependencies: - d3-time: 3.1.0 - - d3-time@3.1.0: - dependencies: - d3-array: 3.2.4 - - d3-timer@3.0.1: {} - - d@1.0.2: - dependencies: - es5-ext: 0.10.64 - type: 2.7.3 - dargs@8.1.0: {} - dashdash@1.14.1: - dependencies: - assert-plus: 1.0.0 - data-urls@5.0.0: dependencies: whatwg-mimetype: 4.0.0 @@ -16511,63 +8064,20 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.2 - date-fns-jalali@4.1.0-0: {} - - date-fns@3.6.0: {} - - date.js@0.3.3: - dependencies: - debug: 3.1.0 - transitivePeerDependencies: - - supports-color - dayjs@1.11.20: {} - debug@2.6.9(supports-color@4.5.0): - dependencies: - ms: 2.0.0 - optionalDependencies: - supports-color: 4.5.0 - optional: true - - debug@2.6.9(supports-color@5.5.0): - dependencies: - ms: 2.0.0 - optionalDependencies: - supports-color: 5.5.0 - - debug@3.1.0: - dependencies: - ms: 2.0.0 - debug@3.2.7: dependencies: ms: 2.1.3 - debug@3.2.7(supports-color@5.5.0): - dependencies: - ms: 2.1.3 - optionalDependencies: - supports-color: 5.5.0 - debug@4.4.3: dependencies: ms: 2.1.3 - debug@4.4.3(supports-color@5.5.0): - dependencies: - ms: 2.1.3 - optionalDependencies: - supports-color: 5.5.0 - decamelize@1.2.0: {} - decimal.js-light@2.5.1: {} - decimal.js@10.6.0: {} - decode-uri-component@0.2.2: {} - decompress-response@4.2.1: dependencies: mimic-response: 2.1.0 @@ -16577,26 +8087,13 @@ snapshots: optionalDependencies: babel-plugin-macros: 3.1.0 - deep-diff@1.0.2: {} - deep-eql@5.0.2: {} - deep-equal@1.1.2: - dependencies: - is-arguments: 1.2.0 - is-date-object: 1.1.0 - is-regex: 1.2.1 - object-is: 1.1.6 - object-keys: 1.1.1 - regexp.prototype.flags: 1.5.4 - deep-is@0.1.4: {} - deepmerge@4.3.1: {} + deepmerge-ts@7.1.5: {} - default-compare@1.0.0: - dependencies: - kind-of: 5.1.0 + deepmerge@4.3.1: {} defaults@1.0.4: dependencies: @@ -16614,88 +8111,38 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 - define-property@0.2.5: - dependencies: - is-descriptor: 0.1.8 - - define-property@1.0.0: - dependencies: - is-descriptor: 1.0.4 - - define-property@2.0.2: - dependencies: - is-descriptor: 1.0.4 - isobject: 3.0.1 - - del@3.0.0: - dependencies: - globby: 6.1.0 - is-path-cwd: 1.0.0 - is-path-in-cwd: 1.0.1 - p-map: 1.2.0 - pify: 3.0.0 - rimraf: 2.7.1 + defu@6.1.7: {} delayed-stream@1.0.0: {} delegates@1.0.0: {} - depd@1.1.2: {} + denque@2.1.0: + optional: true depd@2.0.0: {} - dequal@2.0.3: {} - - des.js@1.1.0: - dependencies: - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - destr@2.0.5: {} - destroy@1.2.0: {} - detect-libc@2.1.2: {} detect-newline@3.1.0: {} - detect-node-es@1.1.0: {} - - detect-node@2.1.0: {} - dezalgo@1.0.4: dependencies: asap: 2.0.6 wrappy: 1.0.2 - dfa@1.2.0: {} - didyoumean@1.2.2: {} diff-sequences@29.6.3: {} diff@4.0.4: {} - diffie-hellman@5.0.3: - dependencies: - bn.js: 4.12.3 - miller-rabin: 4.0.1 - randombytes: 2.1.0 - dijkstrajs@1.0.3: {} dlv@1.1.3: {} - dns-equal@1.0.0: {} - - dns-packet@5.6.1: - dependencies: - '@leichtgewicht/ip-codec': 2.0.5 - - dns-txt@2.0.2: - dependencies: - buffer-indexof: 1.1.1 - doctrine@2.1.0: dependencies: esutils: 2.0.3 @@ -16704,36 +8151,6 @@ snapshots: dependencies: esutils: 2.0.3 - dom-helpers@5.2.1: - dependencies: - '@babel/runtime': 7.29.2 - csstype: 3.2.3 - - dom-serializer@2.0.0: - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - entities: 4.5.0 - - domain-browser@1.2.0: {} - - domelementtype@2.3.0: {} - - domhandler@5.0.3: - dependencies: - domelementtype: 2.3.0 - - dompurify@3.4.2: - optionalDependencies: - '@types/trusted-types': 2.0.7 - optional: true - - domutils@3.2.2: - dependencies: - dom-serializer: 2.0.0 - domelementtype: 2.3.0 - domhandler: 5.0.3 - dot-prop@5.3.0: dependencies: is-obj: 2.0.0 @@ -16752,114 +8169,48 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - duplexer2@0.1.4: - dependencies: - readable-stream: 2.3.8 - eastasianwidth@0.2.0: {} - ebec@1.1.1: - dependencies: - smob: 1.6.1 - - ebec@2.3.0: {} - - ecc-jsbn@0.1.2: - dependencies: - jsbn: 0.1.1 - safer-buffer: 2.1.2 - ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer: 5.2.1 ee-first@1.1.1: {} + effect@3.21.0: + dependencies: + '@standard-schema/spec': 1.1.0 + fast-check: 3.23.2 + electron-to-chromium@1.5.353: {} - elliptic@6.6.1: - dependencies: - bn.js: 4.12.3 - brorand: 1.1.0 - hash.js: 1.1.7 - hmac-drbg: 1.0.1 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - emittery@0.13.1: {} - emoji-regex-xs@1.0.0: {} - emoji-regex@10.6.0: {} emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} - emojis-list@3.0.0: {} + empathic@2.0.0: {} encodeurl@2.0.0: {} - end-of-stream@1.4.5: - dependencies: - once: 1.4.0 - - engine.io-client@6.6.4: - dependencies: - '@socket.io/component-emitter': 3.1.2 - debug: 4.4.3(supports-color@5.5.0) - engine.io-parser: 5.2.3 - ws: 8.18.3 - xmlhttprequest-ssl: 2.1.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - engine.io-parser@5.2.3: {} - - enhanced-resolve@3.4.1: - dependencies: - graceful-fs: 4.2.11 - memory-fs: 0.4.1 - object-assign: 4.1.1 - tapable: 0.2.9 - enhanced-resolve@5.21.3: dependencies: graceful-fs: 4.2.11 tapable: 2.3.3 - ent@2.2.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - punycode: 1.4.1 - safe-regex-test: 1.1.0 - - entities@4.5.0: {} - entities@6.0.1: {} env-paths@2.2.1: {} environment@1.1.0: {} - envix@1.5.0: - dependencies: - std-env: 3.10.0 - - errno@0.1.8: - dependencies: - prr: 1.0.1 - error-ex@1.3.4: dependencies: is-arrayish: 0.2.1 - error-symbol@0.1.0: {} - es-abstract@1.24.2: dependencies: array-buffer-byte-length: 1.0.2 @@ -16965,51 +8316,6 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 - es-toolkit@1.46.1: {} - - es5-ext@0.10.64: - dependencies: - es6-iterator: 2.0.3 - es6-symbol: 3.1.4 - esniff: 2.0.1 - next-tick: 1.1.0 - - es6-iterator@2.0.3: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-symbol: 3.1.4 - - es6-map@0.1.5: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-iterator: 2.0.3 - es6-set: 0.1.6 - es6-symbol: 3.1.4 - event-emitter: 0.3.5 - - es6-set@0.1.6: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-iterator: 2.0.3 - es6-symbol: 3.1.4 - event-emitter: 0.3.5 - type: 2.7.3 - - es6-symbol@3.1.4: - dependencies: - d: 1.0.2 - ext: 1.7.0 - - es6-weak-map@2.0.3: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-iterator: 2.0.3 - es6-symbol: 3.1.4 - esbuild@0.21.5: optionalDependencies: '@esbuild/aix-ppc64': 0.21.5 @@ -17044,13 +8350,6 @@ snapshots: escape-string-regexp@4.0.0: {} - escope@3.6.0: - dependencies: - es6-map: 0.1.5 - es6-weak-map: 2.0.3 - esrecurse: 4.3.0 - estraverse: 4.3.0 - eslint-config-prettier@9.1.2(eslint@8.57.1): dependencies: eslint: 8.57.1 @@ -17189,13 +8488,6 @@ snapshots: transitivePeerDependencies: - supports-color - esniff@2.0.1: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - event-emitter: 0.3.5 - type: 2.7.3 - espree@9.6.1: dependencies: acorn: 8.16.0 @@ -17224,58 +8516,12 @@ snapshots: etag@1.8.1: {} - ethiopian-calendar-date-converter@2.1.6: {} - - ethiopian-calendar-new@1.1.0: {} - - ethiopian-date@0.0.6: {} - - event-emitter@0.3.5: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - - event-target-shim@5.0.1: {} - eventemitter2@6.4.9: {} - eventemitter3@4.0.7: {} - eventemitter3@5.0.4: {} events@3.3.0: {} - eventsource@0.1.6: - dependencies: - original: 1.0.2 - - evp_bytestokey@1.0.3: - dependencies: - md5.js: 1.3.5 - safe-buffer: 5.2.1 - - exceljs@4.4.0: - dependencies: - archiver: 5.3.2 - dayjs: 1.11.20 - fast-csv: 4.3.6 - jszip: 3.10.1 - readable-stream: 3.6.2 - saxes: 5.0.1 - tmp: 0.2.5 - unzipper: 0.10.14 - uuid: 8.3.2 - - execa@0.7.0: - dependencies: - cross-spawn: 5.1.0 - get-stream: 3.0.0 - is-stream: 1.1.0 - npm-run-path: 2.0.2 - p-finally: 1.0.0 - signal-exit: 3.0.7 - strip-eof: 1.0.0 - execa@5.1.1: dependencies: cross-spawn: 7.0.6 @@ -17302,43 +8548,6 @@ snapshots: exit@0.1.2: {} - expand-brackets@2.1.4: - dependencies: - debug: 2.6.9(supports-color@5.5.0) - define-property: 0.2.5 - extend-shallow: 2.0.1 - posix-character-classes: 0.1.1 - regex-not: 1.0.2 - snapdragon: 0.8.2 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - - expand-brackets@2.1.4(supports-color@4.5.0): - dependencies: - debug: 2.6.9(supports-color@4.5.0) - define-property: 0.2.5 - extend-shallow: 2.0.1 - posix-character-classes: 0.1.1 - regex-not: 1.0.2 - snapdragon: 0.8.2(supports-color@4.5.0) - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - optional: true - - expand-brackets@2.1.4(supports-color@5.5.0): - dependencies: - debug: 2.6.9(supports-color@5.5.0) - define-property: 0.2.5 - extend-shallow: 2.0.1 - posix-character-classes: 0.1.1 - regex-not: 1.0.2 - snapdragon: 0.8.2(supports-color@5.5.0) - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - expect-type@1.3.0: {} expect@29.7.0: @@ -17349,42 +8558,6 @@ snapshots: jest-message-util: 29.7.0 jest-util: 29.7.0 - express@4.22.2(supports-color@5.5.0): - dependencies: - accepts: 1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.5(supports-color@5.5.0) - content-disposition: 0.5.4 - content-type: 1.0.5 - cookie: 0.7.2 - cookie-signature: 1.0.7 - debug: 2.6.9(supports-color@5.5.0) - depd: 2.0.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.3.2(supports-color@5.5.0) - fresh: 0.5.2 - http-errors: 2.0.1 - merge-descriptors: 1.0.3 - methods: 1.1.2 - on-finished: 2.4.1 - parseurl: 1.3.3 - path-to-regexp: 0.1.13 - proxy-addr: 2.0.7 - qs: 6.15.1 - range-parser: 1.2.1 - safe-buffer: 5.2.1 - send: 0.19.2(supports-color@5.5.0) - serve-static: 1.16.3(supports-color@5.5.0) - setprototypeof: 1.2.0 - statuses: 2.0.2 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - express@5.2.1: dependencies: accepts: 2.0.0 @@ -17418,76 +8591,14 @@ snapshots: transitivePeerDependencies: - supports-color - ext@1.7.0: + exsolve@1.0.8: {} + + fast-check@3.23.2: dependencies: - type: 2.7.3 - - extend-shallow@2.0.1: - dependencies: - is-extendable: 0.1.1 - - extend-shallow@3.0.2: - dependencies: - assign-symbols: 1.0.0 - is-extendable: 1.0.1 - - extend@3.0.2: {} - - extglob@2.0.4: - dependencies: - array-unique: 0.3.2 - define-property: 1.0.0 - expand-brackets: 2.1.4 - extend-shallow: 2.0.1 - fragment-cache: 0.2.1 - regex-not: 1.0.2 - snapdragon: 0.8.2 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - - extglob@2.0.4(supports-color@4.5.0): - dependencies: - array-unique: 0.3.2 - define-property: 1.0.0 - expand-brackets: 2.1.4(supports-color@4.5.0) - extend-shallow: 2.0.1 - fragment-cache: 0.2.1 - regex-not: 1.0.2 - snapdragon: 0.8.2(supports-color@4.5.0) - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - optional: true - - extglob@2.0.4(supports-color@5.5.0): - dependencies: - array-unique: 0.3.2 - define-property: 1.0.0 - expand-brackets: 2.1.4(supports-color@5.5.0) - extend-shallow: 2.0.1 - fragment-cache: 0.2.1 - regex-not: 1.0.2 - snapdragon: 0.8.2(supports-color@5.5.0) - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - - extsprintf@1.3.0: {} - - falsey@0.3.2: - dependencies: - kind-of: 5.1.0 - - fast-csv@4.3.6: - dependencies: - '@fast-csv/format': 4.3.5 - '@fast-csv/parse': 4.3.6 + pure-rand: 6.1.0 fast-deep-equal@3.1.3: {} - fast-equals@5.4.0: {} - fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -17500,37 +8611,14 @@ snapshots: fast-levenshtein@2.0.6: {} - fast-png@6.4.0: - dependencies: - '@types/pako': 2.0.4 - iobuffer: 5.4.0 - pako: 2.1.0 - fast-safe-stringify@2.1.1: {} fast-uri@3.1.2: {} - fast-xml-parser@4.5.6: - dependencies: - strnum: 1.1.2 - fastq@1.20.1: dependencies: reusify: 1.1.0 - faye-websocket@0.10.0: - dependencies: - websocket-driver: 0.7.4 - - faye-websocket@0.11.4: - dependencies: - websocket-driver: 0.7.4 - - faye@0.8.11: - dependencies: - cookiejar: 2.1.4 - faye-websocket: 0.11.4 - fb-watchman@2.0.2: dependencies: bser: 2.1.1 @@ -17539,22 +8627,10 @@ snapshots: optionalDependencies: picomatch: 4.0.4 - fflate@0.8.2: {} - file-entry-cache@6.0.1: dependencies: flat-cache: 3.2.0 - file-selector@2.1.2: - dependencies: - tslib: 2.8.1 - - file-type@18.7.0: - dependencies: - readable-web-to-node-stream: 3.0.4 - strtok3: 7.1.1 - token-types: 5.0.1 - file-type@21.3.4: dependencies: '@tokenizer/inflate': 0.4.1 @@ -17564,34 +8640,10 @@ snapshots: transitivePeerDependencies: - supports-color - file-uri-to-path@1.0.0: - optional: true - - fill-range@4.0.0: - dependencies: - extend-shallow: 2.0.1 - is-number: 3.0.0 - repeat-string: 1.6.1 - to-regex-range: 2.1.1 - fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 - filter-obj@1.1.0: {} - - finalhandler@1.3.2(supports-color@5.5.0): - dependencies: - debug: 2.6.9(supports-color@5.5.0) - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.2 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - finalhandler@2.1.1: dependencies: debug: 4.4.3 @@ -17603,17 +8655,6 @@ snapshots: transitivePeerDependencies: - supports-color - find-root@1.1.0: {} - - find-up@1.1.2: - dependencies: - path-exists: 2.1.0 - pinkie-promise: 2.0.1 - - find-up@2.1.0: - dependencies: - locate-path: 2.0.0 - find-up@4.1.0: dependencies: locate-path: 5.0.0 @@ -17636,51 +8677,19 @@ snapshots: keyv: 4.5.4 rimraf: 3.0.2 - flat@5.0.2: {} - flatted@3.4.2: {} follow-redirects@1.16.0: {} - follow-redirects@1.16.0(debug@3.2.7(supports-color@5.5.0)): - optionalDependencies: - debug: 3.2.7(supports-color@5.5.0) - - fontkit@2.0.4: - dependencies: - '@swc/helpers': 0.5.21 - brotli: 1.3.3 - clone: 2.1.2 - dfa: 1.2.0 - fast-deep-equal: 3.1.3 - restructure: 3.0.2 - tiny-inflate: 1.0.3 - unicode-properties: 1.4.1 - unicode-trie: 2.0.0 - for-each@0.3.5: dependencies: is-callable: 1.2.7 - for-in@1.0.2: {} - - for-own@1.0.0: - dependencies: - for-in: 1.0.2 - - force@0.0.3: - dependencies: - faye: 0.8.11 - mime: 1.2.11 - request: 2.88.2 - foreground-child@3.3.1: dependencies: cross-spawn: 7.0.6 signal-exit: 4.1.0 - forever-agent@0.6.1: {} - fork-ts-checker-webpack-plugin@9.1.0(typescript@5.9.3)(webpack@5.106.0): dependencies: '@babel/code-frame': 7.29.0 @@ -17698,12 +8707,6 @@ snapshots: typescript: 5.9.3 webpack: 5.106.0 - form-data@2.3.3: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - form-data@4.0.5: dependencies: asynckit: 0.4.0 @@ -17720,32 +8723,10 @@ snapshots: forwarded@0.2.0: {} - frac@1.1.2: {} - fraction.js@5.3.4: {} - fragment-cache@0.2.1: - dependencies: - map-cache: 0.2.2 - - framer-motion@12.38.0(@emotion/is-prop-valid@1.4.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - motion-dom: 12.38.0 - motion-utils: 12.36.0 - tslib: 2.8.1 - optionalDependencies: - '@emotion/is-prop-valid': 1.4.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - - fresh@0.5.2: {} - fresh@2.0.0: {} - fs-constants@1.0.0: {} - - fs-exists-sync@0.1.0: {} - fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 @@ -17760,22 +8741,9 @@ snapshots: fs.realpath@1.0.0: {} - fsevents@1.2.13: - dependencies: - bindings: 1.5.0 - nan: 2.26.2 - optional: true - fsevents@2.3.3: optional: true - fstream@1.0.12: - dependencies: - graceful-fs: 4.2.11 - inherits: 2.0.4 - mkdirp: 0.5.6 - rimraf: 2.7.1 - function-bind@1.1.2: {} function.prototype.name@1.1.8: @@ -17801,12 +8769,15 @@ snapshots: strip-ansi: 6.0.1 wide-align: 1.1.5 + generate-function@2.3.1: + dependencies: + is-property: 1.0.2 + optional: true + generator-function@2.0.1: {} gensync@1.0.0-beta.2: {} - get-caller-file@1.0.3: {} - get-caller-file@2.0.5: {} get-east-asian-width@1.6.0: {} @@ -17824,13 +8795,6 @@ snapshots: hasown: 2.0.3 math-intrinsics: 1.1.0 - get-nonce@1.0.1: {} - - get-object@0.2.0: - dependencies: - is-number: 2.1.0 - isobject: 0.2.0 - get-package-type@0.1.0: {} get-proto@1.0.1: @@ -17838,10 +8802,6 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 - get-stdin@4.0.1: {} - - get-stream@3.0.0: {} - get-stream@6.0.1: {} get-stream@8.0.1: {} @@ -17852,11 +8812,14 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 - get-value@2.0.6: {} - - getpass@0.1.7: + giget@2.0.0: dependencies: - assert-plus: 1.0.0 + citty: 0.1.6 + consola: 3.4.2 + defu: 6.1.7 + node-fetch-native: 1.6.7 + nypm: 0.6.6 + pathe: 2.0.3 git-raw-commits@4.0.0: dependencies: @@ -17864,11 +8827,6 @@ snapshots: meow: 12.1.1 split2: 4.2.0 - glob-parent@3.1.0: - dependencies: - is-glob: 3.1.0 - path-dirname: 1.0.2 - glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -17916,71 +8874,12 @@ snapshots: define-properties: 1.2.1 gopd: 1.2.0 - globby@6.1.0: - dependencies: - array-union: 1.0.2 - glob: 7.2.3 - object-assign: 4.1.1 - pify: 2.3.0 - pinkie-promise: 2.0.1 - gopd@1.2.0: {} graceful-fs@4.2.11: {} graphemer@1.4.0: {} - gulp-header@1.8.12: - dependencies: - concat-with-sourcemaps: 1.1.0 - lodash.template: 4.18.1 - through2: 2.0.5 - - handle-thing@2.0.1: {} - - handlebars-helper-create-frame@0.1.0: - dependencies: - create-frame: 1.0.0 - isobject: 3.0.1 - - handlebars-helpers@0.10.0: - dependencies: - arr-flatten: 1.1.0 - array-sort: 0.1.4 - create-frame: 1.0.0 - define-property: 1.0.0 - falsey: 0.3.2 - for-in: 1.0.2 - for-own: 1.0.0 - get-object: 0.2.0 - get-value: 2.0.6 - handlebars: 4.7.9 - handlebars-helper-create-frame: 0.1.0 - handlebars-utils: 1.0.6 - has-value: 1.0.0 - helper-date: 1.0.1 - helper-markdown: 1.0.0 - helper-md: 0.2.2 - html-tag: 2.0.0 - is-even: 1.0.0 - is-glob: 4.0.3 - is-number: 4.0.0 - kind-of: 6.0.3 - lazy-cache: 2.0.2 - logging-helpers: 1.0.0 - micromatch: 3.1.10 - relative: 3.0.2 - striptags: 3.2.0 - to-gfm-code-block: 0.1.1 - year: 0.2.1 - transitivePeerDependencies: - - supports-color - - handlebars-utils@1.0.6: - dependencies: - kind-of: 6.0.3 - typeof-article: 0.1.1 - handlebars@4.7.9: dependencies: minimist: 1.2.8 @@ -17990,19 +8889,8 @@ snapshots: optionalDependencies: uglify-js: 3.19.3 - har-schema@2.0.0: {} - - har-validator@5.1.5: - dependencies: - ajv: 6.15.0 - har-schema: 2.0.0 - has-bigints@1.1.0: {} - has-flag@2.0.0: {} - - has-flag@3.0.0: {} - has-flag@4.0.0: {} has-property-descriptors@1.0.2: @@ -18021,128 +8909,16 @@ snapshots: has-unicode@2.0.1: {} - has-value@0.3.1: - dependencies: - get-value: 2.0.6 - has-values: 0.1.4 - isobject: 2.1.0 - - has-value@1.0.0: - dependencies: - get-value: 2.0.6 - has-values: 1.0.0 - isobject: 3.0.1 - - has-values@0.1.4: {} - - has-values@1.0.0: - dependencies: - is-number: 3.0.0 - kind-of: 4.0.0 - - hash-base@3.0.5: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - - hash-base@3.1.2: - dependencies: - inherits: 2.0.4 - readable-stream: 2.3.8 - safe-buffer: 5.2.1 - to-buffer: 1.2.2 - - hash.js@1.1.7: - dependencies: - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - hasown@2.0.3: dependencies: function-bind: 1.1.2 - he@1.2.0: {} - - helper-date@1.0.1: - dependencies: - date.js: 0.3.3 - handlebars-utils: 1.0.6 - moment: 2.30.1 - transitivePeerDependencies: - - supports-color - - helper-markdown@1.0.0: - dependencies: - handlebars-utils: 1.0.6 - highlight.js: 9.18.5 - remarkable: 1.7.4 - - helper-md@0.2.2: - dependencies: - ent: 2.2.2 - extend-shallow: 2.0.1 - fs-exists-sync: 0.1.0 - remarkable: 1.7.4 - - highlight.js@9.18.5: {} - - hmac-drbg@1.0.1: - dependencies: - hash.js: 1.1.7 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - - hoist-non-react-statics@3.3.2: - dependencies: - react-is: 16.13.1 - - hosted-git-info@2.8.9: {} - - hpack.js@2.1.6: - dependencies: - inherits: 2.0.4 - obuf: 1.1.2 - readable-stream: 2.3.8 - wbuf: 1.7.3 - - hsl-to-hex@1.0.0: - dependencies: - hsl-to-rgb-for-reals: 1.1.1 - - hsl-to-rgb-for-reals@1.1.1: {} - html-encoding-sniffer@4.0.0: dependencies: whatwg-encoding: 3.1.1 - html-entities@1.4.0: {} - html-escaper@2.0.2: {} - html-parse-stringify@3.0.1: - dependencies: - void-elements: 3.1.0 - - html-tag@2.0.0: - dependencies: - is-self-closing: 1.0.1 - kind-of: 6.0.3 - - html2canvas@1.4.1: - dependencies: - css-line-break: 2.1.0 - text-segmentation: 1.0.3 - - http-deceiver@1.2.7: {} - - http-errors@1.8.1: - dependencies: - depd: 1.1.2 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 1.5.0 - toidentifier: 1.0.1 - http-errors@2.0.1: dependencies: depd: 2.0.0 @@ -18151,8 +8927,6 @@ snapshots: statuses: 2.0.2 toidentifier: 1.0.1 - http-parser-js@0.5.10: {} - http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 @@ -18160,32 +8934,6 @@ snapshots: transitivePeerDependencies: - supports-color - http-proxy-middleware@0.19.2(debug@3.2.7(supports-color@5.5.0))(supports-color@5.5.0): - dependencies: - http-proxy: 1.18.1(debug@3.2.7(supports-color@5.5.0)) - is-glob: 4.0.3 - lodash: 4.18.1 - micromatch: 3.1.10(supports-color@5.5.0) - transitivePeerDependencies: - - debug - - supports-color - - http-proxy@1.18.1(debug@3.2.7(supports-color@5.5.0)): - dependencies: - eventemitter3: 4.0.7 - follow-redirects: 1.16.0(debug@3.2.7(supports-color@5.5.0)) - requires-port: 1.0.0 - transitivePeerDependencies: - - debug - - http-signature@1.2.0: - dependencies: - assert-plus: 1.0.0 - jsprim: 1.4.2 - sshpk: 1.18.0 - - https-browserify@1.0.0: {} - https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 @@ -18206,22 +8954,6 @@ snapshots: husky@9.1.7: {} - hyphen@1.14.1: {} - - i18next-browser-languagedetector@8.2.1: - dependencies: - '@babel/runtime': 7.29.2 - - i18next@25.10.10(typescript@5.9.3): - dependencies: - '@babel/runtime': 7.29.2 - optionalDependencies: - typescript: 5.9.3 - - iconv-lite@0.4.24: - dependencies: - safer-buffer: 2.1.2 - iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 @@ -18230,30 +8962,20 @@ snapshots: dependencies: safer-buffer: 2.1.2 - idb-keyval@6.2.2: {} - ieee754@1.2.1: {} ignore@5.3.2: {} ignore@7.0.5: {} - immediate@3.0.6: {} - - immer@10.2.0: {} - - immer@11.1.8: {} + immer@11.1.8: + optional: true import-fresh@3.3.1: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 - import-local@1.0.0: - dependencies: - pkg-dir: 2.0.0 - resolve-cwd: 2.0.0 - import-local@3.2.0: dependencies: pkg-dir: 4.2.0 @@ -18263,56 +8985,23 @@ snapshots: imurmurhash@0.1.4: {} - indent-string@2.1.0: - dependencies: - repeating: 2.0.1 - inflight@1.0.6: dependencies: once: 1.4.0 wrappy: 1.0.2 - info-symbol@0.1.0: {} - - inherits@2.0.3: {} - inherits@2.0.4: {} ini@4.1.1: {} - internal-ip@1.2.0: - dependencies: - meow: 3.7.0 - internal-slot@1.1.0: dependencies: es-errors: 1.3.0 hasown: 2.0.3 side-channel: 1.1.0 - internmap@2.0.3: {} - - interpret@1.4.0: {} - - invert-kv@1.0.0: {} - - iobuffer@5.4.0: {} - - ip@1.1.9: {} - ipaddr.js@1.9.1: {} - ipaddr.js@2.4.0: {} - - is-accessor-descriptor@1.0.2: - dependencies: - hasown: 2.0.3 - - is-arguments@1.2.0: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - is-array-buffer@3.0.5: dependencies: call-bind: 1.0.9 @@ -18333,10 +9022,6 @@ snapshots: dependencies: has-bigints: 1.1.0 - is-binary-path@1.0.1: - dependencies: - binary-extensions: 1.13.1 - is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 @@ -18346,18 +9031,12 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 - is-buffer@1.1.6: {} - is-callable@1.2.7: {} is-core-module@2.16.2: dependencies: hasown: 2.0.3 - is-data-descriptor@1.0.1: - dependencies: - hasown: 2.0.3 - is-data-view@1.0.2: dependencies: call-bound: 1.0.4 @@ -18369,40 +9048,12 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 - is-descriptor@0.1.8: - dependencies: - is-accessor-descriptor: 1.0.2 - is-data-descriptor: 1.0.1 - - is-descriptor@1.0.4: - dependencies: - is-accessor-descriptor: 1.0.2 - is-data-descriptor: 1.0.1 - - is-even@1.0.0: - dependencies: - is-odd: 0.1.2 - - is-extendable@0.1.1: {} - - is-extendable@1.0.1: - dependencies: - is-plain-object: 2.0.4 - is-extglob@2.1.1: {} is-finalizationregistry@1.1.1: dependencies: call-bound: 1.0.4 - is-finite@1.1.0: {} - - is-fullwidth-code-point@1.0.0: - dependencies: - number-is-nan: 1.0.1 - - is-fullwidth-code-point@2.0.0: {} - is-fullwidth-code-point@3.0.0: {} is-fullwidth-code-point@4.0.0: {} @@ -18421,20 +9072,12 @@ snapshots: has-tostringtag: 1.0.2 safe-regex-test: 1.1.0 - is-glob@3.1.0: - dependencies: - is-extglob: 2.1.1 - is-glob@4.0.3: dependencies: is-extglob: 2.1.1 is-interactive@1.0.0: {} - is-lite@0.8.2: {} - - is-lite@1.2.1: {} - is-map@2.0.3: {} is-negative-zero@2.0.3: {} @@ -18444,44 +9087,19 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 - is-number@2.1.0: - dependencies: - kind-of: 3.2.2 - - is-number@3.0.0: - dependencies: - kind-of: 3.2.2 - - is-number@4.0.0: {} - is-number@7.0.0: {} is-obj@2.0.0: {} - is-odd@0.1.2: - dependencies: - is-number: 3.0.0 - - is-path-cwd@1.0.0: {} - - is-path-in-cwd@1.0.1: - dependencies: - is-path-inside: 1.0.1 - - is-path-inside@1.0.1: - dependencies: - path-is-inside: 1.0.2 - is-path-inside@3.0.3: {} - is-plain-object@2.0.4: - dependencies: - isobject: 3.0.1 - is-potential-custom-element-name@1.0.1: {} is-promise@4.0.0: {} + is-property@1.0.2: + optional: true + is-regex@1.2.1: dependencies: call-bound: 1.0.4 @@ -18489,18 +9107,12 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.3 - is-self-closing@1.0.1: - dependencies: - self-closing-tags: 1.0.1 - is-set@2.0.3: {} is-shared-array-buffer@1.0.4: dependencies: call-bound: 1.0.4 - is-stream@1.1.0: {} - is-stream@2.0.1: {} is-stream@3.0.0: {} @@ -18524,14 +9136,8 @@ snapshots: dependencies: which-typed-array: 1.1.20 - is-typedarray@1.0.0: {} - is-unicode-supported@0.1.0: {} - is-url@1.2.4: {} - - is-utf8@0.2.1: {} - is-weakmap@2.0.2: {} is-weakref@1.1.1: @@ -18543,26 +9149,10 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 - is-windows@1.0.2: {} - - is-wsl@1.1.0: {} - - isarray@1.0.0: {} - isarray@2.0.5: {} isexe@2.0.0: {} - isobject@0.2.0: {} - - isobject@2.1.0: - dependencies: - isarray: 1.0.0 - - isobject@3.0.1: {} - - isstream@0.1.2: {} - istanbul-lib-coverage@3.2.2: {} istanbul-lib-instrument@5.2.1: @@ -18621,10 +9211,6 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jay-peg@1.1.1: - dependencies: - restructure: 3.0.2 - jest-changed-files@29.7.0: dependencies: execa: 5.1.1 @@ -18944,18 +9530,6 @@ snapshots: jiti@2.6.1: {} - jiti@2.7.0: {} - - jmespath@0.16.0: {} - - jose@5.10.0: {} - - jquery@3.7.1: {} - - js-cookie@3.0.5: {} - - js-md5@0.8.3: {} - js-tokens@4.0.0: {} js-yaml@3.14.2: @@ -18971,8 +9545,6 @@ snapshots: dependencies: argparse: 2.0.1 - jsbn@0.1.1: {} - jsdom@25.0.1(canvas@2.11.2): dependencies: cssstyle: 4.6.0 @@ -19007,26 +9579,14 @@ snapshots: json-buffer@3.0.1: {} - json-loader@0.5.7: {} - json-parse-even-better-errors@2.3.1: {} json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} - json-schema@0.4.0: {} - json-stable-stringify-without-jsonify@1.0.1: {} - json-stream@1.0.0: {} - - json-stringify-safe@5.0.1: {} - - json3@3.3.3: {} - - json5@0.5.1: {} - json5@1.0.2: dependencies: minimist: 1.2.8 @@ -19069,24 +9629,6 @@ snapshots: ms: 2.1.3 semver: 7.8.0 - jspdf@3.0.4: - dependencies: - '@babel/runtime': 7.29.2 - fast-png: 6.4.0 - fflate: 0.8.2 - optionalDependencies: - canvg: 3.0.11 - core-js: 3.49.0 - dompurify: 3.4.2 - html2canvas: 1.4.1 - - jsprim@1.4.2: - dependencies: - assert-plus: 1.0.0 - extsprintf: 1.3.0 - json-schema: 0.4.0 - verror: 1.10.0 - jsx-ast-utils@3.3.5: dependencies: array-includes: 3.1.9 @@ -19094,13 +9636,6 @@ snapshots: object.assign: 4.1.7 object.values: 1.2.1 - jszip@3.10.1: - dependencies: - lie: 3.3.0 - pako: 1.0.11 - readable-stream: 2.3.8 - setimmediate: 1.0.5 - jwa@1.4.2: dependencies: buffer-equal-constant-time: 1.0.1 @@ -19127,36 +9662,8 @@ snapshots: dependencies: json-buffer: 3.0.1 - killable@1.0.1: {} - - kind-of@3.2.2: - dependencies: - is-buffer: 1.1.6 - - kind-of@4.0.0: - dependencies: - is-buffer: 1.1.6 - - kind-of@5.1.0: {} - - kind-of@6.0.3: {} - kleur@3.0.3: {} - lazy-cache@1.0.4: {} - - lazy-cache@2.0.2: - dependencies: - set-getter: 0.1.1 - - lazystream@1.0.1: - dependencies: - readable-stream: 2.3.8 - - lcid@1.0.0: - dependencies: - invert-kv: 1.0.0 - leven@3.1.0: {} levn@0.4.1: @@ -19166,15 +9673,6 @@ snapshots: libphonenumber-js@1.13.1: {} - libreoffice-convert@1.8.1: - dependencies: - async: 3.2.6 - tmp: 0.2.5 - - lie@3.3.0: - dependencies: - immediate: 3.0.6 - lightningcss-android-arm64@1.32.0: optional: true @@ -19223,18 +9721,12 @@ snapshots: lightningcss-linux-x64-musl: 1.32.0 lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 + optional: true lilconfig@3.1.3: {} - linebreak@1.1.0: - dependencies: - base64-js: 0.0.8 - unicode-trie: 2.0.0 - lines-and-columns@1.2.4: {} - linkifyjs@4.3.2: {} - lint-staged@15.5.2: dependencies: chalk: 5.6.2 @@ -19250,8 +9742,6 @@ snapshots: transitivePeerDependencies: - supports-color - listenercount@1.0.1: {} - listr2@8.3.3: dependencies: cli-truncate: 4.0.0 @@ -19263,38 +9753,8 @@ snapshots: load-esm@1.0.3: {} - load-json-file@1.1.0: - dependencies: - graceful-fs: 4.2.11 - parse-json: 2.2.0 - pify: 2.3.0 - pinkie-promise: 2.0.1 - strip-bom: 2.0.0 - - load-json-file@2.0.0: - dependencies: - graceful-fs: 4.2.11 - parse-json: 2.2.0 - pify: 2.3.0 - strip-bom: 3.0.0 - - loadash@1.0.0: {} - - loader-runner@2.4.0: {} - loader-runner@4.3.2: {} - loader-utils@1.4.2: - dependencies: - big.js: 5.2.2 - emojis-list: 3.0.0 - json5: 1.0.2 - - locate-path@2.0.0: - dependencies: - p-locate: 2.0.0 - path-exists: 3.0.0 - locate-path@5.0.0: dependencies: p-locate: 4.1.0 @@ -19307,49 +9767,20 @@ snapshots: dependencies: p-locate: 6.0.0 - locter@2.2.1: - dependencies: - destr: 2.0.5 - ebec: 2.3.0 - fast-glob: 3.3.3 - flat: 5.0.2 - jiti: 2.7.0 - yaml: 2.9.0 - - lodash._reinterpolate@3.0.0: {} - lodash.camelcase@4.3.0: {} - lodash.defaults@4.2.0: {} - - lodash.difference@4.5.0: {} - - lodash.escaperegexp@4.1.2: {} - - lodash.flatten@4.4.0: {} - - lodash.groupby@4.6.0: {} - lodash.includes@4.3.0: {} lodash.isboolean@3.0.3: {} - lodash.isequal@4.5.0: {} - - lodash.isfunction@3.0.9: {} - lodash.isinteger@4.0.4: {} - lodash.isnil@4.0.0: {} - lodash.isnumber@3.0.3: {} lodash.isplainobject@4.0.6: {} lodash.isstring@4.0.1: {} - lodash.isundefined@3.0.1: {} - lodash.kebabcase@4.1.1: {} lodash.memoize@4.1.2: {} @@ -19364,17 +9795,6 @@ snapshots: lodash.startcase@4.4.0: {} - lodash.template@4.18.1: - dependencies: - lodash._reinterpolate: 3.0.0 - lodash.templatesettings: 4.2.0 - - lodash.templatesettings@4.2.0: - dependencies: - lodash._reinterpolate: 3.0.0 - - lodash.union@4.6.0: {} - lodash.uniq@4.5.0: {} lodash.upperfirst@4.3.1: {} @@ -19383,11 +9803,6 @@ snapshots: lodash@4.18.1: {} - log-ok@0.1.1: - dependencies: - ansi-green: 0.1.1 - success-symbol: 0.1.0 - log-symbols@4.1.0: dependencies: chalk: 4.1.2 @@ -19401,58 +9816,25 @@ snapshots: strip-ansi: 7.2.0 wrap-ansi: 9.0.2 - log-utils@0.2.1: - dependencies: - ansi-colors: 0.2.0 - error-symbol: 0.1.0 - info-symbol: 0.1.0 - log-ok: 0.1.1 - success-symbol: 0.1.0 - time-stamp: 1.1.0 - warning-symbol: 0.1.0 - - logging-helpers@1.0.0: - dependencies: - isobject: 3.0.1 - log-utils: 0.2.1 - - loglevel@1.9.2: {} - - longest@1.0.1: {} + long@5.3.2: + optional: true loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 - lottie-web@5.13.0: {} - - loud-rejection@1.6.0: - dependencies: - currently-unhandled: 0.4.1 - signal-exit: 3.0.7 - loupe@3.2.1: {} - lower-case@2.0.2: - dependencies: - tslib: 2.8.1 - lru-cache@10.4.3: {} lru-cache@11.3.6: {} - lru-cache@4.1.5: - dependencies: - pseudomap: 1.0.2 - yallist: 2.1.2 - lru-cache@5.1.1: dependencies: yallist: 3.1.1 - lucide-react@0.513.0(react@18.3.1): - dependencies: - react: 18.3.1 + lru.min@1.1.4: + optional: true luxon@3.7.2: {} @@ -19464,8 +9846,6 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 - make-cancellable-promise@2.0.0: {} - make-dir@3.1.0: dependencies: semver: 6.3.1 @@ -19476,143 +9856,35 @@ snapshots: make-error@1.3.6: {} - make-event-props@2.0.0: {} - makeerror@1.0.12: dependencies: tmpl: 1.0.5 - map-cache@0.2.2: {} - - map-obj@1.0.1: {} - - map-visit@1.0.0: - dependencies: - object-visit: 1.0.1 - math-intrinsics@1.1.0: {} - md5.js@1.3.5: - dependencies: - hash-base: 3.0.5 - inherits: 2.0.4 - safe-buffer: 5.2.1 - - mdn-data@2.0.14: {} - - media-engine@1.0.3: {} - media-typer@0.3.0: {} media-typer@1.1.0: {} - mem@1.1.0: - dependencies: - mimic-fn: 1.2.0 - memfs@3.5.3: dependencies: fs-monkey: 1.1.0 - memory-fs@0.4.1: - dependencies: - errno: 0.1.8 - readable-stream: 2.3.8 - meow@12.1.1: {} - meow@3.7.0: - dependencies: - camelcase-keys: 2.1.0 - decamelize: 1.2.0 - loud-rejection: 1.6.0 - map-obj: 1.0.1 - minimist: 1.2.8 - normalize-package-data: 2.5.0 - object-assign: 4.1.1 - read-pkg-up: 1.0.1 - redent: 1.0.0 - trim-newlines: 1.0.0 - - merge-descriptors@1.0.3: {} - merge-descriptors@2.0.0: {} - merge-refs@2.0.0(@types/react@18.3.28): - optionalDependencies: - '@types/react': 18.3.28 - merge-stream@2.0.0: {} merge2@1.4.1: {} methods@1.1.2: {} - micromatch@3.1.10: - dependencies: - arr-diff: 4.0.0 - array-unique: 0.3.2 - braces: 2.3.2 - define-property: 2.0.2 - extend-shallow: 3.0.2 - extglob: 2.0.4 - fragment-cache: 0.2.1 - kind-of: 6.0.3 - nanomatch: 1.2.13 - object.pick: 1.3.0 - regex-not: 1.0.2 - snapdragon: 0.8.2 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - - micromatch@3.1.10(supports-color@4.5.0): - dependencies: - arr-diff: 4.0.0 - array-unique: 0.3.2 - braces: 2.3.2(supports-color@4.5.0) - define-property: 2.0.2 - extend-shallow: 3.0.2 - extglob: 2.0.4(supports-color@4.5.0) - fragment-cache: 0.2.1 - kind-of: 6.0.3 - nanomatch: 1.2.13(supports-color@4.5.0) - object.pick: 1.3.0 - regex-not: 1.0.2 - snapdragon: 0.8.2(supports-color@4.5.0) - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - optional: true - - micromatch@3.1.10(supports-color@5.5.0): - dependencies: - arr-diff: 4.0.0 - array-unique: 0.3.2 - braces: 2.3.2(supports-color@5.5.0) - define-property: 2.0.2 - extend-shallow: 3.0.2 - extglob: 2.0.4(supports-color@5.5.0) - fragment-cache: 0.2.1 - kind-of: 6.0.3 - nanomatch: 1.2.13(supports-color@5.5.0) - object.pick: 1.3.0 - regex-not: 1.0.2 - snapdragon: 0.8.2(supports-color@5.5.0) - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - micromatch@4.0.8: dependencies: braces: 3.0.3 picomatch: 2.3.2 - miller-rabin@4.0.1: - dependencies: - bn.js: 4.12.3 - brorand: 1.1.0 - mime-db@1.52.0: {} mime-db@1.54.0: {} @@ -19625,14 +9897,8 @@ snapshots: dependencies: mime-db: 1.54.0 - mime@1.2.11: {} - - mime@1.6.0: {} - mime@2.6.0: {} - mimic-fn@1.2.0: {} - mimic-fn@2.1.0: {} mimic-fn@4.0.0: {} @@ -19642,10 +9908,6 @@ snapshots: mimic-response@2.1.0: optional: true - minimalistic-assert@1.0.1: {} - - minimalistic-crypto-utils@1.0.1: {} - minimatch@10.2.5: dependencies: brace-expansion: 5.0.6 @@ -19654,33 +9916,12 @@ snapshots: dependencies: brace-expansion: 1.1.14 - minimatch@5.1.9: - dependencies: - brace-expansion: 2.1.0 - minimatch@9.0.9: dependencies: brace-expansion: 2.1.0 minimist@1.2.8: {} - minio@7.1.3: - dependencies: - async: 3.2.6 - block-stream2: 2.1.0 - browser-or-node: 2.1.1 - buffer-crc32: 0.2.13 - fast-xml-parser: 4.5.6 - ipaddr.js: 2.4.0 - json-stream: 1.0.0 - lodash: 4.18.1 - mime-types: 2.1.35 - query-string: 7.1.3 - through2: 4.0.2 - web-encoding: 1.1.5 - xml: 1.0.1 - xml2js: 0.5.0 - minipass@3.3.6: dependencies: yallist: 4.0.0 @@ -19694,40 +9935,10 @@ snapshots: minipass: 3.3.6 yallist: 4.0.0 - mixin-deep@1.3.2: - dependencies: - for-in: 1.0.2 - is-extendable: 1.0.1 - - mkdirp@0.5.6: - dependencies: - minimist: 1.2.8 - mkdirp@1.0.4: {} - moment@2.30.1: {} - - motion-dom@12.38.0: - dependencies: - motion-utils: 12.36.0 - - motion-utils@12.36.0: {} - - ms@2.0.0: {} - ms@2.1.3: {} - mui-ethiopian-datepicker@0.3.2(hjxdxgubdlhng5uhyvidfkiyo4): - dependencies: - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@18.3.1) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) - '@mui/icons-material': 5.18.0(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) - '@mui/material': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/x-date-pickers': 6.20.2(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(date-fns@3.6.0)(dayjs@1.11.20)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - date-fns: 3.6.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - multer@2.1.1: dependencies: append-field: 1.0.0 @@ -19735,111 +9946,47 @@ snapshots: concat-stream: 2.0.0 type-is: 1.6.18 - multicast-dns-service-types@1.1.0: {} - - multicast-dns@7.2.5: - dependencies: - dns-packet: 5.6.1 - thunky: 1.1.0 - mute-stream@2.0.0: {} + mysql2@3.15.3: + dependencies: + aws-ssl-profiles: 1.1.2 + denque: 2.1.0 + generate-function: 2.3.1 + iconv-lite: 0.7.2 + long: 5.3.2 + lru.min: 1.1.4 + named-placeholders: 1.1.6 + seq-queue: 0.0.5 + sqlstring: 2.3.3 + optional: true + mz@2.7.0: dependencies: any-promise: 1.3.0 object-assign: 4.1.1 thenify-all: 1.6.0 + named-placeholders@1.1.6: + dependencies: + lru.min: 1.1.4 + optional: true + nan@2.26.2: optional: true nanoid@3.3.12: {} - nanomatch@1.2.13: - dependencies: - arr-diff: 4.0.0 - array-unique: 0.3.2 - define-property: 2.0.2 - extend-shallow: 3.0.2 - fragment-cache: 0.2.1 - is-windows: 1.0.2 - kind-of: 6.0.3 - object.pick: 1.3.0 - regex-not: 1.0.2 - snapdragon: 0.8.2 - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - - nanomatch@1.2.13(supports-color@4.5.0): - dependencies: - arr-diff: 4.0.0 - array-unique: 0.3.2 - define-property: 2.0.2 - extend-shallow: 3.0.2 - fragment-cache: 0.2.1 - is-windows: 1.0.2 - kind-of: 6.0.3 - object.pick: 1.3.0 - regex-not: 1.0.2 - snapdragon: 0.8.2(supports-color@4.5.0) - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - optional: true - - nanomatch@1.2.13(supports-color@5.5.0): - dependencies: - arr-diff: 4.0.0 - array-unique: 0.3.2 - define-property: 2.0.2 - extend-shallow: 3.0.2 - fragment-cache: 0.2.1 - is-windows: 1.0.2 - kind-of: 6.0.3 - object.pick: 1.3.0 - regex-not: 1.0.2 - snapdragon: 0.8.2(supports-color@5.5.0) - to-regex: 3.0.2 - transitivePeerDependencies: - - supports-color - natural-compare@1.4.0: {} - negotiator@0.6.3: {} - - negotiator@0.6.4: {} - negotiator@1.0.0: {} neo-async@2.6.2: {} - nestjs-minio-client@2.2.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19): - dependencies: - '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.19)(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) - minio: 7.1.3 - reflect-metadata: 0.1.14 - rxjs: 7.8.2 - - next-themes@0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - - next-tick@1.1.0: {} - - no-case@3.0.4: - dependencies: - lower-case: 2.0.2 - tslib: 2.8.1 - node-abort-controller@3.1.1: {} node-addon-api@5.1.0: {} - node-addon-api@8.7.0: {} - node-emoji@1.11.0: dependencies: lodash: 4.18.1 @@ -19851,74 +9998,22 @@ snapshots: object.entries: 1.1.9 semver: 6.3.1 + node-fetch-native@1.6.7: {} + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 - node-forge@0.10.0: {} - - node-gyp-build@4.8.4: {} - - node-html-parser@6.1.13: - dependencies: - css-select: 5.2.2 - he: 1.2.0 - node-int64@0.4.0: {} - node-libs-browser@2.2.1: - dependencies: - assert: 1.5.1 - browserify-zlib: 0.2.0 - buffer: 4.9.2 - console-browserify: 1.2.0 - constants-browserify: 1.0.0 - crypto-browserify: 3.12.1 - domain-browser: 1.2.0 - events: 3.3.0 - https-browserify: 1.0.0 - os-browserify: 0.3.0 - path-browserify: 0.0.1 - process: 0.11.10 - punycode: 1.4.1 - querystring-es3: 0.2.1 - readable-stream: 2.3.8 - stream-browserify: 2.0.2 - stream-http: 2.8.3 - string_decoder: 1.3.0 - timers-browserify: 2.0.12 - tty-browserify: 0.0.0 - url: 0.11.4 - util: 0.11.1 - vm-browserify: 1.1.2 - node-releases@2.0.44: {} nopt@5.0.0: dependencies: abbrev: 1.1.1 - normalize-package-data@2.5.0: - dependencies: - hosted-git-info: 2.8.9 - resolve: 1.22.12 - semver: 5.7.2 - validate-npm-package-license: 3.0.4 - - normalize-path@2.1.1: - dependencies: - remove-trailing-separator: 1.1.0 - normalize-path@3.0.0: {} - normalize-svg-path@1.1.0: - dependencies: - svg-arc-to-cubic-bezier: 3.2.0 - - npm-run-path@2.0.2: - dependencies: - path-key: 2.0.1 - npm-run-path@4.0.1: dependencies: path-key: 3.1.1 @@ -19934,39 +10029,22 @@ snapshots: gauge: 3.0.2 set-blocking: 2.0.0 - nth-check@2.1.1: - dependencies: - boolbase: 1.0.0 - - number-is-nan@1.0.1: {} - nwsapi@2.2.23: {} - oauth-sign@0.9.0: {} + nypm@0.6.6: + dependencies: + citty: 0.2.2 + pathe: 2.0.3 + tinyexec: 1.1.2 object-assign@4.1.1: {} - object-copy@0.1.0: - dependencies: - copy-descriptor: 0.1.1 - define-property: 0.2.5 - kind-of: 3.2.2 - object-hash@3.0.0: {} object-inspect@1.13.4: {} - object-is@1.1.6: - dependencies: - call-bind: 1.0.9 - define-properties: 1.2.1 - object-keys@1.1.1: {} - object-visit@1.0.1: - dependencies: - isobject: 3.0.1 - object.assign@4.1.7: dependencies: call-bind: 1.0.9 @@ -19996,10 +10074,6 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.24.2 - object.pick@1.3.0: - dependencies: - isobject: 3.0.1 - object.values@1.2.1: dependencies: call-bind: 1.0.9 @@ -20007,14 +10081,12 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 - obuf@1.1.2: {} + ohash@2.0.11: {} on-finished@2.4.1: dependencies: ee-first: 1.1.1 - on-headers@1.1.0: {} - once@1.4.0: dependencies: wrappy: 1.0.2 @@ -20031,12 +10103,6 @@ snapshots: dependencies: mimic-function: 5.0.1 - opencollective-postinstall@2.0.3: {} - - opn@5.5.0: - dependencies: - is-wsl: 1.1.0 - optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -20058,36 +10124,12 @@ snapshots: strip-ansi: 6.0.1 wcwidth: 1.0.1 - orderedmap@2.1.1: {} - - original@1.0.2: - dependencies: - url-parse: 1.5.10 - - os-browserify@0.3.0: {} - - os-locale@1.4.0: - dependencies: - lcid: 1.0.0 - - os-locale@2.1.0: - dependencies: - execa: 0.7.0 - lcid: 1.0.0 - mem: 1.1.0 - own-keys@1.0.1: dependencies: get-intrinsic: 1.3.0 object-keys: 1.1.1 safe-push-apply: 1.0.0 - p-finally@1.0.0: {} - - p-limit@1.3.0: - dependencies: - p-try: 1.0.0 - p-limit@2.3.0: dependencies: p-try: 2.2.0 @@ -20100,10 +10142,6 @@ snapshots: dependencies: yocto-queue: 1.2.2 - p-locate@2.0.0: - dependencies: - p-limit: 1.3.0 - p-locate@4.1.0: dependencies: p-limit: 2.3.0 @@ -20116,36 +10154,14 @@ snapshots: dependencies: p-limit: 4.0.0 - p-map@1.2.0: {} - - p-try@1.0.0: {} - p-try@2.2.0: {} package-json-from-dist@1.0.1: {} - pako@0.2.9: {} - - pako@1.0.11: {} - - pako@2.1.0: {} - parent-module@1.0.1: dependencies: callsites: 3.1.0 - parse-asn1@5.1.9: - dependencies: - asn1.js: 4.10.1 - browserify-aes: 1.2.0 - evp_bytestokey: 1.0.3 - pbkdf2: 3.1.5 - safe-buffer: 5.2.1 - - parse-json@2.2.0: - dependencies: - error-ex: 1.3.4 - parse-json@5.2.0: dependencies: '@babel/code-frame': 7.29.0 @@ -20153,21 +10169,12 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - parse-svg-path@0.1.2: {} - parse5@7.3.0: dependencies: entities: 6.0.1 parseurl@1.3.3: {} - pascal-case@3.1.2: - dependencies: - no-case: 3.0.4 - tslib: 2.8.1 - - pascalcase@0.1.1: {} - passport-jwt@4.0.1: dependencies: jsonwebtoken: 9.0.3 @@ -20181,26 +10188,12 @@ snapshots: pause: 0.0.1 utils-merge: 1.0.1 - path-browserify@0.0.1: {} - - path-dirname@1.0.2: {} - - path-exists@2.1.0: - dependencies: - pinkie-promise: 2.0.1 - - path-exists@3.0.0: {} - path-exists@4.0.0: {} path-exists@5.0.0: {} path-is-absolute@1.0.1: {} - path-is-inside@1.0.2: {} - - path-key@2.0.1: {} - path-key@3.1.1: {} path-key@4.0.0: {} @@ -20217,73 +10210,38 @@ snapshots: lru-cache: 11.3.6 minipass: 7.1.3 - path-to-regexp@0.1.13: {} - path-to-regexp@3.3.0: {} path-to-regexp@8.4.2: {} - path-type@1.1.0: - dependencies: - graceful-fs: 4.2.11 - pify: 2.3.0 - pinkie-promise: 2.0.1 - - path-type@2.0.0: - dependencies: - pify: 2.3.0 - path-type@4.0.0: {} - path2d-polyfill@2.0.1: - optional: true - - path@0.12.7: - dependencies: - process: 0.11.10 - util: 0.10.4 - pathe@1.1.2: {} + pathe@2.0.3: {} + pathval@2.0.1: {} pause@0.0.1: {} - pbkdf2@3.1.5: - dependencies: - create-hash: 1.2.0 - create-hmac: 1.1.7 - ripemd160: 2.0.3 - safe-buffer: 5.2.1 - sha.js: 2.4.12 - to-buffer: 1.2.2 - - pdfjs-dist@3.11.174: - optionalDependencies: - canvas: 2.11.2 - path2d-polyfill: 2.0.1 - transitivePeerDependencies: - - encoding - - supports-color - - peek-readable@5.4.2: {} - - perfect-freehand@1.2.3: {} - - performance-now@2.1.0: {} + perfect-debounce@1.0.0: {} pg-cloudflare@1.3.0: optional: true - pg-connection-string@2.12.0: {} + pg-connection-string@2.12.0: + optional: true - pg-int8@1.0.1: {} + pg-int8@1.0.1: + optional: true pg-pool@3.13.0(pg@8.20.0): dependencies: pg: 8.20.0 + optional: true - pg-protocol@1.13.0: {} + pg-protocol@1.13.0: + optional: true pg-types@2.2.0: dependencies: @@ -20292,6 +10250,7 @@ snapshots: postgres-bytea: 1.0.1 postgres-date: 1.0.7 postgres-interval: 1.2.0 + optional: true pg@8.20.0: dependencies: @@ -20302,10 +10261,12 @@ snapshots: pgpass: 1.0.5 optionalDependencies: pg-cloudflare: 1.3.0 + optional: true pgpass@1.0.5: dependencies: split2: 4.2.0 + optional: true picocolors@1.1.1: {} @@ -20317,43 +10278,22 @@ snapshots: pify@2.3.0: {} - pify@3.0.0: {} - - pinkie-promise@2.0.1: - dependencies: - pinkie: 2.0.4 - - pinkie@2.0.4: {} - pirates@4.0.7: {} - pkg-dir@2.0.0: - dependencies: - find-up: 2.1.0 - pkg-dir@4.2.0: dependencies: find-up: 4.1.0 + pkg-types@2.3.1: + dependencies: + confbox: 0.2.4 + exsolve: 1.0.8 + pathe: 2.0.3 + pluralize@8.0.0: {} - png-js@2.0.0: - dependencies: - fflate: 0.8.2 - pngjs@5.0.0: {} - popper.js@1.16.1: {} - - portfinder@1.0.38(supports-color@5.5.0): - dependencies: - async: 3.2.6 - debug: 4.4.3(supports-color@5.5.0) - transitivePeerDependencies: - - supports-color - - posix-character-classes@0.1.1: {} - possible-typed-array-names@1.1.0: {} postcss-import@15.1.0(postcss@8.5.14): @@ -20394,15 +10334,19 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - postgres-array@2.0.0: {} + postgres-array@2.0.0: + optional: true - postgres-bytea@1.0.1: {} + postgres-bytea@1.0.1: + optional: true - postgres-date@1.0.7: {} + postgres-date@1.0.7: + optional: true postgres-interval@1.2.0: dependencies: xtend: 4.0.2 + optional: true prelude-ls@1.2.1: {} @@ -20414,15 +10358,14 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 - prisma@5.22.0: + prisma@6.19.3(typescript@5.9.3): dependencies: - '@prisma/engines': 5.22.0 + '@prisma/config': 6.19.3 + '@prisma/engines': 6.19.3 optionalDependencies: - fsevents: 2.3.3 - - process-nextick-args@2.0.1: {} - - process@0.11.10: {} + typescript: 5.9.3 + transitivePeerDependencies: + - magicast prompts@2.4.2: dependencies: @@ -20435,107 +10378,13 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 - prosemirror-changeset@2.4.1: - dependencies: - prosemirror-transform: 1.12.0 - - prosemirror-commands@1.7.1: - dependencies: - prosemirror-model: 1.25.4 - prosemirror-state: 1.4.4 - prosemirror-transform: 1.12.0 - - prosemirror-dropcursor@1.8.2: - dependencies: - prosemirror-state: 1.4.4 - prosemirror-transform: 1.12.0 - prosemirror-view: 1.41.8 - - prosemirror-gapcursor@1.4.1: - dependencies: - prosemirror-keymap: 1.2.3 - prosemirror-model: 1.25.4 - prosemirror-state: 1.4.4 - prosemirror-view: 1.41.8 - - prosemirror-history@1.5.0: - dependencies: - prosemirror-state: 1.4.4 - prosemirror-transform: 1.12.0 - prosemirror-view: 1.41.8 - rope-sequence: 1.3.4 - - prosemirror-keymap@1.2.3: - dependencies: - prosemirror-state: 1.4.4 - w3c-keyname: 2.2.8 - - prosemirror-model@1.25.4: - dependencies: - orderedmap: 2.1.1 - - prosemirror-schema-list@1.5.1: - dependencies: - prosemirror-model: 1.25.4 - prosemirror-state: 1.4.4 - prosemirror-transform: 1.12.0 - - prosemirror-state@1.4.4: - dependencies: - prosemirror-model: 1.25.4 - prosemirror-transform: 1.12.0 - prosemirror-view: 1.41.8 - - prosemirror-tables@1.8.5: - dependencies: - prosemirror-keymap: 1.2.3 - prosemirror-model: 1.25.4 - prosemirror-state: 1.4.4 - prosemirror-transform: 1.12.0 - prosemirror-view: 1.41.8 - - prosemirror-transform@1.12.0: - dependencies: - prosemirror-model: 1.25.4 - - prosemirror-view@1.41.8: - dependencies: - prosemirror-model: 1.25.4 - prosemirror-state: 1.4.4 - prosemirror-transform: 1.12.0 - proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 ipaddr.js: 1.9.1 - proxy-compare@3.0.1: {} - proxy-from-env@2.1.0: {} - proxy-memoize@3.0.1: - dependencies: - proxy-compare: 3.0.1 - - prr@1.0.1: {} - - pseudomap@1.0.2: {} - - psl@1.15.0: - dependencies: - punycode: 2.3.1 - - public-encrypt@4.0.3: - dependencies: - bn.js: 4.12.3 - browserify-rsa: 4.1.1 - create-hash: 1.2.0 - parse-asn1: 5.1.9 - randombytes: 2.1.0 - safe-buffer: 5.2.1 - - punycode@1.4.1: {} - punycode@2.3.1: {} pure-rand@6.1.0: {} @@ -20550,53 +10399,10 @@ snapshots: dependencies: side-channel: 1.1.0 - qs@6.5.5: {} - - query-string@7.1.3: - dependencies: - decode-uri-component: 0.2.2 - filter-obj: 1.1.0 - split-on-first: 1.1.0 - strict-uri-encode: 2.0.0 - - querystring-es3@0.2.1: {} - - querystringify@2.2.0: {} - queue-microtask@1.2.3: {} - queue@6.0.2: - dependencies: - inherits: 2.0.4 - - raf@3.4.1: - dependencies: - performance-now: 2.1.0 - optional: true - - randombytes@2.1.0: - dependencies: - safe-buffer: 5.2.1 - - randomfill@1.0.4: - dependencies: - randombytes: 2.1.0 - safe-buffer: 5.2.1 - range-parser@1.2.1: {} - rapiq@0.9.0: - dependencies: - ebec: 1.1.1 - smob: 1.6.1 - - raw-body@2.5.3: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.1 - iconv-lite: 0.4.24 - unpipe: 1.0.0 - raw-body@3.0.2: dependencies: bytes: 3.1.2 @@ -20604,30 +10410,10 @@ snapshots: iconv-lite: 0.7.2 unpipe: 1.0.0 - react-cookie@8.1.2(@types/react@18.3.28)(react@18.3.1): + rc9@2.1.2: dependencies: - '@types/hoist-non-react-statics': 3.3.7(@types/react@18.3.28) - hoist-non-react-statics: 3.3.2 - react: 18.3.1 - universal-cookie: 8.1.2 - transitivePeerDependencies: - - '@types/react' - - react-datepicker@8.10.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - '@floating-ui/react': 0.27.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - clsx: 2.1.1 - date-fns: 3.6.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - - react-day-picker@9.14.0(react@18.3.1): - dependencies: - '@date-fns/tz': 1.4.1 - '@tabby_ai/hijri-converter': 1.0.5 - date-fns: 3.6.0 - date-fns-jalali: 4.1.0-0 - react: 18.3.1 + defu: 6.1.7 + destr: 2.0.5 react-dom@18.3.1(react@18.3.1): dependencies: @@ -20635,158 +10421,12 @@ snapshots: react: 18.3.1 scheduler: 0.23.2 - react-dropzone@14.4.1(react@18.3.1): - dependencies: - attr-accept: 2.2.5 - file-selector: 2.1.2 - prop-types: 15.8.1 - react: 18.3.1 - - react-floater@0.7.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - deepmerge: 4.3.1 - is-lite: 0.8.2 - popper.js: 1.16.1 - prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - tree-changes: 0.9.3 - - react-hook-form@7.75.0(react@18.3.1): - dependencies: - react: 18.3.1 - - react-i18next@15.7.4(i18next@25.10.10(typescript@5.9.3))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3): - dependencies: - '@babel/runtime': 7.29.2 - html-parse-stringify: 3.0.1 - i18next: 25.10.10(typescript@5.9.3) - react: 18.3.1 - optionalDependencies: - react-dom: 18.3.1(react@18.3.1) - typescript: 5.9.3 - - react-icons@5.6.0(react@18.3.1): - dependencies: - react: 18.3.1 - - react-image-crop@11.0.10(react@18.3.1): - dependencies: - react: 18.3.1 - - react-innertext@1.1.5(@types/react@18.3.28)(react@18.3.1): - dependencies: - '@types/react': 18.3.28 - react: 18.3.1 - - react-intersection-observer@9.16.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - react: 18.3.1 - optionalDependencies: - react-dom: 18.3.1(react@18.3.1) - react-is@16.13.1: {} react-is@18.3.1: {} - react-is@19.2.6: {} - - react-joyride@2.9.3(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - '@gilbarbara/deep-equal': 0.3.1 - deep-diff: 1.0.2 - deepmerge: 4.3.1 - is-lite: 1.2.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-floater: 0.7.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-innertext: 1.1.5(@types/react@18.3.28)(react@18.3.1) - react-is: 16.13.1 - scroll: 3.0.1 - scrollparent: 2.1.0 - tree-changes: 0.11.3 - type-fest: 4.41.0 - transitivePeerDependencies: - - '@types/react' - - react-number-format@5.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - - react-pdf-html@2.1.5(@react-pdf/renderer@4.5.1(react@18.3.1))(react@18.3.1): - dependencies: - '@react-pdf/renderer': 4.5.1(react@18.3.1) - css-tree: 1.1.3 - node-html-parser: 6.1.13 - react: 18.3.1 - - react-pdf-viewer@0.1.0: - dependencies: - pdfjs-dist: 3.11.174 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - webpack: 3.12.0 - webpack-dev-server: 2.11.5(webpack@3.12.0) - transitivePeerDependencies: - - encoding - - supports-color - - webpack-cli - - webpack-command - - react-pdf@10.4.1(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - clsx: 2.1.1 - dequal: 2.0.3 - make-cancellable-promise: 2.0.0 - make-event-props: 2.0.0 - merge-refs: 2.0.0(@types/react@18.3.28) - pdfjs-dist: 3.11.174 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - tiny-invariant: 1.3.3 - warning: 4.0.3 - optionalDependencies: - '@types/react': 18.3.28 - transitivePeerDependencies: - - encoding - - supports-color - - react-redux@9.2.0(@types/react@18.3.28)(react@18.3.1)(redux@5.0.1): - dependencies: - '@types/use-sync-external-store': 0.0.6 - react: 18.3.1 - use-sync-external-store: 1.6.0(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - redux: 5.0.1 - react-refresh@0.17.0: {} - react-remove-scroll-bar@2.3.8(@types/react@18.3.28)(react@18.3.1): - dependencies: - react: 18.3.1 - react-style-singleton: 2.2.3(@types/react@18.3.28)(react@18.3.1) - tslib: 2.8.1 - optionalDependencies: - '@types/react': 18.3.28 - - react-remove-scroll@2.7.2(@types/react@18.3.28)(react@18.3.1): - dependencies: - react: 18.3.1 - react-remove-scroll-bar: 2.3.8(@types/react@18.3.28)(react@18.3.1) - react-style-singleton: 2.2.3(@types/react@18.3.28)(react@18.3.1) - tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@18.3.28)(react@18.3.1) - use-sidecar: 1.1.3(@types/react@18.3.28)(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - - react-resizable-panels@3.0.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-router-dom@6.30.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@remix-run/router': 1.23.2 @@ -20794,64 +10434,11 @@ snapshots: react-dom: 18.3.1(react@18.3.1) react-router: 6.30.3(react@18.3.1) - react-router-dom@7.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-router: 7.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-router@6.30.3(react@18.3.1): dependencies: '@remix-run/router': 1.23.2 react: 18.3.1 - react-router@7.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - cookie: 1.1.1 - react: 18.3.1 - set-cookie-parser: 2.7.2 - optionalDependencies: - react-dom: 18.3.1(react@18.3.1) - - react-signature-canvas@1.1.0-alpha.2(@types/prop-types@15.7.15)(@types/react@18.3.28)(prop-types@15.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - '@babel/runtime': 7.29.2 - '@types/signature_pad': 2.3.6 - prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - signature_pad: 2.3.2 - trim-canvas: 0.1.2 - optionalDependencies: - '@types/prop-types': 15.7.15 - '@types/react': 18.3.28 - - react-style-singleton@2.2.3(@types/react@18.3.28)(react@18.3.1): - dependencies: - get-nonce: 1.0.1 - react: 18.3.1 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 18.3.28 - - react-textarea-autosize@8.5.9(@types/react@18.3.28)(react@18.3.1): - dependencies: - '@babel/runtime': 7.29.2 - react: 18.3.1 - use-composed-ref: 1.4.0(@types/react@18.3.28)(react@18.3.1) - use-latest: 1.3.0(@types/react@18.3.28)(react@18.3.1) - transitivePeerDependencies: - - '@types/react' - - react-transition-group@4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - '@babel/runtime': 7.29.2 - dom-helpers: 5.2.1 - loose-envify: 1.4.0 - prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react@18.3.1: dependencies: loose-envify: 1.4.0 @@ -20860,116 +10447,18 @@ snapshots: dependencies: pify: 2.3.0 - read-pkg-up@1.0.1: - dependencies: - find-up: 1.1.2 - read-pkg: 1.1.0 - - read-pkg-up@2.0.0: - dependencies: - find-up: 2.1.0 - read-pkg: 2.0.0 - - read-pkg@1.1.0: - dependencies: - load-json-file: 1.1.0 - normalize-package-data: 2.5.0 - path-type: 1.1.0 - - read-pkg@2.0.0: - dependencies: - load-json-file: 2.0.0 - normalize-package-data: 2.5.0 - path-type: 2.0.0 - - readable-stream@2.3.8: - dependencies: - core-util-is: 1.0.3 - inherits: 2.0.4 - isarray: 1.0.0 - process-nextick-args: 2.0.1 - safe-buffer: 5.1.2 - string_decoder: 1.1.1 - util-deprecate: 1.0.2 - readable-stream@3.6.2: dependencies: inherits: 2.0.4 string_decoder: 1.3.0 util-deprecate: 1.0.2 - readable-stream@4.7.0: - dependencies: - abort-controller: 3.0.0 - buffer: 6.0.3 - events: 3.3.0 - process: 0.11.10 - string_decoder: 1.3.0 - - readable-web-to-node-stream@3.0.4: - dependencies: - readable-stream: 4.7.0 - - readdir-glob@1.1.3: - dependencies: - minimatch: 5.1.9 - - readdirp@2.2.1(supports-color@4.5.0): - dependencies: - graceful-fs: 4.2.11 - micromatch: 3.1.10(supports-color@4.5.0) - readable-stream: 2.3.8 - transitivePeerDependencies: - - supports-color - optional: true - - readdirp@2.2.1(supports-color@5.5.0): - dependencies: - graceful-fs: 4.2.11 - micromatch: 3.1.10(supports-color@5.5.0) - readable-stream: 2.3.8 - transitivePeerDependencies: - - supports-color - readdirp@3.6.0: dependencies: picomatch: 2.3.2 readdirp@4.1.2: {} - recharts@3.8.1(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react-is@19.2.6)(react@18.3.1)(redux@5.0.1): - dependencies: - '@reduxjs/toolkit': 2.11.2(react-redux@9.2.0(@types/react@18.3.28)(react@18.3.1)(redux@5.0.1))(react@18.3.1) - clsx: 2.1.1 - decimal.js-light: 2.5.1 - es-toolkit: 1.46.1 - eventemitter3: 5.0.4 - immer: 10.2.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-is: 19.2.6 - react-redux: 9.2.0(@types/react@18.3.28)(react@18.3.1)(redux@5.0.1) - reselect: 5.1.1 - tiny-invariant: 1.3.3 - use-sync-external-store: 1.6.0(react@18.3.1) - victory-vendor: 37.3.6 - transitivePeerDependencies: - - '@types/react' - - redux - - redent@1.0.0: - dependencies: - indent-string: 2.1.0 - strip-indent: 1.0.1 - - redux-thunk@3.1.0(redux@5.0.1): - dependencies: - redux: 5.0.1 - - redux@5.0.1: {} - - reflect-metadata@0.1.14: {} - reflect-metadata@0.2.2: {} reflect.getprototypeof@1.0.10: @@ -20983,13 +10472,6 @@ snapshots: get-proto: 1.0.1 which-builtin-type: 1.2.1 - regenerator-runtime@0.13.11: {} - - regex-not@1.0.2: - dependencies: - extend-shallow: 3.0.2 - safe-regex: 1.1.0 - regexp.prototype.flags@1.5.4: dependencies: call-bind: 1.0.9 @@ -20999,76 +10481,20 @@ snapshots: gopd: 1.2.0 set-function-name: 2.0.2 - relative@3.0.2: - dependencies: - isobject: 2.1.0 - - remarkable@1.7.4: - dependencies: - argparse: 1.0.10 - autolinker: 0.28.1 - - remove-trailing-separator@1.1.0: {} - - repeat-element@1.1.4: {} - - repeat-string@1.6.1: {} - - repeating@2.0.1: - dependencies: - is-finite: 1.1.0 - - request@2.88.2: - dependencies: - aws-sign2: 0.7.0 - aws4: 1.13.2 - caseless: 0.12.0 - combined-stream: 1.0.8 - extend: 3.0.2 - forever-agent: 0.6.1 - form-data: 2.3.3 - har-validator: 5.1.5 - http-signature: 1.2.0 - is-typedarray: 1.0.0 - isstream: 0.1.2 - json-stringify-safe: 5.0.1 - mime-types: 2.1.35 - oauth-sign: 0.9.0 - performance-now: 2.1.0 - qs: 6.5.5 - safe-buffer: 5.2.1 - tough-cookie: 2.5.0 - tunnel-agent: 0.6.0 - uuid: 3.4.0 - require-directory@2.1.1: {} require-from-string@2.0.2: {} - require-main-filename@1.0.1: {} - require-main-filename@2.0.0: {} - requires-port@1.0.0: {} - - reselect@5.1.1: {} - - resolve-cwd@2.0.0: - dependencies: - resolve-from: 3.0.0 - resolve-cwd@3.0.0: dependencies: resolve-from: 5.0.0 - resolve-from@3.0.0: {} - resolve-from@4.0.0: {} resolve-from@5.0.0: {} - resolve-url@0.2.1: {} - resolve.exports@2.0.3: {} resolve@1.22.12: @@ -21097,34 +10523,14 @@ snapshots: onetime: 7.0.0 signal-exit: 4.1.0 - restructure@3.0.2: {} - - ret@0.1.15: {} - reusify@1.1.0: {} rfdc@1.4.1: {} - rgbcolor@1.0.1: - optional: true - - right-align@0.1.3: - dependencies: - align-text: 0.1.4 - - rimraf@2.7.1: - dependencies: - glob: 7.2.3 - rimraf@3.0.2: dependencies: glob: 7.2.3 - ripemd160@2.0.3: - dependencies: - hash-base: 3.1.2 - inherits: 2.0.4 - rollup@4.60.3: dependencies: '@types/estree': 1.0.8 @@ -21156,8 +10562,6 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.60.3 fsevents: 2.3.3 - rope-sequence@1.3.4: {} - router@2.2.0: dependencies: debug: 4.4.3 @@ -21192,8 +10596,6 @@ snapshots: has-symbols: 1.1.0 isarray: 2.0.5 - safe-buffer@5.1.2: {} - safe-buffer@5.2.1: {} safe-push-apply@1.0.0: @@ -21207,18 +10609,8 @@ snapshots: es-errors: 1.3.0 is-regex: 1.2.1 - safe-regex@1.1.0: - dependencies: - ret: 0.1.15 - safer-buffer@2.1.2: {} - sax@1.6.0: {} - - saxes@5.0.1: - dependencies: - xmlchars: 2.2.0 - saxes@6.0.0: dependencies: xmlchars: 2.2.0 @@ -21227,8 +10619,6 @@ snapshots: dependencies: loose-envify: 1.4.0 - scheduler@0.25.0-rc-603e6108-20241029: {} - schema-utils@3.3.0: dependencies: '@types/json-schema': 7.0.15 @@ -21242,42 +10632,10 @@ snapshots: ajv-formats: 2.1.1(ajv@8.20.0) ajv-keywords: 5.1.0(ajv@8.20.0) - scroll@3.0.1: {} - - scrollparent@2.1.0: {} - - select-hose@2.0.0: {} - - self-closing-tags@1.0.1: {} - - selfsigned@1.10.14: - dependencies: - node-forge: 0.10.0 - - semver@5.7.2: {} - semver@6.3.1: {} semver@7.8.0: {} - send@0.19.2(supports-color@5.5.0): - dependencies: - debug: 2.6.9(supports-color@5.5.0) - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.1 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - send@1.2.1: dependencies: debug: 4.4.3 @@ -21294,26 +10652,8 @@ snapshots: transitivePeerDependencies: - supports-color - serve-index@1.9.2(supports-color@5.5.0): - dependencies: - accepts: 1.3.8 - batch: 0.6.1 - debug: 2.6.9(supports-color@5.5.0) - escape-html: 1.0.3 - http-errors: 1.8.1 - mime-types: 2.1.35 - parseurl: 1.3.3 - transitivePeerDependencies: - - supports-color - - serve-static@1.16.3(supports-color@5.5.0): - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.19.2(supports-color@5.5.0) - transitivePeerDependencies: - - supports-color + seq-queue@0.0.5: + optional: true serve-static@2.2.1: dependencies: @@ -21326,8 +10666,6 @@ snapshots: set-blocking@2.0.0: {} - set-cookie-parser@2.7.2: {} - set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -21344,25 +10682,12 @@ snapshots: functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 - set-getter@0.1.1: - dependencies: - to-object-path: 0.3.0 - set-proto@1.0.0: dependencies: dunder-proto: 1.0.1 es-errors: 1.3.0 es-object-atoms: 1.1.1 - set-value@2.0.1: - dependencies: - extend-shallow: 2.0.1 - is-extendable: 0.1.1 - is-plain-object: 2.0.4 - split-string: 3.1.0 - - setimmediate@1.0.5: {} - setprototypeof@1.2.0: {} sha.js@2.4.12: @@ -21371,16 +10696,10 @@ snapshots: safe-buffer: 5.2.1 to-buffer: 1.2.2 - shebang-command@1.2.0: - dependencies: - shebang-regex: 1.0.0 - shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 - shebang-regex@1.0.0: {} - shebang-regex@3.0.0: {} side-channel-list@1.0.1: @@ -21417,8 +10736,6 @@ snapshots: signal-exit@4.1.0: {} - signature_pad@2.3.2: {} - simple-concat@1.0.1: optional: true @@ -21443,109 +10760,8 @@ snapshots: ansi-styles: 6.2.3 is-fullwidth-code-point: 5.1.0 - smob@1.6.1: {} - - snapdragon-node@2.1.1: - dependencies: - define-property: 1.0.0 - isobject: 3.0.1 - snapdragon-util: 3.0.1 - - snapdragon-util@3.0.1: - dependencies: - kind-of: 3.2.2 - - snapdragon@0.8.2: - dependencies: - base: 0.11.2 - debug: 2.6.9(supports-color@5.5.0) - define-property: 0.2.5 - extend-shallow: 2.0.1 - map-cache: 0.2.2 - source-map: 0.5.7 - source-map-resolve: 0.5.3 - use: 3.1.1 - transitivePeerDependencies: - - supports-color - - snapdragon@0.8.2(supports-color@4.5.0): - dependencies: - base: 0.11.2 - debug: 2.6.9(supports-color@4.5.0) - define-property: 0.2.5 - extend-shallow: 2.0.1 - map-cache: 0.2.2 - source-map: 0.5.7 - source-map-resolve: 0.5.3 - use: 3.1.1 - transitivePeerDependencies: - - supports-color - optional: true - - snapdragon@0.8.2(supports-color@5.5.0): - dependencies: - base: 0.11.2 - debug: 2.6.9(supports-color@5.5.0) - define-property: 0.2.5 - extend-shallow: 2.0.1 - map-cache: 0.2.2 - source-map: 0.5.7 - source-map-resolve: 0.5.3 - use: 3.1.1 - transitivePeerDependencies: - - supports-color - - socket.io-client@4.8.3: - dependencies: - '@socket.io/component-emitter': 3.1.2 - debug: 4.4.3(supports-color@5.5.0) - engine.io-client: 6.6.4 - socket.io-parser: 4.2.6 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - socket.io-parser@4.2.6: - dependencies: - '@socket.io/component-emitter': 3.1.2 - debug: 4.4.3(supports-color@5.5.0) - transitivePeerDependencies: - - supports-color - - sockjs-client@1.1.5(supports-color@5.5.0): - dependencies: - debug: 2.6.9(supports-color@5.5.0) - eventsource: 0.1.6 - faye-websocket: 0.11.4 - inherits: 2.0.4 - json3: 3.3.3 - url-parse: 1.5.10 - transitivePeerDependencies: - - supports-color - - sockjs@0.3.19: - dependencies: - faye-websocket: 0.10.0 - uuid: 3.4.0 - - sonner@2.0.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - - source-list-map@2.0.1: {} - source-map-js@1.2.1: {} - source-map-resolve@0.5.3: - dependencies: - atob: 2.1.2 - decode-uri-component: 0.2.2 - resolve-url: 0.2.1 - source-map-url: 0.4.1 - urix: 0.1.0 - source-map-support@0.5.13: dependencies: buffer-from: 1.1.2 @@ -21556,78 +10772,18 @@ snapshots: buffer-from: 1.1.2 source-map: 0.6.1 - source-map-url@0.4.1: {} - - source-map@0.5.7: {} - source-map@0.6.1: {} source-map@0.7.4: {} - source-map@0.7.6: {} - - spdx-correct@3.2.0: - dependencies: - spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.23 - - spdx-exceptions@2.5.0: {} - - spdx-expression-parse@3.0.1: - dependencies: - spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.23 - - spdx-license-ids@3.0.23: {} - - spdy-transport@3.0.0(supports-color@5.5.0): - dependencies: - debug: 4.4.3(supports-color@5.5.0) - detect-node: 2.1.0 - hpack.js: 2.1.6 - obuf: 1.1.2 - readable-stream: 3.6.2 - wbuf: 1.7.3 - transitivePeerDependencies: - - supports-color - - spdy@4.0.2(supports-color@5.5.0): - dependencies: - debug: 4.4.3(supports-color@5.5.0) - handle-thing: 2.0.1 - http-deceiver: 1.2.7 - select-hose: 2.0.0 - spdy-transport: 3.0.0(supports-color@5.5.0) - transitivePeerDependencies: - - supports-color - - split-on-first@1.1.0: {} - - split-string@3.1.0: - dependencies: - extend-shallow: 3.0.2 - split2@4.2.0: {} sprintf-js@1.0.3: {} sql-highlight@6.1.0: {} - ssf@0.11.2: - dependencies: - frac: 1.1.2 - - sshpk@1.18.0: - dependencies: - asn1: 0.2.6 - assert-plus: 1.0.0 - bcrypt-pbkdf: 1.0.2 - dashdash: 1.14.1 - ecc-jsbn: 0.1.2 - getpass: 0.1.7 - jsbn: 0.1.1 - safer-buffer: 2.1.2 - tweetnacl: 0.14.5 + sqlstring@2.3.3: + optional: true stack-utils@2.0.6: dependencies: @@ -21635,16 +10791,6 @@ snapshots: stackback@0.0.2: {} - stackblur-canvas@2.7.0: - optional: true - - static-extend@0.1.2: - dependencies: - define-property: 0.2.5 - object-copy: 0.1.0 - - statuses@1.5.0: {} - statuses@2.0.2: {} std-env@3.10.0: {} @@ -21654,23 +10800,8 @@ snapshots: es-errors: 1.3.0 internal-slot: 1.1.0 - stream-browserify@2.0.2: - dependencies: - inherits: 2.0.4 - readable-stream: 2.3.8 - - stream-http@2.8.3: - dependencies: - builtin-status-codes: 3.0.0 - inherits: 2.0.4 - readable-stream: 2.3.8 - to-arraybuffer: 1.0.1 - xtend: 4.0.2 - streamsearch@1.1.0: {} - strict-uri-encode@2.0.0: {} - string-argv@0.3.2: {} string-length@4.0.2: @@ -21678,17 +10809,6 @@ snapshots: char-regex: 1.0.2 strip-ansi: 6.0.1 - string-width@1.0.2: - dependencies: - code-point-at: 1.1.0 - is-fullwidth-code-point: 1.0.0 - strip-ansi: 3.0.1 - - string-width@2.1.1: - dependencies: - is-fullwidth-code-point: 2.0.0 - strip-ansi: 4.0.0 - string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -21751,22 +10871,10 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 - string_decoder@1.1.1: - dependencies: - safe-buffer: 5.1.2 - string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 - strip-ansi@3.0.1: - dependencies: - ansi-regex: 2.1.1 - - strip-ansi@4.0.0: - dependencies: - ansi-regex: 3.0.1 - strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -21775,45 +10883,20 @@ snapshots: dependencies: ansi-regex: 6.2.2 - strip-bom@2.0.0: - dependencies: - is-utf8: 0.2.1 - strip-bom@3.0.0: {} strip-bom@4.0.0: {} - strip-eof@1.0.0: {} - strip-final-newline@2.0.0: {} strip-final-newline@3.0.0: {} - strip-indent@1.0.1: - dependencies: - get-stdin: 4.0.1 - strip-json-comments@3.1.1: {} - striptags@3.2.0: {} - - strnum@1.1.2: {} - strtok3@10.3.5: dependencies: '@tokenizer/token': 0.3.0 - strtok3@7.1.1: - dependencies: - '@tokenizer/token': 0.3.0 - peek-readable: 5.4.2 - - style-object-to-css-string@1.1.3: {} - - stylis@4.2.0: {} - - success-symbol@0.1.0: {} - sucrase@3.35.1: dependencies: '@jridgewell/gen-mapping': 0.3.13 @@ -21846,14 +10929,6 @@ snapshots: transitivePeerDependencies: - supports-color - supports-color@4.5.0: - dependencies: - has-flag: 2.0.0 - - supports-color@5.5.0: - dependencies: - has-flag: 3.0.0 - supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -21864,11 +10939,6 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svg-arc-to-cubic-bezier@3.2.0: {} - - svg-pathdata@6.0.3: - optional: true - swagger-ui-dist@5.17.14: {} swagger-ui-dist@5.32.4: @@ -21884,18 +10954,6 @@ snapshots: symbol-tree@3.2.4: {} - tabbable@6.4.0: {} - - tailwind-merge@3.6.0: {} - - tailwind-scrollbar-hide@4.0.0(tailwindcss@4.3.0): - dependencies: - tailwindcss: 4.3.0 - - tailwindcss-animate@1.0.7(tailwindcss@4.3.0): - dependencies: - tailwindcss: 4.3.0 - tailwindcss@3.4.19(yaml@2.9.0): dependencies: '@alloc/quick-lru': 5.2.0 @@ -21924,20 +10982,8 @@ snapshots: - tsx - yaml - tailwindcss@4.3.0: {} - - tapable@0.2.9: {} - tapable@2.3.3: {} - tar-stream@2.2.0: - dependencies: - bl: 4.1.0 - end-of-stream: 1.4.5 - fs-constants: 1.0.0 - inherits: 2.0.4 - readable-stream: 3.6.2 - tar@6.2.1: dependencies: chownr: 2.0.0 @@ -21962,22 +11008,6 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 - tesseract.js-core@7.0.0: {} - - tesseract.js@7.0.0: - dependencies: - bmp-js: 0.1.0 - idb-keyval: 6.2.2 - is-url: 1.2.4 - node-fetch: 2.7.0 - opencollective-postinstall: 2.0.3 - regenerator-runtime: 0.13.11 - tesseract.js-core: 7.0.0 - wasm-feature-detect: 1.8.0 - zlibjs: 0.3.1 - transitivePeerDependencies: - - encoding - test-exclude@6.0.0: dependencies: '@istanbuljs/schema': 0.1.6 @@ -21986,10 +11016,6 @@ snapshots: text-extensions@2.4.0: {} - text-segmentation@1.0.3: - dependencies: - utrie: 1.0.2 - text-table@0.2.0: {} thenify-all@1.6.0: @@ -22000,31 +11026,8 @@ snapshots: dependencies: any-promise: 1.3.0 - through2@2.0.5: - dependencies: - readable-stream: 2.3.8 - xtend: 4.0.2 - - through2@4.0.2: - dependencies: - readable-stream: 3.6.2 - through@2.3.8: {} - thunky@1.1.0: {} - - time-stamp@1.1.0: {} - - time-stamp@2.2.0: {} - - timers-browserify@2.0.12: - dependencies: - setimmediate: 1.0.5 - - tiny-inflate@1.0.3: {} - - tiny-invariant@1.3.3: {} - tinybench@2.9.0: {} tinyexec@0.3.2: {} @@ -22036,8 +11039,6 @@ snapshots: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - tinymce@7.9.2: {} - tinypool@1.1.1: {} tinyrainbow@1.2.0: {} @@ -22050,58 +11051,26 @@ snapshots: dependencies: tldts-core: 6.1.86 - tmp@0.2.5: {} - tmpl@1.0.5: {} - to-arraybuffer@1.0.1: {} - to-buffer@1.2.2: dependencies: isarray: 2.0.5 safe-buffer: 5.2.1 typed-array-buffer: 1.0.3 - to-gfm-code-block@0.1.1: {} - - to-object-path@0.3.0: - dependencies: - kind-of: 3.2.2 - - to-regex-range@2.1.1: - dependencies: - is-number: 3.0.0 - repeat-string: 1.6.1 - to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - to-regex@3.0.2: - dependencies: - define-property: 2.0.2 - extend-shallow: 3.0.2 - regex-not: 1.0.2 - safe-regex: 1.1.0 - toidentifier@1.0.1: {} - token-types@5.0.1: - dependencies: - '@tokenizer/token': 0.3.0 - ieee754: 1.2.1 - token-types@6.1.2: dependencies: '@borewit/text-codec': 0.2.2 '@tokenizer/token': 0.3.0 ieee754: 1.2.1 - tough-cookie@2.5.0: - dependencies: - psl: 1.15.0 - punycode: 2.3.1 - tough-cookie@5.1.2: dependencies: tldts: 6.1.86 @@ -22112,22 +11081,6 @@ snapshots: dependencies: punycode: 2.3.1 - traverse@0.3.9: {} - - tree-changes@0.11.3: - dependencies: - '@gilbarbara/deep-equal': 0.3.1 - is-lite: 1.2.1 - - tree-changes@0.9.3: - dependencies: - '@gilbarbara/deep-equal': 0.1.2 - is-lite: 0.8.2 - - trim-canvas@0.1.2: {} - - trim-newlines@1.0.0: {} - ts-api-utils@2.5.0(typescript@5.9.3): dependencies: typescript: 5.9.3 @@ -22154,16 +11107,6 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.29.0) jest-util: 29.7.0 - ts-loader@9.5.7(typescript@5.9.3)(webpack@5.106.0): - dependencies: - chalk: 4.1.2 - enhanced-resolve: 5.21.3 - micromatch: 4.0.8 - semver: 7.8.0 - source-map: 0.7.6 - typescript: 5.9.3 - webpack: 5.106.0 - ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -22204,12 +11147,6 @@ snapshots: tslib@2.8.1: {} - tty-browserify@0.0.0: {} - - tunnel-agent@0.6.0: - dependencies: - safe-buffer: 5.2.1 - turbo@2.9.12: optionalDependencies: '@turbo/darwin-64': 2.9.12 @@ -22219,8 +11156,6 @@ snapshots: '@turbo/windows-64': 2.9.12 '@turbo/windows-arm64': 2.9.12 - tweetnacl@0.14.5: {} - type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -22244,8 +11179,6 @@ snapshots: media-typer: 1.1.0 mime-types: 3.0.2 - type@2.7.3: {} - typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.4 @@ -22281,24 +11214,7 @@ snapshots: typedarray@0.0.6: {} - typeof-article@0.1.1: - dependencies: - kind-of: 3.2.2 - - typeorm-extension@3.9.0(@faker-js/faker@10.4.0)(typeorm@0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))): - dependencies: - '@faker-js/faker': 10.4.0 - consola: 3.4.2 - envix: 1.5.0 - locter: 2.2.1 - pascal-case: 3.1.2 - rapiq: 0.9.0 - reflect-metadata: 0.2.2 - smob: 1.6.1 - typeorm: 0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) - yargs: 18.0.0 - - typeorm@0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)): + typeorm@0.3.29(babel-plugin-macros@3.1.0)(mysql2@3.15.3)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)): dependencies: '@sqltools/formatter': 1.2.5 ansis: 4.3.0 @@ -22316,6 +11232,7 @@ snapshots: uuid: 11.1.1 yargs: 17.7.2 optionalDependencies: + mysql2: 3.15.3 pg: 8.20.0 ts-node: 10.9.2(@types/node@20.19.41)(typescript@5.9.3) transitivePeerDependencies: @@ -22324,26 +11241,9 @@ snapshots: typescript@5.9.3: {} - uglify-js@2.8.29: - dependencies: - source-map: 0.5.7 - yargs: 3.10.0 - optionalDependencies: - uglify-to-browserify: 1.0.2 - uglify-js@3.19.3: optional: true - uglify-to-browserify@1.0.2: - optional: true - - uglifyjs-webpack-plugin@0.4.6(webpack@3.12.0): - dependencies: - source-map: 0.5.7 - uglify-js: 2.8.29 - webpack: 3.12.0 - webpack-sources: 1.4.3 - uid@2.0.2: dependencies: '@lukeed/csprng': 1.1.0 @@ -22361,147 +11261,33 @@ snapshots: undici-types@7.16.0: {} - unicode-properties@1.4.1: - dependencies: - base64-js: 1.5.1 - unicode-trie: 2.0.0 - - unicode-trie@2.0.0: - dependencies: - pako: 0.2.9 - tiny-inflate: 1.0.3 - unicorn-magic@0.1.0: {} - union-value@1.0.1: - dependencies: - arr-union: 3.1.0 - get-value: 2.0.6 - is-extendable: 0.1.1 - set-value: 2.0.1 - - universal-cookie@8.1.2: - dependencies: - cookie: 1.1.1 - universalify@2.0.1: {} unpipe@1.0.0: {} - unset-value@1.0.0: - dependencies: - has-value: 0.3.1 - isobject: 3.0.1 - - unzipper@0.10.14: - dependencies: - big-integer: 1.6.52 - binary: 0.3.0 - bluebird: 3.4.7 - buffer-indexof-polyfill: 1.0.2 - duplexer2: 0.1.4 - fstream: 1.0.12 - graceful-fs: 4.2.11 - listenercount: 1.0.1 - readable-stream: 2.3.8 - setimmediate: 1.0.5 - - upath@1.2.0: {} - update-browserslist-db@1.2.3(browserslist@4.28.2): dependencies: browserslist: 4.28.2 escalade: 3.2.0 picocolors: 1.1.1 - uqr@0.1.2: {} - uri-js@4.4.1: dependencies: punycode: 2.3.1 - urix@0.1.0: {} - - url-parse@1.5.10: - dependencies: - querystringify: 2.2.0 - requires-port: 1.0.0 - - url@0.11.4: - dependencies: - punycode: 1.4.1 - qs: 6.15.1 - - use-callback-ref@1.3.3(@types/react@18.3.28)(react@18.3.1): - dependencies: - react: 18.3.1 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 18.3.28 - - use-composed-ref@1.4.0(@types/react@18.3.28)(react@18.3.1): - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - use-isomorphic-layout-effect@1.2.1(@types/react@18.3.28)(react@18.3.1): - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - - use-latest@1.3.0(@types/react@18.3.28)(react@18.3.1): - dependencies: - react: 18.3.1 - use-isomorphic-layout-effect: 1.2.1(@types/react@18.3.28)(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.28 - - use-sidecar@1.1.3(@types/react@18.3.28)(react@18.3.1): - dependencies: - detect-node-es: 1.1.0 - react: 18.3.1 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 18.3.28 - use-sync-external-store@1.6.0(react@18.3.1): dependencies: react: 18.3.1 - - use@3.1.1: {} + optional: true util-deprecate@1.0.2: {} - util@0.10.4: - dependencies: - inherits: 2.0.3 - - util@0.11.1: - dependencies: - inherits: 2.0.3 - - util@0.12.5: - dependencies: - inherits: 2.0.4 - is-arguments: 1.2.0 - is-generator-function: 1.1.2 - is-typed-array: 1.1.15 - which-typed-array: 1.1.20 - utils-merge@1.0.1: {} - utrie@1.0.2: - dependencies: - base64-arraybuffer: 1.0.2 - uuid@11.1.1: {} - uuid@3.4.0: {} - - uuid@8.3.2: {} - v8-compile-cache-lib@3.0.1: {} v8-to-istanbul@9.3.0: @@ -22510,53 +11296,10 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 - validate-npm-package-license@3.0.4: - dependencies: - spdx-correct: 3.2.0 - spdx-expression-parse: 3.0.1 - validator@13.15.35: {} vary@1.1.2: {} - vaul@1.1.2(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - '@types/react' - - '@types/react-dom' - - verror@1.10.0: - dependencies: - assert-plus: 1.0.0 - core-util-is: 1.0.2 - extsprintf: 1.3.0 - - victory-vendor@37.3.6: - dependencies: - '@types/d3-array': 3.2.2 - '@types/d3-ease': 3.0.2 - '@types/d3-interpolate': 3.0.4 - '@types/d3-scale': 4.0.9 - '@types/d3-shape': 3.1.8 - '@types/d3-time': 3.0.4 - '@types/d3-timer': 3.0.2 - d3-array: 3.2.4 - d3-ease: 3.0.1 - d3-interpolate: 3.0.1 - d3-scale: 4.0.2 - d3-shape: 3.2.0 - d3-time: 3.1.0 - d3-timer: 3.0.1 - - vite-compatible-readable-stream@3.6.1: - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - vite-node@2.1.9(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1): dependencies: cac: 6.7.14 @@ -22622,12 +11365,6 @@ snapshots: - supports-color - terser - vm-browserify@1.1.2: {} - - void-elements@3.1.0: {} - - w3c-keyname@2.2.8: {} - w3c-xmlserializer@5.0.0: dependencies: xml-name-validator: 5.0.0 @@ -22636,128 +11373,23 @@ snapshots: dependencies: makeerror: 1.0.12 - warning-symbol@0.1.0: {} - - warning@4.0.3: - dependencies: - loose-envify: 1.4.0 - - wasm-feature-detect@1.8.0: {} - - watchpack-chokidar2@2.0.1(supports-color@4.5.0): - dependencies: - chokidar: 2.1.8(supports-color@4.5.0) - transitivePeerDependencies: - - supports-color - optional: true - - watchpack@1.7.5(supports-color@4.5.0): - dependencies: - graceful-fs: 4.2.11 - neo-async: 2.6.2 - optionalDependencies: - chokidar: 3.6.0 - watchpack-chokidar2: 2.0.1(supports-color@4.5.0) - transitivePeerDependencies: - - supports-color - watchpack@2.5.1: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 - wbuf@1.7.3: - dependencies: - minimalistic-assert: 1.0.1 - wcwidth@1.0.1: dependencies: defaults: 1.0.4 - web-encoding@1.1.5: - dependencies: - util: 0.12.5 - optionalDependencies: - '@zxing/text-encoding': 0.9.0 - webidl-conversions@3.0.1: {} webidl-conversions@7.0.0: {} - webpack-dev-middleware@1.12.2(webpack@3.12.0): - dependencies: - memory-fs: 0.4.1 - mime: 1.6.0 - path-is-absolute: 1.0.1 - range-parser: 1.2.1 - time-stamp: 2.2.0 - webpack: 3.12.0 - - webpack-dev-server@2.11.5(webpack@3.12.0): - dependencies: - ansi-html: 0.0.7 - array-includes: 3.1.9 - bonjour: 3.5.1 - chokidar: 2.1.8(supports-color@5.5.0) - compression: 1.8.1(supports-color@5.5.0) - connect-history-api-fallback: 1.6.0 - debug: 3.2.7(supports-color@5.5.0) - del: 3.0.0 - express: 4.22.2(supports-color@5.5.0) - html-entities: 1.4.0 - http-proxy-middleware: 0.19.2(debug@3.2.7(supports-color@5.5.0))(supports-color@5.5.0) - import-local: 1.0.0 - internal-ip: 1.2.0 - ip: 1.1.9 - killable: 1.0.1 - loglevel: 1.9.2 - opn: 5.5.0 - portfinder: 1.0.38(supports-color@5.5.0) - selfsigned: 1.10.14 - serve-index: 1.9.2(supports-color@5.5.0) - sockjs: 0.3.19 - sockjs-client: 1.1.5(supports-color@5.5.0) - spdy: 4.0.2(supports-color@5.5.0) - strip-ansi: 3.0.1 - supports-color: 5.5.0 - webpack: 3.12.0 - webpack-dev-middleware: 1.12.2(webpack@3.12.0) - yargs: 6.6.0 - webpack-node-externals@3.0.0: {} - webpack-sources@1.4.3: - dependencies: - source-list-map: 2.0.1 - source-map: 0.6.1 - webpack-sources@3.4.1: {} - webpack@3.12.0: - dependencies: - acorn: 5.7.4 - acorn-dynamic-import: 2.0.2 - ajv: 6.15.0 - ajv-keywords: 3.5.2(ajv@6.15.0) - async: 2.6.4 - enhanced-resolve: 3.4.1 - escope: 3.6.0 - interpret: 1.4.0 - json-loader: 0.5.7 - json5: 0.5.1 - loader-runner: 2.4.0 - loader-utils: 1.4.2 - memory-fs: 0.4.1 - mkdirp: 0.5.6 - node-libs-browser: 2.2.1 - source-map: 0.5.7 - supports-color: 4.5.0 - tapable: 0.2.9 - uglifyjs-webpack-plugin: 0.4.6(webpack@3.12.0) - watchpack: 1.7.5(supports-color@4.5.0) - webpack-sources: 1.4.3 - yargs: 8.0.2 - webpack@5.106.0: dependencies: '@types/eslint-scope': 3.7.7 @@ -22799,14 +11431,6 @@ snapshots: - postcss - uglify-js - websocket-driver@0.7.4: - dependencies: - http-parser-js: 0.5.10 - safe-buffer: 5.2.1 - websocket-extensions: 0.1.4 - - websocket-extensions@0.1.4: {} - whatwg-encoding@3.1.1: dependencies: iconv-lite: 0.6.3 @@ -22854,8 +11478,6 @@ snapshots: is-weakmap: 2.0.2 is-weakset: 2.0.4 - which-module@1.0.0: {} - which-module@2.0.1: {} which-typed-array@1.1.20: @@ -22868,10 +11490,6 @@ snapshots: gopd: 1.2.0 has-tostringtag: 1.0.2 - which@1.3.1: - dependencies: - isexe: 2.0.0 - which@2.0.2: dependencies: isexe: 2.0.0 @@ -22885,23 +11503,10 @@ snapshots: dependencies: string-width: 4.2.3 - window-size@0.1.0: {} - - wmf@1.0.2: {} - word-wrap@1.2.5: {} - word@0.3.0: {} - - wordwrap@0.0.2: {} - wordwrap@1.0.0: {} - wrap-ansi@2.1.0: - dependencies: - string-width: 1.0.2 - strip-ansi: 3.0.1 - wrap-ansi@6.2.0: dependencies: ansi-styles: 4.3.0 @@ -22933,50 +11538,25 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 3.0.7 - ws@8.18.3: {} - ws@8.20.0: {} - xlsx@0.18.5: - dependencies: - adler-32: 1.3.1 - cfb: 1.2.2 - codepage: 1.15.0 - crc-32: 1.2.2 - ssf: 0.11.2 - wmf: 1.0.2 - word: 0.3.0 - xml-name-validator@5.0.0: {} - xml2js@0.5.0: - dependencies: - sax: 1.6.0 - xmlbuilder: 11.0.1 - - xml@1.0.1: {} - - xmlbuilder@11.0.1: {} - xmlchars@2.2.0: {} - xmlhttprequest-ssl@2.1.2: {} - - xtend@4.0.2: {} - - y18n@3.2.2: {} + xtend@4.0.2: + optional: true y18n@4.0.3: {} y18n@5.0.8: {} - yallist@2.1.2: {} - yallist@3.1.1: {} yallist@4.0.0: {} - yaml@1.10.3: {} + yaml@1.10.3: + optional: true yaml@2.9.0: {} @@ -22987,16 +11567,6 @@ snapshots: yargs-parser@21.1.1: {} - yargs-parser@22.0.0: {} - - yargs-parser@4.2.1: - dependencies: - camelcase: 3.0.0 - - yargs-parser@7.0.0: - dependencies: - camelcase: 4.1.0 - yargs@15.4.1: dependencies: cliui: 6.0.0 @@ -23021,56 +11591,6 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 - yargs@18.0.0: - dependencies: - cliui: 9.0.1 - escalade: 3.2.0 - get-caller-file: 2.0.5 - string-width: 7.2.0 - y18n: 5.0.8 - yargs-parser: 22.0.0 - - yargs@3.10.0: - dependencies: - camelcase: 1.2.1 - cliui: 2.1.0 - decamelize: 1.2.0 - window-size: 0.1.0 - - yargs@6.6.0: - dependencies: - camelcase: 3.0.0 - cliui: 3.2.0 - decamelize: 1.2.0 - get-caller-file: 1.0.3 - os-locale: 1.4.0 - read-pkg-up: 1.0.1 - require-directory: 2.1.1 - require-main-filename: 1.0.1 - set-blocking: 2.0.0 - string-width: 1.0.2 - which-module: 1.0.0 - y18n: 3.2.2 - yargs-parser: 4.2.1 - - yargs@8.0.2: - dependencies: - camelcase: 4.1.0 - cliui: 3.2.0 - decamelize: 1.2.0 - get-caller-file: 1.0.3 - os-locale: 2.1.0 - read-pkg-up: 2.0.0 - require-directory: 2.1.1 - require-main-filename: 1.0.1 - set-blocking: 2.0.0 - string-width: 2.1.1 - which-module: 2.0.1 - y18n: 3.2.2 - yargs-parser: 7.0.0 - - year@0.2.1: {} - yn@3.1.1: {} yocto-queue@0.1.0: {} @@ -23079,18 +11599,6 @@ snapshots: yoctocolors-cjs@2.1.3: {} - yoga-layout@3.2.1: {} - - zip-stream@4.1.1: - dependencies: - archiver-utils: 3.0.4 - compress-commons: 4.1.2 - readable-stream: 3.6.2 - - zlibjs@0.3.1: {} - - zod@3.25.76: {} - zustand@5.0.13(@types/react@18.3.28)(immer@11.1.8)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)): optionalDependencies: '@types/react': 18.3.28 From 860170f2291f6bc5de10b10182c074dc9ce945dc Mon Sep 17 00:00:00 2001 From: Stephanos A Date: Thu, 21 May 2026 10:22:08 +0300 Subject: [PATCH 19/38] Implemened verifayda and currency modules --- README.md | 125 +++++++++++- apps/edr-passenger-api/.env.example | 6 + apps/edr-passenger-api/package.json | 4 +- .../migration.sql | 2 - .../migration.sql | 74 ------- .../migration.sql | 171 +++++++++++++++- .../prisma/migrations/migration_lock.toml | 4 +- apps/edr-passenger-api/prisma/schema.prisma | 148 ++++++++++++-- apps/edr-passenger-api/prisma/seed.ts | 74 ++++--- .../src/modules/agents/agents.service.ts | 5 +- .../modules/bookings/bookings.controller.ts | 36 +++- .../src/modules/bookings/bookings.dto.ts | 20 +- .../src/modules/bookings/bookings.module.ts | 10 +- .../src/modules/bookings/bookings.service.ts | 189 +++++++++++++++--- .../src/modules/currency/currency.module.ts | 10 + .../src/modules/currency/currency.service.ts | 83 ++++++++ .../src/modules/search/search.controller.ts | 26 ++- .../src/modules/search/search.dto.ts | 10 +- .../src/modules/search/search.module.ts | 8 +- .../src/modules/search/search.service.ts | 95 ++++++--- .../src/modules/verifayda/verifayda.module.ts | 10 + .../modules/verifayda/verifayda.service.ts | 142 +++++++++++++ 22 files changed, 1032 insertions(+), 220 deletions(-) delete mode 100644 apps/edr-passenger-api/prisma/migrations/20260520000002_language_field_note/migration.sql delete mode 100644 apps/edr-passenger-api/prisma/migrations/20260521000001_add_fraud_detection/migration.sql rename apps/edr-passenger-api/prisma/migrations/{20260519124728_initial_migration => 20260521053749_initial_migration}/migration.sql (87%) create mode 100644 apps/edr-passenger-api/src/modules/currency/currency.module.ts create mode 100644 apps/edr-passenger-api/src/modules/currency/currency.service.ts create mode 100644 apps/edr-passenger-api/src/modules/verifayda/verifayda.module.ts create mode 100644 apps/edr-passenger-api/src/modules/verifayda/verifayda.service.ts diff --git a/README.md b/README.md index eb7cccae0..0a47b6a90 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,47 @@ Enterprise-grade NestJS REST API for the Ethio-Djibouti Railway passenger bookin ## 🚀 Features +### 🆕 NEW: Age-Based Pricing, Verifayda 2.0 & Multi-Currency + +#### Age-Based Pricing +- **ADULT** (≥5 years): Pay 100% of base fare +- **CHILD** (<5 years): First child travels FREE, subsequent children pay 100% +- Automatic age calculation from date of birth +- Example: 2 adults + 3 children = 4× base fare (first child free) + +#### Verifayda 2.0 Integration +- Real-time Ethiopian national ID verification +- Retrieves passenger data from government database +- National IDs NOT stored (policy compliant) +- Non-Ethiopians use passport (no verification required) +- Booking fails if verification unsuccessful + +#### Multi-Currency Support +- **Transaction Currency**: ETB (Ethiopian Birr) +- **Display Currencies**: ETB, DJF (Djiboutian Franc), USD (US Dollar) +- Real-time exchange rate conversion +- Prices shown in user's preferred currency +- Exchange rates: ETB→DJF=3.25, ETB→USD=0.018 + ### Core Modules - **Authentication & Authorization** - Dual authentication system: - **Passenger Auth**: JWT-based auth with OTP verification, password reset, account lockout - **Corporate IAM**: Integration with @tria-plc corporate identity system for back-office operations (agents, supervisors, admins) - Role-based access control (RBAC) with granular permissions +- **Age-Based Pricing** - Smart passenger categorization: + - **ADULT** (≥5 years): Full fare + - **CHILD** (<5 years): First child free, subsequent children full fare + - Automatic age calculation from date of birth +- **Verifayda 2.0 Integration** - Ethiopian national ID verification: + - Real-time verification via government API + - Retrieves passenger data (name, DOB, nationality) + - National IDs NOT stored (policy compliant) + - Non-Ethiopians use passport (no verification) +- **Multi-Currency Support** - Display prices in multiple currencies: + - **ETB** (Ethiopian Birr) - Transaction currency + - **DJF** (Djiboutian Franc) - Display option + - **USD** (US Dollar) - Display option + - Real-time exchange rate conversion - **Booking Management** - Complete booking lifecycle with modification, cancellation, refunds, and fare breakdown - **Payment Integration** - Multi-provider support (Telebirr, CBE Birr, eBirr, Card, Wallet) with webhook handling - **Seat Management** - Real-time seat inventory, holds, releases, and blocking with coach/class management @@ -74,6 +110,16 @@ cp apps/edr-passenger-api/.env.example apps/edr-passenger-api/.env | `SENDGRID_API_KEY` | SendGrid API key (optional) | `SG.xxx` | | `SENDGRID_FROM_EMAIL` | Email sender address | `noreply@edr-platform.com` | +#### Verifayda 2.0 Configuration (Ethiopian National ID Verification) + +| Variable | Description | Example | +|----------|-------------|---------| +| `VERIFAYDA_ENABLED` | Enable Verifayda integration | `true` or `false` | +| `VERIFAYDA_API_URL` | Verifayda API endpoint | `https://api.verifayda.gov.et/v2` | +| `VERIFAYDA_API_KEY` | API key for Verifayda service | `your-verifayda-api-key` | + +**Note:** When `VERIFAYDA_ENABLED=false`, verification is skipped (development mode only). + #### Corporate IAM Configuration (Back-office Authentication) | Variable | Description | Example | @@ -124,15 +170,18 @@ pnpm --filter @edr/passenger-api run prisma:seed ``` **Seed Data Includes:** -- 5 Stations (Addis Ababa, Adama, Awash, Dire Dawa, Djibouti) -- 1 Route with 5 stops and fare rules -- 2 Train services with 2 trips -- 360 seats across 6 coaches (Economy, Bed, VIP classes) +- 21 Stations (Complete Ethiopian-Djibouti Railway with country codes) +- 1 Route with 21 stops and fare rules +- 2 Train services with 4 trips +- 360 seats across 12 coaches (Economy, Bed, VIP classes) - 3 User accounts (Admin, Passenger, Agent) +- Fare rules for ADULT and CHILD passenger categories +- Currency exchange rates (ETB, DJF, USD) - Baggage allowance rules - Notification templates - Promotions and FAQ content - Menu items and station crowd signals +- Fraud detection rules ### 5. Start Development Server ```bash @@ -247,11 +296,41 @@ Content-Type: application/json #### 3. Search Trips ```bash -GET /search/trips?originStationId={id}&destinationStationId={id}&date=2026-06-15 +GET /search/trips?originStationId={id}&destinationStationId={id}&date=2026-06-15&adultCount=2&childCount=1 Authorization: Bearer {token} ``` -#### 4. Create Booking +#### 4. Get Fare Quote +```bash +POST /search/fare-quote +Authorization: Bearer {token} +Content-Type: application/json + +{ + "tripId": "uuid", + "serviceClass": "ECONOMY_REGULAR", + "adultCount": 2, + "childCount": 1, + "displayCurrency": "USD" +} + +# Response includes age-based pricing breakdown +{ + "baseFareMinor": 35000, + "adultCount": 2, + "adultFareMinor": 70000, + "childCount": 1, + "freeChildrenCount": 1, + "paidChildrenCount": 0, + "childFareMinor": 0, + "totalMinor": 73500, + "currency": "ETB", + "displayCurrency": "USD", + "displayTotalMinor": 1323 +} +``` + +#### 5. Create Booking ```bash POST /bookings Authorization: Bearer {token} @@ -259,12 +338,31 @@ Content-Type: application/json { "tripId": "uuid", - "seats": [ + "holdId": "uuid", + "serviceClass": "ECONOMY_REGULAR", + "displayCurrency": "DJF", + "passengers": [ { "seatId": "uuid", - "passengerName": "John Doe", + "passengerName": "Abebe Kebede", + "dateOfBirth": "1985-03-15", + "idDocumentType": "NATIONAL_ID", + "idDocumentNumber": "ET123456789" + }, + { + "seatId": "uuid", + "passengerName": "Sara Abebe", + "dateOfBirth": "2023-01-10", + "idDocumentType": "NATIONAL_ID", + "idDocumentNumber": "ET987654321" + }, + { + "seatId": "uuid", + "passengerName": "John Smith", + "dateOfBirth": "1990-07-20", "idDocumentType": "PASSPORT", - "idDocumentNumber": "ET123456" + "passportNumber": "P1234567", + "passportCountry": "Kenya" } ] } @@ -300,6 +398,7 @@ apps/edr-passenger-api/ │ │ ├── auth/ # Authentication & authorization (JWT) │ │ ├── agents/ # Agent operations (IAM-protected) │ │ ├── bookings/ # Booking management (JWT) +│ │ ├── currency/ # Currency conversion service │ │ ├── dashboard/ # Dashboard aggregations (JWT) │ │ ├── fleet/ # Train fleet management (JWT/IAM) │ │ ├── fraud/ # Fraud detection (IAM-protected) @@ -317,6 +416,7 @@ apps/edr-passenger-api/ │ │ ├── stations/ # Station management (JWT) │ │ ├── support/ # Customer support (JWT) │ │ ├── tickets/ # Ticketing (JWT/IAM) +│ │ ├── verifayda/ # Verifayda 2.0 integration │ │ └── wallet/ # Wallet system (JWT) │ ├── app.module.ts # Root application module │ └── main.ts # Application entry point @@ -351,6 +451,8 @@ apps/edr-passenger-api/ - `Notification`, `NotificationTemplate` - `AuditLog`, `OperationalReport` - `SeatBlock`, `SeatHold` +- `CurrencyExchangeRate` (Multi-currency) +- `VerifaydaVerification` (National ID verification) ## 🔧 Available Scripts @@ -467,6 +569,8 @@ pnpm --filter @edr/passenger-api run test:cov ### Pre-deployment Checklist - [ ] Update environment variables (JWT_SECRET, DATABASE_URL, etc.) - [ ] Configure IAM integration (IAM_ENABLED=true, IAM_API_URL, IAM_API_KEY) +- [ ] Configure Verifayda integration (VERIFAYDA_ENABLED=true, VERIFAYDA_API_KEY) +- [ ] Set up currency exchange rate sync (external API) - [ ] Set NODE_ENV=production - [ ] Configure CORS origins (FRONTEND_URL, PORTAL_URL) - [ ] Set up SSL/TLS certificates @@ -475,6 +579,9 @@ pnpm --filter @edr/passenger-api run test:cov - [ ] Configure backup strategy - [ ] Test payment provider integrations - [ ] Verify IAM token validation endpoint +- [ ] Test Verifayda verification with real national IDs +- [ ] Verify currency conversion accuracy +- [ ] Test age-based pricing calculations - [ ] Review security settings and audit logs - [ ] Test both JWT and IAM authentication flows diff --git a/apps/edr-passenger-api/.env.example b/apps/edr-passenger-api/.env.example index d3f17cdd1..3b788ad3e 100644 --- a/apps/edr-passenger-api/.env.example +++ b/apps/edr-passenger-api/.env.example @@ -79,4 +79,10 @@ SUPPORTED_LOCALES=en,am,fr,om IAM_ENABLED=false IAM_API_URL=https://iam.tria-plc.com/api IAM_API_KEY= + +# Verifayda 2.0 Configuration (Ethiopian National ID Verification) +VERIFAYDA_ENABLED=false +VERIFAYDA_API_URL=https://api.verifayda.gov.et/v2 +VERIFAYDA_API_KEY= + GITHUB_PACKAGE_TOKEN= \ No newline at end of file diff --git a/apps/edr-passenger-api/package.json b/apps/edr-passenger-api/package.json index 122a7897f..c8bcaea1d 100644 --- a/apps/edr-passenger-api/package.json +++ b/apps/edr-passenger-api/package.json @@ -13,7 +13,9 @@ "type-check": "tsc --noEmit", "prisma:generate": "prisma generate", "prisma:migrate": "prisma migrate dev", - "prisma:seed": "ts-node prisma/seed.ts" + "prisma:seed": "ts-node prisma/seed.ts", + "prisma:backfill": "ts-node prisma/backfill-fields.ts", + "prisma:verify": "ts-node prisma/verify-backfill.ts" }, "prisma": { "seed": "ts-node prisma/seed.ts" diff --git a/apps/edr-passenger-api/prisma/migrations/20260520000002_language_field_note/migration.sql b/apps/edr-passenger-api/prisma/migrations/20260520000002_language_field_note/migration.sql deleted file mode 100644 index 70f6b75d7..000000000 --- a/apps/edr-passenger-api/prisma/migrations/20260520000002_language_field_note/migration.sql +++ /dev/null @@ -1,2 +0,0 @@ --- Language field already exists in UserPreferences table --- No migration needed diff --git a/apps/edr-passenger-api/prisma/migrations/20260521000001_add_fraud_detection/migration.sql b/apps/edr-passenger-api/prisma/migrations/20260521000001_add_fraud_detection/migration.sql deleted file mode 100644 index ba2115db9..000000000 --- a/apps/edr-passenger-api/prisma/migrations/20260521000001_add_fraud_detection/migration.sql +++ /dev/null @@ -1,74 +0,0 @@ --- Migration: Add Fraud Detection Tables and User.blockedUntil field --- Date: 2026-05-21 --- Description: Adds FraudRule and FraudAlert tables, and blockedUntil field to User table - --- Add blockedUntil field to User table if not exists -DO $$ -BEGIN - IF NOT EXISTS ( - SELECT 1 FROM information_schema.columns - WHERE table_name = 'User' AND column_name = 'blockedUntil' - ) THEN - ALTER TABLE "User" ADD COLUMN "blockedUntil" TIMESTAMP(3); - END IF; -END $$; - --- CreateTable FraudRule -CREATE TABLE IF NOT EXISTS "FraudRule" ( - "id" TEXT NOT NULL, - "type" TEXT NOT NULL, - "enabled" BOOLEAN NOT NULL DEFAULT true, - "threshold" DOUBLE PRECISION NOT NULL, - "config" JSONB, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "FraudRule_pkey" PRIMARY KEY ("id") -); - --- CreateTable FraudAlert -CREATE TABLE IF NOT EXISTS "FraudAlert" ( - "id" TEXT NOT NULL, - "userId" TEXT NOT NULL, - "eventType" TEXT NOT NULL, - "triggeredRules" TEXT[], - "context" JSONB NOT NULL, - "severity" TEXT NOT NULL DEFAULT 'MEDIUM', - "acknowledged" BOOLEAN NOT NULL DEFAULT false, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "FraudAlert_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX IF NOT EXISTS "FraudRule_type_key" ON "FraudRule"("type"); - --- CreateIndex -CREATE INDEX IF NOT EXISTS "FraudAlert_userId_createdAt_idx" ON "FraudAlert"("userId", "createdAt"); - --- CreateIndex -CREATE INDEX IF NOT EXISTS "FraudAlert_acknowledged_idx" ON "FraudAlert"("acknowledged"); - --- AddForeignKey -DO $$ -BEGIN - IF NOT EXISTS ( - SELECT 1 FROM pg_constraint WHERE conname = 'FraudAlert_userId_fkey' - ) THEN - ALTER TABLE "FraudAlert" ADD CONSTRAINT "FraudAlert_userId_fkey" - FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; - END IF; -END $$; - --- Insert default fraud rules -INSERT INTO "FraudRule" ("id", "type", "enabled", "threshold", "config", "createdAt", "updatedAt") -VALUES - (gen_random_uuid(), 'VELOCITY', true, 5, '{"timeWindowMinutes": 30, "blockDurationMinutes": 30}'::jsonb, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), - (gen_random_uuid(), 'HIGH_VALUE', true, 10000, '{"blockDurationMinutes": 60}'::jsonb, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), - (gen_random_uuid(), 'FAILED_PAYMENTS', true, 3, '{"timeWindowMinutes": 60, "blockDurationMinutes": 30}'::jsonb, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) -ON CONFLICT (type) DO NOTHING; - --- Add comments -COMMENT ON TABLE "FraudRule" IS 'Fraud detection rules for monitoring suspicious activities'; -COMMENT ON TABLE "FraudAlert" IS 'Fraud alerts triggered by rule violations'; -COMMENT ON COLUMN "User"."blockedUntil" IS 'Timestamp until which the user is blocked due to fraud or security reasons'; \ No newline at end of file diff --git a/apps/edr-passenger-api/prisma/migrations/20260519124728_initial_migration/migration.sql b/apps/edr-passenger-api/prisma/migrations/20260521053749_initial_migration/migration.sql similarity index 87% rename from apps/edr-passenger-api/prisma/migrations/20260519124728_initial_migration/migration.sql rename to apps/edr-passenger-api/prisma/migrations/20260521053749_initial_migration/migration.sql index 17c28678c..f82c1f2a2 100644 --- a/apps/edr-passenger-api/prisma/migrations/20260519124728_initial_migration/migration.sql +++ b/apps/edr-passenger-api/prisma/migrations/20260521053749_initial_migration/migration.sql @@ -13,6 +13,15 @@ CREATE TYPE "SeatStatus" AS ENUM ('AVAILABLE', 'HELD', 'BOOKED', 'BLOCKED'); -- CreateEnum CREATE TYPE "ServiceClass" AS ENUM ('ECONOMY_REGULAR', 'ECONOMY_BED_LOWER', 'ECONOMY_BED_MIDDLE', 'ECONOMY_BED_UPPER', 'VIP_BED_LOWER', 'VIP_BED_UPPER'); +-- CreateEnum +CREATE TYPE "PassengerCategory" AS ENUM ('ADULT', 'CHILD'); + +-- CreateEnum +CREATE TYPE "IdDocumentType" AS ENUM ('NATIONAL_ID', 'PASSPORT', 'DRIVING_LICENSE', 'OTHER'); + +-- CreateEnum +CREATE TYPE "Currency" AS ENUM ('ETB', 'DJF', 'USD'); + -- CreateEnum CREATE TYPE "BookingStatus" AS ENUM ('DRAFT', 'PENDING_PAYMENT', 'CONFIRMED', 'CANCELLED', 'COMPLETED', 'NO_SHOW', 'REFUNDED'); @@ -58,10 +67,13 @@ CREATE TABLE "User" ( "passwordHash" TEXT NOT NULL, "role" "UserRole" NOT NULL DEFAULT 'PASSENGER', "nationality" TEXT, + "nationalityCode" TEXT, "passportNumber" TEXT, "nationalId" TEXT, "failedLoginAttempts" INTEGER NOT NULL DEFAULT 0, "lockedUntil" TIMESTAMP(3), + "blockedUntil" TIMESTAMP(3), + "lastLoginAt" TIMESTAMP(3), "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updatedAt" TIMESTAMP(3) NOT NULL, @@ -86,6 +98,8 @@ CREATE TABLE "Session" ( CREATE TABLE "Passenger" ( "id" TEXT NOT NULL, "userId" TEXT NOT NULL, + "defaultTravelerProfileId" TEXT, + "preferredLanguage" TEXT, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "Passenger_pkey" PRIMARY KEY ("id") @@ -111,6 +125,8 @@ CREATE TABLE "Station" ( "code" TEXT NOT NULL, "name" TEXT NOT NULL, "city" TEXT NOT NULL, + "countryCode" TEXT, + "isOperational" BOOLEAN NOT NULL DEFAULT true, "timezone" TEXT NOT NULL DEFAULT 'Africa/Addis_Ababa', "lat" DECIMAL(9,6) NOT NULL, "lng" DECIMAL(9,6) NOT NULL, @@ -124,6 +140,7 @@ CREATE TABLE "TrainService" ( "number" TEXT NOT NULL, "name" TEXT NOT NULL, "operatorId" TEXT NOT NULL DEFAULT 'op_edr', + "operatorName" TEXT, CONSTRAINT "TrainService_pkey" PRIMARY KEY ("id") ); @@ -132,6 +149,7 @@ CREATE TABLE "TrainService" ( CREATE TABLE "Trip" ( "id" TEXT NOT NULL, "serviceId" TEXT NOT NULL, + "routeId" TEXT, "originStationId" TEXT NOT NULL, "destinationStationId" TEXT NOT NULL, "departureAt" TIMESTAMP(3) NOT NULL, @@ -139,8 +157,10 @@ CREATE TABLE "Trip" ( "durationMinutes" INTEGER NOT NULL, "status" "TripStatus" NOT NULL DEFAULT 'SCHEDULED', "stopsCount" INTEGER NOT NULL DEFAULT 0, + "reservedCount" INTEGER NOT NULL DEFAULT 0, "onTimePercent" INTEGER NOT NULL DEFAULT 100, "carbonRating" TEXT NOT NULL DEFAULT 'A', + "notes" TEXT, CONSTRAINT "Trip_pkey" PRIMARY KEY ("id") ); @@ -180,6 +200,10 @@ CREATE TABLE "Coach" ( "tripId" TEXT NOT NULL, "label" TEXT NOT NULL, "serviceClass" "ServiceClass" NOT NULL, + "capacity" INTEGER, + "sequence" INTEGER, + "coachType" TEXT, + "amenities" JSONB, CONSTRAINT "Coach_pkey" PRIMARY KEY ("id") ); @@ -191,9 +215,12 @@ CREATE TABLE "Seat" ( "row" INTEGER NOT NULL, "col" TEXT NOT NULL, "label" TEXT NOT NULL, + "seatNumber" TEXT, "kind" "SeatKind" NOT NULL DEFAULT 'STANDARD', "status" "SeatStatus" NOT NULL DEFAULT 'AVAILABLE', "heldUntil" TIMESTAMP(3), + "isWindow" BOOLEAN NOT NULL DEFAULT false, + "isAisle" BOOLEAN NOT NULL DEFAULT false, "premiumFeeMinor" INTEGER NOT NULL DEFAULT 0, "eligibility" TEXT, @@ -207,6 +234,7 @@ CREATE TABLE "SeatHold" ( "seatIds" TEXT[], "fareQuoteId" TEXT, "passengerId" TEXT NOT NULL, + "createdBy" TEXT, "expiresAt" TIMESTAMP(3) NOT NULL, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, @@ -238,7 +266,15 @@ CREATE TABLE "Booking" ( "status" "BookingStatus" NOT NULL DEFAULT 'DRAFT', "currency" TEXT NOT NULL DEFAULT 'ETB', "totalMinor" INTEGER NOT NULL, + "adultCount" INTEGER NOT NULL DEFAULT 1, + "childCount" INTEGER NOT NULL DEFAULT 0, + "displayCurrency" "Currency", + "displayTotalMinor" INTEGER, "bookingType" TEXT NOT NULL DEFAULT 'ONE_WAY', + "userAgent" TEXT, + "source" TEXT NOT NULL DEFAULT 'WEB', + "promoCode" TEXT, + "paidAt" TIMESTAMP(3), "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updatedAt" TIMESTAMP(3) NOT NULL, @@ -251,8 +287,18 @@ CREATE TABLE "BookingSeat" ( "bookingId" TEXT NOT NULL, "seatId" TEXT NOT NULL, "passengerName" TEXT NOT NULL, - "idDocumentType" TEXT, + "dateOfBirth" TIMESTAMP(3), + "passengerCategory" "PassengerCategory" NOT NULL DEFAULT 'ADULT', + "idDocumentType" "IdDocumentType", "idDocumentNumber" TEXT, + "passportNumber" TEXT, + "passportCountry" TEXT, + "verifaydaVerified" BOOLEAN NOT NULL DEFAULT false, + "verifaydaData" JSONB, + "seatLabelSnapshot" TEXT, + "fareMinor" INTEGER, + "displayCurrency" "Currency", + "displayFareMinor" INTEGER, CONSTRAINT "BookingSeat_pkey" PRIMARY KEY ("id") ); @@ -264,6 +310,7 @@ CREATE TABLE "PaymentMethod" ( "type" "PaymentMethodType" NOT NULL, "displayName" TEXT NOT NULL, "maskedHint" TEXT, + "providerId" TEXT, "isDefault" BOOLEAN NOT NULL DEFAULT false, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, @@ -277,6 +324,7 @@ CREATE TABLE "PaymentIntent" ( "amountMinor" INTEGER NOT NULL, "currency" TEXT NOT NULL DEFAULT 'ETB', "method" "PaymentMethodType" NOT NULL, + "provider" TEXT, "status" "PaymentIntentStatus" NOT NULL DEFAULT 'REQUIRES_ACTION', "providerRef" TEXT, "clientAction" JSONB, @@ -285,6 +333,8 @@ CREATE TABLE "PaymentIntent" ( "providerTxnId" TEXT, "rawInitiation" JSONB, "paidAt" TIMESTAMP(3), + "refundedAt" TIMESTAMP(3), + "captureMethod" TEXT, "failureCode" TEXT, "failureMessage" TEXT, "expiresAt" TIMESTAMP(3), @@ -346,7 +396,9 @@ CREATE TABLE "LoyaltyAccount" ( "id" TEXT NOT NULL, "passengerId" TEXT NOT NULL, "pointsBalance" INTEGER NOT NULL DEFAULT 0, + "lifetimePoints" INTEGER NOT NULL DEFAULT 0, "tier" "LoyaltyTier" NOT NULL DEFAULT 'BRONZE', + "tierUpdatedAt" TIMESTAMP(3), "updatedAt" TIMESTAMP(3) NOT NULL, CONSTRAINT "LoyaltyAccount_pkey" PRIMARY KEY ("id") @@ -382,6 +434,8 @@ CREATE TABLE "WalletAccount" ( "id" TEXT NOT NULL, "passengerId" TEXT NOT NULL, "balanceMinor" INTEGER NOT NULL DEFAULT 0, + "status" TEXT NOT NULL DEFAULT 'ACTIVE', + "holdMinor" INTEGER NOT NULL DEFAULT 0, "currency" TEXT NOT NULL DEFAULT 'ETB', "updatedAt" TIMESTAMP(3) NOT NULL, @@ -441,6 +495,8 @@ CREATE TABLE "StationCrowdSignal" ( "level" TEXT NOT NULL, "label" TEXT NOT NULL, "statusLabel" TEXT NOT NULL, + "confidence" INTEGER, + "observedAt" TIMESTAMP(3), "updatedAt" TIMESTAMP(3) NOT NULL, CONSTRAINT "StationCrowdSignal_pkey" PRIMARY KEY ("id") @@ -476,6 +532,7 @@ CREATE TABLE "MenuItem" ( "priceMinor" INTEGER NOT NULL, "currency" TEXT NOT NULL DEFAULT 'ETB', "available" BOOLEAN NOT NULL DEFAULT true, + "availableUntil" TIMESTAMP(3), CONSTRAINT "MenuItem_pkey" PRIMARY KEY ("id") ); @@ -487,6 +544,8 @@ CREATE TABLE "FoodOrder" ( "status" "FoodOrderStatus" NOT NULL DEFAULT 'PENDING', "totalMinor" INTEGER NOT NULL, "currency" TEXT NOT NULL DEFAULT 'ETB', + "specialInstructions" TEXT, + "estimatedReadyAt" TIMESTAMP(3), "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "FoodOrder_pkey" PRIMARY KEY ("id") @@ -499,6 +558,7 @@ CREATE TABLE "FoodOrderItem" ( "menuItemId" TEXT NOT NULL, "name" TEXT NOT NULL, "quantity" INTEGER NOT NULL, + "unitPriceMinor" INTEGER, "lineTotalMinor" INTEGER NOT NULL, CONSTRAINT "FoodOrderItem_pkey" PRIMARY KEY ("id") @@ -528,6 +588,7 @@ CREATE TABLE "FaqArticle" ( CREATE TABLE "SupportConversation" ( "id" TEXT NOT NULL, "userId" TEXT NOT NULL, + "assignedAgentId" TEXT, "status" "SupportConversationStatus" NOT NULL DEFAULT 'OPEN', "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, @@ -540,6 +601,7 @@ CREATE TABLE "SupportMessage" ( "conversationId" TEXT NOT NULL, "sender" "SupportSender" NOT NULL, "text" TEXT NOT NULL, + "attachments" JSONB, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "SupportMessage_pkey" PRIMARY KEY ("id") @@ -676,9 +738,11 @@ CREATE TABLE "RouteFareRule" ( "id" TEXT NOT NULL, "routeId" TEXT NOT NULL, "serviceClass" "ServiceClass" NOT NULL, - "passengerCategory" TEXT NOT NULL DEFAULT 'ADULT', + "passengerCategory" "PassengerCategory" NOT NULL DEFAULT 'ADULT', "baseFareMinor" INTEGER NOT NULL, "discountPercent" INTEGER, + "taxPercent" INTEGER, + "surchargeMinor" INTEGER, "currency" TEXT NOT NULL DEFAULT 'ETB', "validFrom" TIMESTAMP(3) NOT NULL, "validUntil" TIMESTAMP(3), @@ -865,6 +929,61 @@ CREATE TABLE "OperationalReport" ( CONSTRAINT "OperationalReport_pkey" PRIMARY KEY ("id") ); +-- CreateTable +CREATE TABLE "FraudRule" ( + "id" TEXT NOT NULL, + "type" TEXT NOT NULL, + "enabled" BOOLEAN NOT NULL DEFAULT true, + "threshold" DOUBLE PRECISION NOT NULL, + "config" JSONB, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "FraudRule_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "FraudAlert" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "eventType" TEXT NOT NULL, + "triggeredRules" TEXT[], + "context" JSONB NOT NULL, + "severity" TEXT NOT NULL DEFAULT 'MEDIUM', + "acknowledged" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "FraudAlert_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "CurrencyExchangeRate" ( + "id" TEXT NOT NULL, + "fromCurrency" "Currency" NOT NULL, + "toCurrency" "Currency" NOT NULL, + "rate" DECIMAL(18,6) NOT NULL, + "effectiveDate" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "source" TEXT NOT NULL DEFAULT 'MANUAL', + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "CurrencyExchangeRate_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "VerifaydaVerification" ( + "id" TEXT NOT NULL, + "bookingId" TEXT, + "nationalId" TEXT NOT NULL, + "requestPayload" JSONB NOT NULL, + "responsePayload" JSONB, + "verified" BOOLEAN NOT NULL DEFAULT false, + "failureReason" TEXT, + "verifiedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "VerifaydaVerification_pkey" PRIMARY KEY ("id") +); + -- CreateIndex CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); @@ -877,12 +996,21 @@ CREATE UNIQUE INDEX "Session_token_key" ON "Session"("token"); -- CreateIndex CREATE UNIQUE INDEX "Passenger_userId_key" ON "Passenger"("userId"); +-- CreateIndex +CREATE INDEX "Passenger_userId_idx" ON "Passenger"("userId"); + -- CreateIndex CREATE UNIQUE INDEX "Station_code_key" ON "Station"("code"); +-- CreateIndex +CREATE INDEX "Station_city_countryCode_idx" ON "Station"("city", "countryCode"); + -- CreateIndex CREATE UNIQUE INDEX "TrainService_number_key" ON "TrainService"("number"); +-- CreateIndex +CREATE INDEX "Trip_departureAt_originStationId_idx" ON "Trip"("departureAt", "originStationId"); + -- CreateIndex CREATE UNIQUE INDEX "TripStopTime_tripId_sequence_key" ON "TripStopTime"("tripId", "sequence"); @@ -895,9 +1023,21 @@ CREATE UNIQUE INDEX "Coach_tripId_label_key" ON "Coach"("tripId", "label"); -- CreateIndex CREATE UNIQUE INDEX "Seat_coachId_row_col_key" ON "Seat"("coachId", "row", "col"); +-- CreateIndex +CREATE UNIQUE INDEX "Seat_coachId_seatNumber_key" ON "Seat"("coachId", "seatNumber"); + +-- CreateIndex +CREATE INDEX "SeatHold_expiresAt_idx" ON "SeatHold"("expiresAt"); + -- CreateIndex CREATE UNIQUE INDEX "Booking_bookingRef_key" ON "Booking"("bookingRef"); +-- CreateIndex +CREATE INDEX "Booking_passengerId_status_idx" ON "Booking"("passengerId", "status"); + +-- CreateIndex +CREATE INDEX "PaymentMethod_userId_isDefault_idx" ON "PaymentMethod"("userId", "isDefault"); + -- CreateIndex CREATE UNIQUE INDEX "PaymentIntent_bookingId_key" ON "PaymentIntent"("bookingId"); @@ -925,6 +1065,9 @@ CREATE UNIQUE INDEX "LoyaltyAccount_passengerId_key" ON "LoyaltyAccount"("passen -- CreateIndex CREATE UNIQUE INDEX "WalletAccount_passengerId_key" ON "WalletAccount"("passengerId"); +-- CreateIndex +CREATE INDEX "WalletAccount_passengerId_idx" ON "WalletAccount"("passengerId"); + -- CreateIndex CREATE UNIQUE INDEX "Promotion_code_key" ON "Promotion"("code"); @@ -997,6 +1140,27 @@ CREATE INDEX "SeatBlock_seatId_idx" ON "SeatBlock"("seatId"); -- CreateIndex CREATE INDEX "OperationalReport_reportType_dateFrom_idx" ON "OperationalReport"("reportType", "dateFrom"); +-- CreateIndex +CREATE UNIQUE INDEX "FraudRule_type_key" ON "FraudRule"("type"); + +-- CreateIndex +CREATE INDEX "FraudAlert_userId_createdAt_idx" ON "FraudAlert"("userId", "createdAt"); + +-- CreateIndex +CREATE INDEX "FraudAlert_acknowledged_idx" ON "FraudAlert"("acknowledged"); + +-- CreateIndex +CREATE INDEX "CurrencyExchangeRate_fromCurrency_toCurrency_idx" ON "CurrencyExchangeRate"("fromCurrency", "toCurrency"); + +-- CreateIndex +CREATE UNIQUE INDEX "CurrencyExchangeRate_fromCurrency_toCurrency_effectiveDate_key" ON "CurrencyExchangeRate"("fromCurrency", "toCurrency", "effectiveDate"); + +-- CreateIndex +CREATE INDEX "VerifaydaVerification_nationalId_idx" ON "VerifaydaVerification"("nationalId"); + +-- CreateIndex +CREATE INDEX "VerifaydaVerification_bookingId_idx" ON "VerifaydaVerification"("bookingId"); + -- AddForeignKey ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; @@ -1143,3 +1307,6 @@ ALTER TABLE "AuditLog" ADD CONSTRAINT "AuditLog_userId_fkey" FOREIGN KEY ("userI -- AddForeignKey ALTER TABLE "SeatBlock" ADD CONSTRAINT "SeatBlock_seatId_fkey" FOREIGN KEY ("seatId") REFERENCES "Seat"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "FraudAlert" ADD CONSTRAINT "FraudAlert_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/apps/edr-passenger-api/prisma/migrations/migration_lock.toml b/apps/edr-passenger-api/prisma/migrations/migration_lock.toml index fbffa92c2..044d57cdb 100644 --- a/apps/edr-passenger-api/prisma/migrations/migration_lock.toml +++ b/apps/edr-passenger-api/prisma/migrations/migration_lock.toml @@ -1,3 +1,3 @@ # Please do not edit this file manually -# It should be added in your version-control system (i.e. Git) -provider = "postgresql" \ No newline at end of file +# It should be added in your version-control system (e.g., Git) +provider = "postgresql" diff --git a/apps/edr-passenger-api/prisma/schema.prisma b/apps/edr-passenger-api/prisma/schema.prisma index 72fb4b15b..4720eca82 100644 --- a/apps/edr-passenger-api/prisma/schema.prisma +++ b/apps/edr-passenger-api/prisma/schema.prisma @@ -46,6 +46,24 @@ enum ServiceClass { VIP_BED_UPPER } +enum PassengerCategory { + ADULT + CHILD +} + +enum IdDocumentType { + NATIONAL_ID + PASSPORT + DRIVING_LICENSE + OTHER +} + +enum Currency { + ETB + DJF + USD +} + enum BookingStatus { DRAFT PENDING_PAYMENT @@ -142,11 +160,13 @@ model User { passwordHash String role UserRole @default(PASSENGER) nationality String? + nationalityCode String? passportNumber String? nationalId String? failedLoginAttempts Int @default(0) lockedUntil DateTime? blockedUntil DateTime? + lastLoginAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt passenger Passenger? @@ -173,6 +193,8 @@ model Session { model Passenger { id String @id @default(uuid()) userId String @unique + defaultTravelerProfileId String? + preferredLanguage String? createdAt DateTime @default(now()) user User @relation(fields: [userId], references: [id]) bookings Booking[] @@ -181,6 +203,7 @@ model Passenger { notifications Notification[] travelerProfiles TravelerProfile[] savedRoutes SavedRoute[] + @@index([userId]) } model TravelerProfile { @@ -200,6 +223,8 @@ model Station { code String @unique name String city String + countryCode String? + isOperational Boolean @default(true) timezone String @default("Africa/Addis_Ababa") lat Decimal @db.Decimal(9, 6) lng Decimal @db.Decimal(9, 6) @@ -207,6 +232,7 @@ model Station { destinationTrips Trip[] @relation("DestinationTrips") stopTimes TripStopTime[] crowdSignals StationCrowdSignal[] + @@index([city, countryCode]) } model TrainService { @@ -214,12 +240,14 @@ model TrainService { number String @unique name String operatorId String @default("op_edr") + operatorName String? trips Trip[] } model Trip { id String @id @default(uuid()) serviceId String + routeId String? originStationId String destinationStationId String departureAt DateTime @@ -227,8 +255,10 @@ model Trip { durationMinutes Int status TripStatus @default(SCHEDULED) stopsCount Int @default(0) + reservedCount Int @default(0) onTimePercent Int @default(100) carbonRating String @default("A") + notes String? service TrainService @relation(fields: [serviceId], references: [id]) originStation Station @relation("OriginTrips", fields: [originStationId], references: [id]) destinationStation Station @relation("DestinationTrips", fields: [destinationStationId], references: [id]) @@ -238,6 +268,7 @@ model Trip { liveStatus TripLiveStatus? menuItems MenuItem[] journeySegments JourneySegment[] + @@index([departureAt, originStationId]) } model TripStopTime { @@ -272,6 +303,10 @@ model Coach { tripId String label String serviceClass ServiceClass + capacity Int? + sequence Int? + coachType String? + amenities Json? trip Trip @relation(fields: [tripId], references: [id]) seats Seat[] @@unique([tripId, label]) @@ -283,15 +318,19 @@ model Seat { row Int col String label String + seatNumber String? kind SeatKind @default(STANDARD) status SeatStatus @default(AVAILABLE) heldUntil DateTime? + isWindow Boolean @default(false) + isAisle Boolean @default(false) premiumFeeMinor Int @default(0) eligibility String? coach Coach @relation(fields: [coachId], references: [id]) bookingSeats BookingSeat[] blocks SeatBlock[] @@unique([coachId, row, col]) + @@unique([coachId, seatNumber]) } model SeatHold { @@ -300,8 +339,10 @@ model SeatHold { seatIds String[] fareQuoteId String? passengerId String + createdBy String? expiresAt DateTime createdAt DateTime @default(now()) + @@index([expiresAt]) } model FareRule { @@ -318,16 +359,24 @@ model FareRule { } model Booking { - id String @id @default(uuid()) - bookingRef String @unique - passengerId String - tripId String - status BookingStatus @default(DRAFT) - currency String @default("ETB") - totalMinor Int - bookingType String @default("ONE_WAY") - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + id String @id @default(uuid()) + bookingRef String @unique + passengerId String + tripId String + status BookingStatus @default(DRAFT) + currency String @default("ETB") + totalMinor Int + adultCount Int @default(1) + childCount Int @default(0) + displayCurrency Currency? + displayTotalMinor Int? + bookingType String @default("ONE_WAY") + userAgent String? + source String @default("WEB") + promoCode String? + paidAt DateTime? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt passenger Passenger @relation(fields: [passengerId], references: [id]) trip Trip @relation(fields: [tripId], references: [id]) seats BookingSeat[] @@ -338,15 +387,26 @@ model Booking { modifications BookingModification[] cancellation BookingCancellation? baggage BaggageBooking[] + @@index([passengerId, status]) } model BookingSeat { - id String @id @default(uuid()) - bookingId String - seatId String - passengerName String - idDocumentType String? - idDocumentNumber String? + id String @id @default(uuid()) + bookingId String + seatId String + passengerName String + dateOfBirth DateTime? + passengerCategory PassengerCategory @default(ADULT) + idDocumentType IdDocumentType? + idDocumentNumber String? + passportNumber String? + passportCountry String? + verifaydaVerified Boolean @default(false) + verifaydaData Json? + seatLabelSnapshot String? + fareMinor Int? + displayCurrency Currency? + displayFareMinor Int? booking Booking @relation(fields: [bookingId], references: [id]) seat Seat @relation(fields: [seatId], references: [id]) } @@ -357,8 +417,10 @@ model PaymentMethod { type PaymentMethodType displayName String maskedHint String? + providerId String? isDefault Boolean @default(false) createdAt DateTime @default(now()) + @@index([userId, isDefault]) } model PaymentIntent { @@ -367,6 +429,7 @@ model PaymentIntent { amountMinor Int currency String @default("ETB") method PaymentMethodType + provider String? status PaymentIntentStatus @default(REQUIRES_ACTION) providerRef String? clientAction Json? @@ -375,6 +438,8 @@ model PaymentIntent { providerTxnId String? rawInitiation Json? paidAt DateTime? + refundedAt DateTime? + captureMethod String? failureCode String? failureMessage String? expiresAt DateTime? @@ -433,7 +498,9 @@ model LoyaltyAccount { id String @id @default(uuid()) passengerId String @unique pointsBalance Int @default(0) + lifetimePoints Int @default(0) tier LoyaltyTier @default(BRONZE) + tierUpdatedAt DateTime? updatedAt DateTime @updatedAt passenger Passenger @relation(fields: [passengerId], references: [id]) ledger LoyaltyLedgerEntry[] @@ -465,10 +532,13 @@ model WalletAccount { id String @id @default(uuid()) passengerId String @unique balanceMinor Int @default(0) + status String @default("ACTIVE") + holdMinor Int @default(0) currency String @default("ETB") updatedAt DateTime @updatedAt passenger Passenger @relation(fields: [passengerId], references: [id]) ledger WalletLedgerEntry[] + @@index([passengerId]) } model WalletLedgerEntry { @@ -516,6 +586,8 @@ model StationCrowdSignal { level String label String statusLabel String + confidence Int? + observedAt DateTime? updatedAt DateTime @updatedAt station Station @relation(fields: [stationId], references: [id]) } @@ -544,6 +616,7 @@ model MenuItem { priceMinor Int currency String @default("ETB") available Boolean @default(true) + availableUntil DateTime? trip Trip @relation(fields: [tripId], references: [id]) category MenuCategory @relation(fields: [categoryId], references: [id]) } @@ -554,6 +627,8 @@ model FoodOrder { status FoodOrderStatus @default(PENDING) totalMinor Int currency String @default("ETB") + specialInstructions String? + estimatedReadyAt DateTime? createdAt DateTime @default(now()) booking Booking @relation(fields: [bookingId], references: [id]) items FoodOrderItem[] @@ -565,6 +640,7 @@ model FoodOrderItem { menuItemId String name String quantity Int + unitPriceMinor Int? lineTotalMinor Int order FoodOrder @relation(fields: [orderId], references: [id]) } @@ -588,6 +664,7 @@ model FaqArticle { model SupportConversation { id String @id @default(uuid()) userId String + assignedAgentId String? status SupportConversationStatus @default(OPEN) createdAt DateTime @default(now()) messages SupportMessage[] @@ -598,6 +675,7 @@ model SupportMessage { conversationId String sender SupportSender text String + attachments Json? createdAt DateTime @default(now()) conversation SupportConversation @relation(fields: [conversationId], references: [id]) } @@ -715,17 +793,19 @@ model RouteStop { } model RouteFareRule { - id String @id @default(uuid()) + id String @id @default(uuid()) routeId String serviceClass ServiceClass - passengerCategory String @default("ADULT") + passengerCategory PassengerCategory @default(ADULT) baseFareMinor Int discountPercent Int? - currency String @default("ETB") + taxPercent Int? + surchargeMinor Int? + currency String @default("ETB") validFrom DateTime validUntil DateTime? - createdAt DateTime @default(now()) - route Route @relation(fields: [routeId], references: [id], onDelete: Cascade) + createdAt DateTime @default(now()) + route Route @relation(fields: [routeId], references: [id], onDelete: Cascade) @@index([routeId, serviceClass]) } @@ -915,3 +995,29 @@ model FraudAlert { @@index([userId, createdAt]) @@index([acknowledged]) } + +model CurrencyExchangeRate { + id String @id @default(uuid()) + fromCurrency Currency + toCurrency Currency + rate Decimal @db.Decimal(18, 6) + effectiveDate DateTime @default(now()) + source String @default("MANUAL") + createdAt DateTime @default(now()) + @@unique([fromCurrency, toCurrency, effectiveDate]) + @@index([fromCurrency, toCurrency]) +} + +model VerifaydaVerification { + id String @id @default(uuid()) + bookingId String? + nationalId String + requestPayload Json + responsePayload Json? + verified Boolean @default(false) + failureReason String? + verifiedAt DateTime? + createdAt DateTime @default(now()) + @@index([nationalId]) + @@index([bookingId]) +} diff --git a/apps/edr-passenger-api/prisma/seed.ts b/apps/edr-passenger-api/prisma/seed.ts index 65607813e..b8c276a08 100644 --- a/apps/edr-passenger-api/prisma/seed.ts +++ b/apps/edr-passenger-api/prisma/seed.ts @@ -1,4 +1,4 @@ -import { PrismaClient, ServiceClass, UserRole, LoyaltyTier, SeatKind } from '@prisma/client'; +import { PrismaClient, ServiceClass, UserRole, LoyaltyTier, SeatKind, PassengerCategory, Currency } from '@prisma/client'; import * as bcrypt from 'bcrypt'; const prisma = new PrismaClient(); @@ -6,28 +6,28 @@ const prisma = new PrismaClient(); async function main() { console.log('🌱 Starting comprehensive seed...'); - // All 18 Stations (Ethiopian-Djibouti Railway) - const addis = await prisma.station.upsert({ where: { code: 'ADD' }, update: {}, create: { code: 'ADD', name: 'Addis Ababa Central', city: 'Addis Ababa', lat: 9.0054, lng: 38.7636 } }); - const sebeta = await prisma.station.upsert({ where: { code: 'SBT' }, update: {}, create: { code: 'SBT', name: 'Sebeta', city: 'Sebeta', lat: 8.9167, lng: 38.6167 } }); - const labu = await prisma.station.upsert({ where: { code: 'LBU' }, update: {}, create: { code: 'LBU', name: 'Labu', city: 'Labu', lat: 8.8500, lng: 38.8500 } }); - const indode = await prisma.station.upsert({ where: { code: 'IND' }, update: {}, create: { code: 'IND', name: 'Indode', city: 'Indode', lat: 8.7833, lng: 39.0167 } }); - const bishoftu = await prisma.station.upsert({ where: { code: 'BSH' }, update: {}, create: { code: 'BSH', name: 'Bishoftu', city: 'Bishoftu', lat: 8.7500, lng: 38.9833 } }); - const mojo = await prisma.station.upsert({ where: { code: 'MJO' }, update: {}, create: { code: 'MJO', name: 'Mojo', city: 'Mojo', lat: 8.5833, lng: 39.1167 } }); - const adama = await prisma.station.upsert({ where: { code: 'ADM' }, update: {}, create: { code: 'ADM', name: 'Adama', city: 'Adama', lat: 8.5400, lng: 39.2675 } }); - const feto = await prisma.station.upsert({ where: { code: 'FTO' }, update: {}, create: { code: 'FTO', name: 'Feto', city: 'Feto', lat: 8.7167, lng: 39.5833 } }); - const metahara = await prisma.station.upsert({ where: { code: 'MTH' }, update: {}, create: { code: 'MTH', name: 'Metahara', city: 'Metahara', lat: 8.9000, lng: 39.9167 } }); - const awash = await prisma.station.upsert({ where: { code: 'AWS' }, update: {}, create: { code: 'AWS', name: 'Awash', city: 'Awash', lat: 8.9833, lng: 40.1667 } }); - const mieso = await prisma.station.upsert({ where: { code: 'MSO' }, update: {}, create: { code: 'MSO', name: 'Mieso', city: 'Mieso', lat: 9.2333, lng: 40.7500 } }); - const bike = await prisma.station.upsert({ where: { code: 'BKE' }, update: {}, create: { code: 'BKE', name: 'Bike', city: 'Bike', lat: 9.4167, lng: 41.2500 } }); - const direDawa = await prisma.station.upsert({ where: { code: 'DDW' }, update: {}, create: { code: 'DDW', name: 'Dire Dawa', city: 'Dire Dawa', lat: 9.5931, lng: 41.8661 } }); - const arawa = await prisma.station.upsert({ where: { code: 'ARW' }, update: {}, create: { code: 'ARW', name: 'Arawa', city: 'Arawa', lat: 10.0833, lng: 42.2500 } }); - const adigala = await prisma.station.upsert({ where: { code: 'ADG' }, update: {}, create: { code: 'ADG', name: 'Adigala', city: 'Adigala', lat: 10.5000, lng: 42.5833 } }); - const aysha = await prisma.station.upsert({ where: { code: 'AYS' }, update: {}, create: { code: 'AYS', name: 'Aysha', city: 'Aysha', lat: 11.5500, lng: 42.7167 } }); - const dawanle = await prisma.station.upsert({ where: { code: 'DWN' }, update: {}, create: { code: 'DWN', name: 'Dawanle', city: 'Dawanle', timezone: 'Africa/Djibouti', lat: 11.3833, lng: 42.8500 } }); - const alisabieh = await prisma.station.upsert({ where: { code: 'ALI' }, update: {}, create: { code: 'ALI', name: 'Alisabieh', city: 'Alisabieh', timezone: 'Africa/Djibouti', lat: 11.1667, lng: 42.7167 } }); - const holhol = await prisma.station.upsert({ where: { code: 'HLH' }, update: {}, create: { code: 'HLH', name: 'Holhol', city: 'Holhol', timezone: 'Africa/Djibouti', lat: 11.4167, lng: 43.0000 } }); - const nagad = await prisma.station.upsert({ where: { code: 'NGD' }, update: {}, create: { code: 'NGD', name: 'Nagad', city: 'Nagad', timezone: 'Africa/Djibouti', lat: 11.5167, lng: 43.1000 } }); - const djibouti = await prisma.station.upsert({ where: { code: 'DJI' }, update: {}, create: { code: 'DJI', name: 'Djibouti', city: 'Djibouti', timezone: 'Africa/Djibouti', lat: 11.5720, lng: 43.1456 } }); + // All 21 Stations (Ethiopian-Djibouti Railway) + const addis = await prisma.station.upsert({ where: { code: 'ADD' }, update: {}, create: { code: 'ADD', name: 'Addis Ababa Central', city: 'Addis Ababa', countryCode: 'ET', lat: 9.0054, lng: 38.7636 } }); + const sebeta = await prisma.station.upsert({ where: { code: 'SBT' }, update: {}, create: { code: 'SBT', name: 'Sebeta', city: 'Sebeta', countryCode: 'ET', lat: 8.9167, lng: 38.6167 } }); + const labu = await prisma.station.upsert({ where: { code: 'LBU' }, update: {}, create: { code: 'LBU', name: 'Labu', city: 'Labu', countryCode: 'ET', lat: 8.8500, lng: 38.8500 } }); + const indode = await prisma.station.upsert({ where: { code: 'IND' }, update: {}, create: { code: 'IND', name: 'Indode', city: 'Indode', countryCode: 'ET', lat: 8.7833, lng: 39.0167 } }); + const bishoftu = await prisma.station.upsert({ where: { code: 'BSH' }, update: {}, create: { code: 'BSH', name: 'Bishoftu', city: 'Bishoftu', countryCode: 'ET', lat: 8.7500, lng: 38.9833 } }); + const mojo = await prisma.station.upsert({ where: { code: 'MJO' }, update: {}, create: { code: 'MJO', name: 'Mojo', city: 'Mojo', countryCode: 'ET', lat: 8.5833, lng: 39.1167 } }); + const adama = await prisma.station.upsert({ where: { code: 'ADM' }, update: {}, create: { code: 'ADM', name: 'Adama', city: 'Adama', countryCode: 'ET', lat: 8.5400, lng: 39.2675 } }); + const feto = await prisma.station.upsert({ where: { code: 'FTO' }, update: {}, create: { code: 'FTO', name: 'Feto', city: 'Feto', countryCode: 'ET', lat: 8.7167, lng: 39.5833 } }); + const metahara = await prisma.station.upsert({ where: { code: 'MTH' }, update: {}, create: { code: 'MTH', name: 'Metahara', city: 'Metahara', countryCode: 'ET', lat: 8.9000, lng: 39.9167 } }); + const awash = await prisma.station.upsert({ where: { code: 'AWS' }, update: {}, create: { code: 'AWS', name: 'Awash', city: 'Awash', countryCode: 'ET', lat: 8.9833, lng: 40.1667 } }); + const mieso = await prisma.station.upsert({ where: { code: 'MSO' }, update: {}, create: { code: 'MSO', name: 'Mieso', city: 'Mieso', countryCode: 'ET', lat: 9.2333, lng: 40.7500 } }); + const bike = await prisma.station.upsert({ where: { code: 'BKE' }, update: {}, create: { code: 'BKE', name: 'Bike', city: 'Bike', countryCode: 'ET', lat: 9.4167, lng: 41.2500 } }); + const direDawa = await prisma.station.upsert({ where: { code: 'DDW' }, update: {}, create: { code: 'DDW', name: 'Dire Dawa', city: 'Dire Dawa', countryCode: 'ET', lat: 9.5931, lng: 41.8661 } }); + const arawa = await prisma.station.upsert({ where: { code: 'ARW' }, update: {}, create: { code: 'ARW', name: 'Arawa', city: 'Arawa', countryCode: 'ET', lat: 10.0833, lng: 42.2500 } }); + const adigala = await prisma.station.upsert({ where: { code: 'ADG' }, update: {}, create: { code: 'ADG', name: 'Adigala', city: 'Adigala', countryCode: 'ET', lat: 10.5000, lng: 42.5833 } }); + const aysha = await prisma.station.upsert({ where: { code: 'AYS' }, update: {}, create: { code: 'AYS', name: 'Aysha', city: 'Aysha', countryCode: 'ET', lat: 11.5500, lng: 42.7167 } }); + const dawanle = await prisma.station.upsert({ where: { code: 'DWN' }, update: {}, create: { code: 'DWN', name: 'Dawanle', city: 'Dawanle', countryCode: 'DJ', timezone: 'Africa/Djibouti', lat: 11.3833, lng: 42.8500 } }); + const alisabieh = await prisma.station.upsert({ where: { code: 'ALI' }, update: {}, create: { code: 'ALI', name: 'Alisabieh', city: 'Alisabieh', countryCode: 'DJ', timezone: 'Africa/Djibouti', lat: 11.1667, lng: 42.7167 } }); + const holhol = await prisma.station.upsert({ where: { code: 'HLH' }, update: {}, create: { code: 'HLH', name: 'Holhol', city: 'Holhol', countryCode: 'DJ', timezone: 'Africa/Djibouti', lat: 11.4167, lng: 43.0000 } }); + const nagad = await prisma.station.upsert({ where: { code: 'NGD' }, update: {}, create: { code: 'NGD', name: 'Nagad', city: 'Nagad', countryCode: 'DJ', timezone: 'Africa/Djibouti', lat: 11.5167, lng: 43.1000 } }); + const djibouti = await prisma.station.upsert({ where: { code: 'DJI' }, update: {}, create: { code: 'DJI', name: 'Djibouti', city: 'Djibouti', countryCode: 'DJ', timezone: 'Africa/Djibouti', lat: 11.5720, lng: 43.1456 } }); // Routes const route1 = await prisma.route.upsert({ @@ -62,12 +62,15 @@ async function main() { { routeId: route1.id, stationId: djibouti.id, sequence: 21, distanceKm: 756 }, ]}); - // Route Fare Rules + // Route Fare Rules (with passenger categories) await prisma.routeFareRule.deleteMany({ where: { routeId: route1.id } }); await prisma.routeFareRule.createMany({ data: [ - { routeId: route1.id, serviceClass: 'ECONOMY_REGULAR', baseFareMinor: 45000, validFrom: new Date('2026-01-01') }, - { routeId: route1.id, serviceClass: 'ECONOMY_BED_LOWER', baseFareMinor: 65000, validFrom: new Date('2026-01-01') }, - { routeId: route1.id, serviceClass: 'VIP_BED_LOWER', baseFareMinor: 95000, validFrom: new Date('2026-01-01') }, + { routeId: route1.id, serviceClass: 'ECONOMY_REGULAR', passengerCategory: 'ADULT', baseFareMinor: 45000, validFrom: new Date('2026-01-01') }, + { routeId: route1.id, serviceClass: 'ECONOMY_BED_LOWER', passengerCategory: 'ADULT', baseFareMinor: 65000, validFrom: new Date('2026-01-01') }, + { routeId: route1.id, serviceClass: 'VIP_BED_LOWER', passengerCategory: 'ADULT', baseFareMinor: 95000, validFrom: new Date('2026-01-01') }, + { routeId: route1.id, serviceClass: 'ECONOMY_REGULAR', passengerCategory: 'CHILD', baseFareMinor: 45000, validFrom: new Date('2026-01-01') }, + { routeId: route1.id, serviceClass: 'ECONOMY_BED_LOWER', passengerCategory: 'CHILD', baseFareMinor: 65000, validFrom: new Date('2026-01-01') }, + { routeId: route1.id, serviceClass: 'VIP_BED_LOWER', passengerCategory: 'CHILD', baseFareMinor: 95000, validFrom: new Date('2026-01-01') }, ]}); // Train Services @@ -217,12 +220,24 @@ async function main() { } } + // Currency Exchange Rates + await prisma.currencyExchangeRate.deleteMany({}); + await prisma.currencyExchangeRate.createMany({ data: [ + { fromCurrency: 'ETB', toCurrency: 'ETB', rate: 1.0, effectiveDate: new Date() }, + { fromCurrency: 'ETB', toCurrency: 'DJF', rate: 3.25, effectiveDate: new Date() }, + { fromCurrency: 'ETB', toCurrency: 'USD', rate: 0.018, effectiveDate: new Date() }, + { fromCurrency: 'DJF', toCurrency: 'ETB', rate: 0.3077, effectiveDate: new Date() }, + { fromCurrency: 'USD', toCurrency: 'ETB', rate: 55.56, effectiveDate: new Date() }, + ]}); + console.log('✅ Comprehensive seed complete'); console.log('\n📋 Seed Summary:'); - console.log(' - 18 Stations (Complete Ethiopian-Djibouti Railway)'); + console.log(' - 21 Stations (Complete Ethiopian-Djibouti Railway with country codes)'); console.log(' - 1 Route with 21 stops'); console.log(' - 2 Train services, 4 trips'); console.log(' - 3 Coaches per trip (Economy, Bed, VIP)'); + console.log(' - Fare rules for ADULT and CHILD categories'); + console.log(' - Currency exchange rates (ETB ↔ DJF, USD)'); console.log(' - 3 Users: Admin, Passenger (Silver tier + wallet), Agent'); console.log(' - 3 Fraud detection rules'); console.log(' - 3 Loyalty rewards'); @@ -232,6 +247,9 @@ async function main() { console.log(' Passenger: kelemu@email.com / password123'); console.log(' Agent: agent@edr-platform.com / agent123'); console.log('\n🚉 Stations: Addis Ababa → Sebeta → Labu → Indode → Bishoftu → Mojo → Adama → Feto → Metahara → Awash → Mieso → Bike → Dire Dawa → Arawa → Adigala → Aysha → Dawanle → Alisabieh → Holhol → Nagad → Djibouti'); + console.log('\n💰 Pricing: ADULT (≥5 years) = 100% fare | CHILD (<5 years) = First free, subsequent 100%'); + console.log('\n💱 Currencies: ETB (transaction) | DJF, USD (display) | Rates: ETB→DJF=3.25, ETB→USD=0.018'); + console.log('\n🔐 Verifayda: DISABLED (set VERIFAYDA_ENABLED=true in production)'); } main().catch(console.error).finally(() => prisma.$disconnect()); diff --git a/apps/edr-passenger-api/src/modules/agents/agents.service.ts b/apps/edr-passenger-api/src/modules/agents/agents.service.ts index 37f4fc433..f17289de4 100644 --- a/apps/edr-passenger-api/src/modules/agents/agents.service.ts +++ b/apps/edr-passenger-api/src/modules/agents/agents.service.ts @@ -1,6 +1,7 @@ import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common'; import { PrismaService } from '../../common/prisma.service'; import { CreateAgentBookingDto, OpenShiftDto, CloseShiftDto } from './agents.dto'; +import { IdDocumentType } from '@prisma/client'; function generateRef(): string { const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; @@ -35,9 +36,9 @@ export class AgentsService { totalMinor, seats: { create: dto.passengers.map(p => ({ - seatId: p.seatId, + seat: { connect: { id: p.seatId } }, passengerName: p.fullName, - idDocumentType: p.idDocumentType, + idDocumentType: p.idDocumentType as IdDocumentType | undefined, idDocumentNumber: p.idDocumentNumber })) } diff --git a/apps/edr-passenger-api/src/modules/bookings/bookings.controller.ts b/apps/edr-passenger-api/src/modules/bookings/bookings.controller.ts index b7363ec70..a0fb8afba 100644 --- a/apps/edr-passenger-api/src/modules/bookings/bookings.controller.ts +++ b/apps/edr-passenger-api/src/modules/bookings/bookings.controller.ts @@ -1,5 +1,5 @@ import { Body, Controller, Delete, Get, Param, Post, Patch, UseGuards } from '@nestjs/common'; -import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger'; +import { ApiTags, ApiOperation, ApiBearerAuth, ApiResponse } from '@nestjs/swagger'; import { BookingsService } from './bookings.service'; import { CreateBookingDto, ModifyBookingDto, CancelBookingDto } from './bookings.dto'; import { JwtGuard } from '../../common/jwt.guard'; @@ -12,25 +12,51 @@ export class BookingsController { constructor(private service: BookingsService) {} @Post() - @ApiOperation({ summary: 'Create booking from seat hold' }) + @ApiOperation({ + summary: 'Create booking with age-based pricing and Verifayda verification', + description: `Creates a booking with the following features: + - Age-based pricing: CHILD (<5 years) first child free, ADULT (>=5 years) full fare + - Ethiopian nationals: Verified via Verifayda 2.0 (national ID NOT stored) + - Non-Ethiopians: Passport required, no verification + - Multi-currency: Display in ETB, DJF, or USD (transaction always in ETB) + - All passengers require dateOfBirth for age calculation` + }) + @ApiResponse({ status: 201, description: 'Booking created with fare breakdown' }) + @ApiResponse({ status: 400, description: 'Verifayda verification failed or invalid passenger data' }) + @ApiResponse({ status: 404, description: 'Trip or seat hold not found' }) create(@Body() dto: CreateBookingDto) { return this.service.create(dto); } @Get(':bookingRef') - @ApiOperation({ summary: 'Get booking by reference' }) + @ApiOperation({ + summary: 'Get booking details by reference', + description: 'Returns booking with passenger categories, Verifayda verification status, and multi-currency amounts' + }) + @ApiResponse({ status: 200, description: 'Booking details with adult/child counts and currency conversion' }) + @ApiResponse({ status: 404, description: 'Booking not found' }) getByRef(@Param('bookingRef') ref: string) { return this.service.getByRef(ref); } @Patch(':bookingRef/modify') - @ApiOperation({ summary: 'Modify booking seats or trip' }) + @ApiOperation({ + summary: 'Modify booking seats or trip', + description: 'Allows modification of confirmed bookings before departure' + }) + @ApiResponse({ status: 200, description: 'Booking modified successfully' }) + @ApiResponse({ status: 400, description: 'Cannot modify cancelled or past bookings' }) modify(@Body() dto: ModifyBookingDto) { return this.service.modify(dto); } @Delete(':bookingRef') - @ApiOperation({ summary: 'Cancel booking' }) + @ApiOperation({ + summary: 'Cancel booking with refund', + description: 'Cancels booking and processes refund (80% for confirmed bookings)' + }) + @ApiResponse({ status: 200, description: 'Booking cancelled with refund amount' }) + @ApiResponse({ status: 400, description: 'Booking already cancelled' }) cancel(@Param('bookingRef') ref: string, @Body() dto: CancelBookingDto) { return this.service.cancel(ref, dto.reason); } diff --git a/apps/edr-passenger-api/src/modules/bookings/bookings.dto.ts b/apps/edr-passenger-api/src/modules/bookings/bookings.dto.ts index eae26111e..0ef1debd0 100644 --- a/apps/edr-passenger-api/src/modules/bookings/bookings.dto.ts +++ b/apps/edr-passenger-api/src/modules/bookings/bookings.dto.ts @@ -1,14 +1,16 @@ -import { IsString, IsArray, ValidateNested, IsOptional, IsInt, IsEnum } from 'class-validator'; +import { IsString, IsArray, ValidateNested, IsOptional, IsInt, IsEnum, IsDateString } from 'class-validator'; import { Type } from 'class-transformer'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +import { Currency, IdDocumentType } from '@prisma/client'; export class PassengerInputDto { - @ApiProperty() @IsString() fullName: string; - @ApiProperty() @IsString() phone: string; - @ApiProperty() @IsString() email: string; @ApiProperty() @IsString() seatId: string; - @ApiPropertyOptional() @IsOptional() @IsString() idDocumentType?: string; - @ApiPropertyOptional() @IsOptional() @IsString() idDocumentNumber?: string; + @ApiProperty({ example: 'John Doe' }) @IsString() passengerName: string; + @ApiProperty({ example: '1990-05-15', description: 'Date of birth for age calculation' }) @IsDateString() dateOfBirth: string; + @ApiProperty({ example: 'NATIONAL_ID', enum: IdDocumentType }) @IsEnum(IdDocumentType) idDocumentType: IdDocumentType; + @ApiPropertyOptional({ example: 'ET123456789', description: 'For Ethiopian nationals only - used for Verifayda verification' }) @IsOptional() @IsString() idDocumentNumber?: string; + @ApiPropertyOptional({ example: 'P1234567', description: 'For non-Ethiopians' }) @IsOptional() @IsString() passportNumber?: string; + @ApiPropertyOptional({ example: 'Kenya', description: 'For non-Ethiopians' }) @IsOptional() @IsString() passportCountry?: string; } export class CreateBookingDto { @@ -16,15 +18,15 @@ export class CreateBookingDto { @ApiProperty() @IsString() tripId: string; @ApiProperty() @IsString() holdId: string; @ApiProperty({ type: [PassengerInputDto] }) @IsArray() @ValidateNested({ each: true }) @Type(() => PassengerInputDto) passengers: PassengerInputDto[]; - @ApiPropertyOptional({ + @ApiProperty({ example: 'ECONOMY_REGULAR', enum: ['ECONOMY_REGULAR', 'ECONOMY_BED_LOWER', 'ECONOMY_BED_MIDDLE', 'ECONOMY_BED_UPPER', 'VIP_BED_LOWER', 'VIP_BED_UPPER'] }) - @IsOptional() @IsString() serviceClass?: string; + @IsString() serviceClass: string; @ApiPropertyOptional() @IsOptional() @IsString() promoCode?: string; @ApiPropertyOptional() @IsOptional() @IsInt() loyaltyRedemptionPoints?: number; @ApiPropertyOptional({ example: 'ONE_WAY' }) @IsOptional() @IsString() bookingType?: string; - @ApiPropertyOptional({ description: 'Auto-assign seats instead of manual selection' }) @IsOptional() autoAssign?: boolean; + @ApiPropertyOptional({ example: 'ETB', enum: Currency }) @IsOptional() @IsEnum(Currency) displayCurrency?: Currency; } export class ModifyBookingDto { diff --git a/apps/edr-passenger-api/src/modules/bookings/bookings.module.ts b/apps/edr-passenger-api/src/modules/bookings/bookings.module.ts index 5632af5d7..a73d16796 100644 --- a/apps/edr-passenger-api/src/modules/bookings/bookings.module.ts +++ b/apps/edr-passenger-api/src/modules/bookings/bookings.module.ts @@ -2,7 +2,13 @@ import { Module } from '@nestjs/common'; import { BookingsController } from './bookings.controller'; import { BookingsService } from './bookings.service'; import { SeatsModule } from '../seats/seats.module'; -import { SearchModule } from '../search/search.module'; +import { VerifaydaModule } from '../verifayda/verifayda.module'; +import { CurrencyModule } from '../currency/currency.module'; -@Module({ imports: [SeatsModule, SearchModule], controllers: [BookingsController], providers: [BookingsService], exports: [BookingsService] }) +@Module({ + imports: [SeatsModule, VerifaydaModule, CurrencyModule], + controllers: [BookingsController], + providers: [BookingsService], + exports: [BookingsService] +}) export class BookingsModule {} diff --git a/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts b/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts index 9532531f3..5d99717d4 100644 --- a/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts +++ b/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts @@ -4,16 +4,34 @@ import { SeatsService } from '../seats/seats.service'; import { EventEmitter2 } from '@nestjs/event-emitter'; import { CreateBookingDto, ModifyBookingDto, CancelBookingDto } from './bookings.dto'; import { Cron, CronExpression } from '@nestjs/schedule'; -import { SearchService } from '../search/search.service'; +import { VerifaydaService } from '../verifayda/verifayda.service'; +import { CurrencyService } from '../currency/currency.service'; +import { Currency, PassengerCategory, IdDocumentType } from '@prisma/client'; function generateRef(): string { const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; return Array.from({ length: 6 }, () => chars[Math.floor(Math.random() * chars.length)]).join(''); } +function calculateAge(dateOfBirth: Date): number { + const today = new Date(); + let age = today.getFullYear() - dateOfBirth.getFullYear(); + const monthDiff = today.getMonth() - dateOfBirth.getMonth(); + if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < dateOfBirth.getDate())) { + age--; + } + return age; +} + @Injectable() export class BookingsService { - constructor(private prisma: PrismaService, private seatsService: SeatsService, private eventEmitter: EventEmitter2, private searchService: SearchService) {} + constructor( + private prisma: PrismaService, + private seatsService: SeatsService, + private eventEmitter: EventEmitter2, + private verifaydaService: VerifaydaService, + private currencyService: CurrencyService, + ) {} async create(dto: CreateBookingDto) { const hold = await this.prisma.seatHold.findUnique({ where: { id: dto.holdId } }); @@ -21,45 +39,150 @@ export class BookingsService { const trip = await this.prisma.trip.findUnique({ where: { id: dto.tripId }, include: { originStation: true, destinationStation: true } }); if (!trip) throw new NotFoundException('Trip not found'); - let seatIds: string[]; - if (dto.autoAssign) { - seatIds = await this.seatsService.autoAssignSeats( - dto.tripId, - dto.passengers.length, - dto.serviceClass ?? 'ECONOMY_REGULAR', - ); - await this.seatsService.confirmSeats(seatIds); - } else { - seatIds = dto.passengers.map((p) => p.seatId); + const seatIds = dto.passengers.map((p) => p.seatId); + + // Calculate passenger categories and verify Ethiopian nationals + const passengersData = []; + let adultCount = 0; + let childCount = 0; + + for (const passenger of dto.passengers) { + const dateOfBirth = new Date(passenger.dateOfBirth); + const age = calculateAge(dateOfBirth); + const category: PassengerCategory = age < 5 ? PassengerCategory.CHILD : PassengerCategory.ADULT; + + if (category === PassengerCategory.ADULT) adultCount++; + else childCount++; + + let passengerName = passenger.passengerName; + let verifaydaVerified = false; + let verifaydaData: Record | undefined = undefined; + + // Verify Ethiopian nationals via Verifayda + if (passenger.idDocumentType === IdDocumentType.NATIONAL_ID && passenger.idDocumentNumber) { + const verification = await this.verifaydaService.verifyNationalId(passenger.idDocumentNumber); + + if (!verification.verified) { + throw new BadRequestException( + `Verifayda verification failed for passenger ${passenger.passengerName}: ${verification.failureReason}`, + ); + } + + // Use verified data from Verifayda + passengerName = verification.passengerData?.fullName || passengerName; + verifaydaVerified = true; + verifaydaData = verification.passengerData?.profileData; + } else if (passenger.idDocumentType === IdDocumentType.PASSPORT) { + // Non-Ethiopian: require passport details + if (!passenger.passportNumber || !passenger.passportCountry) { + throw new BadRequestException( + `Passport number and country required for non-Ethiopian passenger ${passenger.passengerName}`, + ); + } + } + + passengersData.push({ + ...passenger, + passengerName, + dateOfBirth, + category, + verifaydaVerified, + verifaydaData, + }); } - - const fareQuote = await this.searchService.getFareQuote({ tripId: dto.tripId, serviceClass: dto.serviceClass ?? 'ECONOMY_REGULAR', passengerCount: dto.passengers.length, promoCode: dto.promoCode, loyaltyRedemptionPoints: dto.loyaltyRedemptionPoints }); + + // Calculate fare with age-based pricing + const baseFareMinor = await this.getBaseFare(dto.tripId, dto.serviceClass); + const adultFareMinor = baseFareMinor * adultCount; + const paidChildrenCount = Math.max(0, childCount - 1); + const childFareMinor = baseFareMinor * paidChildrenCount; + const totalBaseFareMinor = adultFareMinor + childFareMinor; + + let discountMinor = 0; + if (dto.promoCode) { + const promo = await this.prisma.promotion.findUnique({ where: { code: dto.promoCode } }); + if (promo?.active && promo.validUntil > new Date()) { + discountMinor = promo.percentOff + ? Math.round(totalBaseFareMinor * promo.percentOff / 100) + : (promo.amountOffMinor ?? 0); + } + } + + const loyaltyMinor = (dto.loyaltyRedemptionPoints ?? 0) * 10; + const taxesMinor = Math.round(totalBaseFareMinor * 0.05); + const totalMinor = Math.max(0, totalBaseFareMinor - discountMinor - loyaltyMinor + taxesMinor); + + const displayCurrency = dto.displayCurrency || Currency.ETB; + let displayTotalMinor = totalMinor; + + if (displayCurrency !== Currency.ETB) { + displayTotalMinor = await this.currencyService.convertAmount(totalMinor, Currency.ETB, displayCurrency); + } + const booking = await this.prisma.booking.create({ - data: { - bookingRef: generateRef(), - passengerId: dto.passengerId, - tripId: dto.tripId, - status: 'PENDING_PAYMENT', - totalMinor: fareQuote.totalMinor, + data: { + bookingRef: generateRef(), + passengerId: dto.passengerId, + tripId: dto.tripId, + status: 'PENDING_PAYMENT', + totalMinor, + adultCount, + childCount, + displayCurrency, + displayTotalMinor, bookingType: dto.bookingType ?? 'ONE_WAY', - seats: { create: dto.passengers.map((p, i) => ({ seatId: seatIds[i], passengerName: p.fullName, idDocumentType: p.idDocumentType, idDocumentNumber: p.idDocumentNumber })) } + seats: { + create: passengersData.map((p) => ({ + seat: { connect: { id: p.seatId } }, + passengerName: p.passengerName, + dateOfBirth: p.dateOfBirth, + passengerCategory: p.category, + idDocumentType: p.idDocumentType, + idDocumentNumber: p.idDocumentType === IdDocumentType.NATIONAL_ID ? undefined : p.idDocumentNumber, + passportNumber: p.passportNumber, + passportCountry: p.passportCountry, + verifaydaVerified: p.verifaydaVerified, + verifaydaData: p.verifaydaData || undefined, + fareMinor: p.category === PassengerCategory.ADULT ? baseFareMinor : (paidChildrenCount > 0 ? baseFareMinor : 0), + displayCurrency, + })), + }, }, include: { seats: { include: { seat: true } }, trip: { include: { originStation: true, destinationStation: true, service: true } } }, }); + + await this.seatsService.confirmSeats(seatIds); this.eventEmitter.emit('booking.created', { booking }); - return { - ...booking, + + return { + ...booking, fareBreakdown: { - baseFare: fareQuote.baseFareMinor / 100, - discount: fareQuote.discountMinor / 100, - loyaltyRedemption: fareQuote.loyaltyRedemptionMinor / 100, - taxesFees: fareQuote.taxesFeesMinor / 100, - total: fareQuote.totalMinor / 100, - currency: fareQuote.currency - } + baseFareMinor, + adultCount, + adultFareMinor, + childCount, + freeChildrenCount: Math.min(childCount, 1), + paidChildrenCount, + childFareMinor, + totalBaseFareMinor, + discountMinor, + loyaltyRedemptionMinor: loyaltyMinor, + taxesFeesMinor: taxesMinor, + totalMinor, + currency: 'ETB', + displayCurrency, + displayTotalMinor, + }, }; } + private async getBaseFare(tripId: string, serviceClass: string): Promise { + const fareRule = await this.prisma.fareRule.findFirst({ + where: { tripId, serviceClass: serviceClass as any }, + }); + return fareRule?.baseFareMinor ?? 35000; + } + async getByRef(bookingRef: string) { const booking = await this.prisma.booking.findUnique({ where: { bookingRef }, include: { trip: { include: { originStation: true, destinationStation: true, service: true } }, seats: { include: { seat: { include: { coach: true } } } }, paymentIntent: true, ticket: true } }); if (!booking) throw new NotFoundException('Booking not found'); @@ -68,6 +191,10 @@ export class BookingsService { bookingRef: booking.bookingRef, status: booking.status, totalFare: booking.totalMinor / 100, + adultCount: booking.adultCount, + childCount: booking.childCount, + displayCurrency: booking.displayCurrency, + displayTotalFare: booking.displayTotalMinor ? booking.displayTotalMinor / 100 : undefined, bookingType: booking.bookingType, createdAt: booking.createdAt, trip: { @@ -79,6 +206,8 @@ export class BookingsService { }, passengers: booking.seats.map((bs) => ({ fullName: bs.passengerName, + category: bs.passengerCategory, + verifaydaVerified: bs.verifaydaVerified, seat: { number: bs.seat.label, coach: bs.seat.coach.label, class: bs.seat.coach.serviceClass }, })), payment: booking.paymentIntent ? { method: booking.paymentIntent.method, status: booking.paymentIntent.status } : undefined, diff --git a/apps/edr-passenger-api/src/modules/currency/currency.module.ts b/apps/edr-passenger-api/src/modules/currency/currency.module.ts new file mode 100644 index 000000000..445f31e05 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/currency/currency.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { CurrencyService } from './currency.service'; +import { PrismaModule } from '../../common/prisma.module'; + +@Module({ + imports: [PrismaModule], + providers: [CurrencyService], + exports: [CurrencyService], +}) +export class CurrencyModule {} diff --git a/apps/edr-passenger-api/src/modules/currency/currency.service.ts b/apps/edr-passenger-api/src/modules/currency/currency.service.ts new file mode 100644 index 000000000..3fcfce179 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/currency/currency.service.ts @@ -0,0 +1,83 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { PrismaService } from '../../common/prisma.service'; +import { Currency } from '@prisma/client'; + +@Injectable() +export class CurrencyService { + private readonly logger = new Logger(CurrencyService.name); + + constructor(private readonly prisma: PrismaService) {} + + async convertAmount( + amountMinor: number, + fromCurrency: Currency, + toCurrency: Currency, + ): Promise { + if (fromCurrency === toCurrency) { + return amountMinor; + } + + const rate = await this.getExchangeRate(fromCurrency, toCurrency); + return Math.round(amountMinor * rate); + } + + async getExchangeRate( + fromCurrency: Currency, + toCurrency: Currency, + ): Promise { + const exchangeRate = await this.prisma.currencyExchangeRate.findFirst({ + where: { + fromCurrency, + toCurrency, + }, + orderBy: { + effectiveDate: 'desc', + }, + }); + + if (!exchangeRate) { + this.logger.warn( + `No exchange rate found for ${fromCurrency} to ${toCurrency}, using 1.0`, + ); + return 1.0; + } + + return Number(exchangeRate.rate); + } + + async syncExchangeRates(): Promise { + this.logger.log('Syncing exchange rates from external provider'); + + // In production, fetch from external API + // For now, using static rates + const rates = [ + { from: 'ETB', to: 'ETB', rate: 1.0 }, + { from: 'ETB', to: 'DJF', rate: 3.25 }, + { from: 'ETB', to: 'USD', rate: 0.018 }, + { from: 'DJF', to: 'ETB', rate: 0.3077 }, + { from: 'USD', to: 'ETB', rate: 55.56 }, + ]; + + for (const { from, to, rate } of rates) { + await this.prisma.currencyExchangeRate.upsert({ + where: { + fromCurrency_toCurrency_effectiveDate: { + fromCurrency: from as Currency, + toCurrency: to as Currency, + effectiveDate: new Date(), + }, + }, + update: { rate }, + create: { + fromCurrency: from as Currency, + toCurrency: to as Currency, + rate, + effectiveDate: new Date(), + source: 'EXTERNAL_API', + }, + }); + } + + this.logger.log('Exchange rates synced successfully'); + } +} diff --git a/apps/edr-passenger-api/src/modules/search/search.controller.ts b/apps/edr-passenger-api/src/modules/search/search.controller.ts index 9409873ed..2158f9cd4 100644 --- a/apps/edr-passenger-api/src/modules/search/search.controller.ts +++ b/apps/edr-passenger-api/src/modules/search/search.controller.ts @@ -1,5 +1,5 @@ import { Body, Controller, Post } from '@nestjs/common'; -import { ApiTags, ApiOperation } from '@nestjs/swagger'; +import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; import { SearchService } from './search.service'; import { SearchTripsDto, FareQuoteDto } from './search.dto'; @@ -7,6 +7,26 @@ import { SearchTripsDto, FareQuoteDto } from './search.dto'; @Controller('search') export class SearchController { constructor(private service: SearchService) {} - @Post() @ApiOperation({ summary: 'Search trips' }) searchTrips(@Body() dto: SearchTripsDto) { return this.service.searchTrips(dto); } - @Post('fare-quote')@ApiOperation({ summary: 'Get fare quote' }) getFareQuote(@Body() dto: FareQuoteDto) { return this.service.getFareQuote(dto); } + + @Post() + @ApiOperation({ + summary: 'Search trips by origin, destination, and passenger counts', + description: 'Returns available trips WITHOUT pricing. Requires adult count (mandatory) and optional child count. Pricing is shown only in fare quote endpoint.' + }) + @ApiResponse({ status: 200, description: 'List of available trips with seat availability' }) + @ApiResponse({ status: 400, description: 'Invalid search parameters' }) + searchTrips(@Body() dto: SearchTripsDto) { + return this.service.searchTrips(dto); + } + + @Post('fare-quote') + @ApiOperation({ + summary: 'Get detailed fare quote with age-based pricing', + description: 'Calculates fare based on adult/child counts. First child travels free, subsequent children pay full fare. Supports multi-currency display (ETB, DJF, USD).' + }) + @ApiResponse({ status: 200, description: 'Detailed fare breakdown with adult/child pricing and currency conversion' }) + @ApiResponse({ status: 404, description: 'Trip not found' }) + getFareQuote(@Body() dto: FareQuoteDto) { + return this.service.getFareQuote(dto); + } } diff --git a/apps/edr-passenger-api/src/modules/search/search.dto.ts b/apps/edr-passenger-api/src/modules/search/search.dto.ts index 3d8344218..7a85fe816 100644 --- a/apps/edr-passenger-api/src/modules/search/search.dto.ts +++ b/apps/edr-passenger-api/src/modules/search/search.dto.ts @@ -1,12 +1,14 @@ -import { IsString, IsDateString, IsInt, IsOptional, Min } from 'class-validator'; +import { IsString, IsDateString, IsInt, IsOptional, Min, IsEnum } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; +import { Currency } from '@prisma/client'; export class SearchTripsDto { @ApiProperty({ example: 'st_ADD' }) @IsString() originStationId: string; @ApiProperty({ example: 'st_DJI' }) @IsString() destinationStationId: string; @ApiProperty({ example: '2026-05-11' }) @IsDateString() date: string; - @ApiPropertyOptional({ example: 1 }) @IsOptional() @Type(() => Number) @IsInt() @Min(1) passengers?: number; + @ApiProperty({ example: 2, description: 'Number of adults (5 years and above)' }) @Type(() => Number) @IsInt() @Min(1) adultCount: number; + @ApiPropertyOptional({ example: 1, description: 'Number of children (below 5 years)' }) @IsOptional() @Type(() => Number) @IsInt() @Min(0) childCount?: number; } export class FareQuoteDto { @@ -16,7 +18,9 @@ export class FareQuoteDto { enum: ['ECONOMY_REGULAR', 'ECONOMY_BED_LOWER', 'ECONOMY_BED_MIDDLE', 'ECONOMY_BED_UPPER', 'VIP_BED_LOWER', 'VIP_BED_UPPER'] }) @IsString() serviceClass: string; - @ApiPropertyOptional({ example: 1 }) @IsOptional() @Type(() => Number) @IsInt() @Min(1) passengerCount?: number; + @ApiProperty({ example: 2, description: 'Number of adults' }) @Type(() => Number) @IsInt() @Min(1) adultCount: number; + @ApiPropertyOptional({ example: 1, description: 'Number of children' }) @IsOptional() @Type(() => Number) @IsInt() @Min(0) childCount?: number; @ApiPropertyOptional({ example: 'WEEKEND15' }) @IsOptional() @IsString() promoCode?: string; @ApiPropertyOptional({ example: 450 }) @IsOptional() @Type(() => Number) @IsInt() loyaltyRedemptionPoints?: number; + @ApiPropertyOptional({ example: 'ETB', enum: ['ETB', 'DJF', 'USD'] }) @IsOptional() @IsEnum(Currency) displayCurrency?: Currency; } diff --git a/apps/edr-passenger-api/src/modules/search/search.module.ts b/apps/edr-passenger-api/src/modules/search/search.module.ts index e156d3cde..5228590fb 100644 --- a/apps/edr-passenger-api/src/modules/search/search.module.ts +++ b/apps/edr-passenger-api/src/modules/search/search.module.ts @@ -1,6 +1,12 @@ import { Module } from '@nestjs/common'; import { SearchController } from './search.controller'; import { SearchService } from './search.service'; +import { CurrencyModule } from '../currency/currency.module'; -@Module({ controllers: [SearchController], providers: [SearchService], exports: [SearchService] }) +@Module({ + imports: [CurrencyModule], + controllers: [SearchController], + providers: [SearchService], + exports: [SearchService] +}) export class SearchModule {} diff --git a/apps/edr-passenger-api/src/modules/search/search.service.ts b/apps/edr-passenger-api/src/modules/search/search.service.ts index bf709b6d8..7a6bef602 100644 --- a/apps/edr-passenger-api/src/modules/search/search.service.ts +++ b/apps/edr-passenger-api/src/modules/search/search.service.ts @@ -1,12 +1,17 @@ import { Injectable, NotFoundException } from '@nestjs/common'; import { PrismaService } from '../../common/prisma.service'; import { SearchTripsDto, FareQuoteDto } from './search.dto'; +import { CurrencyService } from '../currency/currency.service'; +import { Currency } from '@prisma/client'; const POINTS_TO_MINOR = 10; @Injectable() export class SearchService { - constructor(private prisma: PrismaService) {} + constructor( + private prisma: PrismaService, + private currencyService: CurrencyService, + ) {} async searchTrips(dto: SearchTripsDto) { const date = new Date(dto.date), nextDay = new Date(date.getTime() + 86400000); @@ -14,6 +19,9 @@ export class SearchService { where: { originStationId: dto.originStationId, destinationStationId: dto.destinationStationId, departureAt: { gte: date, lt: nextDay }, status: { in: ['SCHEDULED', 'BOARDING'] } }, include: { service: true, originStation: true, destinationStation: true, coaches: { include: { seats: true } } }, }); + + const totalPassengers = dto.adultCount + (dto.childCount || 0); + return trips.map((trip) => { const seatsByClass = (cls: string) => trip.coaches.filter((c) => c.serviceClass === cls).flatMap((c) => c.seats); const avail = (cls: string) => seatsByClass(cls).filter((s) => s.status === 'AVAILABLE').length; @@ -24,20 +32,12 @@ export class SearchService { destination: { id: trip.destinationStation.id, code: trip.destinationStation.code, name: trip.destinationStation.name, city: trip.destinationStation.city }, departureAt: trip.departureAt, arrivalAt: trip.arrivalAt, status: trip.status, availability: { - ECONOMY_REGULAR: avail('ECONOMY_REGULAR'), - ECONOMY_BED_LOWER: avail('ECONOMY_BED_LOWER'), - ECONOMY_BED_MIDDLE: avail('ECONOMY_BED_MIDDLE'), - ECONOMY_BED_UPPER: avail('ECONOMY_BED_UPPER'), - VIP_BED_LOWER: avail('VIP_BED_LOWER'), - VIP_BED_UPPER: avail('VIP_BED_UPPER') - }, - fares: { - ECONOMY_REGULAR: this.defaultFare('ECONOMY_REGULAR') / 100, - ECONOMY_BED_LOWER: this.defaultFare('ECONOMY_BED_LOWER') / 100, - ECONOMY_BED_MIDDLE: this.defaultFare('ECONOMY_BED_MIDDLE') / 100, - ECONOMY_BED_UPPER: this.defaultFare('ECONOMY_BED_UPPER') / 100, - VIP_BED_LOWER: this.defaultFare('VIP_BED_LOWER') / 100, - VIP_BED_UPPER: this.defaultFare('VIP_BED_UPPER') / 100 + ECONOMY_REGULAR: avail('ECONOMY_REGULAR') >= totalPassengers, + ECONOMY_BED_LOWER: avail('ECONOMY_BED_LOWER') >= totalPassengers, + ECONOMY_BED_MIDDLE: avail('ECONOMY_BED_MIDDLE') >= totalPassengers, + ECONOMY_BED_UPPER: avail('ECONOMY_BED_UPPER') >= totalPassengers, + VIP_BED_LOWER: avail('VIP_BED_LOWER') >= totalPassengers, + VIP_BED_UPPER: avail('VIP_BED_UPPER') >= totalPassengers }, }; }); @@ -46,26 +46,69 @@ export class SearchService { async getFareQuote(dto: FareQuoteDto) { const trip = await this.prisma.trip.findUnique({ where: { id: dto.tripId } }); if (!trip) throw new NotFoundException('Trip not found'); - const count = dto.passengerCount ?? 1; - const baseFareMinor = this.defaultFare(dto.serviceClass) * count; + + const adultCount = dto.adultCount; + const childCount = dto.childCount || 0; + + const baseFareMinor = this.defaultFare(dto.serviceClass); + + // Adult fare: 100% of base fare + const adultFareMinor = baseFareMinor * adultCount; + + // Child fare: First child free, subsequent children pay full fare + const paidChildrenCount = Math.max(0, childCount - 1); + const childFareMinor = baseFareMinor * paidChildrenCount; + + const totalBaseFareMinor = adultFareMinor + childFareMinor; + let discountMinor = 0; if (dto.promoCode) { const promo = await this.prisma.promotion.findUnique({ where: { code: dto.promoCode } }); - if (promo?.active && promo.validUntil > new Date()) discountMinor = promo.percentOff ? Math.round(baseFareMinor * promo.percentOff / 100) : (promo.amountOffMinor ?? 0); + if (promo?.active && promo.validUntil > new Date()) { + discountMinor = promo.percentOff ? Math.round(totalBaseFareMinor * promo.percentOff / 100) : (promo.amountOffMinor ?? 0); + } } + const loyaltyMinor = (dto.loyaltyRedemptionPoints ?? 0) * POINTS_TO_MINOR; - const taxesMinor = Math.round(baseFareMinor * 0.05); - return { tripId: dto.tripId, serviceClass: dto.serviceClass, passengerCount: count, baseFareMinor, discountMinor, loyaltyRedemptionMinor: loyaltyMinor, taxesFeesMinor: taxesMinor, totalMinor: Math.max(0, baseFareMinor - discountMinor - loyaltyMinor + taxesMinor), currency: 'ETB' }; + const taxesMinor = Math.round(totalBaseFareMinor * 0.05); + const totalMinor = Math.max(0, totalBaseFareMinor - discountMinor - loyaltyMinor + taxesMinor); + + const displayCurrency = dto.displayCurrency || Currency.ETB; + let displayTotalMinor = totalMinor; + + if (displayCurrency !== Currency.ETB) { + displayTotalMinor = await this.currencyService.convertAmount(totalMinor, Currency.ETB, displayCurrency); + } + + return { + tripId: dto.tripId, + serviceClass: dto.serviceClass, + adultCount, + childCount, + baseFareMinor, + adultFareMinor, + childFareMinor, + freeChildrenCount: Math.min(childCount, 1), + paidChildrenCount, + totalBaseFareMinor, + discountMinor, + loyaltyRedemptionMinor: loyaltyMinor, + taxesFeesMinor: taxesMinor, + totalMinor, + currency: 'ETB', + displayCurrency, + displayTotalMinor, + }; } private defaultFare(serviceClass: string): number { const fares: Record = { - ECONOMY_REGULAR: 35000, // 350 ETB - ECONOMY_BED_LOWER: 55000, // 550 ETB - ECONOMY_BED_MIDDLE: 50000, // 500 ETB - ECONOMY_BED_UPPER: 45000, // 450 ETB - VIP_BED_LOWER: 85000, // 850 ETB - VIP_BED_UPPER: 80000 // 800 ETB + ECONOMY_REGULAR: 35000, + ECONOMY_BED_LOWER: 55000, + ECONOMY_BED_MIDDLE: 50000, + ECONOMY_BED_UPPER: 45000, + VIP_BED_LOWER: 85000, + VIP_BED_UPPER: 80000 }; return fares[serviceClass] ?? 35000; } diff --git a/apps/edr-passenger-api/src/modules/verifayda/verifayda.module.ts b/apps/edr-passenger-api/src/modules/verifayda/verifayda.module.ts new file mode 100644 index 000000000..c14ba3f1f --- /dev/null +++ b/apps/edr-passenger-api/src/modules/verifayda/verifayda.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { VerifaydaService } from './verifayda.service'; +import { PrismaModule } from '../../common/prisma.module'; + +@Module({ + imports: [PrismaModule], + providers: [VerifaydaService], + exports: [VerifaydaService], +}) +export class VerifaydaModule {} diff --git a/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.ts b/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.ts new file mode 100644 index 000000000..d86ad98a2 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.ts @@ -0,0 +1,142 @@ +import { Injectable, Logger, BadRequestException } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { PrismaService } from '../../common/prisma.service'; +import axios, { AxiosInstance } from 'axios'; + +export interface VerifaydaPassengerData { + fullName: string; + dateOfBirth: Date; + gender?: string; + nationality?: string; + profileData?: Record; +} + +export interface VerifaydaVerificationResult { + verified: boolean; + passengerData?: VerifaydaPassengerData; + failureReason?: string; +} + +@Injectable() +export class VerifaydaService { + private readonly logger = new Logger(VerifaydaService.name); + private readonly httpClient: AxiosInstance; + private readonly enabled: boolean; + private readonly apiUrl: string; + private readonly apiKey: string; + + constructor( + private readonly config: ConfigService, + private readonly prisma: PrismaService, + ) { + this.enabled = this.config.get('VERIFAYDA_ENABLED', false); + this.apiUrl = this.config.get('VERIFAYDA_API_URL', 'https://api.verifayda.gov.et/v2'); + this.apiKey = this.config.get('VERIFAYDA_API_KEY', ''); + + this.httpClient = axios.create({ + baseURL: this.apiUrl, + timeout: 10000, + headers: { + 'Content-Type': 'application/json', + 'X-API-Key': this.apiKey, + }, + }); + } + + async verifyNationalId( + nationalId: string, + bookingId?: string, + ): Promise { + if (!this.enabled) { + this.logger.warn('Verifayda is disabled - skipping verification'); + return { + verified: false, + failureReason: 'Verifayda integration is disabled', + }; + } + + const requestPayload = { + nationalId, + requestedFields: ['fullName', 'dateOfBirth', 'gender', 'nationality'], + timestamp: new Date().toISOString(), + }; + + try { + this.logger.log(`Verifying national ID via Verifayda 2.0`); + + const response = await this.httpClient.post('/verify', requestPayload); + + const { data } = response; + + if (data.status === 'verified' && data.citizen) { + const passengerData: VerifaydaPassengerData = { + fullName: data.citizen.fullName, + dateOfBirth: new Date(data.citizen.dateOfBirth), + gender: data.citizen.gender, + nationality: data.citizen.nationality || 'Ethiopian', + profileData: data.citizen, + }; + + await this.prisma.verifaydaVerification.create({ + data: { + bookingId, + nationalId, + requestPayload, + responsePayload: data, + verified: true, + verifiedAt: new Date(), + }, + }); + + this.logger.log('Verifayda verification successful'); + + return { + verified: true, + passengerData, + }; + } else { + const failureReason = data.message || 'Verification failed'; + + await this.prisma.verifaydaVerification.create({ + data: { + bookingId, + nationalId, + requestPayload, + responsePayload: data, + verified: false, + failureReason, + }, + }); + + this.logger.warn(`Verifayda verification failed: ${failureReason}`); + + return { + verified: false, + failureReason, + }; + } + } catch (error: any) { + const errorMessage = error.response?.data?.message || error.message || 'Unknown error'; + + await this.prisma.verifaydaVerification.create({ + data: { + bookingId, + nationalId, + requestPayload, + verified: false, + failureReason: errorMessage, + }, + }); + + this.logger.error(`Verifayda API error: ${errorMessage}`); + + throw new BadRequestException( + `National ID verification failed: ${errorMessage}`, + ); + } + } + + isEnabled(): boolean { + return this.enabled; + } +} From 4234c2fdd5b6ac9adcf9a722ec93e24a103f94ea Mon Sep 17 00:00:00 2001 From: Stephanos A Date: Thu, 21 May 2026 14:31:07 +0300 Subject: [PATCH 20/38] Refactor seat class handling --- apps/edr-passenger-api/src/app.module.ts | 2 - .../common/filters/http-exception.filter.ts | 3 +- .../src/modules/bookings/bookings.service.ts | 12 ++---- .../src/modules/fleet/fleet.dto.ts | 10 +++-- .../src/modules/fleet/fleet.service.ts | 36 ++++++++++++----- .../modules/passengers/passengers.service.ts | 2 +- .../src/modules/schedules/schedules.dto.ts | 5 ++- .../modules/schedules/schedules.service.ts | 6 +-- .../seat-classes/seat-classes.controller.ts | 40 ------------------- .../modules/seat-classes/seat-classes.dto.ts | 24 ----------- .../seat-classes/seat-classes.module.ts | 6 --- .../seat-classes/seat-classes.service.ts | 40 ------------------- .../src/modules/seats/seats.service.ts | 4 +- .../segments/enhanced-seats.service.ts | 2 +- 14 files changed, 49 insertions(+), 143 deletions(-) delete mode 100644 apps/edr-passenger-api/src/modules/seat-classes/seat-classes.controller.ts delete mode 100644 apps/edr-passenger-api/src/modules/seat-classes/seat-classes.dto.ts delete mode 100644 apps/edr-passenger-api/src/modules/seat-classes/seat-classes.module.ts delete mode 100644 apps/edr-passenger-api/src/modules/seat-classes/seat-classes.service.ts diff --git a/apps/edr-passenger-api/src/app.module.ts b/apps/edr-passenger-api/src/app.module.ts index 7b2f460d3..e5c62a2bb 100644 --- a/apps/edr-passenger-api/src/app.module.ts +++ b/apps/edr-passenger-api/src/app.module.ts @@ -33,7 +33,6 @@ import { SegmentsModule } from './modules/segments/segments.module'; import { AgentsModule } from './modules/agents/agents.module'; import { ReportsModule } from './modules/reports/reports.module'; import { FraudModule } from './modules/fraud/fraud.module'; -import { SeatClassesModule } from './modules/seat-classes/seat-classes.module'; @Module({ imports: [ @@ -67,7 +66,6 @@ import { SeatClassesModule } from './modules/seat-classes/seat-classes.module'; AgentsModule, ReportsModule, FraudModule, - SeatClassesModule, ], }) export class AppModule implements NestModule { diff --git a/apps/edr-passenger-api/src/common/filters/http-exception.filter.ts b/apps/edr-passenger-api/src/common/filters/http-exception.filter.ts index d1f73bf71..f02ce4abf 100644 --- a/apps/edr-passenger-api/src/common/filters/http-exception.filter.ts +++ b/apps/edr-passenger-api/src/common/filters/http-exception.filter.ts @@ -34,8 +34,9 @@ export class HttpExceptionFilter implements ExceptionFilter { if (status >= 500) { this.logger.error( `${request.method} ${request.url} -> ${status}`, - (exception as Error)?.stack, + exception instanceof Error ? exception.stack : JSON.stringify(exception), ); + console.error('Full error details:', exception); } else { this.logger.warn(`${request.method} ${request.url} -> ${status} ${message}`); } diff --git a/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts b/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts index e44492f58..5d99717d4 100644 --- a/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts +++ b/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts @@ -92,7 +92,7 @@ export class BookingsService { } // Calculate fare with age-based pricing - const baseFareMinor = await this.getBaseFare(dto.tripId, dto.serviceClass, dto.seatClassId); + const baseFareMinor = await this.getBaseFare(dto.tripId, dto.serviceClass); const adultFareMinor = baseFareMinor * adultCount; const paidChildrenCount = Math.max(0, childCount - 1); const childFareMinor = baseFareMinor * paidChildrenCount; @@ -176,13 +176,7 @@ export class BookingsService { }; } - private async getBaseFare(tripId: string, serviceClass: string, seatClassId?: string): Promise { - if (seatClassId) { - const fareRule = await this.prisma.fareRule.findFirst({ - where: { tripId, seatClassId }, - }); - if (fareRule) return fareRule.baseFareMinor; - } + private async getBaseFare(tripId: string, serviceClass: string): Promise { const fareRule = await this.prisma.fareRule.findFirst({ where: { tripId, serviceClass: serviceClass as any }, }); @@ -214,7 +208,7 @@ export class BookingsService { fullName: bs.passengerName, category: bs.passengerCategory, verifaydaVerified: bs.verifaydaVerified, - seat: { number: bs.seat.label, coach: bs.seat.coach.label, class: bs.seat.coach.serviceClass, seatClassId: bs.seat.coach.seatClassId }, + seat: { number: bs.seat.label, coach: bs.seat.coach.label, class: bs.seat.coach.serviceClass }, })), payment: booking.paymentIntent ? { method: booking.paymentIntent.method, status: booking.paymentIntent.status } : undefined, }; diff --git a/apps/edr-passenger-api/src/modules/fleet/fleet.dto.ts b/apps/edr-passenger-api/src/modules/fleet/fleet.dto.ts index 5aeadeae7..8f3b12d4f 100644 --- a/apps/edr-passenger-api/src/modules/fleet/fleet.dto.ts +++ b/apps/edr-passenger-api/src/modules/fleet/fleet.dto.ts @@ -1,5 +1,6 @@ -import { IsString, IsInt, IsOptional } from 'class-validator'; +import { IsString, IsInt, IsOptional, IsEnum, IsArray } from 'class-validator'; import { ApiProperty, ApiPropertyOptional, PartialType, OmitType } from '@nestjs/swagger'; +import { ServiceClass } from '@prisma/client'; export class CreateTrainServiceDto { @ApiProperty({ example: '301' }) @IsString() number: string; @@ -9,7 +10,10 @@ export class CreateTrainServiceDto { export class CreateCoachDto { @ApiProperty({ example: 'trip-uuid' }) @IsString() tripId: string; @ApiProperty({ example: 'A' }) @IsString() label: string; - @ApiProperty({ example: 'seat-class-uuid' }) @IsString() seatClassId: string; + @ApiProperty({ enum: ServiceClass, example: 'ECONOMY_REGULAR' }) @IsEnum(ServiceClass) serviceClass: ServiceClass; + @ApiPropertyOptional({ example: 'seat-class-uuid' }) @IsOptional() @IsString() seatClassId?: string; + @ApiPropertyOptional({ example: 60 }) @IsOptional() @IsInt() capacity?: number; + @ApiPropertyOptional({ example: 1 }) @IsOptional() @IsInt() sequence?: number; } export class UpdateCoachDto extends PartialType(OmitType(CreateCoachDto, ['tripId'] as const)) {} @@ -17,5 +21,5 @@ export class UpdateCoachDto extends PartialType(OmitType(CreateCoachDto, ['tripI export class CreateSeatBatchDto { @ApiProperty({ example: 'coach-uuid' }) @IsString() coachId: string; @ApiProperty({ example: 10 }) @IsInt() rows: number; - @ApiProperty({ example: ['A', 'B', 'C', 'D'] }) cols: string[]; + @ApiProperty({ example: ['A', 'B', 'C', 'D'], type: [String] }) @IsArray() @IsString({ each: true }) cols: string[]; } diff --git a/apps/edr-passenger-api/src/modules/fleet/fleet.service.ts b/apps/edr-passenger-api/src/modules/fleet/fleet.service.ts index ef6969aaa..71894e807 100644 --- a/apps/edr-passenger-api/src/modules/fleet/fleet.service.ts +++ b/apps/edr-passenger-api/src/modules/fleet/fleet.service.ts @@ -12,26 +12,44 @@ export class FleetService { listCoaches(tripId?: string) { return this.prisma.coach.findMany({ where: tripId ? { tripId } : undefined, - include: { seatClass: { select: { id: true, name: true, basePrice: true } }, _count: { select: { seats: true } } }, + include: { _count: { select: { seats: true } } }, orderBy: { label: 'asc' }, }); } - createCoach(dto: CreateCoachDto) { return this.prisma.coach.create({ data: dto, include: { seatClass: { select: { id: true, name: true, basePrice: true } } } }); } + createCoach(dto: CreateCoachDto) { return this.prisma.coach.create({ data: dto }); } async updateCoach(id: string, dto: UpdateCoachDto) { const coach = await this.prisma.coach.findUnique({ where: { id } }); if (!coach) throw new NotFoundException('Coach not found'); - return this.prisma.coach.update({ where: { id }, data: dto, include: { seatClass: { select: { id: true, name: true, basePrice: true } } } }); + return this.prisma.coach.update({ where: { id }, data: dto }); } async createSeatBatch(dto: CreateSeatBatchDto) { - const coach = await this.prisma.coach.findUnique({ where: { id: dto.coachId } }); - if (!coach) throw new NotFoundException('Coach not found'); - const seats = []; - for (let row = 1; row <= dto.rows; row++) for (const col of dto.cols) seats.push({ coachId: dto.coachId, row, col, label: `${row}${col}` }); - await this.prisma.seat.createMany({ data: seats, skipDuplicates: true }); - return { created: seats.length }; + try { + const coach = await this.prisma.coach.findUnique({ where: { id: dto.coachId } }); + if (!coach) throw new NotFoundException('Coach not found'); + + const seats = []; + for (let row = 1; row <= dto.rows; row++) { + for (const col of dto.cols) { + const seatNumber = `${coach.label}${row}${col}`; + seats.push({ + coachId: dto.coachId, + row, + col, + label: `${row}${col}`, + seatNumber + }); + } + } + + await this.prisma.seat.createMany({ data: seats, skipDuplicates: true }); + return { created: seats.length }; + } catch (error) { + console.error('Error in createSeatBatch:', error); + throw error; + } } async getAnalytics() { diff --git a/apps/edr-passenger-api/src/modules/passengers/passengers.service.ts b/apps/edr-passenger-api/src/modules/passengers/passengers.service.ts index c1121fbed..54222751e 100644 --- a/apps/edr-passenger-api/src/modules/passengers/passengers.service.ts +++ b/apps/edr-passenger-api/src/modules/passengers/passengers.service.ts @@ -30,7 +30,7 @@ export class PassengersService { destination: { id: b.trip.destinationStation.id, name: b.trip.destinationStation.name, code: b.trip.destinationStation.code, city: b.trip.destinationStation.city }, departureAt: b.trip.departureAt, }, - passengers: b.seats.map((bs) => ({ fullName: bs.passengerName, seat: { number: bs.seat.label, coach: bs.seat.coach.label, class: bs.seat.coach.seatClassId } })), + passengers: b.seats.map((bs) => ({ fullName: bs.passengerName, seat: { number: bs.seat.label, coach: bs.seat.coach.label, class: bs.seat.coach.serviceClass } })), })), }; } diff --git a/apps/edr-passenger-api/src/modules/schedules/schedules.dto.ts b/apps/edr-passenger-api/src/modules/schedules/schedules.dto.ts index b00aaa906..3d1401cfe 100644 --- a/apps/edr-passenger-api/src/modules/schedules/schedules.dto.ts +++ b/apps/edr-passenger-api/src/modules/schedules/schedules.dto.ts @@ -1,5 +1,6 @@ -import { IsString, IsDateString, IsInt, IsOptional } from 'class-validator'; +import { IsString, IsDateString, IsInt, IsOptional, IsEnum } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +import { ServiceClass } from '@prisma/client'; export class CreateTripDto { @ApiProperty() @IsString() serviceId: string; @@ -13,7 +14,7 @@ export class CreateTripDto { export class CreateFareRuleDto { @ApiPropertyOptional() @IsOptional() @IsString() tripId?: string; @ApiPropertyOptional() @IsOptional() @IsString() route?: string; - @ApiProperty({ example: 'seat-class-uuid' }) @IsString() seatClassId: string; + @ApiProperty({ enum: ServiceClass, example: 'ECONOMY_REGULAR' }) @IsEnum(ServiceClass) serviceClass: ServiceClass; @ApiProperty({ example: 45000 }) @IsInt() baseFareMinor: number; @ApiProperty({ example: '2026-01-01T00:00:00Z' }) @IsDateString() validFrom: string; @ApiPropertyOptional() @IsOptional() @IsDateString() validUntil?: string; diff --git a/apps/edr-passenger-api/src/modules/schedules/schedules.service.ts b/apps/edr-passenger-api/src/modules/schedules/schedules.service.ts index 062e7f0df..a97b54fd6 100644 --- a/apps/edr-passenger-api/src/modules/schedules/schedules.service.ts +++ b/apps/edr-passenger-api/src/modules/schedules/schedules.service.ts @@ -26,14 +26,14 @@ export class SchedulesService { return this.prisma.fareRule.create({ data: { ...dto, validFrom: new Date(dto.validFrom), validUntil: dto.validUntil ? new Date(dto.validUntil) : null } }); } - async getFare(tripId: string, seatClassId: string) { + async getFare(tripId: string, serviceClass: string) { const trip = await this.prisma.trip.findUnique({ where: { id: tripId }, include: { originStation: true, destinationStation: true } }); if (!trip) throw new NotFoundException('Trip not found'); const route = `${trip.originStation.code}-${trip.destinationStation.code}`; const rule = await this.prisma.fareRule.findFirst({ - where: { seatClassId, validFrom: { lte: new Date() }, OR: [{ tripId }, { route }, { tripId: null, route: null }], AND: [{ OR: [{ validUntil: null }, { validUntil: { gte: new Date() } }] }] }, + where: { serviceClass: serviceClass as any, validFrom: { lte: new Date() }, OR: [{ tripId }, { route }, { tripId: null, route: null }], AND: [{ OR: [{ validUntil: null }, { validUntil: { gte: new Date() } }] }] }, orderBy: { validFrom: 'desc' }, }); - return rule ?? { baseFareMinor: 45000, currency: 'ETB', seatClassId }; + return rule ?? { baseFareMinor: 45000, currency: 'ETB', serviceClass }; } } diff --git a/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.controller.ts b/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.controller.ts deleted file mode 100644 index 945834ac0..000000000 --- a/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.controller.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Body, Controller, Get, Param, Patch, Post, UseGuards } from '@nestjs/common'; -import { ApiTags, ApiOperation, ApiBearerAuth, ApiParam, ApiResponse, ApiBody } from '@nestjs/swagger'; -import { SeatClassesService } from './seat-classes.service'; -import { CreateSeatClassDto, UpdateSeatClassDto } from './seat-classes.dto'; -import { JwtGuard } from '../../common/jwt.guard'; - -@ApiTags('Seat Classes') -@Controller('seat-classes') -export class SeatClassesController { - constructor(private service: SeatClassesService) {} - - @Get() - @ApiOperation({ summary: 'List all seat classes' }) - @ApiResponse({ status: 200, description: 'Returns all seat classes with their coaches' }) - listSeatClasses() { return this.service.listSeatClasses(); } - - @Get(':id') - @ApiOperation({ summary: 'Get a seat class by ID' }) - @ApiParam({ name: 'id', description: 'Seat class UUID' }) - @ApiResponse({ status: 200, description: 'Returns seat class with its coaches' }) - @ApiResponse({ status: 404, description: 'Seat class not found' }) - getSeatClass(@Param('id') id: string) { return this.service.getSeatClass(id); } - - @Post() - @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') - @ApiOperation({ summary: 'Create a seat class' }) - @ApiBody({ type: CreateSeatClassDto }) - @ApiResponse({ status: 201, description: 'Seat class created' }) - @ApiResponse({ status: 409, description: 'Seat class name already exists' }) - createSeatClass(@Body() dto: CreateSeatClassDto) { return this.service.createSeatClass(dto); } - - @Patch(':id') - @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') - @ApiOperation({ summary: 'Update a seat class' }) - @ApiParam({ name: 'id', description: 'Seat class UUID' }) - @ApiBody({ type: UpdateSeatClassDto }) - @ApiResponse({ status: 200, description: 'Seat class updated' }) - @ApiResponse({ status: 404, description: 'Seat class not found' }) - updateSeatClass(@Param('id') id: string, @Body() dto: UpdateSeatClassDto) { return this.service.updateSeatClass(id, dto); } -} diff --git a/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.dto.ts b/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.dto.ts deleted file mode 100644 index d12fe0fb6..000000000 --- a/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.dto.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { IsString, IsInt, IsBoolean, IsOptional } from 'class-validator'; -import { ApiProperty, ApiPropertyOptional, PartialType } from '@nestjs/swagger'; - -export class CreateSeatClassDto { - @ApiProperty({ example: 'Economy Seat' }) - @IsString() - name: string; - - @ApiPropertyOptional({ example: 'Standard economy seating' }) - @IsOptional() - @IsString() - description?: string; - - @ApiProperty({ example: 45000, description: 'Base price in minor currency units' }) - @IsInt() - basePrice: number; - - @ApiPropertyOptional({ example: true }) - @IsOptional() - @IsBoolean() - isActive?: boolean; -} - -export class UpdateSeatClassDto extends PartialType(CreateSeatClassDto) {} diff --git a/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.module.ts b/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.module.ts deleted file mode 100644 index a7e8648e1..000000000 --- a/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.module.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Module } from '@nestjs/common'; -import { SeatClassesController } from './seat-classes.controller'; -import { SeatClassesService } from './seat-classes.service'; - -@Module({ controllers: [SeatClassesController], providers: [SeatClassesService], exports: [SeatClassesService] }) -export class SeatClassesModule {} diff --git a/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.service.ts b/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.service.ts deleted file mode 100644 index 2e3998651..000000000 --- a/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.service.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Injectable, NotFoundException, ConflictException } from '@nestjs/common'; -import { PrismaService } from '../../common/prisma.service'; -import { CreateSeatClassDto, UpdateSeatClassDto } from './seat-classes.dto'; - -@Injectable() -export class SeatClassesService { - constructor(private prisma: PrismaService) {} - - private readonly coachInclude = { - coaches: { - select: { id: true, label: true, tripId: true, _count: { select: { seats: true } } }, - orderBy: { label: 'asc' as const }, - }, - }; - - listSeatClasses() { - return this.prisma.seatClass.findMany({ orderBy: { createdAt: 'asc' }, include: this.coachInclude }); - } - - async getSeatClass(id: string) { - const sc = await this.prisma.seatClass.findUnique({ where: { id }, include: this.coachInclude }); - if (!sc) throw new NotFoundException('SeatClass not found'); - return sc; - } - - async createSeatClass(dto: CreateSeatClassDto) { - try { - return await this.prisma.seatClass.create({ data: dto }); - } catch (e: any) { - if (e.code === 'P2002') throw new ConflictException(`Seat class "${dto.name}" already exists`); - throw e; - } - } - - async updateSeatClass(id: string, dto: UpdateSeatClassDto) { - const sc = await this.prisma.seatClass.findUnique({ where: { id } }); - if (!sc) throw new NotFoundException('SeatClass not found'); - return this.prisma.seatClass.update({ where: { id }, data: dto, include: this.coachInclude }); - } -} diff --git a/apps/edr-passenger-api/src/modules/seats/seats.service.ts b/apps/edr-passenger-api/src/modules/seats/seats.service.ts index 0edef4ddf..3593c38d1 100644 --- a/apps/edr-passenger-api/src/modules/seats/seats.service.ts +++ b/apps/edr-passenger-api/src/modules/seats/seats.service.ts @@ -9,12 +9,12 @@ export class SeatsService { // ── Seat Map ────────────────────────────────────────────────────────────── async getSeatMap(tripId: string, coachId?: string) { - const coaches = await this.prisma.coach.findMany({ where: { tripId, ...(coachId ? { id: coachId } : {}) }, include: { seatClass: true, seats: { orderBy: [{ row: 'asc' }, { col: 'asc' }] } } }); + const coaches = await this.prisma.coach.findMany({ where: { tripId, ...(coachId ? { id: coachId } : {}) }, include: { seats: { orderBy: [{ row: 'asc' }, { col: 'asc' }] } } }); return { coaches: coaches.map((coach) => ({ id: coach.id, name: `Coach ${coach.label}`, - seatClass: { id: coach.seatClass.id, name: coach.seatClass.name, basePrice: coach.seatClass.basePrice }, + serviceClass: coach.serviceClass, seats: coach.seats.map((s) => ({ id: s.id, number: s.label, status: s.status, kind: s.kind })), })), }; diff --git a/apps/edr-passenger-api/src/modules/segments/enhanced-seats.service.ts b/apps/edr-passenger-api/src/modules/segments/enhanced-seats.service.ts index e7213cf6c..57b6f2d2f 100644 --- a/apps/edr-passenger-api/src/modules/segments/enhanced-seats.service.ts +++ b/apps/edr-passenger-api/src/modules/segments/enhanced-seats.service.ts @@ -353,7 +353,7 @@ export class EnhancedSeatsService { id: seat.id, label: seat.label, coach: coach.label, - serviceClass: coach.seatClassId, + serviceClass: coach.serviceClass, row: seat.row, col: seat.col }); From 95e03e9b76ca860ee193266f1a119e2125d182b8 Mon Sep 17 00:00:00 2001 From: Roba Boru Date: Fri, 22 May 2026 14:47:38 +0300 Subject: [PATCH 21/38] Refactor business logic for train,schedule,coach,seat and search modules --- apps/edr-passenger-api/.env.example | 2 +- apps/edr-passenger-api/REFACTORING_SUMMARY.md | 199 +++ .../migration.sql | 46 +- .../migration.sql | 3 +- .../migration.sql | 1312 ----------------- apps/edr-passenger-api/prisma/schema.prisma | 191 +-- apps/edr-passenger-api/prisma/seed.ts | 285 ++-- apps/edr-passenger-api/src/app.module.ts | 2 + apps/edr-passenger-api/src/main.ts | 5 +- .../src/modules/agents/agents.dto.ts | 2 +- .../src/modules/agents/agents.service.ts | 6 +- .../src/modules/bookings/bookings.dto.ts | 14 +- .../src/modules/bookings/bookings.service.ts | 189 +-- .../modules/dashboard/dashboard.service.ts | 16 +- .../src/modules/fleet/fleet.controller.ts | 89 +- .../src/modules/fleet/fleet.dto.ts | 53 +- .../src/modules/fleet/fleet.service.ts | 272 +++- .../src/modules/live/live.controller.ts | 6 +- .../src/modules/live/live.service.ts | 30 +- .../modules/passengers/passengers.service.ts | 12 +- .../src/modules/payments/payments.e2e-spec.ts | 173 +-- .../modules/payments/payments.service.spec.ts | 4 +- .../src/modules/reports/reports.service.ts | 34 +- .../modules/schedules/routes.controller.ts | 88 ++ .../src/modules/schedules/routes.dto.ts | 44 + .../src/modules/schedules/routes.service.ts | 197 +++ .../modules/schedules/schedules.controller.ts | 105 +- .../src/modules/schedules/schedules.dto.ts | 75 +- .../src/modules/schedules/schedules.module.ts | 8 +- .../modules/schedules/schedules.service.ts | 175 ++- .../src/modules/search/search.controller.ts | 42 +- .../src/modules/search/search.dto.ts | 56 +- .../src/modules/search/search.service.ts | 298 +++- .../seat-classes/seat-classes.controller.ts | 40 + .../modules/seat-classes/seat-classes.dto.ts | 24 + .../seat-classes/seat-classes.module.ts | 6 + .../seat-classes/seat-classes.service.ts | 40 + .../src/modules/seats/seats.controller.ts | 20 +- .../src/modules/seats/seats.dto.ts | 2 +- .../src/modules/seats/seats.service.ts | 47 +- .../modules/segments/booking-flow-example.ts | 270 +--- .../segments/enhanced-seats.service.ts | 358 ++--- .../modules/segments/segments.controller.ts | 16 +- .../src/modules/segments/segments.dto.ts | 67 +- .../src/modules/segments/segments.service.ts | 148 +- .../modules/segments/trip-progress.service.ts | 34 +- .../src/modules/tickets/tickets.controller.ts | 4 +- .../src/modules/tickets/tickets.service.ts | 10 +- 48 files changed, 2254 insertions(+), 2865 deletions(-) create mode 100644 apps/edr-passenger-api/REFACTORING_SUMMARY.md delete mode 100644 apps/edr-passenger-api/prisma/migrations/20260521053749_initial_migration/migration.sql create mode 100644 apps/edr-passenger-api/src/modules/schedules/routes.controller.ts create mode 100644 apps/edr-passenger-api/src/modules/schedules/routes.dto.ts create mode 100644 apps/edr-passenger-api/src/modules/schedules/routes.service.ts create mode 100644 apps/edr-passenger-api/src/modules/seat-classes/seat-classes.controller.ts create mode 100644 apps/edr-passenger-api/src/modules/seat-classes/seat-classes.dto.ts create mode 100644 apps/edr-passenger-api/src/modules/seat-classes/seat-classes.module.ts create mode 100644 apps/edr-passenger-api/src/modules/seat-classes/seat-classes.service.ts diff --git a/apps/edr-passenger-api/.env.example b/apps/edr-passenger-api/.env.example index 3b788ad3e..d0e64691d 100644 --- a/apps/edr-passenger-api/.env.example +++ b/apps/edr-passenger-api/.env.example @@ -3,7 +3,7 @@ NODE_ENV=development PORT=4000 # Database (Prisma) -DATABASE_URL=postgresql://edr:edr_secret@localhost:5432/edr_passenger +DATABASE_URL=postgresql://edr:edr_secret@localhost:5432/edr_passenger?schema=edr_passenger # CORS FRONTEND_URL=http://localhost:3000 diff --git a/apps/edr-passenger-api/REFACTORING_SUMMARY.md b/apps/edr-passenger-api/REFACTORING_SUMMARY.md new file mode 100644 index 000000000..30648fa3f --- /dev/null +++ b/apps/edr-passenger-api/REFACTORING_SUMMARY.md @@ -0,0 +1,199 @@ +# Train Reservation System Refactoring - Complete + +## ✅ Refactoring Summary + +Successfully refactored the train reservation system from an incorrect tight-coupling model to a flexible, realistic railway architecture. + +--- + +## 🔄 Architecture Changes + +### Before (Incorrect) +``` +TrainService → Trip → Coach → Seat +``` +- Coaches were permanently bound to specific trips +- No reusability of physical coaches +- Inflexible train composition + +### After (Correct) +``` +Train → TrainSchedule ↔ CoachAssignment ↔ Coach → Seat +``` +- **Train**: Logical service entity (e.g., "Express 301") +- **TrainSchedule**: Specific journey with date/time +- **Coach**: Physical reusable railway carriage +- **CoachAssignment**: Join table linking schedules to coaches +- **Seat**: Belongs strictly to physical coach + +--- + +## 📋 Files Modified + +### Schema & Database +- ✅ `prisma/schema.prisma` - Complete entity redesign +- ✅ `prisma/seed.ts` - Rewritten for new architecture + +### DTOs +- ✅ `fleet/fleet.dto.ts` - New Train/Coach/Assignment DTOs +- ✅ `schedules/schedules.dto.ts` - TrainSchedule DTOs +- ✅ `bookings/bookings.dto.ts` - scheduleId instead of tripId + +### Services +- ✅ `fleet/fleet.service.ts` - Physical coach management +- ✅ `fleet/fleet.controller.ts` - New endpoints +- ✅ `schedules/schedules.service.ts` - TrainSchedule operations +- ✅ `schedules/schedules.controller.ts` - Updated routes +- ✅ `bookings/bookings.service.ts` - scheduleId references +- ✅ `seats/seats.service.ts` - CoachAssignment queries +- ✅ `search/search.service.ts` - TrainSchedule search +- ✅ `segments/segments.service.ts` - scheduleId throughout +- ✅ `segments/enhanced-seats.service.ts` - Fixed references +- ✅ `passengers/passengers.service.ts` - schedule.train +- ✅ `live/live.service.ts` - TrainSchedule live tracking +- ✅ `live/live.controller.ts` - scheduleId routes +- ✅ `dashboard/dashboard.service.ts` - schedule references +- ✅ `reports/reports.service.ts` - Occupancy with assignments + +--- + +## 🗄️ Database Schema Changes + +### New Models +```prisma +model Train { + id String @id @default(uuid()) + number String @unique + name String + schedules TrainSchedule[] +} + +model TrainSchedule { + id String @id @default(uuid()) + trainId String + departureAt DateTime + train Train @relation(...) + coachAssignments CoachAssignment[] +} + +model Coach { + id String @id @default(uuid()) + coachNumber String @unique // Physical identifier + label String + seatClassId String + mode String // 'seat', 'bed', 'convertible' + totalUnits Int + seats Seat[] + assignments CoachAssignment[] +} + +model CoachAssignment { + id String @id @default(uuid()) + scheduleId String + coachId String + positionNumber Int + schedule TrainSchedule @relation(...) + coach Coach @relation(...) +} +``` + +### Renamed Models +- `TrainService` → `Train` +- `Trip` → `TrainSchedule` +- `TripStopTime.tripId` → `scheduleId` +- `TripLiveStatus.tripId` → `scheduleId` +- `Booking.tripId` → `scheduleId` +- `SeatHold.tripId` → `scheduleId` +- `MenuItem.tripId` → `scheduleId` +- `JourneySegment.tripId` → `scheduleId` + +--- + +## 🎯 Key Benefits + +1. **Reusability**: Physical coaches can be assigned to different schedules +2. **Flexibility**: Train composition can change per schedule +3. **Realistic**: Matches real-world railway operations +4. **Maintainability**: Clear separation of logical vs physical entities +5. **Scalability**: Easy to add/remove coaches from schedules + +--- + +## 🚂 Example Usage + +### Creating a Physical Coach +```typescript +const coach = await prisma.coach.create({ + data: { + coachNumber: 'C-A1', + label: 'A', + seatClassId: economyClassId, + mode: 'seat', + totalUnits: 60, + }, +}); +``` + +### Assigning Coach to Schedule +```typescript +await prisma.coachAssignment.create({ + data: { + scheduleId: schedule1.id, + coachId: coach.id, + positionNumber: 1, + }, +}); +``` + +### Querying Schedule with Coaches +```typescript +const schedule = await prisma.trainSchedule.findUnique({ + where: { id: scheduleId }, + include: { + train: true, + coachAssignments: { + include: { + coach: { + include: { seats: true, seatClass: true }, + }, + }, + orderBy: { positionNumber: 'asc' }, + }, + }, +}); +``` + +--- + +## 🔑 Seed Data + +- **2 Trains**: Express 301, Express 302 +- **6 Physical Coaches**: C-A1, C-B1, C-C1, C-A2, C-B2, C-C2 +- **4 Train Schedules**: With flexible coach assignments +- **3 Seat Classes**: Economy Regular, Economy Bed, VIP Bed +- **Users**: Admin, Passenger (with wallet/loyalty), Agent + +--- + +## ✨ Migration Status + +✅ Schema pushed to database successfully +✅ Seed data populated +✅ All services updated +✅ All controllers updated +✅ All DTOs updated + +--- + +## 📝 Notes + +- Coaches are now reusable physical entities +- Same coach can serve different schedules at different times +- Seats belong to coaches, not schedules +- CoachAssignment provides the many-to-many relationship +- All references to `tripId` changed to `scheduleId` +- All references to `service` changed to `train` + +--- + +**Refactoring completed successfully! 🎉** diff --git a/apps/edr-passenger-api/prisma/migrations/20260516000000_seat_class_model/migration.sql b/apps/edr-passenger-api/prisma/migrations/20260516000000_seat_class_model/migration.sql index 09761e476..5ff34f87e 100644 --- a/apps/edr-passenger-api/prisma/migrations/20260516000000_seat_class_model/migration.sql +++ b/apps/edr-passenger-api/prisma/migrations/20260516000000_seat_class_model/migration.sql @@ -1,52 +1,14 @@ --- CreateTable -CREATE TABLE "SeatClass" ( +-- CreateTable SeatClass (runs before initial migration) +CREATE TABLE IF NOT EXISTS "SeatClass" ( "id" TEXT NOT NULL, "name" TEXT NOT NULL, "description" TEXT, "basePrice" INTEGER NOT NULL, "isActive" BOOLEAN NOT NULL DEFAULT true, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT NOW(), CONSTRAINT "SeatClass_pkey" PRIMARY KEY ("id") ); -CREATE UNIQUE INDEX "SeatClass_name_key" ON "SeatClass"("name"); - --- Seed default seat classes so existing coaches can be migrated -INSERT INTO "SeatClass" ("id", "name", "description", "basePrice", "isActive", "createdAt", "updatedAt") -VALUES - ('sc_economy', 'Economy Seat', 'Standard economy seating', 45000, true, NOW(), NOW()), - ('sc_business', 'Business Seat','Comfortable business class', 90000, true, NOW(), NOW()), - ('sc_first', 'VIP Bed', 'First class VIP bed', 135000, true, NOW(), NOW()); - --- Add seatClassId column to Coach (nullable first for migration safety) -ALTER TABLE "Coach" ADD COLUMN "seatClassId" TEXT; - --- Map existing serviceClass enum values to new SeatClass ids -UPDATE "Coach" SET "seatClassId" = 'sc_economy' WHERE "serviceClass" = 'ECONOMY'; -UPDATE "Coach" SET "seatClassId" = 'sc_business' WHERE "serviceClass" = 'BUSINESS'; -UPDATE "Coach" SET "seatClassId" = 'sc_first' WHERE "serviceClass" = 'FIRST'; - --- Make seatClassId NOT NULL now that all rows are populated -ALTER TABLE "Coach" ALTER COLUMN "seatClassId" SET NOT NULL; - --- Drop old serviceClass column -ALTER TABLE "Coach" DROP COLUMN "serviceClass"; - --- Add seatClassId to FareRule -ALTER TABLE "FareRule" ADD COLUMN "seatClassId" TEXT; - -UPDATE "FareRule" SET "seatClassId" = 'sc_economy' WHERE "serviceClass" = 'ECONOMY'; -UPDATE "FareRule" SET "seatClassId" = 'sc_business' WHERE "serviceClass" = 'BUSINESS'; -UPDATE "FareRule" SET "seatClassId" = 'sc_first' WHERE "serviceClass" = 'FIRST'; - -ALTER TABLE "FareRule" ALTER COLUMN "seatClassId" SET NOT NULL; -ALTER TABLE "FareRule" DROP COLUMN "serviceClass"; - --- AddForeignKey -ALTER TABLE "Coach" ADD CONSTRAINT "Coach_seatClassId_fkey" - FOREIGN KEY ("seatClassId") REFERENCES "SeatClass"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - -ALTER TABLE "FareRule" ADD CONSTRAINT "FareRule_seatClassId_fkey" - FOREIGN KEY ("seatClassId") REFERENCES "SeatClass"("id") ON DELETE RESTRICT ON UPDATE CASCADE; +CREATE UNIQUE INDEX IF NOT EXISTS "SeatClass_name_key" ON "SeatClass"("name"); diff --git a/apps/edr-passenger-api/prisma/migrations/20260516000001_seat_class_updated_at_default/migration.sql b/apps/edr-passenger-api/prisma/migrations/20260516000001_seat_class_updated_at_default/migration.sql index e1dc713c8..8f938d14e 100644 --- a/apps/edr-passenger-api/prisma/migrations/20260516000001_seat_class_updated_at_default/migration.sql +++ b/apps/edr-passenger-api/prisma/migrations/20260516000001_seat_class_updated_at_default/migration.sql @@ -1 +1,2 @@ -ALTER TABLE "SeatClass" ALTER COLUMN "updatedAt" SET DEFAULT NOW(); +-- updatedAt default already set in initial migration, no-op +SELECT 1; diff --git a/apps/edr-passenger-api/prisma/migrations/20260521053749_initial_migration/migration.sql b/apps/edr-passenger-api/prisma/migrations/20260521053749_initial_migration/migration.sql deleted file mode 100644 index f82c1f2a2..000000000 --- a/apps/edr-passenger-api/prisma/migrations/20260521053749_initial_migration/migration.sql +++ /dev/null @@ -1,1312 +0,0 @@ --- CreateEnum -CREATE TYPE "UserRole" AS ENUM ('PASSENGER', 'AGENT', 'SUPERVISOR', 'ADMIN', 'STAFF'); - --- CreateEnum -CREATE TYPE "TripStatus" AS ENUM ('SCHEDULED', 'BOARDING', 'EN_ROUTE', 'ARRIVED', 'CANCELLED', 'DELAYED'); - --- CreateEnum -CREATE TYPE "SeatKind" AS ENUM ('STANDARD', 'PREMIUM', 'ACCESSIBLE'); - --- CreateEnum -CREATE TYPE "SeatStatus" AS ENUM ('AVAILABLE', 'HELD', 'BOOKED', 'BLOCKED'); - --- CreateEnum -CREATE TYPE "ServiceClass" AS ENUM ('ECONOMY_REGULAR', 'ECONOMY_BED_LOWER', 'ECONOMY_BED_MIDDLE', 'ECONOMY_BED_UPPER', 'VIP_BED_LOWER', 'VIP_BED_UPPER'); - --- CreateEnum -CREATE TYPE "PassengerCategory" AS ENUM ('ADULT', 'CHILD'); - --- CreateEnum -CREATE TYPE "IdDocumentType" AS ENUM ('NATIONAL_ID', 'PASSPORT', 'DRIVING_LICENSE', 'OTHER'); - --- CreateEnum -CREATE TYPE "Currency" AS ENUM ('ETB', 'DJF', 'USD'); - --- CreateEnum -CREATE TYPE "BookingStatus" AS ENUM ('DRAFT', 'PENDING_PAYMENT', 'CONFIRMED', 'CANCELLED', 'COMPLETED', 'NO_SHOW', 'REFUNDED'); - --- CreateEnum -CREATE TYPE "PaymentMethodType" AS ENUM ('TELEBIRR', 'CBE_BIRR', 'EBIRR', 'CARD', 'WALLET'); - --- CreateEnum -CREATE TYPE "PaymentIntentStatus" AS ENUM ('REQUIRES_ACTION', 'PROCESSING', 'SUCCEEDED', 'FAILED', 'CANCELLED', 'REFUNDED'); - --- CreateEnum -CREATE TYPE "WalletLedgerType" AS ENUM ('CREDIT', 'DEBIT'); - --- CreateEnum -CREATE TYPE "NotificationCategory" AS ENUM ('BOOKING', 'PAYMENT', 'DISRUPTION', 'PROMOTION', 'SYSTEM'); - --- CreateEnum -CREATE TYPE "StopStatus" AS ENUM ('COMPLETED', 'APPROACHING', 'CURRENT', 'UPCOMING'); - --- CreateEnum -CREATE TYPE "SupportConversationStatus" AS ENUM ('OPEN', 'RESOLVED', 'CLOSED'); - --- CreateEnum -CREATE TYPE "SupportSender" AS ENUM ('USER', 'BOT', 'AGENT'); - --- CreateEnum -CREATE TYPE "LoyaltyTier" AS ENUM ('BRONZE', 'SILVER', 'GOLD', 'PLATINUM'); - --- CreateEnum -CREATE TYPE "LoyaltyLedgerReason" AS ENUM ('TRIP_COMPLETED', 'REWARD_REDEEMED', 'PROMO_BONUS', 'MANUAL_ADJUSTMENT', 'EXPIRY'); - --- CreateEnum -CREATE TYPE "FoodOrderStatus" AS ENUM ('PENDING', 'PREPARING', 'READY', 'DELIVERED', 'CANCELLED'); - --- CreateEnum -CREATE TYPE "DevicePlatform" AS ENUM ('IOS', 'ANDROID', 'WEB'); - --- CreateTable -CREATE TABLE "User" ( - "id" TEXT NOT NULL, - "email" TEXT NOT NULL, - "phone" TEXT NOT NULL, - "fullName" TEXT NOT NULL, - "passwordHash" TEXT NOT NULL, - "role" "UserRole" NOT NULL DEFAULT 'PASSENGER', - "nationality" TEXT, - "nationalityCode" TEXT, - "passportNumber" TEXT, - "nationalId" TEXT, - "failedLoginAttempts" INTEGER NOT NULL DEFAULT 0, - "lockedUntil" TIMESTAMP(3), - "blockedUntil" TIMESTAMP(3), - "lastLoginAt" TIMESTAMP(3), - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "User_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Session" ( - "id" TEXT NOT NULL, - "userId" TEXT NOT NULL, - "token" TEXT NOT NULL, - "expiresAt" TIMESTAMP(3) NOT NULL, - "ipAddress" TEXT, - "userAgent" TEXT, - "lastActivityAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "Session_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Passenger" ( - "id" TEXT NOT NULL, - "userId" TEXT NOT NULL, - "defaultTravelerProfileId" TEXT, - "preferredLanguage" TEXT, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "Passenger_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "TravelerProfile" ( - "id" TEXT NOT NULL, - "passengerId" TEXT NOT NULL, - "fullName" TEXT NOT NULL, - "relationship" TEXT NOT NULL, - "dateOfBirth" TIMESTAMP(3), - "nationalId" TEXT, - "notes" TEXT, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "TravelerProfile_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Station" ( - "id" TEXT NOT NULL, - "code" TEXT NOT NULL, - "name" TEXT NOT NULL, - "city" TEXT NOT NULL, - "countryCode" TEXT, - "isOperational" BOOLEAN NOT NULL DEFAULT true, - "timezone" TEXT NOT NULL DEFAULT 'Africa/Addis_Ababa', - "lat" DECIMAL(9,6) NOT NULL, - "lng" DECIMAL(9,6) NOT NULL, - - CONSTRAINT "Station_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "TrainService" ( - "id" TEXT NOT NULL, - "number" TEXT NOT NULL, - "name" TEXT NOT NULL, - "operatorId" TEXT NOT NULL DEFAULT 'op_edr', - "operatorName" TEXT, - - CONSTRAINT "TrainService_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Trip" ( - "id" TEXT NOT NULL, - "serviceId" TEXT NOT NULL, - "routeId" TEXT, - "originStationId" TEXT NOT NULL, - "destinationStationId" TEXT NOT NULL, - "departureAt" TIMESTAMP(3) NOT NULL, - "arrivalAt" TIMESTAMP(3) NOT NULL, - "durationMinutes" INTEGER NOT NULL, - "status" "TripStatus" NOT NULL DEFAULT 'SCHEDULED', - "stopsCount" INTEGER NOT NULL DEFAULT 0, - "reservedCount" INTEGER NOT NULL DEFAULT 0, - "onTimePercent" INTEGER NOT NULL DEFAULT 100, - "carbonRating" TEXT NOT NULL DEFAULT 'A', - "notes" TEXT, - - CONSTRAINT "Trip_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "TripStopTime" ( - "id" TEXT NOT NULL, - "tripId" TEXT NOT NULL, - "stationId" TEXT NOT NULL, - "sequence" INTEGER NOT NULL, - "plannedArrivalAt" TIMESTAMP(3), - "plannedDepartureAt" TIMESTAMP(3), - "actualArrivalAt" TIMESTAMP(3), - "status" "StopStatus" NOT NULL DEFAULT 'UPCOMING', - - CONSTRAINT "TripStopTime_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "TripLiveStatus" ( - "id" TEXT NOT NULL, - "tripId" TEXT NOT NULL, - "state" TEXT NOT NULL, - "currentLocationLabel" TEXT, - "progressPercent" INTEGER NOT NULL DEFAULT 0, - "delayMinutes" INTEGER NOT NULL DEFAULT 0, - "currentSpeedKph" INTEGER, - "platformLabel" TEXT, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "TripLiveStatus_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Coach" ( - "id" TEXT NOT NULL, - "tripId" TEXT NOT NULL, - "label" TEXT NOT NULL, - "serviceClass" "ServiceClass" NOT NULL, - "capacity" INTEGER, - "sequence" INTEGER, - "coachType" TEXT, - "amenities" JSONB, - - CONSTRAINT "Coach_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Seat" ( - "id" TEXT NOT NULL, - "coachId" TEXT NOT NULL, - "row" INTEGER NOT NULL, - "col" TEXT NOT NULL, - "label" TEXT NOT NULL, - "seatNumber" TEXT, - "kind" "SeatKind" NOT NULL DEFAULT 'STANDARD', - "status" "SeatStatus" NOT NULL DEFAULT 'AVAILABLE', - "heldUntil" TIMESTAMP(3), - "isWindow" BOOLEAN NOT NULL DEFAULT false, - "isAisle" BOOLEAN NOT NULL DEFAULT false, - "premiumFeeMinor" INTEGER NOT NULL DEFAULT 0, - "eligibility" TEXT, - - CONSTRAINT "Seat_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "SeatHold" ( - "id" TEXT NOT NULL, - "tripId" TEXT NOT NULL, - "seatIds" TEXT[], - "fareQuoteId" TEXT, - "passengerId" TEXT NOT NULL, - "createdBy" TEXT, - "expiresAt" TIMESTAMP(3) NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "SeatHold_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "FareRule" ( - "id" TEXT NOT NULL, - "tripId" TEXT, - "route" TEXT, - "serviceClass" "ServiceClass" NOT NULL, - "baseFareMinor" INTEGER NOT NULL, - "currency" TEXT NOT NULL DEFAULT 'ETB', - "refundable" BOOLEAN NOT NULL DEFAULT true, - "validFrom" TIMESTAMP(3) NOT NULL, - "validUntil" TIMESTAMP(3), - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "FareRule_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Booking" ( - "id" TEXT NOT NULL, - "bookingRef" TEXT NOT NULL, - "passengerId" TEXT NOT NULL, - "tripId" TEXT NOT NULL, - "status" "BookingStatus" NOT NULL DEFAULT 'DRAFT', - "currency" TEXT NOT NULL DEFAULT 'ETB', - "totalMinor" INTEGER NOT NULL, - "adultCount" INTEGER NOT NULL DEFAULT 1, - "childCount" INTEGER NOT NULL DEFAULT 0, - "displayCurrency" "Currency", - "displayTotalMinor" INTEGER, - "bookingType" TEXT NOT NULL DEFAULT 'ONE_WAY', - "userAgent" TEXT, - "source" TEXT NOT NULL DEFAULT 'WEB', - "promoCode" TEXT, - "paidAt" TIMESTAMP(3), - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "Booking_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "BookingSeat" ( - "id" TEXT NOT NULL, - "bookingId" TEXT NOT NULL, - "seatId" TEXT NOT NULL, - "passengerName" TEXT NOT NULL, - "dateOfBirth" TIMESTAMP(3), - "passengerCategory" "PassengerCategory" NOT NULL DEFAULT 'ADULT', - "idDocumentType" "IdDocumentType", - "idDocumentNumber" TEXT, - "passportNumber" TEXT, - "passportCountry" TEXT, - "verifaydaVerified" BOOLEAN NOT NULL DEFAULT false, - "verifaydaData" JSONB, - "seatLabelSnapshot" TEXT, - "fareMinor" INTEGER, - "displayCurrency" "Currency", - "displayFareMinor" INTEGER, - - CONSTRAINT "BookingSeat_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "PaymentMethod" ( - "id" TEXT NOT NULL, - "userId" TEXT NOT NULL, - "type" "PaymentMethodType" NOT NULL, - "displayName" TEXT NOT NULL, - "maskedHint" TEXT, - "providerId" TEXT, - "isDefault" BOOLEAN NOT NULL DEFAULT false, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "PaymentMethod_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "PaymentIntent" ( - "id" TEXT NOT NULL, - "bookingId" TEXT NOT NULL, - "amountMinor" INTEGER NOT NULL, - "currency" TEXT NOT NULL DEFAULT 'ETB', - "method" "PaymentMethodType" NOT NULL, - "provider" TEXT, - "status" "PaymentIntentStatus" NOT NULL DEFAULT 'REQUIRES_ACTION', - "providerRef" TEXT, - "clientAction" JSONB, - "merchantOrderId" TEXT, - "providerOrderId" TEXT, - "providerTxnId" TEXT, - "rawInitiation" JSONB, - "paidAt" TIMESTAMP(3), - "refundedAt" TIMESTAMP(3), - "captureMethod" TEXT, - "failureCode" TEXT, - "failureMessage" TEXT, - "expiresAt" TIMESTAMP(3), - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "PaymentIntent_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "PaymentWebhookEvent" ( - "id" TEXT NOT NULL, - "provider" "PaymentMethodType" NOT NULL, - "externalEventId" TEXT NOT NULL, - "merchantOrderId" TEXT, - "providerTxnId" TEXT, - "signatureValid" BOOLEAN NOT NULL, - "status" TEXT NOT NULL, - "payload" JSONB NOT NULL, - "receivedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "processedAt" TIMESTAMP(3), - "processingError" TEXT, - - CONSTRAINT "PaymentWebhookEvent_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "PaymentRefund" ( - "id" TEXT NOT NULL, - "paymentIntentId" TEXT NOT NULL, - "amountMinor" INTEGER NOT NULL, - "reason" TEXT, - "providerRefundId" TEXT, - "status" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "PaymentRefund_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Ticket" ( - "id" TEXT NOT NULL, - "bookingId" TEXT NOT NULL, - "bookingRef" TEXT NOT NULL, - "status" TEXT NOT NULL DEFAULT 'CONFIRMED', - "qrPayload" TEXT NOT NULL, - "barcodePayload" TEXT, - "pdfUrl" TEXT, - "deliveryChannel" TEXT NOT NULL DEFAULT 'EMAIL', - "issuedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "validatedAt" TIMESTAMP(3), - "validatorId" TEXT, - - CONSTRAINT "Ticket_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "LoyaltyAccount" ( - "id" TEXT NOT NULL, - "passengerId" TEXT NOT NULL, - "pointsBalance" INTEGER NOT NULL DEFAULT 0, - "lifetimePoints" INTEGER NOT NULL DEFAULT 0, - "tier" "LoyaltyTier" NOT NULL DEFAULT 'BRONZE', - "tierUpdatedAt" TIMESTAMP(3), - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "LoyaltyAccount_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "LoyaltyLedgerEntry" ( - "id" TEXT NOT NULL, - "accountId" TEXT NOT NULL, - "delta" INTEGER NOT NULL, - "reason" "LoyaltyLedgerReason" NOT NULL, - "bookingId" TEXT, - "balanceAfter" INTEGER NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "LoyaltyLedgerEntry_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "LoyaltyReward" ( - "id" TEXT NOT NULL, - "accountId" TEXT NOT NULL, - "title" TEXT NOT NULL, - "costPoints" INTEGER NOT NULL, - "available" BOOLEAN NOT NULL DEFAULT true, - "description" TEXT, - - CONSTRAINT "LoyaltyReward_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "WalletAccount" ( - "id" TEXT NOT NULL, - "passengerId" TEXT NOT NULL, - "balanceMinor" INTEGER NOT NULL DEFAULT 0, - "status" TEXT NOT NULL DEFAULT 'ACTIVE', - "holdMinor" INTEGER NOT NULL DEFAULT 0, - "currency" TEXT NOT NULL DEFAULT 'ETB', - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "WalletAccount_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "WalletLedgerEntry" ( - "id" TEXT NOT NULL, - "walletId" TEXT NOT NULL, - "type" "WalletLedgerType" NOT NULL, - "amountMinor" INTEGER NOT NULL, - "balanceAfterMinor" INTEGER NOT NULL, - "description" TEXT NOT NULL, - "relatedBookingId" TEXT, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "WalletLedgerEntry_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Notification" ( - "id" TEXT NOT NULL, - "passengerId" TEXT NOT NULL, - "title" TEXT NOT NULL, - "body" TEXT NOT NULL, - "category" "NotificationCategory" NOT NULL, - "read" BOOLEAN NOT NULL DEFAULT false, - "deepLink" TEXT, - "metadata" JSONB, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "Notification_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Promotion" ( - "id" TEXT NOT NULL, - "title" TEXT NOT NULL, - "subtitle" TEXT, - "code" TEXT NOT NULL, - "percentOff" INTEGER, - "amountOffMinor" INTEGER, - "validUntil" TIMESTAMP(3) NOT NULL, - "ctaLabel" TEXT, - "deepLink" TEXT, - "active" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "Promotion_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "StationCrowdSignal" ( - "id" TEXT NOT NULL, - "stationId" TEXT NOT NULL, - "level" TEXT NOT NULL, - "label" TEXT NOT NULL, - "statusLabel" TEXT NOT NULL, - "confidence" INTEGER, - "observedAt" TIMESTAMP(3), - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "StationCrowdSignal_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "WeatherAlert" ( - "id" TEXT NOT NULL, - "region" TEXT NOT NULL, - "severity" TEXT NOT NULL, - "title" TEXT NOT NULL, - "message" TEXT NOT NULL, - "validUntil" TIMESTAMP(3) NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "WeatherAlert_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "MenuCategory" ( - "id" TEXT NOT NULL, - "name" TEXT NOT NULL, - - CONSTRAINT "MenuCategory_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "MenuItem" ( - "id" TEXT NOT NULL, - "tripId" TEXT NOT NULL, - "categoryId" TEXT NOT NULL, - "name" TEXT NOT NULL, - "priceMinor" INTEGER NOT NULL, - "currency" TEXT NOT NULL DEFAULT 'ETB', - "available" BOOLEAN NOT NULL DEFAULT true, - "availableUntil" TIMESTAMP(3), - - CONSTRAINT "MenuItem_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "FoodOrder" ( - "id" TEXT NOT NULL, - "bookingId" TEXT NOT NULL, - "status" "FoodOrderStatus" NOT NULL DEFAULT 'PENDING', - "totalMinor" INTEGER NOT NULL, - "currency" TEXT NOT NULL DEFAULT 'ETB', - "specialInstructions" TEXT, - "estimatedReadyAt" TIMESTAMP(3), - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "FoodOrder_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "FoodOrderItem" ( - "id" TEXT NOT NULL, - "orderId" TEXT NOT NULL, - "menuItemId" TEXT NOT NULL, - "name" TEXT NOT NULL, - "quantity" INTEGER NOT NULL, - "unitPriceMinor" INTEGER, - "lineTotalMinor" INTEGER NOT NULL, - - CONSTRAINT "FoodOrderItem_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "FaqCategory" ( - "id" TEXT NOT NULL, - "title" TEXT NOT NULL, - "iconKey" TEXT, - - CONSTRAINT "FaqCategory_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "FaqArticle" ( - "id" TEXT NOT NULL, - "categoryId" TEXT NOT NULL, - "question" TEXT NOT NULL, - "answerMarkdown" TEXT NOT NULL, - "rank" INTEGER NOT NULL DEFAULT 0, - - CONSTRAINT "FaqArticle_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "SupportConversation" ( - "id" TEXT NOT NULL, - "userId" TEXT NOT NULL, - "assignedAgentId" TEXT, - "status" "SupportConversationStatus" NOT NULL DEFAULT 'OPEN', - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "SupportConversation_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "SupportMessage" ( - "id" TEXT NOT NULL, - "conversationId" TEXT NOT NULL, - "sender" "SupportSender" NOT NULL, - "text" TEXT NOT NULL, - "attachments" JSONB, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "SupportMessage_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "UserPreferences" ( - "id" TEXT NOT NULL, - "userId" TEXT NOT NULL, - "pushEnabled" BOOLEAN NOT NULL DEFAULT true, - "emailEnabled" BOOLEAN NOT NULL DEFAULT true, - "smsEnabled" BOOLEAN NOT NULL DEFAULT false, - "promosEnabled" BOOLEAN NOT NULL DEFAULT true, - "biometricEnabled" BOOLEAN NOT NULL DEFAULT false, - "twoFactorEnabled" BOOLEAN NOT NULL DEFAULT false, - "defaultPaymentMethodId" TEXT, - "autoDownloadTickets" BOOLEAN NOT NULL DEFAULT true, - "dataSharing" BOOLEAN NOT NULL DEFAULT false, - "locale" TEXT NOT NULL DEFAULT 'en', - "darkMode" BOOLEAN NOT NULL DEFAULT false, - "language" TEXT NOT NULL DEFAULT 'en', - - CONSTRAINT "UserPreferences_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Device" ( - "id" TEXT NOT NULL, - "userId" TEXT NOT NULL, - "platform" "DevicePlatform" NOT NULL, - "name" TEXT NOT NULL, - "pushToken" TEXT, - "trusted" BOOLEAN NOT NULL DEFAULT false, - "lastSeenAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "Device_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "SavedRoute" ( - "id" TEXT NOT NULL, - "passengerId" TEXT NOT NULL, - "fromStationId" TEXT NOT NULL, - "toStationId" TEXT NOT NULL, - "fromName" TEXT NOT NULL, - "toName" TEXT NOT NULL, - "tripCount" INTEGER NOT NULL DEFAULT 0, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "SavedRoute_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Journey" ( - "id" TEXT NOT NULL, - "passengerId" TEXT NOT NULL, - "status" TEXT NOT NULL, - "totalMinor" INTEGER NOT NULL, - "currency" TEXT NOT NULL DEFAULT 'ETB', - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "Journey_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "JourneySegment" ( - "id" TEXT NOT NULL, - "journeyId" TEXT NOT NULL, - "tripId" TEXT NOT NULL, - "segmentOrder" INTEGER NOT NULL, - "seatId" TEXT, - "coachId" TEXT, - "departureStationId" TEXT NOT NULL, - "arrivalStationId" TEXT NOT NULL, - - CONSTRAINT "JourneySegment_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "OtpCode" ( - "id" TEXT NOT NULL, - "userId" TEXT, - "email" TEXT, - "phone" TEXT, - "code" TEXT NOT NULL, - "purpose" TEXT NOT NULL, - "expiresAt" TIMESTAMP(3) NOT NULL, - "verified" BOOLEAN NOT NULL DEFAULT false, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "OtpCode_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "PasswordResetToken" ( - "id" TEXT NOT NULL, - "userId" TEXT NOT NULL, - "token" TEXT NOT NULL, - "expiresAt" TIMESTAMP(3) NOT NULL, - "used" BOOLEAN NOT NULL DEFAULT false, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "PasswordResetToken_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Route" ( - "id" TEXT NOT NULL, - "code" TEXT NOT NULL, - "name" TEXT NOT NULL, - "description" TEXT, - "effectiveFrom" TIMESTAMP(3) NOT NULL, - "effectiveUntil" TIMESTAMP(3), - "active" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "Route_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "RouteStop" ( - "id" TEXT NOT NULL, - "routeId" TEXT NOT NULL, - "stationId" TEXT NOT NULL, - "sequence" INTEGER NOT NULL, - "distanceKm" INTEGER, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "RouteStop_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "RouteFareRule" ( - "id" TEXT NOT NULL, - "routeId" TEXT NOT NULL, - "serviceClass" "ServiceClass" NOT NULL, - "passengerCategory" "PassengerCategory" NOT NULL DEFAULT 'ADULT', - "baseFareMinor" INTEGER NOT NULL, - "discountPercent" INTEGER, - "taxPercent" INTEGER, - "surchargeMinor" INTEGER, - "currency" TEXT NOT NULL DEFAULT 'ETB', - "validFrom" TIMESTAMP(3) NOT NULL, - "validUntil" TIMESTAMP(3), - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "RouteFareRule_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Agent" ( - "id" TEXT NOT NULL, - "userId" TEXT NOT NULL, - "agentCode" TEXT NOT NULL, - "stationId" TEXT, - "commissionRate" INTEGER NOT NULL DEFAULT 5, - "active" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "Agent_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "AgentBooking" ( - "id" TEXT NOT NULL, - "agentId" TEXT NOT NULL, - "bookingId" TEXT NOT NULL, - "paymentMethod" TEXT NOT NULL, - "cashReceived" INTEGER, - "changeGiven" INTEGER, - "paperTicket" BOOLEAN NOT NULL DEFAULT false, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "AgentBooking_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "AgentShift" ( - "id" TEXT NOT NULL, - "agentId" TEXT NOT NULL, - "openedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "closedAt" TIMESTAMP(3), - "openingBalance" INTEGER NOT NULL DEFAULT 0, - "closingBalance" INTEGER, - "reconciled" BOOLEAN NOT NULL DEFAULT false, - "notes" TEXT, - - CONSTRAINT "AgentShift_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "AgentCommission" ( - "id" TEXT NOT NULL, - "agentId" TEXT NOT NULL, - "bookingId" TEXT NOT NULL, - "amountMinor" INTEGER NOT NULL, - "rate" INTEGER NOT NULL, - "paidAt" TIMESTAMP(3), - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "AgentCommission_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "BookingModification" ( - "id" TEXT NOT NULL, - "bookingId" TEXT NOT NULL, - "modifiedBy" TEXT NOT NULL, - "modificationType" TEXT NOT NULL, - "oldData" JSONB NOT NULL, - "newData" JSONB NOT NULL, - "fareAdjustment" INTEGER NOT NULL DEFAULT 0, - "reason" TEXT, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "BookingModification_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "BookingCancellation" ( - "id" TEXT NOT NULL, - "bookingId" TEXT NOT NULL, - "cancelledBy" TEXT NOT NULL, - "reason" TEXT, - "refundAmount" INTEGER NOT NULL, - "refundMethod" TEXT NOT NULL, - "refundStatus" TEXT NOT NULL, - "processedAt" TIMESTAMP(3), - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "BookingCancellation_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "GateValidationLog" ( - "id" TEXT NOT NULL, - "ticketId" TEXT NOT NULL, - "validatorId" TEXT NOT NULL, - "gateId" TEXT, - "status" TEXT NOT NULL, - "reason" TEXT, - "validatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "GateValidationLog_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "BaggageAllowance" ( - "id" TEXT NOT NULL, - "serviceClass" "ServiceClass" NOT NULL, - "maxWeightKg" INTEGER NOT NULL, - "maxPiecesCount" INTEGER NOT NULL, - "excessFeePerKg" INTEGER NOT NULL, - "currency" TEXT NOT NULL DEFAULT 'ETB', - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "BaggageAllowance_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "BaggageBooking" ( - "id" TEXT NOT NULL, - "bookingId" TEXT NOT NULL, - "weightKg" INTEGER NOT NULL, - "piecesCount" INTEGER NOT NULL, - "excessFeeMinor" INTEGER NOT NULL DEFAULT 0, - "paid" BOOLEAN NOT NULL DEFAULT false, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "BaggageBooking_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "AuditLog" ( - "id" TEXT NOT NULL, - "userId" TEXT, - "action" TEXT NOT NULL, - "entityType" TEXT NOT NULL, - "entityId" TEXT, - "oldData" JSONB, - "newData" JSONB, - "ipAddress" TEXT, - "userAgent" TEXT, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "AuditLog_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "NotificationTemplate" ( - "id" TEXT NOT NULL, - "code" TEXT NOT NULL, - "channel" TEXT NOT NULL, - "subject" TEXT, - "bodyTemplate" TEXT NOT NULL, - "active" BOOLEAN NOT NULL DEFAULT true, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "NotificationTemplate_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "SeatBlock" ( - "id" TEXT NOT NULL, - "seatId" TEXT NOT NULL, - "reason" TEXT NOT NULL, - "blockedBy" TEXT NOT NULL, - "approvedBy" TEXT, - "blockedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "unblockAt" TIMESTAMP(3), - - CONSTRAINT "SeatBlock_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "OperationalReport" ( - "id" TEXT NOT NULL, - "reportType" TEXT NOT NULL, - "dateFrom" TIMESTAMP(3) NOT NULL, - "dateTo" TIMESTAMP(3) NOT NULL, - "data" JSONB NOT NULL, - "generatedBy" TEXT, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "OperationalReport_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "FraudRule" ( - "id" TEXT NOT NULL, - "type" TEXT NOT NULL, - "enabled" BOOLEAN NOT NULL DEFAULT true, - "threshold" DOUBLE PRECISION NOT NULL, - "config" JSONB, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - - CONSTRAINT "FraudRule_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "FraudAlert" ( - "id" TEXT NOT NULL, - "userId" TEXT NOT NULL, - "eventType" TEXT NOT NULL, - "triggeredRules" TEXT[], - "context" JSONB NOT NULL, - "severity" TEXT NOT NULL DEFAULT 'MEDIUM', - "acknowledged" BOOLEAN NOT NULL DEFAULT false, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "FraudAlert_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "CurrencyExchangeRate" ( - "id" TEXT NOT NULL, - "fromCurrency" "Currency" NOT NULL, - "toCurrency" "Currency" NOT NULL, - "rate" DECIMAL(18,6) NOT NULL, - "effectiveDate" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "source" TEXT NOT NULL DEFAULT 'MANUAL', - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "CurrencyExchangeRate_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "VerifaydaVerification" ( - "id" TEXT NOT NULL, - "bookingId" TEXT, - "nationalId" TEXT NOT NULL, - "requestPayload" JSONB NOT NULL, - "responsePayload" JSONB, - "verified" BOOLEAN NOT NULL DEFAULT false, - "failureReason" TEXT, - "verifiedAt" TIMESTAMP(3), - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - - CONSTRAINT "VerifaydaVerification_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); - --- CreateIndex -CREATE UNIQUE INDEX "User_phone_key" ON "User"("phone"); - --- CreateIndex -CREATE UNIQUE INDEX "Session_token_key" ON "Session"("token"); - --- CreateIndex -CREATE UNIQUE INDEX "Passenger_userId_key" ON "Passenger"("userId"); - --- CreateIndex -CREATE INDEX "Passenger_userId_idx" ON "Passenger"("userId"); - --- CreateIndex -CREATE UNIQUE INDEX "Station_code_key" ON "Station"("code"); - --- CreateIndex -CREATE INDEX "Station_city_countryCode_idx" ON "Station"("city", "countryCode"); - --- CreateIndex -CREATE UNIQUE INDEX "TrainService_number_key" ON "TrainService"("number"); - --- CreateIndex -CREATE INDEX "Trip_departureAt_originStationId_idx" ON "Trip"("departureAt", "originStationId"); - --- CreateIndex -CREATE UNIQUE INDEX "TripStopTime_tripId_sequence_key" ON "TripStopTime"("tripId", "sequence"); - --- CreateIndex -CREATE UNIQUE INDEX "TripLiveStatus_tripId_key" ON "TripLiveStatus"("tripId"); - --- CreateIndex -CREATE UNIQUE INDEX "Coach_tripId_label_key" ON "Coach"("tripId", "label"); - --- CreateIndex -CREATE UNIQUE INDEX "Seat_coachId_row_col_key" ON "Seat"("coachId", "row", "col"); - --- CreateIndex -CREATE UNIQUE INDEX "Seat_coachId_seatNumber_key" ON "Seat"("coachId", "seatNumber"); - --- CreateIndex -CREATE INDEX "SeatHold_expiresAt_idx" ON "SeatHold"("expiresAt"); - --- CreateIndex -CREATE UNIQUE INDEX "Booking_bookingRef_key" ON "Booking"("bookingRef"); - --- CreateIndex -CREATE INDEX "Booking_passengerId_status_idx" ON "Booking"("passengerId", "status"); - --- CreateIndex -CREATE INDEX "PaymentMethod_userId_isDefault_idx" ON "PaymentMethod"("userId", "isDefault"); - --- CreateIndex -CREATE UNIQUE INDEX "PaymentIntent_bookingId_key" ON "PaymentIntent"("bookingId"); - --- CreateIndex -CREATE UNIQUE INDEX "PaymentIntent_merchantOrderId_key" ON "PaymentIntent"("merchantOrderId"); - --- CreateIndex -CREATE INDEX "PaymentIntent_providerOrderId_idx" ON "PaymentIntent"("providerOrderId"); - --- CreateIndex -CREATE INDEX "PaymentIntent_providerTxnId_idx" ON "PaymentIntent"("providerTxnId"); - --- CreateIndex -CREATE INDEX "PaymentWebhookEvent_merchantOrderId_idx" ON "PaymentWebhookEvent"("merchantOrderId"); - --- CreateIndex -CREATE UNIQUE INDEX "PaymentWebhookEvent_provider_externalEventId_key" ON "PaymentWebhookEvent"("provider", "externalEventId"); - --- CreateIndex -CREATE UNIQUE INDEX "Ticket_bookingId_key" ON "Ticket"("bookingId"); - --- CreateIndex -CREATE UNIQUE INDEX "LoyaltyAccount_passengerId_key" ON "LoyaltyAccount"("passengerId"); - --- CreateIndex -CREATE UNIQUE INDEX "WalletAccount_passengerId_key" ON "WalletAccount"("passengerId"); - --- CreateIndex -CREATE INDEX "WalletAccount_passengerId_idx" ON "WalletAccount"("passengerId"); - --- CreateIndex -CREATE UNIQUE INDEX "Promotion_code_key" ON "Promotion"("code"); - --- CreateIndex -CREATE UNIQUE INDEX "UserPreferences_userId_key" ON "UserPreferences"("userId"); - --- CreateIndex -CREATE INDEX "OtpCode_email_phone_idx" ON "OtpCode"("email", "phone"); - --- CreateIndex -CREATE UNIQUE INDEX "PasswordResetToken_token_key" ON "PasswordResetToken"("token"); - --- CreateIndex -CREATE INDEX "PasswordResetToken_userId_idx" ON "PasswordResetToken"("userId"); - --- CreateIndex -CREATE UNIQUE INDEX "Route_code_key" ON "Route"("code"); - --- CreateIndex -CREATE INDEX "RouteStop_routeId_stationId_idx" ON "RouteStop"("routeId", "stationId"); - --- CreateIndex -CREATE UNIQUE INDEX "RouteStop_routeId_sequence_key" ON "RouteStop"("routeId", "sequence"); - --- CreateIndex -CREATE INDEX "RouteFareRule_routeId_serviceClass_idx" ON "RouteFareRule"("routeId", "serviceClass"); - --- CreateIndex -CREATE UNIQUE INDEX "Agent_userId_key" ON "Agent"("userId"); - --- CreateIndex -CREATE UNIQUE INDEX "Agent_agentCode_key" ON "Agent"("agentCode"); - --- CreateIndex -CREATE UNIQUE INDEX "AgentBooking_bookingId_key" ON "AgentBooking"("bookingId"); - --- CreateIndex -CREATE INDEX "AgentShift_agentId_openedAt_idx" ON "AgentShift"("agentId", "openedAt"); - --- CreateIndex -CREATE INDEX "AgentCommission_agentId_paidAt_idx" ON "AgentCommission"("agentId", "paidAt"); - --- CreateIndex -CREATE INDEX "BookingModification_bookingId_idx" ON "BookingModification"("bookingId"); - --- CreateIndex -CREATE UNIQUE INDEX "BookingCancellation_bookingId_key" ON "BookingCancellation"("bookingId"); - --- CreateIndex -CREATE INDEX "GateValidationLog_ticketId_idx" ON "GateValidationLog"("ticketId"); - --- CreateIndex -CREATE INDEX "GateValidationLog_validatorId_idx" ON "GateValidationLog"("validatorId"); - --- CreateIndex -CREATE INDEX "BaggageBooking_bookingId_idx" ON "BaggageBooking"("bookingId"); - --- CreateIndex -CREATE INDEX "AuditLog_userId_createdAt_idx" ON "AuditLog"("userId", "createdAt"); - --- CreateIndex -CREATE INDEX "AuditLog_entityType_entityId_idx" ON "AuditLog"("entityType", "entityId"); - --- CreateIndex -CREATE UNIQUE INDEX "NotificationTemplate_code_key" ON "NotificationTemplate"("code"); - --- CreateIndex -CREATE INDEX "SeatBlock_seatId_idx" ON "SeatBlock"("seatId"); - --- CreateIndex -CREATE INDEX "OperationalReport_reportType_dateFrom_idx" ON "OperationalReport"("reportType", "dateFrom"); - --- CreateIndex -CREATE UNIQUE INDEX "FraudRule_type_key" ON "FraudRule"("type"); - --- CreateIndex -CREATE INDEX "FraudAlert_userId_createdAt_idx" ON "FraudAlert"("userId", "createdAt"); - --- CreateIndex -CREATE INDEX "FraudAlert_acknowledged_idx" ON "FraudAlert"("acknowledged"); - --- CreateIndex -CREATE INDEX "CurrencyExchangeRate_fromCurrency_toCurrency_idx" ON "CurrencyExchangeRate"("fromCurrency", "toCurrency"); - --- CreateIndex -CREATE UNIQUE INDEX "CurrencyExchangeRate_fromCurrency_toCurrency_effectiveDate_key" ON "CurrencyExchangeRate"("fromCurrency", "toCurrency", "effectiveDate"); - --- CreateIndex -CREATE INDEX "VerifaydaVerification_nationalId_idx" ON "VerifaydaVerification"("nationalId"); - --- CreateIndex -CREATE INDEX "VerifaydaVerification_bookingId_idx" ON "VerifaydaVerification"("bookingId"); - --- AddForeignKey -ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Passenger" ADD CONSTRAINT "Passenger_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "TravelerProfile" ADD CONSTRAINT "TravelerProfile_passengerId_fkey" FOREIGN KEY ("passengerId") REFERENCES "Passenger"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Trip" ADD CONSTRAINT "Trip_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "TrainService"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Trip" ADD CONSTRAINT "Trip_originStationId_fkey" FOREIGN KEY ("originStationId") REFERENCES "Station"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Trip" ADD CONSTRAINT "Trip_destinationStationId_fkey" FOREIGN KEY ("destinationStationId") REFERENCES "Station"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "TripStopTime" ADD CONSTRAINT "TripStopTime_tripId_fkey" FOREIGN KEY ("tripId") REFERENCES "Trip"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "TripStopTime" ADD CONSTRAINT "TripStopTime_stationId_fkey" FOREIGN KEY ("stationId") REFERENCES "Station"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "TripLiveStatus" ADD CONSTRAINT "TripLiveStatus_tripId_fkey" FOREIGN KEY ("tripId") REFERENCES "Trip"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Coach" ADD CONSTRAINT "Coach_tripId_fkey" FOREIGN KEY ("tripId") REFERENCES "Trip"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Seat" ADD CONSTRAINT "Seat_coachId_fkey" FOREIGN KEY ("coachId") REFERENCES "Coach"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Booking" ADD CONSTRAINT "Booking_passengerId_fkey" FOREIGN KEY ("passengerId") REFERENCES "Passenger"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Booking" ADD CONSTRAINT "Booking_tripId_fkey" FOREIGN KEY ("tripId") REFERENCES "Trip"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "BookingSeat" ADD CONSTRAINT "BookingSeat_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "BookingSeat" ADD CONSTRAINT "BookingSeat_seatId_fkey" FOREIGN KEY ("seatId") REFERENCES "Seat"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "PaymentIntent" ADD CONSTRAINT "PaymentIntent_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "PaymentRefund" ADD CONSTRAINT "PaymentRefund_paymentIntentId_fkey" FOREIGN KEY ("paymentIntentId") REFERENCES "PaymentIntent"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Ticket" ADD CONSTRAINT "Ticket_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "LoyaltyAccount" ADD CONSTRAINT "LoyaltyAccount_passengerId_fkey" FOREIGN KEY ("passengerId") REFERENCES "Passenger"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "LoyaltyLedgerEntry" ADD CONSTRAINT "LoyaltyLedgerEntry_accountId_fkey" FOREIGN KEY ("accountId") REFERENCES "LoyaltyAccount"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "LoyaltyReward" ADD CONSTRAINT "LoyaltyReward_accountId_fkey" FOREIGN KEY ("accountId") REFERENCES "LoyaltyAccount"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "WalletAccount" ADD CONSTRAINT "WalletAccount_passengerId_fkey" FOREIGN KEY ("passengerId") REFERENCES "Passenger"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "WalletLedgerEntry" ADD CONSTRAINT "WalletLedgerEntry_walletId_fkey" FOREIGN KEY ("walletId") REFERENCES "WalletAccount"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Notification" ADD CONSTRAINT "Notification_passengerId_fkey" FOREIGN KEY ("passengerId") REFERENCES "Passenger"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "StationCrowdSignal" ADD CONSTRAINT "StationCrowdSignal_stationId_fkey" FOREIGN KEY ("stationId") REFERENCES "Station"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "MenuItem" ADD CONSTRAINT "MenuItem_tripId_fkey" FOREIGN KEY ("tripId") REFERENCES "Trip"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "MenuItem" ADD CONSTRAINT "MenuItem_categoryId_fkey" FOREIGN KEY ("categoryId") REFERENCES "MenuCategory"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "FoodOrder" ADD CONSTRAINT "FoodOrder_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "FoodOrderItem" ADD CONSTRAINT "FoodOrderItem_orderId_fkey" FOREIGN KEY ("orderId") REFERENCES "FoodOrder"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "FaqArticle" ADD CONSTRAINT "FaqArticle_categoryId_fkey" FOREIGN KEY ("categoryId") REFERENCES "FaqCategory"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "SupportMessage" ADD CONSTRAINT "SupportMessage_conversationId_fkey" FOREIGN KEY ("conversationId") REFERENCES "SupportConversation"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "UserPreferences" ADD CONSTRAINT "UserPreferences_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Device" ADD CONSTRAINT "Device_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "SavedRoute" ADD CONSTRAINT "SavedRoute_passengerId_fkey" FOREIGN KEY ("passengerId") REFERENCES "Passenger"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "JourneySegment" ADD CONSTRAINT "JourneySegment_journeyId_fkey" FOREIGN KEY ("journeyId") REFERENCES "Journey"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "JourneySegment" ADD CONSTRAINT "JourneySegment_tripId_fkey" FOREIGN KEY ("tripId") REFERENCES "Trip"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "RouteStop" ADD CONSTRAINT "RouteStop_routeId_fkey" FOREIGN KEY ("routeId") REFERENCES "Route"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "RouteFareRule" ADD CONSTRAINT "RouteFareRule_routeId_fkey" FOREIGN KEY ("routeId") REFERENCES "Route"("id") ON DELETE CASCADE ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Agent" ADD CONSTRAINT "Agent_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "AgentBooking" ADD CONSTRAINT "AgentBooking_agentId_fkey" FOREIGN KEY ("agentId") REFERENCES "Agent"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "AgentBooking" ADD CONSTRAINT "AgentBooking_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "AgentShift" ADD CONSTRAINT "AgentShift_agentId_fkey" FOREIGN KEY ("agentId") REFERENCES "Agent"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "AgentCommission" ADD CONSTRAINT "AgentCommission_agentId_fkey" FOREIGN KEY ("agentId") REFERENCES "Agent"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "BookingModification" ADD CONSTRAINT "BookingModification_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "BookingCancellation" ADD CONSTRAINT "BookingCancellation_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "GateValidationLog" ADD CONSTRAINT "GateValidationLog_ticketId_fkey" FOREIGN KEY ("ticketId") REFERENCES "Ticket"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "BaggageBooking" ADD CONSTRAINT "BaggageBooking_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "AuditLog" ADD CONSTRAINT "AuditLog_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "SeatBlock" ADD CONSTRAINT "SeatBlock_seatId_fkey" FOREIGN KEY ("seatId") REFERENCES "Seat"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "FraudAlert" ADD CONSTRAINT "FraudAlert_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/apps/edr-passenger-api/prisma/schema.prisma b/apps/edr-passenger-api/prisma/schema.prisma index a8d995698..7b2df1e81 100644 --- a/apps/edr-passenger-api/prisma/schema.prisma +++ b/apps/edr-passenger-api/prisma/schema.prisma @@ -3,8 +3,9 @@ generator client { } datasource db { - provider = "postgresql" - url = env("DATABASE_URL") + provider = "postgresql" + url = env("DATABASE_URL") + schemas = ["edr_passenger"] } enum UserRole { @@ -37,15 +38,6 @@ enum SeatStatus { BLOCKED } -enum ServiceClass { - ECONOMY_REGULAR - ECONOMY_BED_LOWER - ECONOMY_BED_MIDDLE - ECONOMY_BED_UPPER - VIP_BED_LOWER - VIP_BED_UPPER -} - enum PassengerCategory { ADULT CHILD @@ -74,6 +66,7 @@ model SeatClass { updatedAt DateTime @updatedAt coaches Coach[] fareRules FareRule[] + routeFareRules RouteFareRule[] } enum BookingStatus { @@ -240,41 +233,45 @@ model Station { timezone String @default("Africa/Addis_Ababa") lat Decimal @db.Decimal(9, 6) lng Decimal @db.Decimal(9, 6) - originTrips Trip[] @relation("OriginTrips") - destinationTrips Trip[] @relation("DestinationTrips") - stopTimes TripStopTime[] - crowdSignals StationCrowdSignal[] + originSchedules TrainSchedule[] @relation("OriginTrips") + destinationSchedules TrainSchedule[] @relation("DestinationTrips") + stopTimes TripStopTime[] + crowdSignals StationCrowdSignal[] @@index([city, countryCode]) } -model TrainService { - id String @id @default(uuid()) - number String @unique - name String - operatorId String @default("op_edr") +model Train { + id String @id @default(uuid()) + number String @unique + name String + operatorId String @default("op_edr") operatorName String? - trips Trip[] + description String? + isActive Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + schedules TrainSchedule[] } -model Trip { - id String @id @default(uuid()) - serviceId String +model TrainSchedule { + id String @id @default(uuid()) + trainId String routeId String? originStationId String destinationStationId String departureAt DateTime arrivalAt DateTime durationMinutes Int - status TripStatus @default(SCHEDULED) - stopsCount Int @default(0) - reservedCount Int @default(0) - onTimePercent Int @default(100) - carbonRating String @default("A") + status TripStatus @default(SCHEDULED) + stopsCount Int @default(0) + reservedCount Int @default(0) + onTimePercent Int @default(100) + carbonRating String @default("A") notes String? - service TrainService @relation(fields: [serviceId], references: [id]) - originStation Station @relation("OriginTrips", fields: [originStationId], references: [id]) - destinationStation Station @relation("DestinationTrips", fields: [destinationStationId], references: [id]) - coaches Coach[] + train Train @relation(fields: [trainId], references: [id]) + originStation Station @relation("OriginTrips", fields: [originStationId], references: [id]) + destinationStation Station @relation("DestinationTrips", fields: [destinationStationId], references: [id]) + coachAssignments CoachAssignment[] bookings Booking[] stopTimes TripStopTime[] liveStatus TripLiveStatus? @@ -284,62 +281,79 @@ model Trip { } model TripStopTime { - id String @id @default(uuid()) - tripId String + id String @id @default(uuid()) + scheduleId String stationId String sequence Int plannedArrivalAt DateTime? plannedDepartureAt DateTime? actualArrivalAt DateTime? - status StopStatus @default(UPCOMING) - trip Trip @relation(fields: [tripId], references: [id]) - station Station @relation(fields: [stationId], references: [id]) - @@unique([tripId, sequence]) + status StopStatus @default(UPCOMING) + schedule TrainSchedule @relation(fields: [scheduleId], references: [id]) + station Station @relation(fields: [stationId], references: [id]) + @@unique([scheduleId, sequence]) } model TripLiveStatus { - id String @id @default(uuid()) - tripId String @unique + id String @id @default(uuid()) + scheduleId String @unique state String currentLocationLabel String? - progressPercent Int @default(0) - delayMinutes Int @default(0) + progressPercent Int @default(0) + delayMinutes Int @default(0) currentSpeedKph Int? platformLabel String? - updatedAt DateTime @updatedAt - trip Trip @relation(fields: [tripId], references: [id]) + updatedAt DateTime @updatedAt + schedule TrainSchedule @relation(fields: [scheduleId], references: [id]) } model Coach { - id String @id @default(uuid()) - tripId String - label String - serviceClass ServiceClass - seatClassId String? - capacity Int? - sequence Int? - coachType String? - amenities Json? - trip Trip @relation(fields: [tripId], references: [id]) - seatClass SeatClass? @relation(fields: [seatClassId], references: [id]) - seats Seat[] - @@unique([tripId, label]) + id String @id @default(uuid()) + coachNumber String @unique + label String + seatClassId String + coachType String? + mode String @default("seat") // 'seat', 'bed', 'convertible' + seatArrangement String? + bedArrangement String? + amenities Json? + totalUnits Int @default(0) + isActive Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + seatClass SeatClass @relation(fields: [seatClassId], references: [id]) + seats Seat[] + assignments CoachAssignment[] +} + +model CoachAssignment { + id String @id @default(uuid()) + scheduleId String + coachId String + positionNumber Int + isOperational Boolean @default(true) + createdAt DateTime @default(now()) + schedule TrainSchedule @relation(fields: [scheduleId], references: [id]) + coach Coach @relation(fields: [coachId], references: [id]) + @@unique([scheduleId, positionNumber]) + @@index([scheduleId]) } model Seat { - id String @id @default(uuid()) - coachId String - row Int - col String - label String - seatNumber String? - kind SeatKind @default(STANDARD) - status SeatStatus @default(AVAILABLE) - heldUntil DateTime? - isWindow Boolean @default(false) - isAisle Boolean @default(false) - premiumFeeMinor Int @default(0) - eligibility String? + id String @id @default(uuid()) + coachId String + row Int + col String + label String + seatNumber String? + kind SeatKind @default(STANDARD) + status SeatStatus @default(AVAILABLE) + heldUntil DateTime? + isWindow Boolean @default(false) + isAisle Boolean @default(false) + bedPosition String? // 'lower', 'middle', 'upper' + premiumFeeMinor Int @default(0) + eligibility String? coach Coach @relation(fields: [coachId], references: [id]) bookingSeats BookingSeat[] blocks SeatBlock[] @@ -349,7 +363,7 @@ model Seat { model SeatHold { id String @id @default(uuid()) - tripId String + scheduleId String seatIds String[] fareQuoteId String? passengerId String @@ -377,7 +391,7 @@ model Booking { id String @id @default(uuid()) bookingRef String @unique passengerId String - tripId String + scheduleId String status BookingStatus @default(DRAFT) currency String @default("ETB") totalMinor Int @@ -393,7 +407,7 @@ model Booking { createdAt DateTime @default(now()) updatedAt DateTime @updatedAt passenger Passenger @relation(fields: [passengerId], references: [id]) - trip Trip @relation(fields: [tripId], references: [id]) + schedule TrainSchedule @relation(fields: [scheduleId], references: [id]) seats BookingSeat[] paymentIntent PaymentIntent? ticket Ticket? @@ -625,15 +639,15 @@ model MenuCategory { model MenuItem { id String @id @default(uuid()) - tripId String + scheduleId String categoryId String name String priceMinor Int currency String @default("ETB") available Boolean @default(true) availableUntil DateTime? - trip Trip @relation(fields: [tripId], references: [id]) - category MenuCategory @relation(fields: [categoryId], references: [id]) + schedule TrainSchedule @relation(fields: [scheduleId], references: [id]) + category MenuCategory @relation(fields: [categoryId], references: [id]) } model FoodOrder { @@ -747,16 +761,16 @@ model Journey { } model JourneySegment { - id String @id @default(uuid()) + id String @id @default(uuid()) journeyId String - tripId String + scheduleId String segmentOrder Int seatId String? coachId String? departureStationId String arrivalStationId String - journey Journey @relation(fields: [journeyId], references: [id]) - trip Trip @relation(fields: [tripId], references: [id]) + journey Journey @relation(fields: [journeyId], references: [id]) + schedule TrainSchedule @relation(fields: [scheduleId], references: [id]) } model OtpCode { @@ -810,7 +824,7 @@ model RouteStop { model RouteFareRule { id String @id @default(uuid()) routeId String - serviceClass ServiceClass + seatClassId String passengerCategory PassengerCategory @default(ADULT) baseFareMinor Int discountPercent Int? @@ -820,8 +834,9 @@ model RouteFareRule { validFrom DateTime validUntil DateTime? createdAt DateTime @default(now()) - route Route @relation(fields: [routeId], references: [id], onDelete: Cascade) - @@index([routeId, serviceClass]) + route Route @relation(fields: [routeId], references: [id], onDelete: Cascade) + seatClass SeatClass @relation(fields: [seatClassId], references: [id]) + @@index([routeId, seatClassId]) } model Agent { @@ -917,13 +932,13 @@ model GateValidationLog { } model BaggageAllowance { - id String @id @default(uuid()) - serviceClass ServiceClass + id String @id @default(uuid()) + seatClassId String maxWeightKg Int maxPiecesCount Int excessFeePerKg Int - currency String @default("ETB") - createdAt DateTime @default(now()) + currency String @default("ETB") + createdAt DateTime @default(now()) } model BaggageBooking { diff --git a/apps/edr-passenger-api/prisma/seed.ts b/apps/edr-passenger-api/prisma/seed.ts index b8c276a08..4e8c1a68f 100644 --- a/apps/edr-passenger-api/prisma/seed.ts +++ b/apps/edr-passenger-api/prisma/seed.ts @@ -1,4 +1,4 @@ -import { PrismaClient, ServiceClass, UserRole, LoyaltyTier, SeatKind, PassengerCategory, Currency } from '@prisma/client'; +import { PrismaClient, SeatKind } from '@prisma/client'; import * as bcrypt from 'bcrypt'; const prisma = new PrismaClient(); @@ -6,130 +6,113 @@ const prisma = new PrismaClient(); async function main() { console.log('🌱 Starting comprehensive seed...'); - // All 21 Stations (Ethiopian-Djibouti Railway) + // Stations const addis = await prisma.station.upsert({ where: { code: 'ADD' }, update: {}, create: { code: 'ADD', name: 'Addis Ababa Central', city: 'Addis Ababa', countryCode: 'ET', lat: 9.0054, lng: 38.7636 } }); const sebeta = await prisma.station.upsert({ where: { code: 'SBT' }, update: {}, create: { code: 'SBT', name: 'Sebeta', city: 'Sebeta', countryCode: 'ET', lat: 8.9167, lng: 38.6167 } }); - const labu = await prisma.station.upsert({ where: { code: 'LBU' }, update: {}, create: { code: 'LBU', name: 'Labu', city: 'Labu', countryCode: 'ET', lat: 8.8500, lng: 38.8500 } }); - const indode = await prisma.station.upsert({ where: { code: 'IND' }, update: {}, create: { code: 'IND', name: 'Indode', city: 'Indode', countryCode: 'ET', lat: 8.7833, lng: 39.0167 } }); - const bishoftu = await prisma.station.upsert({ where: { code: 'BSH' }, update: {}, create: { code: 'BSH', name: 'Bishoftu', city: 'Bishoftu', countryCode: 'ET', lat: 8.7500, lng: 38.9833 } }); - const mojo = await prisma.station.upsert({ where: { code: 'MJO' }, update: {}, create: { code: 'MJO', name: 'Mojo', city: 'Mojo', countryCode: 'ET', lat: 8.5833, lng: 39.1167 } }); const adama = await prisma.station.upsert({ where: { code: 'ADM' }, update: {}, create: { code: 'ADM', name: 'Adama', city: 'Adama', countryCode: 'ET', lat: 8.5400, lng: 39.2675 } }); - const feto = await prisma.station.upsert({ where: { code: 'FTO' }, update: {}, create: { code: 'FTO', name: 'Feto', city: 'Feto', countryCode: 'ET', lat: 8.7167, lng: 39.5833 } }); - const metahara = await prisma.station.upsert({ where: { code: 'MTH' }, update: {}, create: { code: 'MTH', name: 'Metahara', city: 'Metahara', countryCode: 'ET', lat: 8.9000, lng: 39.9167 } }); const awash = await prisma.station.upsert({ where: { code: 'AWS' }, update: {}, create: { code: 'AWS', name: 'Awash', city: 'Awash', countryCode: 'ET', lat: 8.9833, lng: 40.1667 } }); - const mieso = await prisma.station.upsert({ where: { code: 'MSO' }, update: {}, create: { code: 'MSO', name: 'Mieso', city: 'Mieso', countryCode: 'ET', lat: 9.2333, lng: 40.7500 } }); - const bike = await prisma.station.upsert({ where: { code: 'BKE' }, update: {}, create: { code: 'BKE', name: 'Bike', city: 'Bike', countryCode: 'ET', lat: 9.4167, lng: 41.2500 } }); const direDawa = await prisma.station.upsert({ where: { code: 'DDW' }, update: {}, create: { code: 'DDW', name: 'Dire Dawa', city: 'Dire Dawa', countryCode: 'ET', lat: 9.5931, lng: 41.8661 } }); - const arawa = await prisma.station.upsert({ where: { code: 'ARW' }, update: {}, create: { code: 'ARW', name: 'Arawa', city: 'Arawa', countryCode: 'ET', lat: 10.0833, lng: 42.2500 } }); - const adigala = await prisma.station.upsert({ where: { code: 'ADG' }, update: {}, create: { code: 'ADG', name: 'Adigala', city: 'Adigala', countryCode: 'ET', lat: 10.5000, lng: 42.5833 } }); const aysha = await prisma.station.upsert({ where: { code: 'AYS' }, update: {}, create: { code: 'AYS', name: 'Aysha', city: 'Aysha', countryCode: 'ET', lat: 11.5500, lng: 42.7167 } }); - const dawanle = await prisma.station.upsert({ where: { code: 'DWN' }, update: {}, create: { code: 'DWN', name: 'Dawanle', city: 'Dawanle', countryCode: 'DJ', timezone: 'Africa/Djibouti', lat: 11.3833, lng: 42.8500 } }); - const alisabieh = await prisma.station.upsert({ where: { code: 'ALI' }, update: {}, create: { code: 'ALI', name: 'Alisabieh', city: 'Alisabieh', countryCode: 'DJ', timezone: 'Africa/Djibouti', lat: 11.1667, lng: 42.7167 } }); - const holhol = await prisma.station.upsert({ where: { code: 'HLH' }, update: {}, create: { code: 'HLH', name: 'Holhol', city: 'Holhol', countryCode: 'DJ', timezone: 'Africa/Djibouti', lat: 11.4167, lng: 43.0000 } }); - const nagad = await prisma.station.upsert({ where: { code: 'NGD' }, update: {}, create: { code: 'NGD', name: 'Nagad', city: 'Nagad', countryCode: 'DJ', timezone: 'Africa/Djibouti', lat: 11.5167, lng: 43.1000 } }); const djibouti = await prisma.station.upsert({ where: { code: 'DJI' }, update: {}, create: { code: 'DJI', name: 'Djibouti', city: 'Djibouti', countryCode: 'DJ', timezone: 'Africa/Djibouti', lat: 11.5720, lng: 43.1456 } }); - // Routes - const route1 = await prisma.route.upsert({ - where: { code: 'R001' }, - update: {}, - create: { code: 'R001', name: 'Addis Ababa - Djibouti Express', effectiveFrom: new Date('2026-01-01'), active: true } - }); - - // Delete existing route stops and recreate - await prisma.routeStop.deleteMany({ where: { routeId: route1.id } }); - await prisma.routeStop.createMany({ data: [ - { routeId: route1.id, stationId: addis.id, sequence: 1, distanceKm: 0 }, - { routeId: route1.id, stationId: sebeta.id, sequence: 2, distanceKm: 23 }, - { routeId: route1.id, stationId: labu.id, sequence: 3, distanceKm: 45 }, - { routeId: route1.id, stationId: indode.id, sequence: 4, distanceKm: 62 }, - { routeId: route1.id, stationId: bishoftu.id, sequence: 5, distanceKm: 47 }, - { routeId: route1.id, stationId: mojo.id, sequence: 6, distanceKm: 73 }, - { routeId: route1.id, stationId: adama.id, sequence: 7, distanceKm: 99 }, - { routeId: route1.id, stationId: feto.id, sequence: 8, distanceKm: 145 }, - { routeId: route1.id, stationId: metahara.id, sequence: 9, distanceKm: 198 }, - { routeId: route1.id, stationId: awash.id, sequence: 10, distanceKm: 225 }, - { routeId: route1.id, stationId: mieso.id, sequence: 11, distanceKm: 305 }, - { routeId: route1.id, stationId: bike.id, sequence: 12, distanceKm: 375 }, - { routeId: route1.id, stationId: direDawa.id, sequence: 13, distanceKm: 453 }, - { routeId: route1.id, stationId: arawa.id, sequence: 14, distanceKm: 520 }, - { routeId: route1.id, stationId: adigala.id, sequence: 15, distanceKm: 580 }, - { routeId: route1.id, stationId: aysha.id, sequence: 16, distanceKm: 656 }, - { routeId: route1.id, stationId: dawanle.id, sequence: 17, distanceKm: 680 }, - { routeId: route1.id, stationId: alisabieh.id, sequence: 18, distanceKm: 700 }, - { routeId: route1.id, stationId: holhol.id, sequence: 19, distanceKm: 730 }, - { routeId: route1.id, stationId: nagad.id, sequence: 20, distanceKm: 750 }, - { routeId: route1.id, stationId: djibouti.id, sequence: 21, distanceKm: 756 }, - ]}); + // Seat Classes + const scEconomyRegular = await prisma.seatClass.upsert({ where: { name: 'Economy Regular' }, update: {}, create: { name: 'Economy Regular', description: 'Standard economy seating', basePrice: 45000, isActive: true } }); + const scEconomyBed = await prisma.seatClass.upsert({ where: { name: 'Economy Bed' }, update: {}, create: { name: 'Economy Bed', description: 'Economy bed lower berth', basePrice: 65000, isActive: true } }); + const scVipBed = await prisma.seatClass.upsert({ where: { name: 'VIP Bed' }, update: {}, create: { name: 'VIP Bed', description: 'First class VIP bed', basePrice: 95000, isActive: true } }); - // Route Fare Rules (with passenger categories) - await prisma.routeFareRule.deleteMany({ where: { routeId: route1.id } }); - await prisma.routeFareRule.createMany({ data: [ - { routeId: route1.id, serviceClass: 'ECONOMY_REGULAR', passengerCategory: 'ADULT', baseFareMinor: 45000, validFrom: new Date('2026-01-01') }, - { routeId: route1.id, serviceClass: 'ECONOMY_BED_LOWER', passengerCategory: 'ADULT', baseFareMinor: 65000, validFrom: new Date('2026-01-01') }, - { routeId: route1.id, serviceClass: 'VIP_BED_LOWER', passengerCategory: 'ADULT', baseFareMinor: 95000, validFrom: new Date('2026-01-01') }, - { routeId: route1.id, serviceClass: 'ECONOMY_REGULAR', passengerCategory: 'CHILD', baseFareMinor: 45000, validFrom: new Date('2026-01-01') }, - { routeId: route1.id, serviceClass: 'ECONOMY_BED_LOWER', passengerCategory: 'CHILD', baseFareMinor: 65000, validFrom: new Date('2026-01-01') }, - { routeId: route1.id, serviceClass: 'VIP_BED_LOWER', passengerCategory: 'CHILD', baseFareMinor: 95000, validFrom: new Date('2026-01-01') }, - ]}); + // Trains (logical services) + const train301 = await prisma.train.upsert({ where: { number: '301' }, update: {}, create: { number: '301', name: 'Express 301', description: 'Addis-Djibouti Express' } }); + const train302 = await prisma.train.upsert({ where: { number: '302' }, update: {}, create: { number: '302', name: 'Express 302', description: 'Djibouti-Addis Express' } }); - // Train Services - const service301 = await prisma.trainService.upsert({ where: { number: '301' }, update: {}, create: { number: '301', name: 'Express 301' } }); - const service302 = await prisma.trainService.upsert({ where: { number: '302' }, update: {}, create: { number: '302', name: 'Express 302' } }); + // Physical Coaches (reusable) + const coachA1 = await prisma.coach.upsert({ where: { coachNumber: 'C-A1' }, update: {}, create: { coachNumber: 'C-A1', label: 'A', seatClassId: scEconomyRegular.id, mode: 'seat', totalUnits: 60 } }); + const coachB1 = await prisma.coach.upsert({ where: { coachNumber: 'C-B1' }, update: {}, create: { coachNumber: 'C-B1', label: 'B', seatClassId: scEconomyBed.id, mode: 'bed', totalUnits: 40 } }); + const coachC1 = await prisma.coach.upsert({ where: { coachNumber: 'C-C1' }, update: {}, create: { coachNumber: 'C-C1', label: 'C', seatClassId: scVipBed.id, mode: 'bed', totalUnits: 20 } }); + const coachA2 = await prisma.coach.upsert({ where: { coachNumber: 'C-A2' }, update: {}, create: { coachNumber: 'C-A2', label: 'A', seatClassId: scEconomyRegular.id, mode: 'seat', totalUnits: 60 } }); + const coachB2 = await prisma.coach.upsert({ where: { coachNumber: 'C-B2' }, update: {}, create: { coachNumber: 'C-B2', label: 'B', seatClassId: scEconomyBed.id, mode: 'bed', totalUnits: 40 } }); + const coachC2 = await prisma.coach.upsert({ where: { coachNumber: 'C-C2' }, update: {}, create: { coachNumber: 'C-C2', label: 'C', seatClassId: scVipBed.id, mode: 'bed', totalUnits: 20 } }); - // Trips (Multiple schedules) - Delete existing trips for clean seed - await prisma.trip.deleteMany({ where: { serviceId: { in: [service301.id, service302.id] } } }); - const trip1 = await prisma.trip.create({ - data: { serviceId: service301.id, originStationId: addis.id, destinationStationId: djibouti.id, departureAt: new Date('2026-06-15T08:00:00Z'), arrivalAt: new Date('2026-06-15T20:00:00Z'), durationMinutes: 720, stopsCount: 19 }, - }); - const trip2 = await prisma.trip.create({ - data: { serviceId: service302.id, originStationId: djibouti.id, destinationStationId: addis.id, departureAt: new Date('2026-06-16T09:00:00Z'), arrivalAt: new Date('2026-06-16T21:30:00Z'), durationMinutes: 750, stopsCount: 19 }, - }); - const trip3 = await prisma.trip.create({ - data: { serviceId: service301.id, originStationId: addis.id, destinationStationId: djibouti.id, departureAt: new Date('2026-06-17T07:30:00Z'), arrivalAt: new Date('2026-06-17T19:45:00Z'), durationMinutes: 735, stopsCount: 19 }, - }); - const trip4 = await prisma.trip.create({ - data: { serviceId: service302.id, originStationId: djibouti.id, destinationStationId: addis.id, departureAt: new Date('2026-06-18T08:30:00Z'), arrivalAt: new Date('2026-06-18T21:00:00Z'), durationMinutes: 750, stopsCount: 19 }, - }); - - // Trip Stop Times (Major stops only for brevity) - await prisma.tripStopTime.createMany({ data: [ - { tripId: trip1.id, stationId: addis.id, sequence: 1, plannedDepartureAt: new Date('2026-06-15T08:00:00Z'), status: 'UPCOMING' }, - { tripId: trip1.id, stationId: adama.id, sequence: 7, plannedArrivalAt: new Date('2026-06-15T09:30:00Z'), plannedDepartureAt: new Date('2026-06-15T09:45:00Z'), status: 'UPCOMING' }, - { tripId: trip1.id, stationId: awash.id, sequence: 10, plannedArrivalAt: new Date('2026-06-15T11:30:00Z'), plannedDepartureAt: new Date('2026-06-15T11:45:00Z'), status: 'UPCOMING' }, - { tripId: trip1.id, stationId: direDawa.id, sequence: 13, plannedArrivalAt: new Date('2026-06-15T15:00:00Z'), plannedDepartureAt: new Date('2026-06-15T15:20:00Z'), status: 'UPCOMING' }, - { tripId: trip1.id, stationId: aysha.id, sequence: 16, plannedArrivalAt: new Date('2026-06-15T18:00:00Z'), plannedDepartureAt: new Date('2026-06-15T18:10:00Z'), status: 'UPCOMING' }, - { tripId: trip1.id, stationId: djibouti.id, sequence: 21, plannedArrivalAt: new Date('2026-06-15T20:00:00Z'), status: 'UPCOMING' }, - ]}); - - // Coaches & Seats - for (const trip of [trip1, trip2, trip3, trip4]) { - const coaches = [ - { label: 'A', serviceClass: 'ECONOMY_REGULAR' as ServiceClass, seatCount: 60 }, - { label: 'B', serviceClass: 'ECONOMY_BED_LOWER' as ServiceClass, seatCount: 40 }, - { label: 'C', serviceClass: 'VIP_BED_LOWER' as ServiceClass, seatCount: 20 }, - ]; - for (const { label, serviceClass, seatCount } of coaches) { - const coach = await prisma.coach.create({ data: { tripId: trip.id, label, serviceClass } }); + // Create seats for each physical coach + for (const coach of [coachA1, coachB1, coachC1, coachA2, coachB2, coachC2]) { + const existingSeats = await prisma.seat.count({ where: { coachId: coach.id } }); + if (existingSeats === 0) { const seats = []; - const rows = Math.ceil(seatCount / 4); + const rows = Math.ceil(coach.totalUnits / 4); for (let row = 1; row <= rows; row++) { for (const col of ['A', 'B', 'C', 'D']) { - if (seats.length >= seatCount) break; - seats.push({ coachId: coach.id, row, col, label: `${row}${col}`, kind: (row === 1 && col === 'A' ? 'ACCESSIBLE' : 'STANDARD') as SeatKind }); + if (seats.length >= coach.totalUnits) break; + seats.push({ coachId: coach.id, row, col, label: `${row}${col}`, seatNumber: `${coach.label}${row}${col}`, kind: (row === 1 && col === 'A' ? 'ACCESSIBLE' : 'STANDARD') as SeatKind }); } } await prisma.seat.createMany({ data: seats }); } } - // Fare Rules (All trips) - for (const trip of [trip1, trip2, trip3, trip4]) { - await prisma.fareRule.createMany({ data: [ - { tripId: trip.id, serviceClass: 'ECONOMY_REGULAR', baseFareMinor: 45000, validFrom: new Date('2026-01-01'), refundable: true }, - { tripId: trip.id, serviceClass: 'ECONOMY_BED_LOWER', baseFareMinor: 65000, validFrom: new Date('2026-01-01'), refundable: true }, - { tripId: trip.id, serviceClass: 'VIP_BED_LOWER', baseFareMinor: 95000, validFrom: new Date('2026-01-01'), refundable: true }, - ]}); + // Train Schedules — delete dependents first to avoid FK violations + const existingScheduleIds = (await prisma.trainSchedule.findMany({ + where: { trainId: { in: [train301.id, train302.id] } }, + select: { id: true }, + })).map((s) => s.id); + if (existingScheduleIds.length > 0) { + await prisma.fareRule.deleteMany({ where: { tripId: { in: existingScheduleIds } } }); + await prisma.tripStopTime.deleteMany({ where: { scheduleId: { in: existingScheduleIds } } }); + await prisma.coachAssignment.deleteMany({ where: { scheduleId: { in: existingScheduleIds } } }); + await prisma.trainSchedule.deleteMany({ where: { id: { in: existingScheduleIds } } }); + } + const schedule1 = await prisma.trainSchedule.create({ + data: { trainId: train301.id, originStationId: addis.id, destinationStationId: djibouti.id, departureAt: new Date('2026-06-15T08:00:00Z'), arrivalAt: new Date('2026-06-15T20:00:00Z'), durationMinutes: 720, stopsCount: 6 }, + }); + const schedule2 = await prisma.trainSchedule.create({ + data: { trainId: train302.id, originStationId: djibouti.id, destinationStationId: addis.id, departureAt: new Date('2026-06-16T09:00:00Z'), arrivalAt: new Date('2026-06-16T21:30:00Z'), durationMinutes: 750, stopsCount: 5 }, + }); + const schedule3 = await prisma.trainSchedule.create({ + data: { trainId: train301.id, originStationId: addis.id, destinationStationId: djibouti.id, departureAt: new Date('2026-06-17T07:30:00Z'), arrivalAt: new Date('2026-06-17T19:45:00Z'), durationMinutes: 735, stopsCount: 5 }, + }); + const schedule4 = await prisma.trainSchedule.create({ + data: { trainId: train302.id, originStationId: djibouti.id, destinationStationId: addis.id, departureAt: new Date('2026-06-18T08:30:00Z'), arrivalAt: new Date('2026-06-18T21:00:00Z'), durationMinutes: 750, stopsCount: 5 }, + }); + + // Assign coaches to schedules + await prisma.coachAssignment.createMany({ + data: [ + { scheduleId: schedule1.id, coachId: coachA1.id, positionNumber: 1 }, + { scheduleId: schedule1.id, coachId: coachB1.id, positionNumber: 2 }, + { scheduleId: schedule1.id, coachId: coachC1.id, positionNumber: 3 }, + { scheduleId: schedule2.id, coachId: coachA2.id, positionNumber: 1 }, + { scheduleId: schedule2.id, coachId: coachB2.id, positionNumber: 2 }, + { scheduleId: schedule2.id, coachId: coachC2.id, positionNumber: 3 }, + { scheduleId: schedule3.id, coachId: coachA1.id, positionNumber: 1 }, + { scheduleId: schedule3.id, coachId: coachB1.id, positionNumber: 2 }, + { scheduleId: schedule3.id, coachId: coachC1.id, positionNumber: 3 }, + { scheduleId: schedule4.id, coachId: coachA2.id, positionNumber: 1 }, + { scheduleId: schedule4.id, coachId: coachB2.id, positionNumber: 2 }, + { scheduleId: schedule4.id, coachId: coachC2.id, positionNumber: 3 }, + ], + skipDuplicates: true, + }); + + // Stop Times + await prisma.tripStopTime.createMany({ + data: [ + { scheduleId: schedule1.id, stationId: addis.id, sequence: 1, plannedDepartureAt: new Date('2026-06-15T08:00:00Z'), status: 'UPCOMING' }, + { scheduleId: schedule1.id, stationId: adama.id, sequence: 2, plannedArrivalAt: new Date('2026-06-15T09:30:00Z'), plannedDepartureAt: new Date('2026-06-15T09:45:00Z'), status: 'UPCOMING' }, + { scheduleId: schedule1.id, stationId: awash.id, sequence: 3, plannedArrivalAt: new Date('2026-06-15T11:30:00Z'), plannedDepartureAt: new Date('2026-06-15T11:45:00Z'), status: 'UPCOMING' }, + { scheduleId: schedule1.id, stationId: direDawa.id, sequence: 4, plannedArrivalAt: new Date('2026-06-15T15:00:00Z'), plannedDepartureAt: new Date('2026-06-15T15:20:00Z'), status: 'UPCOMING' }, + { scheduleId: schedule1.id, stationId: aysha.id, sequence: 5, plannedArrivalAt: new Date('2026-06-15T18:00:00Z'), plannedDepartureAt: new Date('2026-06-15T18:10:00Z'), status: 'UPCOMING' }, + { scheduleId: schedule1.id, stationId: djibouti.id, sequence: 6, plannedArrivalAt: new Date('2026-06-15T20:00:00Z'), status: 'UPCOMING' }, + ], + }); + + // Fare Rules + for (const schedule of [schedule1, schedule2, schedule3, schedule4]) { + await prisma.fareRule.createMany({ + data: [ + { tripId: schedule.id, seatClassId: scEconomyRegular.id, baseFareMinor: 45000, validFrom: new Date('2026-01-01'), refundable: true }, + { tripId: schedule.id, seatClassId: scEconomyBed.id, baseFareMinor: 65000, validFrom: new Date('2026-01-01'), refundable: true }, + { tripId: schedule.id, seatClassId: scVipBed.id, baseFareMinor: 95000, validFrom: new Date('2026-01-01'), refundable: true }, + ], + skipDuplicates: true, + }); } // Users @@ -137,8 +120,7 @@ async function main() { const adminHash = await bcrypt.hash('admin123', 10); const agentHash = await bcrypt.hash('agent123', 10); - const adminUser = await prisma.user.upsert({ where: { email: 'admin@edr-platform.com' }, update: { passwordHash: adminHash, role: 'ADMIN' }, create: { fullName: 'EDR Admin', email: 'admin@edr-platform.com', phone: '+251900000000', passwordHash: adminHash, role: 'ADMIN' } }); - + await prisma.user.upsert({ where: { email: 'admin@edr-platform.com' }, update: { passwordHash: adminHash, role: 'ADMIN' }, create: { fullName: 'EDR Admin', email: 'admin@edr-platform.com', phone: '+251900000000', passwordHash: adminHash, role: 'ADMIN' } }); const passengerUser = await prisma.user.upsert({ where: { email: 'kelemu@email.com' }, update: {}, create: { fullName: 'Kelemu Ketsela', email: 'kelemu@email.com', phone: '+251912345678', passwordHash: hash, nationality: 'Ethiopian', nationalId: 'ET123456789' } }); let passenger = await prisma.passenger.findUnique({ where: { userId: passengerUser.id } }); if (!passenger) { @@ -151,105 +133,52 @@ async function main() { const agentUser = await prisma.user.upsert({ where: { email: 'agent@edr-platform.com' }, update: { passwordHash: agentHash, role: 'AGENT' }, create: { fullName: 'Agent Abebe', email: 'agent@edr-platform.com', phone: '+251911111111', passwordHash: agentHash, role: 'AGENT' } }); await prisma.agent.upsert({ where: { userId: agentUser.id }, update: {}, create: { userId: agentUser.id, agentCode: 'AG001', stationId: addis.id, commissionRate: 5, active: true } }); - // Baggage Allowance - Delete and recreate + // Baggage Allowance await prisma.baggageAllowance.deleteMany({}); - await prisma.baggageAllowance.createMany({ data: [ - { serviceClass: 'ECONOMY_REGULAR', maxWeightKg: 20, maxPiecesCount: 2, excessFeePerKg: 500 }, - { serviceClass: 'ECONOMY_BED_LOWER', maxWeightKg: 25, maxPiecesCount: 2, excessFeePerKg: 450 }, - { serviceClass: 'VIP_BED_LOWER', maxWeightKg: 30, maxPiecesCount: 3, excessFeePerKg: 400 }, - ]}); + await prisma.baggageAllowance.createMany({ + data: [ + { seatClassId: scEconomyRegular.id, maxWeightKg: 20, maxPiecesCount: 2, excessFeePerKg: 500 }, + { seatClassId: scEconomyBed.id, maxWeightKg: 25, maxPiecesCount: 2, excessFeePerKg: 450 }, + { seatClassId: scVipBed.id, maxWeightKg: 30, maxPiecesCount: 3, excessFeePerKg: 400 }, + ], + }); // Notification Templates await prisma.notificationTemplate.upsert({ where: { code: 'BOOKING_CONFIRMED' }, update: {}, create: { code: 'BOOKING_CONFIRMED', channel: 'EMAIL', subject: 'Booking Confirmed', bodyTemplate: 'Your booking {{bookingRef}} is confirmed for {{tripDate}}.', active: true } }); await prisma.notificationTemplate.upsert({ where: { code: 'PAYMENT_SUCCESS' }, update: {}, create: { code: 'PAYMENT_SUCCESS', channel: 'SMS', bodyTemplate: 'Payment successful for {{bookingRef}}. Amount: {{amount}} ETB', active: true } }); - await prisma.notificationTemplate.upsert({ where: { code: 'TRIP_REMINDER' }, update: {}, create: { code: 'TRIP_REMINDER', channel: 'PUSH', subject: 'Trip Reminder', bodyTemplate: 'Your trip departs in {{hours}} hours from {{station}}.', active: true } }); // Promotions await prisma.promotion.upsert({ where: { code: 'WEEKEND15' }, update: {}, create: { title: 'Weekend Sale', subtitle: '15% off all trips', code: 'WEEKEND15', percentOff: 15, validUntil: new Date('2026-12-31'), ctaLabel: 'Book Now', active: true } }); - await prisma.promotion.upsert({ where: { code: 'NEWUSER20' }, update: {}, create: { title: 'New User Bonus', code: 'NEWUSER20', percentOff: 20, validUntil: new Date('2026-12-31'), active: true } }); - // FAQ - Delete and recreate for clean seed + // FAQ await prisma.faqArticle.deleteMany({}); await prisma.faqCategory.deleteMany({}); const faqBooking = await prisma.faqCategory.create({ data: { title: 'Booking & Tickets', iconKey: 'confirmation_number' } }); - const faqPayment = await prisma.faqCategory.create({ data: { title: 'Payment & Refunds', iconKey: 'payment' } }); - - await prisma.faqArticle.createMany({ data: [ - { categoryId: faqBooking.id, question: 'How do I book a train ticket?', answerMarkdown: 'Open Search, select origin and destination stations, choose date, select seats, and proceed to payment.', rank: 1 }, - { categoryId: faqBooking.id, question: 'Can I modify my booking?', answerMarkdown: 'Yes, you can modify your booking up to 24 hours before departure through the Bookings section.', rank: 2 }, - { categoryId: faqPayment.id, question: 'What payment methods are accepted?', answerMarkdown: 'We accept Telebirr, CBE Birr, eBirr, Card, and Wallet payments.', rank: 1 }, - { categoryId: faqPayment.id, question: 'How do refunds work?', answerMarkdown: 'Refunds are processed within 5-7 business days to your original payment method.', rank: 2 }, - ]}); + await prisma.faqArticle.createMany({ data: [{ categoryId: faqBooking.id, question: 'How do I book a train ticket?', answerMarkdown: 'Open Search, select origin and destination stations, choose date, select seats, and proceed to payment.', rank: 1 }] }); - // Menu Categories & Items - Delete and recreate - await prisma.menuItem.deleteMany({}); - await prisma.menuCategory.deleteMany({}); - const menuBeverages = await prisma.menuCategory.create({ data: { name: 'Beverages' } }); - const menuSnacks = await prisma.menuCategory.create({ data: { name: 'Snacks' } }); - - await prisma.menuItem.createMany({ data: [ - { tripId: trip1.id, categoryId: menuBeverages.id, name: 'Coffee', priceMinor: 2500, available: true }, - { tripId: trip1.id, categoryId: menuBeverages.id, name: 'Tea', priceMinor: 2000, available: true }, - { tripId: trip1.id, categoryId: menuSnacks.id, name: 'Sandwich', priceMinor: 5000, available: true }, - ]}); - - // Station Crowd Signals - Delete and recreate + // Station Crowd Signals await prisma.stationCrowdSignal.deleteMany({}); - await prisma.stationCrowdSignal.createMany({ data: [ - { stationId: addis.id, level: 'MODERATE', label: 'Moderate', statusLabel: 'Normal operations' }, - { stationId: adama.id, level: 'LOW', label: 'Low', statusLabel: 'Quiet' }, - { stationId: direDawa.id, level: 'LOW', label: 'Low', statusLabel: 'Quiet' }, - { stationId: djibouti.id, level: 'HIGH', label: 'High', statusLabel: 'Busy terminal' }, - ]}); + await prisma.stationCrowdSignal.createMany({ data: [{ stationId: addis.id, level: 'MODERATE', label: 'Moderate', statusLabel: 'Normal operations' }, { stationId: djibouti.id, level: 'HIGH', label: 'High', statusLabel: 'Busy terminal' }] }); // Fraud Detection Rules await prisma.fraudRule.upsert({ where: { type: 'VELOCITY' }, update: {}, create: { type: 'VELOCITY', enabled: true, threshold: 3, config: { windowMinutes: 60, action: 'FLAG' } } }); - await prisma.fraudRule.upsert({ where: { type: 'HIGH_VALUE' }, update: {}, create: { type: 'HIGH_VALUE', enabled: true, threshold: 500000, config: { action: 'REVIEW' } } }); - await prisma.fraudRule.upsert({ where: { type: 'FAILED_PAYMENTS' }, update: {}, create: { type: 'FAILED_PAYMENTS', enabled: true, threshold: 5, config: { windowMinutes: 1440, action: 'BLOCK' } } }); - - // Loyalty Rewards (linked to loyalty account) - Delete and recreate - if (passenger) { - const loyaltyAccount = await prisma.loyaltyAccount.findUnique({ where: { passengerId: passenger.id } }); - if (loyaltyAccount) { - await prisma.loyaltyReward.deleteMany({ where: { accountId: loyaltyAccount.id } }); - await prisma.loyaltyReward.createMany({ data: [ - { accountId: loyaltyAccount.id, title: '10% Discount Voucher', costPoints: 1000, available: true, description: 'Get 10% off your next booking' }, - { accountId: loyaltyAccount.id, title: 'Free Upgrade to VIP', costPoints: 2500, available: true, description: 'Upgrade to VIP class on any trip' }, - { accountId: loyaltyAccount.id, title: '500 ETB Wallet Credit', costPoints: 5000, available: true, description: 'Add 500 ETB to your wallet' }, - ]}); - } - } // Currency Exchange Rates await prisma.currencyExchangeRate.deleteMany({}); - await prisma.currencyExchangeRate.createMany({ data: [ - { fromCurrency: 'ETB', toCurrency: 'ETB', rate: 1.0, effectiveDate: new Date() }, - { fromCurrency: 'ETB', toCurrency: 'DJF', rate: 3.25, effectiveDate: new Date() }, - { fromCurrency: 'ETB', toCurrency: 'USD', rate: 0.018, effectiveDate: new Date() }, - { fromCurrency: 'DJF', toCurrency: 'ETB', rate: 0.3077, effectiveDate: new Date() }, - { fromCurrency: 'USD', toCurrency: 'ETB', rate: 55.56, effectiveDate: new Date() }, - ]}); + await prisma.currencyExchangeRate.createMany({ data: [{ fromCurrency: 'ETB', toCurrency: 'ETB', rate: 1.0, effectiveDate: new Date() }, { fromCurrency: 'ETB', toCurrency: 'USD', rate: 0.018, effectiveDate: new Date() }] }); console.log('✅ Comprehensive seed complete'); console.log('\n📋 Seed Summary:'); - console.log(' - 21 Stations (Complete Ethiopian-Djibouti Railway with country codes)'); - console.log(' - 1 Route with 21 stops'); - console.log(' - 2 Train services, 4 trips'); - console.log(' - 3 Coaches per trip (Economy, Bed, VIP)'); - console.log(' - Fare rules for ADULT and CHILD categories'); - console.log(' - Currency exchange rates (ETB ↔ DJF, USD)'); + console.log(' - 2 Trains (Express 301, Express 302)'); + console.log(' - 6 Physical Coaches (reusable across schedules)'); + console.log(' - 4 Train Schedules with coach assignments'); + console.log(' - 3 Seat Classes (Economy Regular, Economy Bed, VIP Bed)'); console.log(' - 3 Users: Admin, Passenger (Silver tier + wallet), Agent'); - console.log(' - 3 Fraud detection rules'); - console.log(' - 3 Loyalty rewards'); - console.log(' - Baggage rules, Notification templates, Promotions, FAQ'); console.log('\n🔑 Login Credentials:'); console.log(' Admin: admin@edr-platform.com / admin123'); console.log(' Passenger: kelemu@email.com / password123'); console.log(' Agent: agent@edr-platform.com / agent123'); - console.log('\n🚉 Stations: Addis Ababa → Sebeta → Labu → Indode → Bishoftu → Mojo → Adama → Feto → Metahara → Awash → Mieso → Bike → Dire Dawa → Arawa → Adigala → Aysha → Dawanle → Alisabieh → Holhol → Nagad → Djibouti'); - console.log('\n💰 Pricing: ADULT (≥5 years) = 100% fare | CHILD (<5 years) = First free, subsequent 100%'); - console.log('\n💱 Currencies: ETB (transaction) | DJF, USD (display) | Rates: ETB→DJF=3.25, ETB→USD=0.018'); - console.log('\n🔐 Verifayda: DISABLED (set VERIFAYDA_ENABLED=true in production)'); + console.log('\n🚂 Architecture: Train → TrainSchedule ↔ CoachAssignment ↔ Coach → Seat'); } main().catch(console.error).finally(() => prisma.$disconnect()); diff --git a/apps/edr-passenger-api/src/app.module.ts b/apps/edr-passenger-api/src/app.module.ts index e5c62a2bb..7b2f460d3 100644 --- a/apps/edr-passenger-api/src/app.module.ts +++ b/apps/edr-passenger-api/src/app.module.ts @@ -33,6 +33,7 @@ import { SegmentsModule } from './modules/segments/segments.module'; import { AgentsModule } from './modules/agents/agents.module'; import { ReportsModule } from './modules/reports/reports.module'; import { FraudModule } from './modules/fraud/fraud.module'; +import { SeatClassesModule } from './modules/seat-classes/seat-classes.module'; @Module({ imports: [ @@ -66,6 +67,7 @@ import { FraudModule } from './modules/fraud/fraud.module'; AgentsModule, ReportsModule, FraudModule, + SeatClassesModule, ], }) export class AppModule implements NestModule { diff --git a/apps/edr-passenger-api/src/main.ts b/apps/edr-passenger-api/src/main.ts index 51dbe061e..1528aa0da 100644 --- a/apps/edr-passenger-api/src/main.ts +++ b/apps/edr-passenger-api/src/main.ts @@ -168,7 +168,7 @@ Payment providers send notifications to: .addTag('Agents', '👨‍💼 Agent booking, shifts, commissions, reconciliation') .addTag('Booking', '🎫 Booking lifecycle, modification, cancellation, refunds') .addTag('Dashboard', '📊 Home dashboard aggregated data') - .addTag('Fleet', '🚂 Train services, coaches, seat configurations') + .addTag('Fleet', '🚂 Trains, physical coaches, seat auto-generation, coach-to-schedule assignments') .addTag('Seat Classes', '🎨 Seat class management and configuration') .addTag('Fraud Detection', '🔒 Fraud detection, risk scoring, user blocking') .addTag('Live Tracking', '📍 Real-time trip status, location updates, crowd signals') @@ -179,7 +179,8 @@ Payment providers send notifications to: .addTag('Payment Webhooks', '🔗 Payment provider callback endpoints') .addTag('Promotions', '🎁 Promo codes, campaigns, discount validation') .addTag('Reports', '📈 Revenue reports, occupancy analytics, agent sales') - .addTag('Schedule', '🗓️ Trip schedules, fare rules, status updates') + .addTag('Routes', '🗺️ Reusable route templates with ordered stops — referenced by schedules') + .addTag('Schedule', '🗓️ Train schedules (created from routes), stop time management, fare rules') .addTag('Search', '🔍 Trip search, availability, fare quotes') .addTag('Seats', '🪑 Seat maps, holds, releases, blocking, auto-assign') .addTag('Segment-based Seats', '🎯 Segment-based seat availability and booking') diff --git a/apps/edr-passenger-api/src/modules/agents/agents.dto.ts b/apps/edr-passenger-api/src/modules/agents/agents.dto.ts index 62bdc59ad..75f718d23 100644 --- a/apps/edr-passenger-api/src/modules/agents/agents.dto.ts +++ b/apps/edr-passenger-api/src/modules/agents/agents.dto.ts @@ -13,7 +13,7 @@ export class AgentPassengerDto { export class CreateAgentBookingDto { @ApiProperty() @IsString() agentId: string; - @ApiProperty() @IsString() tripId: string; + @ApiProperty({ example: 'schedule-uuid' }) @IsString() scheduleId: string; @ApiProperty({ type: [AgentPassengerDto] }) @IsArray() @ValidateNested({ each: true }) @Type(() => AgentPassengerDto) passengers: AgentPassengerDto[]; @ApiProperty() @IsString() paymentMethod: string; @ApiPropertyOptional() @IsOptional() @IsInt() cashReceived?: number; diff --git a/apps/edr-passenger-api/src/modules/agents/agents.service.ts b/apps/edr-passenger-api/src/modules/agents/agents.service.ts index f17289de4..12982f570 100644 --- a/apps/edr-passenger-api/src/modules/agents/agents.service.ts +++ b/apps/edr-passenger-api/src/modules/agents/agents.service.ts @@ -17,8 +17,8 @@ export class AgentsService { if (!agent || !agent.active) throw new NotFoundException('Agent not found or inactive'); if (!agent.user.passenger) throw new BadRequestException('Agent must have passenger account'); - const trip = await this.prisma.trip.findUnique({ where: { id: dto.tripId } }); - if (!trip) throw new NotFoundException('Trip not found'); + const schedule = await this.prisma.trainSchedule.findUnique({ where: { id: dto.scheduleId } }); + if (!schedule) throw new NotFoundException('Schedule not found'); const seatIds = dto.passengers.map(p => p.seatId); const seats = await this.prisma.seat.findMany({ where: { id: { in: seatIds } } }); @@ -31,7 +31,7 @@ export class AgentsService { data: { bookingRef: generateRef(), passengerId: agent.user.passenger.id, - tripId: dto.tripId, + scheduleId: dto.scheduleId, status: dto.paymentMethod === 'CASH' ? 'CONFIRMED' : 'PENDING_PAYMENT', totalMinor, seats: { diff --git a/apps/edr-passenger-api/src/modules/bookings/bookings.dto.ts b/apps/edr-passenger-api/src/modules/bookings/bookings.dto.ts index 03b3b4aeb..82d75f2dc 100644 --- a/apps/edr-passenger-api/src/modules/bookings/bookings.dto.ts +++ b/apps/edr-passenger-api/src/modules/bookings/bookings.dto.ts @@ -15,15 +15,13 @@ export class PassengerInputDto { export class CreateBookingDto { @ApiProperty() @IsString() passengerId: string; - @ApiProperty() @IsString() tripId: string; + @ApiProperty() @IsString() scheduleId: string; @ApiProperty() @IsString() holdId: string; + @ApiProperty({ example: 'station-uuid', description: 'Origin station UUID for this leg (must match the hold)' }) @IsString() originStationId: string; + @ApiProperty({ example: 'station-uuid', description: 'Destination station UUID for this leg (must match the hold)' }) @IsString() destinationStationId: string; @ApiProperty({ type: [PassengerInputDto] }) @IsArray() @ValidateNested({ each: true }) @Type(() => PassengerInputDto) passengers: PassengerInputDto[]; - @ApiProperty({ - example: 'ECONOMY_REGULAR', - enum: ['ECONOMY_REGULAR', 'ECONOMY_BED_LOWER', 'ECONOMY_BED_MIDDLE', 'ECONOMY_BED_UPPER', 'VIP_BED_LOWER', 'VIP_BED_UPPER'] - }) - @IsString() serviceClass: string; - @ApiPropertyOptional({ example: 'seat-class-uuid' }) @IsOptional() @IsString() seatClassId?: string; + @ApiProperty({ example: 'seat-class-uuid', description: 'Seat class UUID' }) + @IsString() seatClassId: string; @ApiPropertyOptional() @IsOptional() @IsString() promoCode?: string; @ApiPropertyOptional() @IsOptional() @IsInt() loyaltyRedemptionPoints?: number; @ApiPropertyOptional({ example: 'ONE_WAY' }) @IsOptional() @IsString() bookingType?: string; @@ -32,7 +30,7 @@ export class CreateBookingDto { export class ModifyBookingDto { @ApiProperty() @IsString() bookingRef: string; - @ApiProperty() @IsString() newTripId: string; + @ApiProperty({ example: 'schedule-uuid' }) @IsString() newScheduleId: string; @ApiProperty({ type: [String] }) @IsArray() newSeatIds: string[]; @ApiPropertyOptional() @IsOptional() @IsString() reason?: string; } diff --git a/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts b/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts index 5d99717d4..6645f6f63 100644 --- a/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts +++ b/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts @@ -2,7 +2,7 @@ import { Injectable, NotFoundException, BadRequestException } from '@nestjs/comm import { PrismaService } from '../../common/prisma.service'; import { SeatsService } from '../seats/seats.service'; import { EventEmitter2 } from '@nestjs/event-emitter'; -import { CreateBookingDto, ModifyBookingDto, CancelBookingDto } from './bookings.dto'; +import { CreateBookingDto, ModifyBookingDto } from './bookings.dto'; import { Cron, CronExpression } from '@nestjs/schedule'; import { VerifaydaService } from '../verifayda/verifayda.service'; import { CurrencyService } from '../currency/currency.service'; @@ -17,9 +17,7 @@ function calculateAge(dateOfBirth: Date): number { const today = new Date(); let age = today.getFullYear() - dateOfBirth.getFullYear(); const monthDiff = today.getMonth() - dateOfBirth.getMonth(); - if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < dateOfBirth.getDate())) { - age--; - } + if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < dateOfBirth.getDate())) age--; return age; } @@ -36,100 +34,67 @@ export class BookingsService { async create(dto: CreateBookingDto) { const hold = await this.prisma.seatHold.findUnique({ where: { id: dto.holdId } }); if (!hold || hold.expiresAt < new Date()) throw new BadRequestException('Seat hold expired'); - const trip = await this.prisma.trip.findUnique({ where: { id: dto.tripId }, include: { originStation: true, destinationStation: true } }); - if (!trip) throw new NotFoundException('Trip not found'); + const schedule = await this.prisma.trainSchedule.findUnique({ where: { id: dto.scheduleId }, include: { originStation: true, destinationStation: true } }); + if (!schedule) throw new NotFoundException('Schedule not found'); const seatIds = dto.passengers.map((p) => p.seatId); - - // Calculate passenger categories and verify Ethiopian nationals const passengersData = []; - let adultCount = 0; - let childCount = 0; - + let adultCount = 0, childCount = 0; + for (const passenger of dto.passengers) { const dateOfBirth = new Date(passenger.dateOfBirth); const age = calculateAge(dateOfBirth); const category: PassengerCategory = age < 5 ? PassengerCategory.CHILD : PassengerCategory.ADULT; - - if (category === PassengerCategory.ADULT) adultCount++; - else childCount++; - + if (category === PassengerCategory.ADULT) adultCount++; else childCount++; + let passengerName = passenger.passengerName; let verifaydaVerified = false; - let verifaydaData: Record | undefined = undefined; - - // Verify Ethiopian nationals via Verifayda + let verifaydaData: Record | undefined; + if (passenger.idDocumentType === IdDocumentType.NATIONAL_ID && passenger.idDocumentNumber) { const verification = await this.verifaydaService.verifyNationalId(passenger.idDocumentNumber); - - if (!verification.verified) { - throw new BadRequestException( - `Verifayda verification failed for passenger ${passenger.passengerName}: ${verification.failureReason}`, - ); - } - - // Use verified data from Verifayda + if (!verification.verified) throw new BadRequestException(`Verifayda verification failed for ${passenger.passengerName}: ${verification.failureReason}`); passengerName = verification.passengerData?.fullName || passengerName; verifaydaVerified = true; verifaydaData = verification.passengerData?.profileData; } else if (passenger.idDocumentType === IdDocumentType.PASSPORT) { - // Non-Ethiopian: require passport details - if (!passenger.passportNumber || !passenger.passportCountry) { - throw new BadRequestException( - `Passport number and country required for non-Ethiopian passenger ${passenger.passengerName}`, - ); - } + if (!passenger.passportNumber || !passenger.passportCountry) throw new BadRequestException(`Passport number and country required for ${passenger.passengerName}`); } - - passengersData.push({ - ...passenger, - passengerName, - dateOfBirth, - category, - verifaydaVerified, - verifaydaData, - }); + + passengersData.push({ ...passenger, passengerName, dateOfBirth, category, verifaydaVerified, verifaydaData }); } - - // Calculate fare with age-based pricing - const baseFareMinor = await this.getBaseFare(dto.tripId, dto.serviceClass); + + const baseFareMinor = await this.getBaseFare(dto.scheduleId, dto.seatClassId); const adultFareMinor = baseFareMinor * adultCount; const paidChildrenCount = Math.max(0, childCount - 1); const childFareMinor = baseFareMinor * paidChildrenCount; const totalBaseFareMinor = adultFareMinor + childFareMinor; - + let discountMinor = 0; if (dto.promoCode) { const promo = await this.prisma.promotion.findUnique({ where: { code: dto.promoCode } }); if (promo?.active && promo.validUntil > new Date()) { - discountMinor = promo.percentOff - ? Math.round(totalBaseFareMinor * promo.percentOff / 100) - : (promo.amountOffMinor ?? 0); + discountMinor = promo.percentOff ? Math.round(totalBaseFareMinor * promo.percentOff / 100) : (promo.amountOffMinor ?? 0); } } - + const loyaltyMinor = (dto.loyaltyRedemptionPoints ?? 0) * 10; const taxesMinor = Math.round(totalBaseFareMinor * 0.05); const totalMinor = Math.max(0, totalBaseFareMinor - discountMinor - loyaltyMinor + taxesMinor); - + const displayCurrency = dto.displayCurrency || Currency.ETB; let displayTotalMinor = totalMinor; - if (displayCurrency !== Currency.ETB) { displayTotalMinor = await this.currencyService.convertAmount(totalMinor, Currency.ETB, displayCurrency); } - + const booking = await this.prisma.booking.create({ data: { bookingRef: generateRef(), passengerId: dto.passengerId, - tripId: dto.tripId, + scheduleId: dto.scheduleId, status: 'PENDING_PAYMENT', - totalMinor, - adultCount, - childCount, - displayCurrency, - displayTotalMinor, + totalMinor, adultCount, childCount, displayCurrency, displayTotalMinor, bookingType: dto.bookingType ?? 'ONE_WAY', seats: { create: passengersData.map((p) => ({ @@ -148,96 +113,64 @@ export class BookingsService { })), }, }, - include: { seats: { include: { seat: true } }, trip: { include: { originStation: true, destinationStation: true, service: true } } }, + include: { seats: { include: { seat: true } }, schedule: { include: { originStation: true, destinationStation: true, train: true } } }, }); - + await this.seatsService.confirmSeats(seatIds); this.eventEmitter.emit('booking.created', { booking }); - + return { ...booking, - fareBreakdown: { - baseFareMinor, - adultCount, - adultFareMinor, - childCount, - freeChildrenCount: Math.min(childCount, 1), - paidChildrenCount, - childFareMinor, - totalBaseFareMinor, - discountMinor, - loyaltyRedemptionMinor: loyaltyMinor, - taxesFeesMinor: taxesMinor, - totalMinor, - currency: 'ETB', - displayCurrency, - displayTotalMinor, - }, + fareBreakdown: { baseFareMinor, adultCount, adultFareMinor, childCount, freeChildrenCount: Math.min(childCount, 1), paidChildrenCount, childFareMinor, totalBaseFareMinor, discountMinor, loyaltyRedemptionMinor: loyaltyMinor, taxesFeesMinor: taxesMinor, totalMinor, currency: 'ETB', displayCurrency, displayTotalMinor }, }; } - private async getBaseFare(tripId: string, serviceClass: string): Promise { - const fareRule = await this.prisma.fareRule.findFirst({ - where: { tripId, serviceClass: serviceClass as any }, - }); + private async getBaseFare(scheduleId: string, seatClassId: string): Promise { + const fareRule = await this.prisma.fareRule.findFirst({ where: { tripId: scheduleId, seatClassId } }); return fareRule?.baseFareMinor ?? 35000; } async getByRef(bookingRef: string) { - const booking = await this.prisma.booking.findUnique({ where: { bookingRef }, include: { trip: { include: { originStation: true, destinationStation: true, service: true } }, seats: { include: { seat: { include: { coach: true } } } }, paymentIntent: true, ticket: true } }); + const booking = await this.prisma.booking.findUnique({ + where: { bookingRef }, + include: { + schedule: { include: { originStation: true, destinationStation: true, train: true } }, + seats: { include: { seat: { include: { coach: { include: { seatClass: true } } } } } }, + paymentIntent: true, ticket: true, + }, + }); if (!booking) throw new NotFoundException('Booking not found'); return { - id: booking.id, - bookingRef: booking.bookingRef, - status: booking.status, - totalFare: booking.totalMinor / 100, - adultCount: booking.adultCount, - childCount: booking.childCount, - displayCurrency: booking.displayCurrency, - displayTotalFare: booking.displayTotalMinor ? booking.displayTotalMinor / 100 : undefined, - bookingType: booking.bookingType, - createdAt: booking.createdAt, - trip: { - number: booking.trip.service.number, - origin: { id: booking.trip.originStation.id, name: booking.trip.originStation.name, code: booking.trip.originStation.code, city: booking.trip.originStation.city }, - destination: { id: booking.trip.destinationStation.id, name: booking.trip.destinationStation.name, code: booking.trip.destinationStation.code, city: booking.trip.destinationStation.city }, - departureAt: booking.trip.departureAt, - arrivalAt: booking.trip.arrivalAt, + id: booking.id, bookingRef: booking.bookingRef, status: booking.status, + totalFare: booking.totalMinor / 100, adultCount: booking.adultCount, childCount: booking.childCount, + displayCurrency: booking.displayCurrency, displayTotalFare: booking.displayTotalMinor ? booking.displayTotalMinor / 100 : undefined, + bookingType: booking.bookingType, createdAt: booking.createdAt, + schedule: { + number: booking.schedule.train.number, + origin: { id: booking.schedule.originStation.id, name: booking.schedule.originStation.name, code: booking.schedule.originStation.code, city: booking.schedule.originStation.city }, + destination: { id: booking.schedule.destinationStation.id, name: booking.schedule.destinationStation.name, code: booking.schedule.destinationStation.code, city: booking.schedule.destinationStation.city }, + departureAt: booking.schedule.departureAt, arrivalAt: booking.schedule.arrivalAt, }, passengers: booking.seats.map((bs) => ({ - fullName: bs.passengerName, - category: bs.passengerCategory, - verifaydaVerified: bs.verifaydaVerified, - seat: { number: bs.seat.label, coach: bs.seat.coach.label, class: bs.seat.coach.serviceClass }, + fullName: bs.passengerName, category: bs.passengerCategory, verifaydaVerified: bs.verifaydaVerified, + seat: { number: bs.seat.label, coach: bs.seat.coach.label, class: bs.seat.coach.seatClass.name }, })), payment: booking.paymentIntent ? { method: booking.paymentIntent.method, status: booking.paymentIntent.status } : undefined, }; } async modify(dto: ModifyBookingDto) { - const booking = await this.prisma.booking.findUnique({ where: { bookingRef: dto.bookingRef }, include: { seats: true, trip: true } }); + const booking = await this.prisma.booking.findUnique({ where: { bookingRef: dto.bookingRef }, include: { seats: true, schedule: true } }); if (!booking) throw new NotFoundException('Booking not found'); if (booking.status !== 'CONFIRMED') throw new BadRequestException('Only confirmed bookings can be modified'); - if (booking.trip.departureAt < new Date()) throw new BadRequestException('Cannot modify past bookings'); + if (booking.schedule.departureAt < new Date()) throw new BadRequestException('Cannot modify past bookings'); const oldSeats = booking.seats.map(s => s.seatId); - const fareAdjustment = 0; - await this.prisma.bookingModification.create({ - data: { - bookingId: booking.id, - modifiedBy: booking.passengerId, - modificationType: 'SEAT_CHANGE', - oldData: { tripId: booking.tripId, seatIds: oldSeats }, - newData: { tripId: dto.newTripId, seatIds: dto.newSeatIds }, - fareAdjustment, - reason: dto.reason - } + data: { bookingId: booking.id, modifiedBy: booking.passengerId, modificationType: 'SEAT_CHANGE', oldData: { scheduleId: booking.scheduleId, seatIds: oldSeats }, newData: { scheduleId: dto.newScheduleId, seatIds: dto.newSeatIds }, fareAdjustment: 0, reason: dto.reason }, }); - await this.seatsService.releaseSeats(oldSeats); await this.seatsService.confirmSeats(dto.newSeatIds); - return { modified: true, bookingRef: dto.bookingRef }; } @@ -245,23 +178,10 @@ export class BookingsService { const booking = await this.prisma.booking.findUnique({ where: { bookingRef }, include: { seats: true, paymentIntent: true } }); if (!booking) throw new NotFoundException('Booking not found'); if (booking.status === 'CANCELLED') throw new BadRequestException('Booking already cancelled'); - const refundAmount = booking.status === 'CONFIRMED' ? Math.floor(booking.totalMinor * 0.8) : 0; - - await this.prisma.bookingCancellation.create({ - data: { - bookingId: booking.id, - cancelledBy: booking.passengerId, - reason, - refundAmount, - refundMethod: booking.paymentIntent?.method ?? 'ORIGINAL', - refundStatus: 'PENDING' - } - }); - + await this.prisma.bookingCancellation.create({ data: { bookingId: booking.id, cancelledBy: booking.passengerId, reason, refundAmount, refundMethod: booking.paymentIntent?.method ?? 'ORIGINAL', refundStatus: 'PENDING' } }); await this.seatsService.releaseSeats(booking.seats.map((s) => s.seatId)); await this.prisma.booking.update({ where: { bookingRef }, data: { status: 'CANCELLED' } }); - return { cancelled: true, refundAmount: refundAmount / 100, currency: 'ETB' }; } @@ -269,6 +189,9 @@ export class BookingsService { async expirePendingBookings() { const cutoff = new Date(Date.now() - 20 * 60 * 1000); const expired = await this.prisma.booking.findMany({ where: { status: 'PENDING_PAYMENT', createdAt: { lt: cutoff } }, include: { seats: true } }); - for (const b of expired) { await this.seatsService.releaseSeats(b.seats.map((s) => s.seatId)); await this.prisma.booking.update({ where: { id: b.id }, data: { status: 'CANCELLED' } }); } + for (const b of expired) { + await this.seatsService.releaseSeats(b.seats.map((s) => s.seatId)); + await this.prisma.booking.update({ where: { id: b.id }, data: { status: 'CANCELLED' } }); + } } } diff --git a/apps/edr-passenger-api/src/modules/dashboard/dashboard.service.ts b/apps/edr-passenger-api/src/modules/dashboard/dashboard.service.ts index 22b6ddeb1..e104a507f 100644 --- a/apps/edr-passenger-api/src/modules/dashboard/dashboard.service.ts +++ b/apps/edr-passenger-api/src/modules/dashboard/dashboard.service.ts @@ -10,8 +10,12 @@ export class DashboardService { const [passenger, upcomingBooking, wallet, promos, weatherAlerts, stationSignals, savedRoutes] = await Promise.all([ this.prisma.passenger.findUnique({ where: { id: passengerId }, include: { user: { select: { fullName: true } }, loyalty: true } }), this.prisma.booking.findFirst({ - where: { passengerId, status: 'CONFIRMED', trip: { departureAt: { gte: now } } }, - include: { trip: { include: { originStation: true, destinationStation: true, service: true, liveStatus: true } }, seats: { include: { seat: { include: { coach: true } } }, take: 1 }, ticket: true }, + where: { passengerId, status: 'CONFIRMED', schedule: { departureAt: { gte: now } } }, + include: { + schedule: { include: { originStation: true, destinationStation: true, train: true, liveStatus: true } }, + seats: { include: { seat: { include: { coach: true } } }, take: 1 }, + ticket: true, + }, orderBy: { createdAt: 'asc' }, }), this.prisma.walletAccount.findUnique({ where: { passengerId } }), @@ -30,10 +34,10 @@ export class DashboardService { user: { firstName, greetingKey }, upcomingTicket: upcomingBooking ? { ticketId: upcomingBooking.ticket?.id, bookingRef: upcomingBooking.bookingRef, - from: upcomingBooking.trip.originStation.name, to: upcomingBooking.trip.destinationStation.name, - trainName: upcomingBooking.trip.service.name, coachLabel: seat?.seat.coach.label, seatLabel: seat?.seat.label, - departureAt: upcomingBooking.trip.departureAt, - punctualityLabel: (upcomingBooking.trip.liveStatus?.delayMinutes ?? 0) > 0 ? 'DELAYED' : 'ON_TIME', + from: upcomingBooking.schedule.originStation.name, to: upcomingBooking.schedule.destinationStation.name, + trainName: upcomingBooking.schedule.train.name, coachLabel: seat?.seat.coach.label, seatLabel: seat?.seat.label, + departureAt: upcomingBooking.schedule.departureAt, + punctualityLabel: (upcomingBooking.schedule.liveStatus?.delayMinutes ?? 0) > 0 ? 'DELAYED' : 'ON_TIME', } : null, wallet: wallet ? { balanceMinor: wallet.balanceMinor, currency: wallet.currency } : null, activePromotionsCount: promos, diff --git a/apps/edr-passenger-api/src/modules/fleet/fleet.controller.ts b/apps/edr-passenger-api/src/modules/fleet/fleet.controller.ts index c8b2c23ff..bc236a8f8 100644 --- a/apps/edr-passenger-api/src/modules/fleet/fleet.controller.ts +++ b/apps/edr-passenger-api/src/modules/fleet/fleet.controller.ts @@ -1,7 +1,7 @@ -import { Body, Controller, Get, Param, Patch, Post, Query, UseGuards } from '@nestjs/common'; -import { ApiTags, ApiOperation, ApiBearerAuth, ApiParam, ApiQuery, ApiResponse, ApiBody } from '@nestjs/swagger'; +import { Body, Controller, Delete, Get, Param, Patch, Post, Query, UseGuards } from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiBearerAuth, ApiParam, ApiQuery, ApiBody, ApiResponse } from '@nestjs/swagger'; import { FleetService } from './fleet.service'; -import { CreateTrainServiceDto, CreateCoachDto, CreateSeatBatchDto, UpdateCoachDto } from './fleet.dto'; +import { CreateTrainDto, CreateCoachDto, UpdateCoachDto, AssignCoachDto, CreateSeatBatchDto, ListCoachesDto } from './fleet.dto'; import { JwtGuard } from '../../common/jwt.guard'; @ApiTags('Fleet') @@ -11,46 +11,91 @@ import { JwtGuard } from '../../common/jwt.guard'; export class FleetController { constructor(private service: FleetService) {} - @Get('services') - @ApiOperation({ summary: 'List train services' }) - @ApiResponse({ status: 200, description: 'Returns all train services with recent trips' }) - getServices() { return this.service.getServices(); } + @Get('trains') + @ApiOperation({ summary: 'List all trains with their recent schedules' }) + @ApiResponse({ status: 200, description: 'Array of trains each with up to 5 most recent schedules' }) + getTrains() { return this.service.getTrains(); } - @Post('services') + @Post('trains') @ApiOperation({ summary: 'Create a train service' }) - @ApiBody({ type: CreateTrainServiceDto }) - @ApiResponse({ status: 201, description: 'Train service created' }) - createService(@Body() dto: CreateTrainServiceDto) { return this.service.createService(dto); } + @ApiBody({ type: CreateTrainDto }) + @ApiResponse({ status: 201, description: 'Train created' }) + createTrain(@Body() dto: CreateTrainDto) { return this.service.createTrain(dto); } @Get('coaches') - @ApiOperation({ summary: 'List coaches' }) - @ApiQuery({ name: 'tripId', required: false, description: 'Filter by trip UUID' }) - @ApiResponse({ status: 200, description: 'Returns coaches with seat class and seat count' }) - listCoaches(@Query('tripId') tripId?: string) { return this.service.listCoaches(tripId); } + @ApiOperation({ summary: 'List coaches filtered by status, mode, seat class, or schedule assignment' }) + @ApiQuery({ name: 'isActive', required: false, type: Boolean, description: 'true = active only, false = inactive only, omit = all' }) + @ApiQuery({ name: 'mode', required: false, description: 'Filter by mode: seat | bed | convertible' }) + @ApiQuery({ name: 'seatClassId', required: false, description: 'Filter by SeatClass UUID' }) + @ApiQuery({ name: 'scheduleId', required: false, description: 'Filter to coaches assigned to this TrainSchedule UUID' }) + @ApiResponse({ status: 200, description: 'Coaches with seat class info, assignment count, and seat status summary (total/available/held/booked/blocked)' }) + listCoaches( + @Query('isActive') isActive?: string, + @Query('mode') mode?: string, + @Query('seatClassId') seatClassId?: string, + @Query('scheduleId') scheduleId?: string, + ) { + const dto: ListCoachesDto = { + isActive: isActive === 'true' ? true : isActive === 'false' ? false : undefined, + mode, + seatClassId, + scheduleId, + }; + return this.service.listCoaches(dto); + } + + @Get('coaches/:id') + @ApiOperation({ summary: 'Get a single coach with full seat layout and arrangement' }) + @ApiParam({ name: 'id', description: 'Coach UUID' }) + @ApiResponse({ + status: 200, + description: `Coach detail including: +- seatClass: seat class info +- seatsByRow: seats grouped by row number, each seat includes label, seatNumber, col, kind (STANDARD/PREMIUM/ACCESSIBLE), status (AVAILABLE/HELD/BOOKED/BLOCKED), isWindow, isAisle, bedPosition (bed mode only), premiumFeeMinor +- seatStatusSummary: total/available/held/booked/blocked counts +- assignments: up to 5 most recent schedule assignments with origin/destination`, + }) + @ApiResponse({ status: 404, description: 'Coach not found' }) + getCoach(@Param('id') id: string) { return this.service.getCoach(id); } @Post('coaches') - @ApiOperation({ summary: 'Add a coach to a trip' }) + @ApiOperation({ summary: 'Register a new physical coach and auto-generate its seats from arrangement config' }) @ApiBody({ type: CreateCoachDto }) - @ApiResponse({ status: 201, description: 'Coach created' }) + @ApiResponse({ status: 201, description: 'Coach created with seats auto-generated from mode + arrangement + totalUnits' }) + @ApiResponse({ status: 400, description: 'Invalid arrangement format' }) createCoach(@Body() dto: CreateCoachDto) { return this.service.createCoach(dto); } @Patch('coaches/:id') - @ApiOperation({ summary: 'Update a coach' }) + @ApiOperation({ summary: 'Update coach properties (label, mode, arrangement, etc.)' }) @ApiParam({ name: 'id', description: 'Coach UUID' }) @ApiBody({ type: UpdateCoachDto }) @ApiResponse({ status: 200, description: 'Coach updated' }) @ApiResponse({ status: 404, description: 'Coach not found' }) updateCoach(@Param('id') id: string, @Body() dto: UpdateCoachDto) { return this.service.updateCoach(id, dto); } + @Post('assignments') + @ApiOperation({ summary: 'Assign a physical coach to a train schedule at a given position' }) + @ApiBody({ type: AssignCoachDto }) + @ApiResponse({ status: 201, description: 'CoachAssignment created' }) + @ApiResponse({ status: 404, description: 'Schedule or coach not found' }) + assignCoach(@Body() dto: AssignCoachDto) { return this.service.assignCoach(dto); } + + @Delete('assignments/:id') + @ApiOperation({ summary: 'Remove a coach assignment from a schedule' }) + @ApiParam({ name: 'id', description: 'CoachAssignment UUID' }) + @ApiResponse({ status: 200, description: 'Assignment removed' }) + @ApiResponse({ status: 404, description: 'Assignment not found' }) + removeAssignment(@Param('id') id: string) { return this.service.removeAssignment(id); } + @Post('seats/batch') - @ApiOperation({ summary: 'Batch-create seats for a coach' }) + @ApiOperation({ summary: 'Batch-generate seats for a coach (rows × cols)' }) @ApiBody({ type: CreateSeatBatchDto }) - @ApiResponse({ status: 201, description: 'Seats created' }) + @ApiResponse({ status: 201, description: 'Returns count of seats created' }) @ApiResponse({ status: 404, description: 'Coach not found' }) createSeatBatch(@Body() dto: CreateSeatBatchDto) { return this.service.createSeatBatch(dto); } @Get('analytics') - @ApiOperation({ summary: 'Fleet analytics' }) - @ApiResponse({ status: 200, description: 'Returns fleet occupancy analytics' }) + @ApiOperation({ summary: 'Fleet analytics: train count, schedule count, seat occupancy rate' }) + @ApiResponse({ status: 200, description: 'Returns totalTrains, totalSchedules, totalSeats, bookedSeats, occupancyRate' }) getAnalytics() { return this.service.getAnalytics(); } } diff --git a/apps/edr-passenger-api/src/modules/fleet/fleet.dto.ts b/apps/edr-passenger-api/src/modules/fleet/fleet.dto.ts index 8f3b12d4f..6046b1068 100644 --- a/apps/edr-passenger-api/src/modules/fleet/fleet.dto.ts +++ b/apps/edr-passenger-api/src/modules/fleet/fleet.dto.ts @@ -1,25 +1,50 @@ -import { IsString, IsInt, IsOptional, IsEnum, IsArray } from 'class-validator'; +import { IsString, IsInt, IsOptional, IsArray, IsBoolean } from 'class-validator'; import { ApiProperty, ApiPropertyOptional, PartialType, OmitType } from '@nestjs/swagger'; -import { ServiceClass } from '@prisma/client'; -export class CreateTrainServiceDto { - @ApiProperty({ example: '301' }) @IsString() number: string; +export class CreateTrainDto { + @ApiProperty({ example: '301', description: 'Unique train service number' }) @IsString() number: string; @ApiProperty({ example: 'Express 301' }) @IsString() name: string; + @ApiPropertyOptional({ example: 'EDR', description: 'Operator ID (defaults to op_edr)' }) @IsOptional() @IsString() operatorId?: string; + @ApiPropertyOptional({ example: 'Ethiopian-Djibouti Railway' }) @IsOptional() @IsString() operatorName?: string; + @ApiPropertyOptional({ example: 'Addis-Djibouti Express' }) @IsOptional() @IsString() description?: string; } export class CreateCoachDto { - @ApiProperty({ example: 'trip-uuid' }) @IsString() tripId: string; - @ApiProperty({ example: 'A' }) @IsString() label: string; - @ApiProperty({ enum: ServiceClass, example: 'ECONOMY_REGULAR' }) @IsEnum(ServiceClass) serviceClass: ServiceClass; - @ApiPropertyOptional({ example: 'seat-class-uuid' }) @IsOptional() @IsString() seatClassId?: string; - @ApiPropertyOptional({ example: 60 }) @IsOptional() @IsInt() capacity?: number; - @ApiPropertyOptional({ example: 1 }) @IsOptional() @IsInt() sequence?: number; + @ApiProperty({ example: 'C-A1', description: 'Unique physical coach identifier' }) @IsString() coachNumber: string; + @ApiProperty({ example: 'A', description: 'Display label shown on tickets' }) @IsString() label: string; + @ApiProperty({ example: 'seat-class-uuid', description: 'SeatClass UUID this coach belongs to' }) @IsString() seatClassId: string; + @ApiPropertyOptional({ example: 'sleeper', description: 'Coach type descriptor' }) @IsOptional() @IsString() coachType?: string; + @ApiPropertyOptional({ example: 'seat', description: 'seat | bed | convertible. Determines which arrangement field is used for seat generation.' }) @IsOptional() @IsString() mode?: string; + @ApiPropertyOptional({ example: '2+2', description: 'Seat arrangement for seat/convertible mode. Format: groups separated by +, e.g. "2+2" (4 cols: A/B aisle C/D) or "1+2+1". Used to derive columns, window and aisle flags. Required when mode=seat and totalUnits>0.' }) @IsOptional() @IsString() seatArrangement?: string; + @ApiPropertyOptional({ example: '2+2', description: 'Bed arrangement for bed mode. First number = tiers per berth: 2 → lower/upper, 3 → lower/middle/upper. E.g. "2+2" = 2-tier berths. Required when mode=bed and totalUnits>0.' }) @IsOptional() @IsString() bedArrangement?: string; + @ApiPropertyOptional({ example: 60, description: 'Total seat/bed units. When >0, seats are auto-generated from the arrangement on coach creation.' }) @IsOptional() @IsInt() totalUnits?: number; } -export class UpdateCoachDto extends PartialType(OmitType(CreateCoachDto, ['tripId'] as const)) {} +export class UpdateCoachDto extends PartialType(OmitType(CreateCoachDto, ['coachNumber'] as const)) {} + +export class AssignCoachDto { + @ApiProperty({ example: 'schedule-uuid', description: 'TrainSchedule UUID' }) @IsString() scheduleId: string; + @ApiProperty({ example: 'coach-uuid', description: 'Coach UUID' }) @IsString() coachId: string; + @ApiProperty({ example: 1, description: 'Position in the train consist (1 = first coach)' }) @IsInt() positionNumber: number; + @ApiPropertyOptional({ example: true, description: 'Whether this coach is operational for this schedule' }) @IsOptional() @IsBoolean() isOperational?: boolean; +} export class CreateSeatBatchDto { - @ApiProperty({ example: 'coach-uuid' }) @IsString() coachId: string; - @ApiProperty({ example: 10 }) @IsInt() rows: number; - @ApiProperty({ example: ['A', 'B', 'C', 'D'], type: [String] }) @IsArray() @IsString({ each: true }) cols: string[]; + @ApiProperty({ example: 'coach-uuid', description: 'Coach UUID to generate seats for' }) @IsString() coachId: string; + @ApiProperty({ example: 15, description: 'Number of rows to generate' }) @IsInt() rows: number; + @ApiProperty({ example: ['A', 'B', 'C', 'D'], type: [String], description: 'Column labels per row' }) @IsArray() @IsString({ each: true }) cols: string[]; +} + +export class ListCoachesDto { + @ApiPropertyOptional({ example: true, description: 'Filter by active/inactive status. Omit to return all.' }) + @IsOptional() @IsBoolean() isActive?: boolean; + + @ApiPropertyOptional({ example: 'seat', description: 'Filter by mode: seat | bed | convertible' }) + @IsOptional() @IsString() mode?: string; + + @ApiPropertyOptional({ example: 'seat-class-uuid', description: 'Filter by SeatClass UUID' }) + @IsOptional() @IsString() seatClassId?: string; + + @ApiPropertyOptional({ example: 'schedule-uuid', description: 'Filter to coaches assigned to this TrainSchedule UUID' }) + @IsOptional() @IsString() scheduleId?: string; } diff --git a/apps/edr-passenger-api/src/modules/fleet/fleet.service.ts b/apps/edr-passenger-api/src/modules/fleet/fleet.service.ts index 71894e807..b6fdce100 100644 --- a/apps/edr-passenger-api/src/modules/fleet/fleet.service.ts +++ b/apps/edr-passenger-api/src/modules/fleet/fleet.service.ts @@ -1,23 +1,215 @@ -import { Injectable, NotFoundException } from '@nestjs/common'; +import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common'; import { PrismaService } from '../../common/prisma.service'; -import { CreateTrainServiceDto, CreateCoachDto, CreateSeatBatchDto, UpdateCoachDto } from './fleet.dto'; +import { CreateTrainDto, CreateCoachDto, UpdateCoachDto, AssignCoachDto, CreateSeatBatchDto, ListCoachesDto } from './fleet.dto'; +import { SeatKind } from '@prisma/client'; + +// Parses '2+2' → [2, 2], '2+2+2' → [2, 2, 2] +function parseArrangement(arrangement: string): number[] { + return arrangement.split('+').map((n) => parseInt(n, 10)); +} + +// Derives column labels from a seat-mode arrangement string. +// '2+2' → ['A','B','C','D'] (A/D window, B/C aisle) +// '1+2+1' → ['A','B','C','D'] +function seatCols(arrangement: string): string[] { + const groups = parseArrangement(arrangement); + const total = groups.reduce((s, n) => s + n, 0); + return Array.from({ length: total }, (_, i) => String.fromCharCode(65 + i)); // A, B, C … +} + +// Returns true if the column index is a window seat given the arrangement groups. +function isWindowCol(colIndex: number, groups: number[]): boolean { + const total = groups.reduce((s, n) => s + n, 0); + return colIndex === 0 || colIndex === total - 1; +} + +// Returns true if the column index is an aisle seat. +function isAisleCol(colIndex: number, groups: number[]): boolean { + let cursor = 0; + for (const g of groups) { + cursor += g; + const leftAisle = cursor - 1; + const rightAisle = cursor; + if (colIndex === leftAisle || colIndex === rightAisle) return true; + } + return false; +} + +// Bed positions for a given tier count: 2 → lower/upper, 3 → lower/middle/upper +const BED_POSITIONS: Record = { + 2: ['lower', 'upper'], + 3: ['lower', 'middle', 'upper'], +}; + +type SeatRow = { + coachId: string; + row: number; + col: string; + label: string; + seatNumber: string; + kind: SeatKind; + isWindow: boolean; + isAisle: boolean; + bedPosition?: string; +}; + +function buildSeatSeats(coachId: string, coachLabel: string, arrangement: string, totalUnits: number): SeatRow[] { + const cols = seatCols(arrangement); + const groups = parseArrangement(arrangement); + const seats: SeatRow[] = []; + let row = 1; + while (seats.length < totalUnits) { + for (let ci = 0; ci < cols.length && seats.length < totalUnits; ci++) { + const col = cols[ci]; + seats.push({ + coachId, row, col, + label: `${row}${col}`, + seatNumber: `${coachLabel}${row}${col}`, + kind: SeatKind.STANDARD, + isWindow: isWindowCol(ci, groups), + isAisle: isAisleCol(ci, groups), + }); + } + row++; + } + return seats; +} + +function buildBedSeats(coachId: string, coachLabel: string, arrangement: string, totalUnits: number): SeatRow[] { + // arrangement for beds describes tiers per berth, e.g. '2+2' = 2 lower+upper on each side + // Each compartment number is the row; each tier is the col (L=lower, M=middle, U=upper) + const groups = parseArrangement(arrangement); + const tiersPerSide = groups[0]; // e.g. 2 → lower+upper + const positions = BED_POSITIONS[tiersPerSide] ?? ['lower', 'upper']; + const tierCols = positions.map((_, i) => String.fromCharCode(65 + i)); // A=lower, B=upper, C=middle + const seats: SeatRow[] = []; + let compartment = 1; + while (seats.length < totalUnits) { + for (let ti = 0; ti < tierCols.length && seats.length < totalUnits; ti++) { + const col = tierCols[ti]; + seats.push({ + coachId, row: compartment, col, + label: `${compartment}${col}`, + seatNumber: `${coachLabel}${compartment}${col}`, + kind: SeatKind.STANDARD, + isWindow: false, + isAisle: false, + bedPosition: positions[ti], + }); + } + compartment++; + } + return seats; +} @Injectable() export class FleetService { constructor(private prisma: PrismaService) {} - getServices() { return this.prisma.trainService.findMany({ include: { trips: { take: 5, orderBy: { departureAt: 'desc' } } } }); } - createService(dto: CreateTrainServiceDto) { return this.prisma.trainService.create({ data: dto }); } - - listCoaches(tripId?: string) { - return this.prisma.coach.findMany({ - where: tripId ? { tripId } : undefined, - include: { _count: { select: { seats: true } } }, - orderBy: { label: 'asc' }, - }); + getTrains() { + return this.prisma.train.findMany({ include: { schedules: { take: 5, orderBy: { departureAt: 'desc' } } } }); } - createCoach(dto: CreateCoachDto) { return this.prisma.coach.create({ data: dto }); } + createTrain(dto: CreateTrainDto) { return this.prisma.train.create({ data: dto }); } + + async getCoach(id: string) { + const coach = await this.prisma.coach.findUnique({ + where: { id }, + include: { + seatClass: true, + seats: { + orderBy: [{ row: 'asc' }, { col: 'asc' }], + }, + assignments: { + include: { schedule: { include: { originStation: true, destinationStation: true } } }, + orderBy: { schedule: { departureAt: 'desc' } }, + take: 5, + }, + _count: { select: { seats: true, assignments: true } }, + }, + }); + if (!coach) throw new NotFoundException('Coach not found'); + + // Group seats by row to reflect the physical arrangement layout + const rowMap = new Map(); + for (const seat of coach.seats) { + if (!rowMap.has(seat.row)) rowMap.set(seat.row, []); + rowMap.get(seat.row)!.push(seat); + } + + const seatsByRow = Array.from(rowMap.entries()).map(([row, seats]) => ({ row, seats })); + + const seatStatusSummary = { + total: coach.seats.length, + available: coach.seats.filter(s => s.status === 'AVAILABLE').length, + held: coach.seats.filter(s => s.status === 'HELD').length, + booked: coach.seats.filter(s => s.status === 'BOOKED').length, + blocked: coach.seats.filter(s => s.status === 'BLOCKED').length, + }; + + const { seats, ...coachData } = coach; + return { ...coachData, seatsByRow, seatStatusSummary }; + } + + async listCoaches(dto: ListCoachesDto) { + const where: any = {}; + if (dto.isActive !== undefined) where.isActive = dto.isActive; + if (dto.mode) where.mode = dto.mode; + if (dto.seatClassId) where.seatClassId = dto.seatClassId; + if (dto.scheduleId) where.assignments = { some: { scheduleId: dto.scheduleId } }; + + const coaches = await this.prisma.coach.findMany({ + where, + include: { + seatClass: true, + seats: { select: { status: true } }, + _count: { select: { seats: true, assignments: true } }, + }, + orderBy: [{ isActive: 'desc' }, { label: 'asc' }], + }); + + return coaches.map(({ seats, ...coach }) => ({ + ...coach, + seatStatusSummary: { + total: seats.length, + available: seats.filter(s => s.status === 'AVAILABLE').length, + held: seats.filter(s => s.status === 'HELD').length, + booked: seats.filter(s => s.status === 'BOOKED').length, + blocked: seats.filter(s => s.status === 'BLOCKED').length, + }, + })); + } + + async createCoach(dto: CreateCoachDto) { + const mode = dto.mode ?? 'seat'; + const totalUnits = dto.totalUnits ?? 0; + + const isBed = mode === 'bed'; + const arrangement = isBed + ? (dto.bedArrangement ?? dto.seatArrangement ?? '2+2') + : (dto.seatArrangement ?? '2+2'); + + if (totalUnits > 0) { + const groups = parseArrangement(arrangement); + if (groups.some(isNaN)) { + throw new BadRequestException(`Invalid arrangement format "${arrangement}". Use e.g. "2+2" or "2+2+2"`); + } + } + + const coach = await this.prisma.coach.create({ data: dto }); + + if (totalUnits > 0) { + const seats = isBed + ? buildBedSeats(coach.id, coach.label, arrangement, totalUnits) + : buildSeatSeats(coach.id, coach.label, arrangement, totalUnits); + await this.prisma.seat.createMany({ data: seats, skipDuplicates: true }); + } + + return this.prisma.coach.findUnique({ + where: { id: coach.id }, + include: { seatClass: true, _count: { select: { seats: true } } }, + }); + } async updateCoach(id: string, dto: UpdateCoachDto) { const coach = await this.prisma.coach.findUnique({ where: { id } }); @@ -25,38 +217,42 @@ export class FleetService { return this.prisma.coach.update({ where: { id }, data: dto }); } + async assignCoach(dto: AssignCoachDto) { + const [schedule, coach] = await Promise.all([ + this.prisma.trainSchedule.findUnique({ where: { id: dto.scheduleId } }), + this.prisma.coach.findUnique({ where: { id: dto.coachId } }), + ]); + if (!schedule) throw new NotFoundException('Schedule not found'); + if (!coach) throw new NotFoundException('Coach not found'); + return this.prisma.coachAssignment.create({ data: dto }); + } + + async removeAssignment(id: string) { + const assignment = await this.prisma.coachAssignment.findUnique({ where: { id } }); + if (!assignment) throw new NotFoundException('Assignment not found'); + return this.prisma.coachAssignment.delete({ where: { id } }); + } + async createSeatBatch(dto: CreateSeatBatchDto) { - try { - const coach = await this.prisma.coach.findUnique({ where: { id: dto.coachId } }); - if (!coach) throw new NotFoundException('Coach not found'); - - const seats = []; - for (let row = 1; row <= dto.rows; row++) { - for (const col of dto.cols) { - const seatNumber = `${coach.label}${row}${col}`; - seats.push({ - coachId: dto.coachId, - row, - col, - label: `${row}${col}`, - seatNumber - }); - } + const coach = await this.prisma.coach.findUnique({ where: { id: dto.coachId } }); + if (!coach) throw new NotFoundException('Coach not found'); + const seats = []; + for (let row = 1; row <= dto.rows; row++) { + for (const col of dto.cols) { + seats.push({ coachId: dto.coachId, row, col, label: `${row}${col}`, seatNumber: `${coach.label}${row}${col}` }); } - - await this.prisma.seat.createMany({ data: seats, skipDuplicates: true }); - return { created: seats.length }; - } catch (error) { - console.error('Error in createSeatBatch:', error); - throw error; } + await this.prisma.seat.createMany({ data: seats, skipDuplicates: true }); + return { created: seats.length }; } async getAnalytics() { - const [totalServices, totalTrips, totalSeats, bookedSeats] = await Promise.all([ - this.prisma.trainService.count(), this.prisma.trip.count(), - this.prisma.seat.count(), this.prisma.seat.count({ where: { status: 'BOOKED' } }), + const [totalTrains, totalSchedules, totalSeats, bookedSeats] = await Promise.all([ + this.prisma.train.count(), + this.prisma.trainSchedule.count(), + this.prisma.seat.count(), + this.prisma.seat.count({ where: { status: 'BOOKED' } }), ]); - return { totalServices, totalTrips, totalSeats, bookedSeats, occupancyRate: totalSeats > 0 ? +((bookedSeats / totalSeats) * 100).toFixed(2) : 0 }; + return { totalTrains, totalSchedules, totalSeats, bookedSeats, occupancyRate: totalSeats > 0 ? +((bookedSeats / totalSeats) * 100).toFixed(2) : 0 }; } } diff --git a/apps/edr-passenger-api/src/modules/live/live.controller.ts b/apps/edr-passenger-api/src/modules/live/live.controller.ts index a34e92e35..13058a1cb 100644 --- a/apps/edr-passenger-api/src/modules/live/live.controller.ts +++ b/apps/edr-passenger-api/src/modules/live/live.controller.ts @@ -8,9 +8,9 @@ import { JwtGuard } from '../../common/jwt.guard'; @Controller('live') export class LiveController { constructor(private service: LiveService) {} - @Get('trips/:tripId') @ApiOperation({ summary: 'Get live status for a trip' }) getTripLiveStatus(@Param('tripId') id: string) { return this.service.getTripLiveStatus(id); } - @Get('trips/:tripId/stops') @ApiOperation({ summary: 'Get stop timeline for a trip' }) getStopTimeline(@Param('tripId') id: string) { return this.service.getStopTimeline(id); } - @Patch('trips/:tripId/status')@UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') @ApiOperation({ summary: 'Update live trip status (staff/system)' }) updateLiveStatus(@Param('tripId') id: string, @Body() dto: UpdateLiveStatusDto) { return this.service.updateLiveStatus(id, dto); } + @Get('schedules/:scheduleId') @ApiOperation({ summary: 'Get live status for a schedule' }) getTripLiveStatus(@Param('scheduleId') id: string) { return this.service.getTripLiveStatus(id); } + @Get('schedules/:scheduleId/stops') @ApiOperation({ summary: 'Get stop timeline for a schedule' }) getStopTimeline(@Param('scheduleId') id: string) { return this.service.getStopTimeline(id); } + @Patch('schedules/:scheduleId/status') @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') @ApiOperation({ summary: 'Update live schedule status (staff/system)' }) updateLiveStatus(@Param('scheduleId') id: string, @Body() dto: UpdateLiveStatusDto) { return this.service.updateLiveStatus(id, dto); } @Get('crowd-signals') @ApiOperation({ summary: 'Get station crowd signals' }) getCrowdSignals() { return this.service.getStationCrowdSignals(); } @Get('weather-alerts') @ApiOperation({ summary: 'Get active weather alerts' }) getWeatherAlerts() { return this.service.getWeatherAlerts(); } } diff --git a/apps/edr-passenger-api/src/modules/live/live.service.ts b/apps/edr-passenger-api/src/modules/live/live.service.ts index bfc538059..7f0a858dc 100644 --- a/apps/edr-passenger-api/src/modules/live/live.service.ts +++ b/apps/edr-passenger-api/src/modules/live/live.service.ts @@ -5,29 +5,31 @@ import { PrismaService } from '../../common/prisma.service'; export class LiveService { constructor(private prisma: PrismaService) {} - async getTripLiveStatus(tripId: string) { - const trip = await this.prisma.trip.findUnique({ - where: { id: tripId }, - include: { service: true, originStation: true, destinationStation: true, liveStatus: true, stopTimes: { include: { station: true }, orderBy: { sequence: 'asc' } } }, + async getTripLiveStatus(scheduleId: string) { + const schedule = await this.prisma.trainSchedule.findUnique({ + where: { id: scheduleId }, + include: { train: true, originStation: true, destinationStation: true, liveStatus: true, stopTimes: { include: { station: true }, orderBy: { sequence: 'asc' } } }, }); - if (!trip) throw new NotFoundException('Trip not found'); - const live = trip.liveStatus; - const nextStop = trip.stopTimes.find((s) => s.status === 'UPCOMING' || s.status === 'APPROACHING'); + if (!schedule) throw new NotFoundException('Schedule not found'); + const live = schedule.liveStatus; + const nextStop = schedule.stopTimes.find((s) => s.status === 'UPCOMING' || s.status === 'APPROACHING'); return { - tripId: trip.id, trainName: trip.service.name, - fromStationName: trip.originStation.name, toStationName: trip.destinationStation.name, - state: live?.state ?? trip.status, currentLocationLabel: live?.currentLocationLabel, + scheduleId: schedule.id, trainName: schedule.train.name, + fromStationName: schedule.originStation.name, toStationName: schedule.destinationStation.name, + state: live?.state ?? schedule.status, currentLocationLabel: live?.currentLocationLabel, progressPercent: live?.progressPercent ?? 0, delayMinutes: live?.delayMinutes ?? 0, currentSpeedKph: live?.currentSpeedKph, platformLabel: live?.platformLabel, - nextStopStationName: nextStop?.station.name, updatedAt: live?.updatedAt ?? trip.departureAt, + nextStopStationName: nextStop?.station.name, updatedAt: live?.updatedAt ?? schedule.departureAt, }; } - updateLiveStatus(tripId: string, data: any) { - return this.prisma.tripLiveStatus.upsert({ where: { tripId }, update: data, create: { tripId, state: data.state ?? 'SCHEDULED', ...data } }); + updateLiveStatus(scheduleId: string, data: any) { + return this.prisma.tripLiveStatus.upsert({ where: { scheduleId }, update: data, create: { scheduleId, state: data.state ?? 'SCHEDULED', ...data } }); } - getStopTimeline(tripId: string) { return this.prisma.tripStopTime.findMany({ where: { tripId }, include: { station: true }, orderBy: { sequence: 'asc' } }); } + getStopTimeline(scheduleId: string) { + return this.prisma.tripStopTime.findMany({ where: { scheduleId }, include: { station: true }, orderBy: { sequence: 'asc' } }); + } getStationCrowdSignals() { return this.prisma.stationCrowdSignal.findMany({ include: { station: true } }); } diff --git a/apps/edr-passenger-api/src/modules/passengers/passengers.service.ts b/apps/edr-passenger-api/src/modules/passengers/passengers.service.ts index 54222751e..a454fdd70 100644 --- a/apps/edr-passenger-api/src/modules/passengers/passengers.service.ts +++ b/apps/edr-passenger-api/src/modules/passengers/passengers.service.ts @@ -11,7 +11,7 @@ export class PassengersService { where: { id: passengerId }, include: { user: { select: { fullName: true, email: true, phone: true } }, - bookings: { orderBy: { createdAt: 'desc' }, take: 10, include: { trip: { include: { originStation: true, destinationStation: true, service: true } }, seats: { include: { seat: { include: { coach: true } } } } } }, + bookings: { orderBy: { createdAt: 'desc' }, take: 10, include: { schedule: { include: { originStation: true, destinationStation: true, train: true } }, seats: { include: { seat: { include: { coach: { include: { seatClass: true } } } } } } } }, loyalty: true, wallet: true, travelerProfiles: true, savedRoutes: true, }, }); @@ -25,12 +25,12 @@ export class PassengersService { bookings: p.bookings.map((b) => ({ id: b.id, bookingRef: b.bookingRef, status: b.status, totalFare: b.totalMinor / 100, createdAt: b.createdAt, trip: { - number: b.trip.service.number, - origin: { id: b.trip.originStation.id, name: b.trip.originStation.name, code: b.trip.originStation.code, city: b.trip.originStation.city }, - destination: { id: b.trip.destinationStation.id, name: b.trip.destinationStation.name, code: b.trip.destinationStation.code, city: b.trip.destinationStation.city }, - departureAt: b.trip.departureAt, + number: b.schedule.train.number, + origin: { id: b.schedule.originStation.id, name: b.schedule.originStation.name, code: b.schedule.originStation.code, city: b.schedule.originStation.city }, + destination: { id: b.schedule.destinationStation.id, name: b.schedule.destinationStation.name, code: b.schedule.destinationStation.code, city: b.schedule.destinationStation.city }, + departureAt: b.schedule.departureAt, }, - passengers: b.seats.map((bs) => ({ fullName: bs.passengerName, seat: { number: bs.seat.label, coach: bs.seat.coach.label, class: bs.seat.coach.serviceClass } })), + passengers: b.seats.map((bs) => ({ fullName: bs.passengerName, seat: { number: bs.seat.label, coach: bs.seat.coach.label, class: bs.seat.coach.seatClass?.name ?? 'N/A' } })), })), }; } diff --git a/apps/edr-passenger-api/src/modules/payments/payments.e2e-spec.ts b/apps/edr-passenger-api/src/modules/payments/payments.e2e-spec.ts index 4918ce4fd..78ffe2196 100644 --- a/apps/edr-passenger-api/src/modules/payments/payments.e2e-spec.ts +++ b/apps/edr-passenger-api/src/modules/payments/payments.e2e-spec.ts @@ -21,110 +21,44 @@ describe('Payments E2E', () => { prisma = app.get(PrismaService); - // Create test user and authenticate const testUser = await prisma.user.create({ - data: { - email: 'payment-test@example.com', - phone: '+251911111111', - fullName: 'Payment Test User', - passwordHash: '$2b$10$abcdefghijklmnopqrstuvwxyz', // Mock hash - role: 'PASSENGER', - }, + data: { email: 'payment-test@example.com', phone: '+251911111112', fullName: 'Payment Test User', passwordHash: '$2b$10$abcdefghijklmnopqrstuvwxyz', role: 'PASSENGER' }, }); - const passenger = await prisma.passenger.create({ - data: { - userId: testUser.id, - }, - }); + const passenger = await prisma.passenger.create({ data: { userId: testUser.id } }); - // Create wallet for test user - await prisma.walletAccount.create({ - data: { - passengerId: passenger.id, - balanceMinor: 100000, // 1000 ETB - currency: 'ETB', - }, - }); + await prisma.walletAccount.create({ data: { passengerId: passenger.id, balanceMinor: 100000, currency: 'ETB' } }); - // Mock JWT token (in real test, call /auth/login) authToken = 'mock-jwt-token'; - // Create test booking - const station1 = await prisma.station.create({ - data: { - code: 'TEST1', - name: 'Test Station 1', - city: 'Test City', - lat: 9.0, - lng: 38.0, - }, + const station1 = await prisma.station.create({ data: { code: 'TST1', name: 'Test Station 1', city: 'Test City', lat: 9.0, lng: 38.0 } }); + const station2 = await prisma.station.create({ data: { code: 'TST2', name: 'Test Station 2', city: 'Test City 2', lat: 9.5, lng: 38.5 } }); + + const train = await prisma.train.create({ data: { number: 'TEST-001', name: 'Test Train' } }); + + const schedule = await prisma.trainSchedule.create({ + data: { trainId: train.id, originStationId: station1.id, destinationStationId: station2.id, departureAt: new Date(Date.now() + 86400000), arrivalAt: new Date(Date.now() + 90000000), durationMinutes: 60 }, }); - const station2 = await prisma.station.create({ - data: { - code: 'TEST2', - name: 'Test Station 2', - city: 'Test City 2', - lat: 9.5, - lng: 38.5, - }, - }); - - const service = await prisma.trainService.create({ - data: { - number: 'TEST-001', - name: 'Test Service', - }, - }); - - const trip = await prisma.trip.create({ - data: { - serviceId: service.id, - originStationId: station1.id, - destinationStationId: station2.id, - departureAt: new Date(Date.now() + 86400000), - arrivalAt: new Date(Date.now() + 90000000), - durationMinutes: 60, - }, + const seatClass = await prisma.seatClass.upsert({ + where: { name: 'Economy Regular' }, + update: {}, + create: { name: 'Economy Regular', description: 'Standard economy seating', basePrice: 45000, isActive: true }, }); const coach = await prisma.coach.create({ - data: { - tripId: trip.id, - label: 'A', - serviceClass: 'ECONOMY_REGULAR', - }, + data: { coachNumber: 'TEST-C1', label: 'A', seatClassId: seatClass.id, mode: 'seat', totalUnits: 10 }, }); - const seat = await prisma.seat.create({ - data: { - coachId: coach.id, - row: 1, - col: 'A', - label: '1A', - status: 'AVAILABLE', - }, - }); + await prisma.coachAssignment.create({ data: { scheduleId: schedule.id, coachId: coach.id, positionNumber: 1 } }); + + const seat = await prisma.seat.create({ data: { coachId: coach.id, row: 1, col: 'A', label: '1A', status: 'AVAILABLE' } }); const booking = await prisma.booking.create({ - data: { - bookingRef: 'TEST-BOOK-001', - passengerId: passenger.id, - tripId: trip.id, - status: 'PENDING_PAYMENT', - totalMinor: 50000, // 500 ETB - currency: 'ETB', - }, + data: { bookingRef: 'TEST-BOOK-001', passengerId: passenger.id, scheduleId: schedule.id, status: 'PENDING_PAYMENT', totalMinor: 50000, currency: 'ETB' }, }); - await prisma.bookingSeat.create({ - data: { - bookingId: booking.id, - seatId: seat.id, - passengerName: 'Test Passenger', - }, - }); + await prisma.bookingSeat.create({ data: { bookingId: booking.id, seatId: seat.id, passengerName: 'Test Passenger' } }); bookingId = booking.id; }); @@ -134,15 +68,16 @@ describe('Payments E2E', () => { prisma.bookingSeat.deleteMany(), prisma.paymentIntent.deleteMany(), prisma.booking.deleteMany(), + prisma.coachAssignment.deleteMany(), prisma.seat.deleteMany(), prisma.coach.deleteMany(), - prisma.trip.deleteMany(), - prisma.trainService.deleteMany(), - prisma.station.deleteMany(), + prisma.trainSchedule.deleteMany(), + prisma.train.deleteMany(), + prisma.station.deleteMany({ where: { code: { in: ['TST1', 'TST2'] } } }), prisma.walletLedgerEntry.deleteMany(), prisma.walletAccount.deleteMany(), prisma.passenger.deleteMany(), - prisma.user.deleteMany(), + prisma.user.deleteMany({ where: { email: 'payment-test@example.com' } }), ]); await app.close(); }); @@ -152,12 +87,8 @@ describe('Payments E2E', () => { const response = await request(app.getHttpServer()) .post('/payments/initiate') .set('Authorization', `Bearer ${authToken}`) - .send({ - bookingId, - method: 'WALLET', - }) + .send({ bookingId, method: 'WALLET' }) .expect(201); - expect(response.body.intentId).toBeDefined(); expect(response.body.status).toBe('SUCCEEDED'); }); @@ -166,10 +97,7 @@ describe('Payments E2E', () => { await request(app.getHttpServer()) .post('/payments/initiate') .set('Authorization', `Bearer ${authToken}`) - .send({ - bookingId, - method: 'INVALID_METHOD', - }) + .send({ bookingId, method: 'INVALID_METHOD' }) .expect(400); }); @@ -177,10 +105,7 @@ describe('Payments E2E', () => { await request(app.getHttpServer()) .post('/payments/initiate') .set('Authorization', `Bearer ${authToken}`) - .send({ - bookingId: 'non-existent-id', - method: 'WALLET', - }) + .send({ bookingId: 'non-existent-id', method: 'WALLET' }) .expect(404); }); }); @@ -191,7 +116,6 @@ describe('Payments E2E', () => { .get(`/payments/intents/${bookingId}`) .set('Authorization', `Bearer ${authToken}`) .expect(200); - expect(response.body.intentId).toBeDefined(); expect(response.body.status).toBeDefined(); }); @@ -208,38 +132,21 @@ describe('Payments E2E', () => { it('should handle Telebirr webhook', async () => { await request(app.getHttpServer()) .post('/payments/webhooks/telebirr') - .send({ - merch_order_id: 'TEST-ORDER-123', - payment_order_id: 'PAY-123', - trade_status: 'Completed', - sign: 'mock-signature', - }) + .send({ merch_order_id: 'TEST-ORDER-123', payment_order_id: 'PAY-123', trade_status: 'Completed', sign: 'mock-signature' }) .expect(200); }); it('should handle CBE Birr webhook', async () => { await request(app.getHttpServer()) .post('/payments/webhooks/cbe-birr') - .send({ - merchantId: 'TEST-MERCHANT', - merchantOrderId: 'TEST-ORDER-123', - orderId: 'CBE-ORDER-123', - status: 'SUCCESS', - signature: 'mock-signature', - }) + .send({ merchantId: 'TEST-MERCHANT', merchantOrderId: 'TEST-ORDER-123', orderId: 'CBE-ORDER-123', status: 'SUCCESS', signature: 'mock-signature' }) .expect(200); }); it('should handle eBirr webhook', async () => { await request(app.getHttpServer()) .post('/payments/webhooks/ebirr') - .send({ - merchantCode: 'TEST-MERCHANT', - orderNo: 'TEST-ORDER-123', - tradeStatus: 'TRADE_SUCCESS', - timestamp: Date.now(), - sign: 'mock-signature', - }) + .send({ merchantCode: 'TEST-MERCHANT', orderNo: 'TEST-ORDER-123', tradeStatus: 'TRADE_SUCCESS', timestamp: Date.now(), sign: 'mock-signature' }) .expect(200); }); @@ -247,23 +154,7 @@ describe('Payments E2E', () => { await request(app.getHttpServer()) .post('/payments/webhooks/card') .set('stripe-signature', 'mock-signature') - .send({ - id: 'evt_123', - type: 'payment_intent.succeeded', - data: { - object: { - id: 'pi_123', - status: 'succeeded', - amount: 50000, - currency: 'ETB', - metadata: { - merchantOrderId: 'TEST-ORDER-123', - bookingRef: 'TEST-BOOK-001', - }, - }, - }, - created: Math.floor(Date.now() / 1000), - }) + .send({ id: 'evt_123', type: 'payment_intent.succeeded', data: { object: { id: 'pi_123', status: 'succeeded', amount: 50000, currency: 'ETB', metadata: { merchantOrderId: 'TEST-ORDER-123', bookingRef: 'TEST-BOOK-001' } } }, created: Math.floor(Date.now() / 1000) }) .expect(200); }); }); diff --git a/apps/edr-passenger-api/src/modules/payments/payments.service.spec.ts b/apps/edr-passenger-api/src/modules/payments/payments.service.spec.ts index e6ebd9035..66775648a 100644 --- a/apps/edr-passenger-api/src/modules/payments/payments.service.spec.ts +++ b/apps/edr-passenger-api/src/modules/payments/payments.service.spec.ts @@ -18,7 +18,7 @@ describe('PaymentsService', () => { let ticketsService: TicketsService; let eventEmitter: EventEmitter2; - const mockPrisma = { + const mockPrisma: Record = { booking: { findUnique: jest.fn(), update: jest.fn(), @@ -44,7 +44,7 @@ describe('PaymentsService', () => { loyaltyLedgerEntry: { create: jest.fn(), }, - $transaction: jest.fn((callback) => callback(mockPrisma)), + $transaction: jest.fn((callback: (tx: any) => any) => callback(mockPrisma)), }; const mockSeatsService = { diff --git a/apps/edr-passenger-api/src/modules/reports/reports.service.ts b/apps/edr-passenger-api/src/modules/reports/reports.service.ts index 0d2699a99..29bc82a55 100644 --- a/apps/edr-passenger-api/src/modules/reports/reports.service.ts +++ b/apps/edr-passenger-api/src/modules/reports/reports.service.ts @@ -69,37 +69,23 @@ export class ReportsService { } private async generateOccupancyReport(dateFrom: Date, dateTo: Date) { - const trips = await this.prisma.trip.findMany({ + const schedules = await this.prisma.trainSchedule.findMany({ where: { departureAt: { gte: dateFrom, lte: dateTo } }, include: { - coaches: { include: { seats: true } }, - bookings: { where: { status: { in: ['CONFIRMED', 'COMPLETED'] } }, include: { seats: true } } - } + coachAssignments: { include: { coach: { include: { seats: true } } } }, + bookings: { where: { status: { in: ['CONFIRMED', 'COMPLETED'] } }, include: { seats: true } }, + }, }); - const tripData = trips.map(trip => { - const totalSeats = trip.coaches.reduce((sum, c) => sum + c.seats.length, 0); - const bookedSeats = trip.bookings.reduce((sum, b) => sum + b.seats.length, 0); + const tripData = schedules.map(schedule => { + const totalSeats = schedule.coachAssignments.reduce((sum, a) => sum + a.coach.seats.length, 0); + const bookedSeats = schedule.bookings.reduce((sum, b) => sum + b.seats.length, 0); const occupancyRate = totalSeats > 0 ? (bookedSeats / totalSeats) * 100 : 0; - - return { - tripId: trip.id, - departureAt: trip.departureAt, - totalSeats, - bookedSeats, - occupancyRate: +occupancyRate.toFixed(2) - }; + return { scheduleId: schedule.id, departureAt: schedule.departureAt, totalSeats, bookedSeats, occupancyRate: +occupancyRate.toFixed(2) }; }); - const avgOccupancy = tripData.length > 0 - ? tripData.reduce((sum, t) => sum + t.occupancyRate, 0) / tripData.length - : 0; - - return { - totalTrips: trips.length, - averageOccupancyRate: +avgOccupancy.toFixed(2), - trips: tripData - }; + const avgOccupancy = tripData.length > 0 ? tripData.reduce((sum, t) => sum + t.occupancyRate, 0) / tripData.length : 0; + return { totalSchedules: schedules.length, averageOccupancyRate: +avgOccupancy.toFixed(2), schedules: tripData }; } private async generateAgentSalesReport(dateFrom: Date, dateTo: Date, agentId?: string) { diff --git a/apps/edr-passenger-api/src/modules/schedules/routes.controller.ts b/apps/edr-passenger-api/src/modules/schedules/routes.controller.ts new file mode 100644 index 000000000..75224c3f9 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/schedules/routes.controller.ts @@ -0,0 +1,88 @@ +import { Body, Controller, Delete, Get, Param, Patch, Post, Query, ParseIntPipe, UseGuards } from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiBearerAuth, ApiParam, ApiQuery, ApiResponse } from '@nestjs/swagger'; +import { RoutesService } from './routes.service'; +import { CreateRouteDto, AddRouteStopDto, UpdateRouteDto } from './routes.dto'; +import { JwtGuard } from '../../common/jwt.guard'; + +@ApiTags('Routes') +@Controller('routes') +export class RoutesController { + constructor(private service: RoutesService) {} + + // ── Routes ───────────────────────────────────────────────────────────────── + + @Post() + @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') + @ApiOperation({ + summary: 'Create a reusable route with its ordered stops', + description: `Define the physical corridor once (e.g. ADD→ADM→AWS→DDW→AYS→DJI). +Schedules reference this route via routeId and supply actual planned times per stop. +Route stops carry distanceKm for fare-by-distance calculations.`, + }) + @ApiResponse({ status: 201, description: 'Route created with stops' }) + @ApiResponse({ status: 409, description: 'Route code already exists or duplicate sequences' }) + @ApiResponse({ status: 400, description: 'Fewer than 2 stops or invalid station IDs' }) + createRoute(@Body() dto: CreateRouteDto) { return this.service.createRoute(dto); } + + @Get() + @ApiOperation({ summary: 'List all routes' }) + @ApiQuery({ name: 'activeOnly', required: false, type: Boolean, description: 'Filter to active routes only' }) + @ApiResponse({ status: 200, description: 'Array of routes with stop count' }) + listRoutes(@Query('activeOnly') activeOnly?: string) { + return this.service.listRoutes(activeOnly === 'true'); + } + + @Get(':id') + @ApiOperation({ summary: 'Get route with all stops and station details' }) + @ApiParam({ name: 'id', description: 'Route UUID' }) + @ApiResponse({ status: 200, description: 'Route with enriched stop list (station name, code, city)' }) + @ApiResponse({ status: 404, description: 'Route not found' }) + getRoute(@Param('id') id: string) { return this.service.getRoute(id); } + + @Patch(':id') + @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') + @ApiOperation({ summary: 'Update route metadata (name, description, active flag, effectiveUntil)' }) + @ApiParam({ name: 'id', description: 'Route UUID' }) + @ApiResponse({ status: 200, description: 'Route updated' }) + @ApiResponse({ status: 404, description: 'Route not found' }) + updateRoute(@Param('id') id: string, @Body() dto: UpdateRouteDto) { return this.service.updateRoute(id, dto); } + + // ── Route Stops ──────────────────────────────────────────────────────────── + + @Get(':id/stops') + @ApiOperation({ summary: 'List all stops for a route ordered by sequence' }) + @ApiParam({ name: 'id', description: 'Route UUID' }) + @ApiResponse({ status: 200, description: 'Ordered stop list with station details' }) + @ApiResponse({ status: 404, description: 'Route not found' }) + getStops(@Param('id') id: string) { return this.service.getStops(id); } + + @Post(':id/stops') + @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') + @ApiOperation({ summary: 'Add a stop to an existing route' }) + @ApiParam({ name: 'id', description: 'Route UUID' }) + @ApiResponse({ status: 201, description: 'Stop added' }) + @ApiResponse({ status: 409, description: 'Sequence already exists on this route' }) + @ApiResponse({ status: 404, description: 'Route or station not found' }) + addStop(@Param('id') id: string, @Body() dto: AddRouteStopDto) { return this.service.addStop(id, dto); } + + @Delete(':id/stops/:sequence') + @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') + @ApiOperation({ summary: 'Remove a stop from a route by sequence number' }) + @ApiParam({ name: 'id', description: 'Route UUID' }) + @ApiParam({ name: 'sequence', description: 'Stop sequence number to remove' }) + @ApiResponse({ status: 200, description: 'Stop removed' }) + @ApiResponse({ status: 400, description: 'Cannot remove — route would have fewer than 2 stops' }) + @ApiResponse({ status: 404, description: 'Stop not found' }) + removeStop(@Param('id') id: string, @Param('sequence', ParseIntPipe) sequence: number) { + return this.service.removeStop(id, sequence); + } + + // ── Schedules for a Route ────────────────────────────────────────────────── + + @Get(':id/schedules') + @ApiOperation({ summary: 'List all train schedules that use this route' }) + @ApiParam({ name: 'id', description: 'Route UUID' }) + @ApiResponse({ status: 200, description: 'Schedules with train and terminal station details' }) + @ApiResponse({ status: 404, description: 'Route not found' }) + getSchedules(@Param('id') id: string) { return this.service.getSchedulesForRoute(id); } +} diff --git a/apps/edr-passenger-api/src/modules/schedules/routes.dto.ts b/apps/edr-passenger-api/src/modules/schedules/routes.dto.ts new file mode 100644 index 000000000..230dad3f8 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/schedules/routes.dto.ts @@ -0,0 +1,44 @@ +import { IsString, IsInt, IsOptional, IsArray, ValidateNested, IsBoolean, IsDateString, Min } from 'class-validator'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +import { Type } from 'class-transformer'; + +export class RouteStopInputDto { + @ApiProperty({ example: 'station-uuid', description: 'Station UUID' }) @IsString() stationId: string; + @ApiProperty({ example: 1, description: 'Stop order (1 = origin, ascending)' }) @IsInt() @Min(1) sequence: number; + @ApiPropertyOptional({ example: 120, description: 'Distance in km from previous stop' }) @IsOptional() @IsInt() distanceKm?: number; +} + +export class CreateRouteDto { + @ApiProperty({ example: 'ADD-DJI', description: 'Unique route code' }) @IsString() code: string; + @ApiProperty({ example: 'Addis Ababa – Djibouti' }) @IsString() name: string; + @ApiPropertyOptional({ example: 'Main corridor via Dire Dawa' }) @IsOptional() @IsString() description?: string; + @ApiProperty({ example: '2026-01-01T00:00:00Z', description: 'Date from which this route is effective' }) @IsDateString() effectiveFrom: string; + @ApiPropertyOptional({ example: '2027-12-31T23:59:59Z' }) @IsOptional() @IsDateString() effectiveUntil?: string; + @ApiProperty({ + type: [RouteStopInputDto], + description: 'Ordered stops for this route. Sequence 1 = origin, last sequence = destination.', + example: [ + { stationId: 'uuid-ADD', sequence: 1 }, + { stationId: 'uuid-ADM', sequence: 2, distanceKm: 99 }, + { stationId: 'uuid-AWS', sequence: 3, distanceKm: 120 }, + { stationId: 'uuid-DDW', sequence: 4, distanceKm: 180 }, + { stationId: 'uuid-AYS', sequence: 5, distanceKm: 95 }, + { stationId: 'uuid-DJI', sequence: 6, distanceKm: 60 }, + ], + }) + @IsArray() @ValidateNested({ each: true }) @Type(() => RouteStopInputDto) + stops: RouteStopInputDto[]; +} + +export class AddRouteStopDto { + @ApiProperty({ example: 'station-uuid' }) @IsString() stationId: string; + @ApiProperty({ example: 3 }) @IsInt() @Min(1) sequence: number; + @ApiPropertyOptional({ example: 75 }) @IsOptional() @IsInt() distanceKm?: number; +} + +export class UpdateRouteDto { + @ApiPropertyOptional({ example: 'Addis Ababa – Djibouti Express' }) @IsOptional() @IsString() name?: string; + @ApiPropertyOptional() @IsOptional() @IsString() description?: string; + @ApiPropertyOptional({ example: true }) @IsOptional() @IsBoolean() active?: boolean; + @ApiPropertyOptional({ example: '2027-12-31T23:59:59Z' }) @IsOptional() @IsDateString() effectiveUntil?: string; +} diff --git a/apps/edr-passenger-api/src/modules/schedules/routes.service.ts b/apps/edr-passenger-api/src/modules/schedules/routes.service.ts new file mode 100644 index 000000000..38705f435 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/schedules/routes.service.ts @@ -0,0 +1,197 @@ +import { Injectable, NotFoundException, ConflictException, BadRequestException } from '@nestjs/common'; +import { PrismaService } from '../../common/prisma.service'; +import { CreateRouteDto, AddRouteStopDto, UpdateRouteDto } from './routes.dto'; + +@Injectable() +export class RoutesService { + constructor(private prisma: PrismaService) {} + + // ── Route CRUD ───────────────────────────────────────────────────────────── + + async createRoute(dto: CreateRouteDto) { + const existing = await this.prisma.route.findUnique({ where: { code: dto.code } }); + if (existing) throw new ConflictException(`Route code "${dto.code}" already exists`); + + if (dto.stops.length < 2) throw new BadRequestException('A route must have at least 2 stops'); + + const seqs = dto.stops.map(s => s.sequence); + if (new Set(seqs).size !== seqs.length) throw new ConflictException('Duplicate sequence numbers in stop list'); + + const stationIds = [...new Set(dto.stops.map(s => s.stationId))]; + const stations = await this.prisma.station.findMany({ where: { id: { in: stationIds } } }); + if (stations.length !== stationIds.length) throw new BadRequestException('One or more station IDs not found'); + + return this.prisma.route.create({ + data: { + code: dto.code, + name: dto.name, + description: dto.description, + effectiveFrom: new Date(dto.effectiveFrom), + effectiveUntil: dto.effectiveUntil ? new Date(dto.effectiveUntil) : null, + stops: { + create: dto.stops.map(s => ({ + stationId: s.stationId, + sequence: s.sequence, + distanceKm: s.distanceKm, + })), + }, + }, + include: { stops: { include: { route: false }, orderBy: { sequence: 'asc' } } }, + }); + } + + async listRoutes(activeOnly = false) { + return this.prisma.route.findMany({ + where: activeOnly ? { active: true } : undefined, + include: { + stops: { orderBy: { sequence: 'asc' } }, + _count: { select: { stops: true } }, + }, + orderBy: { code: 'asc' }, + }); + } + + async getRoute(id: string) { + const route = await this.prisma.route.findUnique({ + where: { id }, + include: { + stops: { + orderBy: { sequence: 'asc' }, + include: { + route: false, + }, + }, + }, + }); + if (!route) throw new NotFoundException('Route not found'); + + // Enrich stops with station details + const stationIds = route.stops.map(s => s.stationId); + const stations = await this.prisma.station.findMany({ where: { id: { in: stationIds } } }); + const stationMap = Object.fromEntries(stations.map(s => [s.id, s])); + + return { + ...route, + stops: route.stops.map(s => ({ ...s, station: stationMap[s.stationId] })), + }; + } + + async updateRoute(id: string, dto: UpdateRouteDto) { + const route = await this.prisma.route.findUnique({ where: { id } }); + if (!route) throw new NotFoundException('Route not found'); + return this.prisma.route.update({ + where: { id }, + data: { + name: dto.name, + description: dto.description, + active: dto.active, + effectiveUntil: dto.effectiveUntil ? new Date(dto.effectiveUntil) : undefined, + }, + include: { stops: { orderBy: { sequence: 'asc' } } }, + }); + } + + // ── Route Stops ──────────────────────────────────────────────────────────── + + async addStop(routeId: string, dto: AddRouteStopDto) { + const route = await this.prisma.route.findUnique({ where: { id: routeId } }); + if (!route) throw new NotFoundException('Route not found'); + + const station = await this.prisma.station.findUnique({ where: { id: dto.stationId } }); + if (!station) throw new NotFoundException(`Station ${dto.stationId} not found`); + + const existing = await this.prisma.routeStop.findUnique({ + where: { routeId_sequence: { routeId, sequence: dto.sequence } }, + }); + if (existing) throw new ConflictException(`Sequence ${dto.sequence} already exists on this route`); + + return this.prisma.routeStop.create({ + data: { routeId, stationId: dto.stationId, sequence: dto.sequence, distanceKm: dto.distanceKm }, + }); + } + + async removeStop(routeId: string, sequence: number) { + const stop = await this.prisma.routeStop.findUnique({ + where: { routeId_sequence: { routeId, sequence } }, + }); + if (!stop) throw new NotFoundException(`Stop at sequence ${sequence} not found on route`); + + const total = await this.prisma.routeStop.count({ where: { routeId } }); + if (total <= 2) throw new BadRequestException('A route must retain at least 2 stops'); + + await this.prisma.routeStop.delete({ where: { routeId_sequence: { routeId, sequence } } }); + return { deleted: true, sequence }; + } + + async getStops(routeId: string) { + const route = await this.prisma.route.findUnique({ where: { id: routeId } }); + if (!route) throw new NotFoundException('Route not found'); + + const stops = await this.prisma.routeStop.findMany({ + where: { routeId }, + orderBy: { sequence: 'asc' }, + }); + + const stationIds = stops.map(s => s.stationId); + const stations = await this.prisma.station.findMany({ where: { id: { in: stationIds } } }); + const stationMap = Object.fromEntries(stations.map(s => [s.id, s])); + + return stops.map(s => ({ ...s, station: stationMap[s.stationId] })); + } + + async getSchedulesForRoute(routeId: string) { + const route = await this.prisma.route.findUnique({ where: { id: routeId } }); + if (!route) throw new NotFoundException('Route not found'); + + return this.prisma.trainSchedule.findMany({ + where: { routeId }, + include: { train: true, originStation: true, destinationStation: true }, + orderBy: { departureAt: 'asc' }, + }); + } + + // ── Used by SchedulesService ─────────────────────────────────────────────── + + /** + * Copies RouteStop definitions into TripStopTime rows for a schedule. + * plannedTimes maps sequence → { arrivalAt?, departureAt? } for actual timing. + */ + async applyRouteToSchedule( + routeId: string, + scheduleId: string, + plannedTimes: Record, + ) { + const stops = await this.prisma.routeStop.findMany({ + where: { routeId }, + orderBy: { sequence: 'asc' }, + }); + if (stops.length === 0) throw new BadRequestException('Route has no stops defined'); + + await this.prisma.tripStopTime.deleteMany({ where: { scheduleId } }); + + await this.prisma.tripStopTime.createMany({ + data: stops.map(s => { + const times = plannedTimes[s.sequence] ?? {}; + return { + scheduleId, + stationId: s.stationId, + sequence: s.sequence, + plannedArrivalAt: times.plannedArrivalAt ? new Date(times.plannedArrivalAt) : null, + plannedDepartureAt: times.plannedDepartureAt ? new Date(times.plannedDepartureAt) : null, + }; + }), + }); + + const intermediateCount = Math.max(0, stops.length - 2); + await this.prisma.trainSchedule.update({ + where: { id: scheduleId }, + data: { stopsCount: intermediateCount }, + }); + + return this.prisma.tripStopTime.findMany({ + where: { scheduleId }, + include: { station: true }, + orderBy: { sequence: 'asc' }, + }); + } +} diff --git a/apps/edr-passenger-api/src/modules/schedules/schedules.controller.ts b/apps/edr-passenger-api/src/modules/schedules/schedules.controller.ts index 9f3972a49..07d0362af 100644 --- a/apps/edr-passenger-api/src/modules/schedules/schedules.controller.ts +++ b/apps/edr-passenger-api/src/modules/schedules/schedules.controller.ts @@ -1,21 +1,100 @@ -import { Body, Controller, Get, Param, Patch, Post, Query, UseGuards } from '@nestjs/common'; -import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger'; +import { Body, Controller, Get, Param, Patch, Post, Query, ParseIntPipe, UseGuards } from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiBearerAuth, ApiParam, ApiQuery, ApiResponse } from '@nestjs/swagger'; import { SchedulesService } from './schedules.service'; -import { CreateTripDto, CreateFareRuleDto, UpdateTripStatusDto } from './schedules.dto'; +import { CreateScheduleDto, CreateFareRuleDto, UpdateScheduleStatusDto, UpdateStopTimeDto, ListSchedulesDto } from './schedules.dto'; import { JwtGuard } from '../../common/jwt.guard'; +import { TripStatus } from '@prisma/client'; @ApiTags('Schedule') -@Controller('schedule') +@Controller('schedules') export class SchedulesController { constructor(private service: SchedulesService) {} - @Post('trips') @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') @ApiOperation({ summary: 'Create trip' }) - createTrip(@Body() dto: CreateTripDto) { return this.service.createTrip(dto); } - @Get('trips/:id') @ApiOperation({ summary: 'Get trip details' }) - getTrip(@Param('id') id: string) { return this.service.getTrip(id); } - @Patch('trips/:id/status') @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') @ApiOperation({ summary: 'Update trip status' }) - updateStatus(@Param('id') id: string, @Body() dto: UpdateTripStatusDto) { return this.service.updateTripStatus(id, dto); } - @Post('fares') @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') @ApiOperation({ summary: 'Create fare rule' }) + + @Post() + @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') + @ApiOperation({ + summary: 'Create a train schedule from a route template', + description: `Creates a schedule by referencing a Route (routeId). +Stops are automatically copied from the route's RouteStop definitions. +You supply the actual planned arrival/departure times per stop sequence. +Origin and destination are derived from the first and last route stop — no need to specify them manually.`, + }) + @ApiResponse({ status: 201, description: 'Schedule created with stops copied from route template' }) + @ApiResponse({ status: 400, description: 'Invalid times, inactive route, or missing planned times for some stops' }) + @ApiResponse({ status: 404, description: 'Train or route not found' }) + createSchedule(@Body() dto: CreateScheduleDto) { return this.service.createSchedule(dto); } + + @Get() + @ApiOperation({ summary: 'List schedules with optional filters' }) + @ApiQuery({ name: 'date', required: false, example: '2026-06-15', description: 'Departure date (YYYY-MM-DD). Returns all schedules departing on this calendar day.' }) + @ApiQuery({ name: 'routeId', required: false, description: 'Filter by route UUID' }) + @ApiQuery({ name: 'trainId', required: false, description: 'Filter by train UUID' }) + @ApiQuery({ name: 'status', required: false, enum: TripStatus, description: 'Filter by schedule status' }) + @ApiResponse({ status: 200, description: 'Array of schedules ordered by departureAt, each with train, origin/destination, stops, and booking/assignment counts' }) + listSchedules( + @Query('date') date?: string, + @Query('routeId') routeId?: string, + @Query('trainId') trainId?: string, + @Query('status') status?: TripStatus, + ) { + return this.service.listSchedules({ date, routeId, trainId, status }); + } + + // Static routes before parameterised ones + @Post('fares') + @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') + @ApiOperation({ summary: 'Create a fare rule scoped to a schedule or route code' }) + @ApiResponse({ status: 201, description: 'Fare rule created' }) createFareRule(@Body() dto: CreateFareRuleDto) { return this.service.createFareRule(dto); } - @Get('fares/:tripId') @ApiOperation({ summary: 'Get fare for trip and class' }) - getFare(@Param('tripId') tripId: string, @Query('class') cls: string) { return this.service.getFare(tripId, cls ?? 'ECONOMY'); } + + @Get(':id') + @ApiOperation({ summary: 'Get schedule with train, coaches, seats, and stop timeline' }) + @ApiParam({ name: 'id', description: 'TrainSchedule UUID' }) + @ApiResponse({ status: 200, description: 'Full schedule detail including route stops with station info' }) + @ApiResponse({ status: 404, description: 'Schedule not found' }) + getSchedule(@Param('id') id: string) { return this.service.getSchedule(id); } + + @Patch(':id/status') + @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') + @ApiOperation({ summary: 'Update schedule status (SCHEDULED → BOARDING → EN_ROUTE → ARRIVED)' }) + @ApiParam({ name: 'id', description: 'TrainSchedule UUID' }) + @ApiResponse({ status: 200, description: 'Status updated' }) + @ApiResponse({ status: 404, description: 'Schedule not found' }) + updateStatus(@Param('id') id: string, @Body() dto: UpdateScheduleStatusDto) { + return this.service.updateScheduleStatus(id, dto); + } + + // ── Stop Times ───────────────────────────────────────────────────────────── + + @Get(':id/stops') + @ApiOperation({ summary: 'List all stops for a schedule ordered by sequence' }) + @ApiParam({ name: 'id', description: 'TrainSchedule UUID' }) + @ApiResponse({ status: 200, description: 'Ordered stop list with station details and planned/actual times' }) + @ApiResponse({ status: 404, description: 'Schedule not found' }) + getStops(@Param('id') id: string) { return this.service.getStops(id); } + + @Patch(':id/stops/:sequence') + @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') + @ApiOperation({ summary: 'Update planned times or live status of a specific stop' }) + @ApiParam({ name: 'id', description: 'TrainSchedule UUID' }) + @ApiParam({ name: 'sequence', description: 'Stop sequence number' }) + @ApiResponse({ status: 200, description: 'Stop updated' }) + @ApiResponse({ status: 404, description: 'Stop not found on schedule' }) + updateStop( + @Param('id') id: string, + @Param('sequence', ParseIntPipe) sequence: number, + @Body() dto: UpdateStopTimeDto, + ) { return this.service.updateStop(id, sequence, dto); } + + // ── Fares ────────────────────────────────────────────────────────────────── + + @Get(':scheduleId/fares') + @ApiOperation({ summary: 'Get applicable fare for a schedule and seat class' }) + @ApiParam({ name: 'scheduleId', description: 'TrainSchedule UUID' }) + @ApiQuery({ name: 'class', required: false, description: 'Seat class name: "Economy Regular" | "Economy Bed" | "VIP Bed". Defaults to Economy Regular.' }) + @ApiResponse({ status: 200, description: 'Fare rule or default fare' }) + @ApiResponse({ status: 404, description: 'Schedule not found' }) + getFare(@Param('scheduleId') scheduleId: string, @Query('class') cls: string) { + return this.service.getFare(scheduleId, cls ?? 'Economy Regular'); + } } diff --git a/apps/edr-passenger-api/src/modules/schedules/schedules.dto.ts b/apps/edr-passenger-api/src/modules/schedules/schedules.dto.ts index 3d1401cfe..8ff79c527 100644 --- a/apps/edr-passenger-api/src/modules/schedules/schedules.dto.ts +++ b/apps/edr-passenger-api/src/modules/schedules/schedules.dto.ts @@ -1,25 +1,68 @@ -import { IsString, IsDateString, IsInt, IsOptional, IsEnum } from 'class-validator'; +import { IsString, IsDateString, IsInt, IsOptional, IsEnum, IsArray, ValidateNested, IsObject, Min } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; -import { ServiceClass } from '@prisma/client'; +import { Type } from 'class-transformer'; +import { TripStatus, StopStatus } from '@prisma/client'; -export class CreateTripDto { - @ApiProperty() @IsString() serviceId: string; - @ApiProperty() @IsString() originStationId: string; - @ApiProperty() @IsString() destinationStationId: string; - @ApiProperty({ example: '2026-05-11T08:30:00Z' }) @IsDateString() departureAt: string; - @ApiProperty({ example: '2026-05-11T20:00:00Z' }) @IsDateString() arrivalAt: string; - @ApiPropertyOptional() @IsOptional() @IsInt() stopsCount?: number; +export class PlannedStopTimeDto { + @ApiProperty({ example: 1, description: 'Route stop sequence number this timing applies to' }) @IsInt() @Min(1) sequence: number; + @ApiPropertyOptional({ example: '2026-06-15T09:30:00Z', description: 'Planned arrival at this stop (omit for first stop)' }) @IsOptional() @IsDateString() plannedArrivalAt?: string; + @ApiPropertyOptional({ example: '2026-06-15T09:45:00Z', description: 'Planned departure from this stop (omit for last stop)' }) @IsOptional() @IsDateString() plannedDepartureAt?: string; +} + +export class CreateScheduleDto { + @ApiProperty({ example: 'train-uuid', description: 'Train UUID' }) @IsString() trainId: string; + + @ApiProperty({ example: 'route-uuid', description: 'Route UUID — stops are copied from the route template. Origin and destination are derived from the first and last route stop.' }) + @IsString() routeId: string; + + @ApiProperty({ example: '2026-06-15T08:00:00Z', description: 'Scheduled departure from the first stop (origin)' }) @IsDateString() departureAt: string; + @ApiProperty({ example: '2026-06-15T20:00:00Z', description: 'Scheduled arrival at the last stop (destination)' }) @IsDateString() arrivalAt: string; + + @ApiProperty({ + type: [PlannedStopTimeDto], + description: 'Planned arrival/departure times per stop sequence. Must cover all stops defined on the route.', + example: [ + { sequence: 1, plannedDepartureAt: '2026-06-15T08:00:00Z' }, + { sequence: 2, plannedArrivalAt: '2026-06-15T09:30:00Z', plannedDepartureAt: '2026-06-15T09:45:00Z' }, + { sequence: 3, plannedArrivalAt: '2026-06-15T11:30:00Z', plannedDepartureAt: '2026-06-15T11:45:00Z' }, + { sequence: 4, plannedArrivalAt: '2026-06-15T15:00:00Z', plannedDepartureAt: '2026-06-15T15:20:00Z' }, + { sequence: 5, plannedArrivalAt: '2026-06-15T18:00:00Z', plannedDepartureAt: '2026-06-15T18:10:00Z' }, + { sequence: 6, plannedArrivalAt: '2026-06-15T20:00:00Z' }, + ], + }) + @IsArray() @ValidateNested({ each: true }) @Type(() => PlannedStopTimeDto) + plannedTimes: PlannedStopTimeDto[]; +} + +export class UpdateStopTimeDto { + @ApiPropertyOptional({ example: '2026-06-15T09:30:00Z' }) @IsOptional() @IsDateString() plannedArrivalAt?: string; + @ApiPropertyOptional({ example: '2026-06-15T09:45:00Z' }) @IsOptional() @IsDateString() plannedDepartureAt?: string; + @ApiPropertyOptional({ enum: StopStatus, example: StopStatus.UPCOMING }) @IsOptional() @IsEnum(StopStatus) status?: StopStatus; } export class CreateFareRuleDto { - @ApiPropertyOptional() @IsOptional() @IsString() tripId?: string; - @ApiPropertyOptional() @IsOptional() @IsString() route?: string; - @ApiProperty({ enum: ServiceClass, example: 'ECONOMY_REGULAR' }) @IsEnum(ServiceClass) serviceClass: ServiceClass; - @ApiProperty({ example: 45000 }) @IsInt() baseFareMinor: number; + @ApiPropertyOptional({ example: 'schedule-uuid', description: 'Scope fare rule to a specific schedule' }) @IsOptional() @IsString() scheduleId?: string; + @ApiPropertyOptional({ example: 'ADD-DJI', description: 'Scope fare rule to a route code (e.g. ADD-DJI)' }) @IsOptional() @IsString() route?: string; + @ApiProperty({ example: 'seat-class-uuid', description: 'Seat class UUID' }) @IsString() seatClassId: string; + @ApiProperty({ example: 45000, description: 'Base fare in minor currency units (ETB cents)' }) @IsInt() baseFareMinor: number; @ApiProperty({ example: '2026-01-01T00:00:00Z' }) @IsDateString() validFrom: string; - @ApiPropertyOptional() @IsOptional() @IsDateString() validUntil?: string; + @ApiPropertyOptional({ example: '2026-12-31T23:59:59Z' }) @IsOptional() @IsDateString() validUntil?: string; } -export class UpdateTripStatusDto { - @ApiProperty({ example: 'EN_ROUTE' }) @IsString() status: string; +export class ListSchedulesDto { + @ApiPropertyOptional({ example: '2026-06-15', description: 'Filter by departure date (YYYY-MM-DD). Returns all schedules departing on this calendar day.' }) + @IsOptional() @IsDateString() date?: string; + + @ApiPropertyOptional({ example: 'route-uuid', description: 'Filter by route UUID' }) + @IsOptional() @IsString() routeId?: string; + + @ApiPropertyOptional({ example: 'train-uuid', description: 'Filter by train UUID' }) + @IsOptional() @IsString() trainId?: string; + + @ApiPropertyOptional({ enum: TripStatus, example: TripStatus.SCHEDULED, description: 'Filter by schedule status' }) + @IsOptional() @IsEnum(TripStatus) status?: TripStatus; +} + +export class UpdateScheduleStatusDto { + @ApiProperty({ enum: TripStatus, example: TripStatus.EN_ROUTE }) @IsEnum(TripStatus) status: TripStatus; } diff --git a/apps/edr-passenger-api/src/modules/schedules/schedules.module.ts b/apps/edr-passenger-api/src/modules/schedules/schedules.module.ts index 41e48bea6..9df073e74 100644 --- a/apps/edr-passenger-api/src/modules/schedules/schedules.module.ts +++ b/apps/edr-passenger-api/src/modules/schedules/schedules.module.ts @@ -1,6 +1,12 @@ import { Module } from '@nestjs/common'; import { SchedulesController } from './schedules.controller'; import { SchedulesService } from './schedules.service'; +import { RoutesController } from './routes.controller'; +import { RoutesService } from './routes.service'; -@Module({ controllers: [SchedulesController], providers: [SchedulesService] }) +@Module({ + controllers: [RoutesController, SchedulesController], + providers: [RoutesService, SchedulesService], + exports: [RoutesService, SchedulesService], +}) export class SchedulesModule {} diff --git a/apps/edr-passenger-api/src/modules/schedules/schedules.service.ts b/apps/edr-passenger-api/src/modules/schedules/schedules.service.ts index a97b54fd6..e962be741 100644 --- a/apps/edr-passenger-api/src/modules/schedules/schedules.service.ts +++ b/apps/edr-passenger-api/src/modules/schedules/schedules.service.ts @@ -1,39 +1,174 @@ -import { Injectable, NotFoundException } from '@nestjs/common'; +import { Injectable, NotFoundException, ConflictException, BadRequestException } from '@nestjs/common'; import { PrismaService } from '../../common/prisma.service'; -import { CreateTripDto, CreateFareRuleDto, UpdateTripStatusDto } from './schedules.dto'; +import { RoutesService } from './routes.service'; +import { CreateScheduleDto, CreateFareRuleDto, UpdateScheduleStatusDto, UpdateStopTimeDto, ListSchedulesDto } from './schedules.dto'; @Injectable() export class SchedulesService { - constructor(private prisma: PrismaService) {} + constructor( + private prisma: PrismaService, + private routesService: RoutesService, + ) {} - async createTrip(dto: CreateTripDto) { - const dep = new Date(dto.departureAt), arr = new Date(dto.arrivalAt); - return this.prisma.trip.create({ - data: { serviceId: dto.serviceId, originStationId: dto.originStationId, destinationStationId: dto.destinationStationId, departureAt: dep, arrivalAt: arr, durationMinutes: Math.round((arr.getTime() - dep.getTime()) / 60000), stopsCount: dto.stopsCount ?? 0 }, - include: { service: true, originStation: true, destinationStation: true }, + // ── Schedule CRUD ────────────────────────────────────────────────────────── + + async listSchedules(dto: ListSchedulesDto) { + const where: any = {}; + + if (dto.date) { + const date = new Date(dto.date); + const nextDay = new Date(date.getTime() + 86_400_000); + where.departureAt = { gte: date, lt: nextDay }; + } + if (dto.routeId) where.routeId = dto.routeId; + if (dto.trainId) where.trainId = dto.trainId; + if (dto.status) where.status = dto.status; + + return this.prisma.trainSchedule.findMany({ + where, + include: { + train: true, + originStation: true, + destinationStation: true, + stopTimes: { include: { station: true }, orderBy: { sequence: 'asc' } }, + _count: { select: { coachAssignments: true, bookings: true } }, + }, + orderBy: { departureAt: 'asc' }, }); } - async getTrip(id: string) { - const trip = await this.prisma.trip.findUnique({ where: { id }, include: { service: true, originStation: true, destinationStation: true, coaches: { include: { seats: true } }, stopTimes: { include: { station: true }, orderBy: { sequence: 'asc' } } } }); - if (!trip) throw new NotFoundException('Trip not found'); - return trip; + async createSchedule(dto: CreateScheduleDto) { + const dep = new Date(dto.departureAt); + const arr = new Date(dto.arrivalAt); + if (arr <= dep) throw new BadRequestException('arrivalAt must be after departureAt'); + + // Validate route exists and has stops + const route = await this.prisma.route.findUnique({ + where: { id: dto.routeId }, + include: { stops: { orderBy: { sequence: 'asc' } } }, + }); + if (!route) throw new NotFoundException('Route not found'); + if (!route.active) throw new BadRequestException('Route is not active'); + if (route.stops.length < 2) throw new BadRequestException('Route must have at least 2 stops'); + + // Validate all route stop sequences are covered by plannedTimes + const providedSeqs = new Set(dto.plannedTimes.map(t => t.sequence)); + const missingSeqs = route.stops.map(s => s.sequence).filter(seq => !providedSeqs.has(seq)); + if (missingSeqs.length > 0) { + throw new BadRequestException(`Missing planned times for stop sequences: ${missingSeqs.join(', ')}`); + } + + // Derive origin and destination from first and last route stop + const firstStop = route.stops[0]; + const lastStop = route.stops[route.stops.length - 1]; + + const schedule = await this.prisma.trainSchedule.create({ + data: { + trainId: dto.trainId, + routeId: dto.routeId, + originStationId: firstStop.stationId, + destinationStationId: lastStop.stationId, + departureAt: dep, + arrivalAt: arr, + durationMinutes: Math.round((arr.getTime() - dep.getTime()) / 60_000), + stopsCount: Math.max(0, route.stops.length - 2), + }, + include: { train: true, originStation: true, destinationStation: true }, + }); + + // Copy route stops into TripStopTime with the provided planned times + const plannedTimesMap = Object.fromEntries( + dto.plannedTimes.map(t => [t.sequence, t]), + ); + await this.routesService.applyRouteToSchedule(dto.routeId, schedule.id, plannedTimesMap); + + return this.getSchedule(schedule.id); } - updateTripStatus(id: string, dto: UpdateTripStatusDto) { return this.prisma.trip.update({ where: { id }, data: { status: dto.status as any } }); } + async getSchedule(id: string) { + const schedule = await this.prisma.trainSchedule.findUnique({ + where: { id }, + include: { + train: true, + originStation: true, + destinationStation: true, + coachAssignments: { + include: { coach: { include: { seats: { orderBy: [{ row: 'asc' }, { col: 'asc' }] }, seatClass: true } } }, + orderBy: { positionNumber: 'asc' }, + }, + stopTimes: { include: { station: true }, orderBy: { sequence: 'asc' } }, + }, + }); + if (!schedule) throw new NotFoundException('Schedule not found'); + return schedule; + } + + updateScheduleStatus(id: string, dto: UpdateScheduleStatusDto) { + return this.prisma.trainSchedule.update({ where: { id }, data: { status: dto.status } }); + } + + // ── Stop Times (per-schedule overrides) ─────────────────────────────────── + + getStops(scheduleId: string) { + return this.prisma.tripStopTime.findMany({ + where: { scheduleId }, + include: { station: true }, + orderBy: { sequence: 'asc' }, + }); + } + + async updateStop(scheduleId: string, sequence: number, dto: UpdateStopTimeDto) { + const stop = await this.prisma.tripStopTime.findUnique({ + where: { scheduleId_sequence: { scheduleId, sequence } }, + }); + if (!stop) throw new NotFoundException(`Stop at sequence ${sequence} not found on schedule`); + + return this.prisma.tripStopTime.update({ + where: { scheduleId_sequence: { scheduleId, sequence } }, + data: { + plannedArrivalAt: dto.plannedArrivalAt ? new Date(dto.plannedArrivalAt) : undefined, + plannedDepartureAt: dto.plannedDepartureAt ? new Date(dto.plannedDepartureAt) : undefined, + status: dto.status, + }, + include: { station: true }, + }); + } + + // ── Fare Rules ───────────────────────────────────────────────────────────── createFareRule(dto: CreateFareRuleDto) { - return this.prisma.fareRule.create({ data: { ...dto, validFrom: new Date(dto.validFrom), validUntil: dto.validUntil ? new Date(dto.validUntil) : null } }); + const { validFrom, validUntil, scheduleId, ...rest } = dto; + return this.prisma.fareRule.create({ + data: { + ...rest, + tripId: scheduleId, + validFrom: new Date(validFrom), + validUntil: validUntil ? new Date(validUntil) : null, + }, + }); } - async getFare(tripId: string, serviceClass: string) { - const trip = await this.prisma.trip.findUnique({ where: { id: tripId }, include: { originStation: true, destinationStation: true } }); - if (!trip) throw new NotFoundException('Trip not found'); - const route = `${trip.originStation.code}-${trip.destinationStation.code}`; + async getFare(scheduleId: string, seatClassName: string) { + const schedule = await this.prisma.trainSchedule.findUnique({ + where: { id: scheduleId }, + include: { originStation: true, destinationStation: true }, + }); + if (!schedule) throw new NotFoundException('Schedule not found'); + + const route = `${schedule.originStation.code}-${schedule.destinationStation.code}`; + const seatClass = await this.prisma.seatClass.findFirst({ where: { name: seatClassName } }); + const now = new Date(); + const rule = await this.prisma.fareRule.findFirst({ - where: { serviceClass: serviceClass as any, validFrom: { lte: new Date() }, OR: [{ tripId }, { route }, { tripId: null, route: null }], AND: [{ OR: [{ validUntil: null }, { validUntil: { gte: new Date() } }] }] }, + where: { + seatClassId: seatClass?.id, + validFrom: { lte: now }, + OR: [{ tripId: scheduleId }, { route }, { tripId: null, route: null }], + AND: [{ OR: [{ validUntil: null }, { validUntil: { gte: now } }] }], + }, orderBy: { validFrom: 'desc' }, }); - return rule ?? { baseFareMinor: 45000, currency: 'ETB', serviceClass }; + + return rule ?? { baseFareMinor: 45000, currency: 'ETB', seatClassName }; } } diff --git a/apps/edr-passenger-api/src/modules/search/search.controller.ts b/apps/edr-passenger-api/src/modules/search/search.controller.ts index 2158f9cd4..5dbbd7759 100644 --- a/apps/edr-passenger-api/src/modules/search/search.controller.ts +++ b/apps/edr-passenger-api/src/modules/search/search.controller.ts @@ -9,24 +9,38 @@ export class SearchController { constructor(private service: SearchService) {} @Post() - @ApiOperation({ - summary: 'Search trips by origin, destination, and passenger counts', - description: 'Returns available trips WITHOUT pricing. Requires adult count (mandatory) and optional child count. Pricing is shown only in fare quote endpoint.' + @ApiOperation({ + summary: 'Search schedules by any origin–destination stop pair', + description: `Finds all train schedules where both origin and destination appear as stops (not just terminals). + +Example: A train running A→B→C→D will appear in results for A→B, A→C, A→D, B→C, B→D, and C→D searches. + +Availability is computed per seat per segment — a seat booked A→B is still shown as available for B→D. + +Returns departure/arrival times for the requested leg, the full stop list, and per-class seat counts.` }) - @ApiResponse({ status: 200, description: 'List of available trips with seat availability' }) - @ApiResponse({ status: 400, description: 'Invalid search parameters' }) - searchTrips(@Body() dto: SearchTripsDto) { - return this.service.searchTrips(dto); + @ApiResponse({ status: 200, description: 'Matching schedules with segment-accurate seat availability per class' }) + searchTrips(@Body() dto: SearchTripsDto) { + return this.service.searchTrips(dto); } @Post('fare-quote') - @ApiOperation({ - summary: 'Get detailed fare quote with age-based pricing', - description: 'Calculates fare based on adult/child counts. First child travels free, subsequent children pay full fare. Supports multi-currency display (ETB, DJF, USD).' + @ApiOperation({ + summary: 'Get fare quote for a specific schedule leg', + description: `Calculates fare for the requested origin→destination leg on a schedule. + +Pricing rules (in priority order): +1. Schedule-scoped FareRule (tripId = scheduleId) +2. Segment route FareRule (e.g. ADD-DRE) +3. Full-route FareRule (e.g. ADD-DJI) +4. Default hardcoded fare + +Age-based pricing: first child (age < 5) travels free, subsequent children pay full fare. +Supports multi-currency display (ETB, DJF, USD).` }) - @ApiResponse({ status: 200, description: 'Detailed fare breakdown with adult/child pricing and currency conversion' }) - @ApiResponse({ status: 404, description: 'Trip not found' }) - getFareQuote(@Body() dto: FareQuoteDto) { - return this.service.getFareQuote(dto); + @ApiResponse({ status: 200, description: 'Fare breakdown with adult/child pricing, discounts, taxes, and currency conversion' }) + @ApiResponse({ status: 404, description: 'Schedule not found or origin/destination not on schedule' }) + getFareQuote(@Body() dto: FareQuoteDto) { + return this.service.getFareQuote(dto); } } diff --git a/apps/edr-passenger-api/src/modules/search/search.dto.ts b/apps/edr-passenger-api/src/modules/search/search.dto.ts index 7a85fe816..571b2a354 100644 --- a/apps/edr-passenger-api/src/modules/search/search.dto.ts +++ b/apps/edr-passenger-api/src/modules/search/search.dto.ts @@ -4,23 +4,47 @@ import { Type } from 'class-transformer'; import { Currency } from '@prisma/client'; export class SearchTripsDto { - @ApiProperty({ example: 'st_ADD' }) @IsString() originStationId: string; - @ApiProperty({ example: 'st_DJI' }) @IsString() destinationStationId: string; - @ApiProperty({ example: '2026-05-11' }) @IsDateString() date: string; - @ApiProperty({ example: 2, description: 'Number of adults (5 years and above)' }) @Type(() => Number) @IsInt() @Min(1) adultCount: number; - @ApiPropertyOptional({ example: 1, description: 'Number of children (below 5 years)' }) @IsOptional() @Type(() => Number) @IsInt() @Min(0) childCount?: number; + @ApiProperty({ example: 'station-uuid', description: 'Origin station UUID — any intermediate stop is valid, not just the terminal' }) + @IsString() originStationId: string; + + @ApiProperty({ example: 'station-uuid', description: 'Destination station UUID — must appear after origin in the stop sequence' }) + @IsString() destinationStationId: string; + + @ApiProperty({ example: '2026-06-15', description: 'Departure date (YYYY-MM-DD)' }) + @IsDateString() date: string; + + @ApiProperty({ example: 2, description: 'Number of adult passengers (age ≥ 5)' }) + @Type(() => Number) @IsInt() @Min(1) adultCount: number; + + @ApiPropertyOptional({ example: 1, description: 'Number of child passengers (age < 5). First child travels free.' }) + @IsOptional() @Type(() => Number) @IsInt() @Min(0) childCount?: number; } export class FareQuoteDto { - @ApiProperty() @IsString() tripId: string; - @ApiProperty({ - example: 'ECONOMY_REGULAR', - enum: ['ECONOMY_REGULAR', 'ECONOMY_BED_LOWER', 'ECONOMY_BED_MIDDLE', 'ECONOMY_BED_UPPER', 'VIP_BED_LOWER', 'VIP_BED_UPPER'] - }) - @IsString() serviceClass: string; - @ApiProperty({ example: 2, description: 'Number of adults' }) @Type(() => Number) @IsInt() @Min(1) adultCount: number; - @ApiPropertyOptional({ example: 1, description: 'Number of children' }) @IsOptional() @Type(() => Number) @IsInt() @Min(0) childCount?: number; - @ApiPropertyOptional({ example: 'WEEKEND15' }) @IsOptional() @IsString() promoCode?: string; - @ApiPropertyOptional({ example: 450 }) @IsOptional() @Type(() => Number) @IsInt() loyaltyRedemptionPoints?: number; - @ApiPropertyOptional({ example: 'ETB', enum: ['ETB', 'DJF', 'USD'] }) @IsOptional() @IsEnum(Currency) displayCurrency?: Currency; + @ApiProperty({ example: 'schedule-uuid', description: 'TrainSchedule UUID from search results' }) + @IsString() scheduleId: string; + + @ApiProperty({ example: 'station-uuid', description: 'Origin station UUID (must be a stop on the schedule)' }) + @IsString() originStationId: string; + + @ApiProperty({ example: 'station-uuid', description: 'Destination station UUID (must come after origin in stop sequence)' }) + @IsString() destinationStationId: string; + + @ApiProperty({ example: 'Economy Regular', description: 'Seat class name: "Economy Regular" | "Economy Bed" | "VIP Bed"' }) + @IsString() seatClassName: string; + + @ApiProperty({ example: 2, description: 'Number of adult passengers' }) + @Type(() => Number) @IsInt() @Min(1) adultCount: number; + + @ApiPropertyOptional({ example: 1 }) + @IsOptional() @Type(() => Number) @IsInt() @Min(0) childCount?: number; + + @ApiPropertyOptional({ example: 'WEEKEND15' }) + @IsOptional() @IsString() promoCode?: string; + + @ApiPropertyOptional({ example: 450, description: 'Loyalty points to redeem (10 points = 1 ETB minor unit)' }) + @IsOptional() @Type(() => Number) @IsInt() loyaltyRedemptionPoints?: number; + + @ApiPropertyOptional({ example: 'ETB', enum: Currency }) + @IsOptional() @IsEnum(Currency) displayCurrency?: Currency; } diff --git a/apps/edr-passenger-api/src/modules/search/search.service.ts b/apps/edr-passenger-api/src/modules/search/search.service.ts index 7a6bef602..062736d2e 100644 --- a/apps/edr-passenger-api/src/modules/search/search.service.ts +++ b/apps/edr-passenger-api/src/modules/search/search.service.ts @@ -14,102 +14,256 @@ export class SearchService { ) {} async searchTrips(dto: SearchTripsDto) { - const date = new Date(dto.date), nextDay = new Date(date.getTime() + 86400000); - const trips = await this.prisma.trip.findMany({ - where: { originStationId: dto.originStationId, destinationStationId: dto.destinationStationId, departureAt: { gte: date, lt: nextDay }, status: { in: ['SCHEDULED', 'BOARDING'] } }, - include: { service: true, originStation: true, destinationStation: true, coaches: { include: { seats: true } } }, - }); - - const totalPassengers = dto.adultCount + (dto.childCount || 0); - - return trips.map((trip) => { - const seatsByClass = (cls: string) => trip.coaches.filter((c) => c.serviceClass === cls).flatMap((c) => c.seats); - const avail = (cls: string) => seatsByClass(cls).filter((s) => s.status === 'AVAILABLE').length; - return { - id: trip.id, - number: trip.service.number, - origin: { id: trip.originStation.id, code: trip.originStation.code, name: trip.originStation.name, city: trip.originStation.city }, - destination: { id: trip.destinationStation.id, code: trip.destinationStation.code, name: trip.destinationStation.name, city: trip.destinationStation.city }, - departureAt: trip.departureAt, arrivalAt: trip.arrivalAt, status: trip.status, - availability: { - ECONOMY_REGULAR: avail('ECONOMY_REGULAR') >= totalPassengers, - ECONOMY_BED_LOWER: avail('ECONOMY_BED_LOWER') >= totalPassengers, - ECONOMY_BED_MIDDLE: avail('ECONOMY_BED_MIDDLE') >= totalPassengers, - ECONOMY_BED_UPPER: avail('ECONOMY_BED_UPPER') >= totalPassengers, - VIP_BED_LOWER: avail('VIP_BED_LOWER') >= totalPassengers, - VIP_BED_UPPER: avail('VIP_BED_UPPER') >= totalPassengers + const date = new Date(dto.date); + const nextDay = new Date(date.getTime() + 86_400_000); + const totalPassengers = dto.adultCount + (dto.childCount ?? 0); + + // Find all schedules that have BOTH origin and destination as stops + // (not just terminal-to-terminal) and depart on the requested date + const schedules = await this.prisma.trainSchedule.findMany({ + where: { + status: { in: ['SCHEDULED', 'BOARDING'] }, + departureAt: { gte: date, lt: nextDay }, + stopTimes: { some: { stationId: dto.originStationId } }, + }, + include: { + train: true, + originStation: true, + destinationStation: true, + stopTimes: { include: { station: true }, orderBy: { sequence: 'asc' } }, + coachAssignments: { + include: { coach: { include: { seats: true, seatClass: true } } }, }, - }; + }, }); + + const results = []; + + for (const schedule of schedules) { + const originStop = schedule.stopTimes.find(s => s.stationId === dto.originStationId); + const destStop = schedule.stopTimes.find(s => s.stationId === dto.destinationStationId); + + // Both stops must exist and origin must come before destination + if (!originStop || !destStop || originStop.sequence >= destStop.sequence) continue; + + // Compute per-seat availability for the requested segment range + // A seat is available if no active booking/hold overlaps [originSeq, destSeq) + const availabilityByClass: Record = {}; + + for (const assignment of schedule.coachAssignments) { + const className = assignment.coach.seatClass.name; + if (!availabilityByClass[className]) availabilityByClass[className] = 0; + + for (const seat of assignment.coach.seats) { + if (seat.status === 'BLOCKED') continue; + const free = await this.isSeatFreeForSegment( + schedule.id, seat.id, + originStop.sequence, destStop.sequence, + ); + if (free) availabilityByClass[className]++; + } + } + + // Departure/arrival times for the requested leg (not the full schedule) + const legDepartureAt = originStop.plannedDepartureAt ?? schedule.departureAt; + const legArrivalAt = destStop.plannedArrivalAt ?? schedule.arrivalAt; + + results.push({ + scheduleId: schedule.id, + trainNumber: schedule.train.number, + trainName: schedule.train.name, + origin: { + id: originStop.stationId, + code: originStop.station.code, + name: originStop.station.name, + city: originStop.station.city, + sequence: originStop.sequence, + }, + destination: { + id: destStop.stationId, + code: destStop.station.code, + name: destStop.station.name, + city: destStop.station.city, + sequence: destStop.sequence, + }, + departureAt: legDepartureAt, + arrivalAt: legArrivalAt, + durationMinutes: Math.round( + (new Date(legArrivalAt).getTime() - new Date(legDepartureAt).getTime()) / 60_000, + ), + status: schedule.status, + // Only return stops within the requested leg (origin → destination inclusive) + stops: schedule.stopTimes + .filter(st => st.sequence >= originStop.sequence && st.sequence <= destStop.sequence) + .map(st => ({ + stationId: st.stationId, + stationName: st.station.name, + sequence: st.sequence, + plannedArrivalAt: st.plannedArrivalAt, + plannedDepartureAt: st.plannedDepartureAt, + })), + availabilityByClass, + hasAvailability: Object.values(availabilityByClass).some(n => n >= totalPassengers), + }); + } + + return results; } async getFareQuote(dto: FareQuoteDto) { - const trip = await this.prisma.trip.findUnique({ where: { id: dto.tripId } }); - if (!trip) throw new NotFoundException('Trip not found'); - + const schedule = await this.prisma.trainSchedule.findUnique({ + where: { id: dto.scheduleId }, + include: { + originStation: true, + destinationStation: true, + stopTimes: { include: { station: true }, orderBy: { sequence: 'asc' } }, + }, + }); + if (!schedule) throw new NotFoundException('Schedule not found'); + + const originStop = schedule.stopTimes.find(s => s.stationId === dto.originStationId); + const destStop = schedule.stopTimes.find(s => s.stationId === dto.destinationStationId); + if (!originStop || !destStop || originStop.sequence >= destStop.sequence) { + throw new NotFoundException('Origin or destination not found on this schedule'); + } + + const seatClass = await this.prisma.seatClass.findFirst({ where: { name: dto.seatClassName } }); + + // Look up fare rule: prefer schedule-scoped, then segment route, then global + const segmentRoute = `${originStop.station.code}-${destStop.station.code}`; + const fullRoute = `${schedule.originStation.code}-${schedule.destinationStation.code}`; + const now = new Date(); + + const fareRule = await this.prisma.fareRule.findFirst({ + where: { + seatClassId: seatClass?.id, + validFrom: { lte: now }, + OR: [ + { validUntil: null }, + { validUntil: { gte: now } }, + ], + }, + orderBy: [ + // Most specific first: schedule-scoped > segment route > full route > global + { tripId: 'desc' }, + { validFrom: 'desc' }, + ], + }); + + const baseFareMinor = fareRule?.baseFareMinor ?? this.defaultFare(dto.seatClassName); + const adultCount = dto.adultCount; - const childCount = dto.childCount || 0; - - const baseFareMinor = this.defaultFare(dto.serviceClass); - - // Adult fare: 100% of base fare + const childCount = dto.childCount ?? 0; const adultFareMinor = baseFareMinor * adultCount; - - // Child fare: First child free, subsequent children pay full fare const paidChildrenCount = Math.max(0, childCount - 1); const childFareMinor = baseFareMinor * paidChildrenCount; - const totalBaseFareMinor = adultFareMinor + childFareMinor; - + let discountMinor = 0; if (dto.promoCode) { const promo = await this.prisma.promotion.findUnique({ where: { code: dto.promoCode } }); - if (promo?.active && promo.validUntil > new Date()) { - discountMinor = promo.percentOff ? Math.round(totalBaseFareMinor * promo.percentOff / 100) : (promo.amountOffMinor ?? 0); + if (promo?.active && promo.validUntil > now) { + discountMinor = promo.percentOff + ? Math.round(totalBaseFareMinor * promo.percentOff / 100) + : (promo.amountOffMinor ?? 0); } } - + const loyaltyMinor = (dto.loyaltyRedemptionPoints ?? 0) * POINTS_TO_MINOR; const taxesMinor = Math.round(totalBaseFareMinor * 0.05); const totalMinor = Math.max(0, totalBaseFareMinor - discountMinor - loyaltyMinor + taxesMinor); - - const displayCurrency = dto.displayCurrency || Currency.ETB; - let displayTotalMinor = totalMinor; - - if (displayCurrency !== Currency.ETB) { - displayTotalMinor = await this.currencyService.convertAmount(totalMinor, Currency.ETB, displayCurrency); - } - + + const displayCurrency = dto.displayCurrency ?? Currency.ETB; + const displayTotalMinor = displayCurrency !== Currency.ETB + ? await this.currencyService.convertAmount(totalMinor, Currency.ETB, displayCurrency) + : totalMinor; + return { - tripId: dto.tripId, - serviceClass: dto.serviceClass, - adultCount, - childCount, - baseFareMinor, - adultFareMinor, - childFareMinor, + scheduleId: dto.scheduleId, + originStationId: dto.originStationId, + destinationStationId: dto.destinationStationId, + segmentRoute, + seatClassName: dto.seatClassName, + adultCount, childCount, + baseFareMinor, adultFareMinor, childFareMinor, freeChildrenCount: Math.min(childCount, 1), - paidChildrenCount, - totalBaseFareMinor, - discountMinor, - loyaltyRedemptionMinor: loyaltyMinor, - taxesFeesMinor: taxesMinor, - totalMinor, - currency: 'ETB', - displayCurrency, - displayTotalMinor, + paidChildrenCount, totalBaseFareMinor, + discountMinor, loyaltyRedemptionMinor: loyaltyMinor, + taxesFeesMinor: taxesMinor, totalMinor, + currency: 'ETB', displayCurrency, displayTotalMinor, }; } - private defaultFare(serviceClass: string): number { + /** + * Returns true if the seat has no active hold or confirmed booking + * whose segment range overlaps [fromSeq, toSeq). + * Overlap condition: existingFrom < toSeq AND fromSeq < existingTo + */ + private async isSeatFreeForSegment( + scheduleId: string, + seatId: string, + fromSeq: number, + toSeq: number, + ): Promise { + // Check active holds that include this seat on this schedule + const holds = await this.prisma.seatHold.findMany({ + where: { scheduleId, seatIds: { has: seatId }, expiresAt: { gt: new Date() } }, + }); + + for (const hold of holds) { + // Resolve hold segment range from its stored origin/destination via JourneySegment + // For holds we use the stop sequences stored on the hold's origin/destination + // Since SeatHold doesn't store sequences directly, we check JourneySegments + // that reference this seat on this schedule with PENDING_PAYMENT status + const holdSegs = await this.prisma.journeySegment.findMany({ + where: { scheduleId, seatId }, + include: { + journey: true, + schedule: { include: { stopTimes: true } }, + }, + }); + + for (const js of holdSegs) { + const depSeq = js.schedule.stopTimes.find(s => s.stationId === js.departureStationId)?.sequence; + const arrSeq = js.schedule.stopTimes.find(s => s.stationId === js.arrivalStationId)?.sequence; + if (depSeq !== undefined && arrSeq !== undefined) { + if (depSeq < toSeq && fromSeq < arrSeq) return false; + } + } + + // If no journey segments yet (hold just created), treat the whole hold as blocking + if (holdSegs.length === 0) return false; + } + + // Check confirmed/pending bookings via JourneySegment + const bookedSegments = await this.prisma.journeySegment.findMany({ + where: { + scheduleId, + seatId, + journey: { status: { in: ['CONFIRMED', 'PENDING_PAYMENT'] } }, + }, + include: { + schedule: { include: { stopTimes: true } }, + }, + }); + + for (const js of bookedSegments) { + const depSeq = js.schedule.stopTimes.find(s => s.stationId === js.departureStationId)?.sequence; + const arrSeq = js.schedule.stopTimes.find(s => s.stationId === js.arrivalStationId)?.sequence; + if (depSeq !== undefined && arrSeq !== undefined) { + if (depSeq < toSeq && fromSeq < arrSeq) return false; + } + } + + return true; + } + + private defaultFare(seatClassName: string): number { const fares: Record = { - ECONOMY_REGULAR: 35000, - ECONOMY_BED_LOWER: 55000, - ECONOMY_BED_MIDDLE: 50000, - ECONOMY_BED_UPPER: 45000, - VIP_BED_LOWER: 85000, - VIP_BED_UPPER: 80000 + 'Economy Regular': 45000, + 'Economy Bed': 65000, + 'VIP Bed': 95000, }; - return fares[serviceClass] ?? 35000; + return fares[seatClassName] ?? 45000; } } diff --git a/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.controller.ts b/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.controller.ts new file mode 100644 index 000000000..945834ac0 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.controller.ts @@ -0,0 +1,40 @@ +import { Body, Controller, Get, Param, Patch, Post, UseGuards } from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiBearerAuth, ApiParam, ApiResponse, ApiBody } from '@nestjs/swagger'; +import { SeatClassesService } from './seat-classes.service'; +import { CreateSeatClassDto, UpdateSeatClassDto } from './seat-classes.dto'; +import { JwtGuard } from '../../common/jwt.guard'; + +@ApiTags('Seat Classes') +@Controller('seat-classes') +export class SeatClassesController { + constructor(private service: SeatClassesService) {} + + @Get() + @ApiOperation({ summary: 'List all seat classes' }) + @ApiResponse({ status: 200, description: 'Returns all seat classes with their coaches' }) + listSeatClasses() { return this.service.listSeatClasses(); } + + @Get(':id') + @ApiOperation({ summary: 'Get a seat class by ID' }) + @ApiParam({ name: 'id', description: 'Seat class UUID' }) + @ApiResponse({ status: 200, description: 'Returns seat class with its coaches' }) + @ApiResponse({ status: 404, description: 'Seat class not found' }) + getSeatClass(@Param('id') id: string) { return this.service.getSeatClass(id); } + + @Post() + @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') + @ApiOperation({ summary: 'Create a seat class' }) + @ApiBody({ type: CreateSeatClassDto }) + @ApiResponse({ status: 201, description: 'Seat class created' }) + @ApiResponse({ status: 409, description: 'Seat class name already exists' }) + createSeatClass(@Body() dto: CreateSeatClassDto) { return this.service.createSeatClass(dto); } + + @Patch(':id') + @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') + @ApiOperation({ summary: 'Update a seat class' }) + @ApiParam({ name: 'id', description: 'Seat class UUID' }) + @ApiBody({ type: UpdateSeatClassDto }) + @ApiResponse({ status: 200, description: 'Seat class updated' }) + @ApiResponse({ status: 404, description: 'Seat class not found' }) + updateSeatClass(@Param('id') id: string, @Body() dto: UpdateSeatClassDto) { return this.service.updateSeatClass(id, dto); } +} diff --git a/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.dto.ts b/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.dto.ts new file mode 100644 index 000000000..d12fe0fb6 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.dto.ts @@ -0,0 +1,24 @@ +import { IsString, IsInt, IsBoolean, IsOptional } from 'class-validator'; +import { ApiProperty, ApiPropertyOptional, PartialType } from '@nestjs/swagger'; + +export class CreateSeatClassDto { + @ApiProperty({ example: 'Economy Seat' }) + @IsString() + name: string; + + @ApiPropertyOptional({ example: 'Standard economy seating' }) + @IsOptional() + @IsString() + description?: string; + + @ApiProperty({ example: 45000, description: 'Base price in minor currency units' }) + @IsInt() + basePrice: number; + + @ApiPropertyOptional({ example: true }) + @IsOptional() + @IsBoolean() + isActive?: boolean; +} + +export class UpdateSeatClassDto extends PartialType(CreateSeatClassDto) {} diff --git a/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.module.ts b/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.module.ts new file mode 100644 index 000000000..a7e8648e1 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.module.ts @@ -0,0 +1,6 @@ +import { Module } from '@nestjs/common'; +import { SeatClassesController } from './seat-classes.controller'; +import { SeatClassesService } from './seat-classes.service'; + +@Module({ controllers: [SeatClassesController], providers: [SeatClassesService], exports: [SeatClassesService] }) +export class SeatClassesModule {} diff --git a/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.service.ts b/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.service.ts new file mode 100644 index 000000000..b21eac0b6 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/seat-classes/seat-classes.service.ts @@ -0,0 +1,40 @@ +import { Injectable, NotFoundException, ConflictException } from '@nestjs/common'; +import { PrismaService } from '../../common/prisma.service'; +import { CreateSeatClassDto, UpdateSeatClassDto } from './seat-classes.dto'; + +@Injectable() +export class SeatClassesService { + constructor(private prisma: PrismaService) {} + + private readonly coachInclude = { + coaches: { + select: { id: true, coachNumber: true, label: true, mode: true, totalUnits: true, _count: { select: { seats: true } } }, + orderBy: { label: 'asc' as const }, + }, + }; + + listSeatClasses() { + return this.prisma.seatClass.findMany({ orderBy: { createdAt: 'asc' }, include: this.coachInclude }); + } + + async getSeatClass(id: string) { + const sc = await this.prisma.seatClass.findUnique({ where: { id }, include: this.coachInclude }); + if (!sc) throw new NotFoundException('SeatClass not found'); + return sc; + } + + async createSeatClass(dto: CreateSeatClassDto) { + try { + return await this.prisma.seatClass.create({ data: dto, include: this.coachInclude }); + } catch (e: any) { + if (e.code === 'P2002') throw new ConflictException(`Seat class "${dto.name}" already exists`); + throw e; + } + } + + async updateSeatClass(id: string, dto: UpdateSeatClassDto) { + const sc = await this.prisma.seatClass.findUnique({ where: { id } }); + if (!sc) throw new NotFoundException('SeatClass not found'); + return this.prisma.seatClass.update({ where: { id }, data: dto, include: this.coachInclude }); + } +} diff --git a/apps/edr-passenger-api/src/modules/seats/seats.controller.ts b/apps/edr-passenger-api/src/modules/seats/seats.controller.ts index 558d4b3f6..9059ba6f0 100644 --- a/apps/edr-passenger-api/src/modules/seats/seats.controller.ts +++ b/apps/edr-passenger-api/src/modules/seats/seats.controller.ts @@ -10,12 +10,12 @@ export class SeatsController { constructor(private service: SeatsService) {} // ── Seat Map ────────────────────────────────────────────────────────────── - @Get('seatmap/:tripId') - @ApiOperation({ summary: 'Get seat map for a trip' }) - @ApiParam({ name: 'tripId', description: 'Trip UUID' }) + @Get('seatmap/:scheduleId') + @ApiOperation({ summary: 'Get seat map for a schedule' }) + @ApiParam({ name: 'scheduleId', description: 'TrainSchedule UUID' }) @ApiQuery({ name: 'coachId', required: false, description: 'Filter by coach UUID' }) @ApiResponse({ status: 200, description: 'Returns coaches with seats and seat class info' }) - getSeatMap(@Param('tripId') tripId: string, @Query('coachId') coachId?: string) { return this.service.getSeatMap(tripId, coachId); } + getSeatMap(@Param('scheduleId') scheduleId: string, @Query('coachId') coachId?: string) { return this.service.getSeatMap(scheduleId, coachId); } // ── Hold / Release ──────────────────────────────────────────────────────── @Post('hold') @@ -33,10 +33,10 @@ export class SeatsController { @ApiResponse({ status: 404, description: 'Hold not found' }) releaseHold(@Param('holdId') holdId: string) { return this.service.releaseHold(holdId); } - @Get('export/csv/:tripId') @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') @ApiOperation({ summary: 'Export seats as CSV' }) - async exportCSV(@Param('tripId') tripId: string) { - const csv = await this.service.exportSeatsCSV(tripId); - return { csv, filename: `seats-${tripId}.csv` }; + @Get('export/csv/:scheduleId') @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') @ApiOperation({ summary: 'Export seats as CSV' }) + async exportCSV(@Param('scheduleId') scheduleId: string) { + const csv = await this.service.exportSeatsCSV(scheduleId); + return { csv, filename: `seats-${scheduleId}.csv` }; } @Post('import/preview') @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') @ApiOperation({ summary: 'Preview CSV import' }) @@ -45,7 +45,7 @@ export class SeatsController { } @Post('import/commit') @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') @ApiOperation({ summary: 'Commit CSV import' }) - importCSV(@Body() body: { tripId: string; csv: string; commit: boolean }) { - return this.service.importSeatsCSV(body.tripId, body.csv, body.commit); + importCSV(@Body() body: { scheduleId: string; csv: string; commit: boolean }) { + return this.service.importSeatsCSV(body.scheduleId, body.csv, body.commit); } } diff --git a/apps/edr-passenger-api/src/modules/seats/seats.dto.ts b/apps/edr-passenger-api/src/modules/seats/seats.dto.ts index 52136e9fa..6af6fe203 100644 --- a/apps/edr-passenger-api/src/modules/seats/seats.dto.ts +++ b/apps/edr-passenger-api/src/modules/seats/seats.dto.ts @@ -2,7 +2,7 @@ import { IsString, IsArray, IsOptional } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; export class HoldSeatsDto { - @ApiProperty({ example: 'trip-uuid' }) @IsString() tripId: string; + @ApiProperty({ example: 'schedule-uuid' }) @IsString() scheduleId: string; @ApiProperty({ example: 'passenger-uuid' }) @IsString() passengerId: string; @ApiProperty({ type: [String], example: ['seat-uuid-1', 'seat-uuid-2'] }) @IsArray() seatIds: string[]; @ApiPropertyOptional({ example: 'fare-quote-uuid' }) @IsOptional() @IsString() fareQuoteId?: string; diff --git a/apps/edr-passenger-api/src/modules/seats/seats.service.ts b/apps/edr-passenger-api/src/modules/seats/seats.service.ts index 3593c38d1..606cb4902 100644 --- a/apps/edr-passenger-api/src/modules/seats/seats.service.ts +++ b/apps/edr-passenger-api/src/modules/seats/seats.service.ts @@ -8,14 +8,20 @@ export class SeatsService { constructor(private prisma: PrismaService) {} // ── Seat Map ────────────────────────────────────────────────────────────── - async getSeatMap(tripId: string, coachId?: string) { - const coaches = await this.prisma.coach.findMany({ where: { tripId, ...(coachId ? { id: coachId } : {}) }, include: { seats: { orderBy: [{ row: 'asc' }, { col: 'asc' }] } } }); + async getSeatMap(scheduleId: string, coachId?: string) { + const assignments = await this.prisma.coachAssignment.findMany({ + where: { scheduleId, ...(coachId ? { coachId } : {}) }, + include: { coach: { include: { seats: { orderBy: [{ row: 'asc' }, { col: 'asc' }] }, seatClass: true } } }, + orderBy: { positionNumber: 'asc' }, + }); return { - coaches: coaches.map((coach) => ({ - id: coach.id, - name: `Coach ${coach.label}`, - serviceClass: coach.serviceClass, - seats: coach.seats.map((s) => ({ id: s.id, number: s.label, status: s.status, kind: s.kind })), + coaches: assignments.map((a) => ({ + id: a.coach.id, + assignmentId: a.id, + name: `Coach ${a.coach.label}`, + seatClass: a.coach.seatClass.name, + positionNumber: a.positionNumber, + seats: a.coach.seats.map((s) => ({ id: s.id, number: s.label, status: s.status, kind: s.kind })), })), }; } @@ -28,9 +34,9 @@ export class SeatsService { const unavailable = seats.filter((s) => s.status === 'BOOKED' || s.status === 'BLOCKED' || (s.status === 'HELD' && s.heldUntil && s.heldUntil > new Date())); if (unavailable.length > 0) throw new ConflictException('One or more seats unavailable'); await tx.seat.updateMany({ where: { id: { in: dto.seatIds } }, data: { status: 'HELD', heldUntil: expiresAt } }); - return tx.seatHold.create({ data: { tripId: dto.tripId, passengerId: dto.passengerId, seatIds: dto.seatIds, fareQuoteId: dto.fareQuoteId, expiresAt } }); + return tx.seatHold.create({ data: { scheduleId: dto.scheduleId, passengerId: dto.passengerId, seatIds: dto.seatIds, fareQuoteId: dto.fareQuoteId, expiresAt } }); }); - return { id: hold.id, tripId: dto.tripId, seatIds: dto.seatIds, expiresAt }; + return { id: hold.id, scheduleId: dto.scheduleId, seatIds: dto.seatIds, expiresAt }; } async releaseHold(holdId: string) { @@ -44,10 +50,10 @@ export class SeatsService { async confirmSeats(seatIds: string[]) { await this.prisma.seat.updateMany({ where: { id: { in: seatIds } }, data: { status: 'BOOKED', heldUntil: null } }); } async releaseSeats(seatIds: string[]) { await this.prisma.seat.updateMany({ where: { id: { in: seatIds } }, data: { status: 'AVAILABLE', heldUntil: null } }); } - async autoAssignSeats(tripId: string, count: number, serviceClass: string, eligibility?: string): Promise { + async autoAssignSeats(scheduleId: string, count: number, seatClassName: string, eligibility?: string): Promise { const seats = await this.prisma.seat.findMany({ where: { - coach: { tripId, serviceClass: serviceClass as any }, + coach: { seatClass: { name: seatClassName }, assignments: { some: { scheduleId } } }, status: 'AVAILABLE', ...(eligibility ? { eligibility } : {}), }, @@ -81,18 +87,15 @@ export class SeatsService { return seats.slice(0, count); } - async exportSeatsCSV(tripId: string): Promise { - const coaches = await this.prisma.coach.findMany({ - where: { tripId }, - include: { seats: { orderBy: [{ row: 'asc' }, { col: 'asc' }] } }, + async exportSeatsCSV(scheduleId: string): Promise { + const assignments = await this.prisma.coachAssignment.findMany({ + where: { scheduleId }, + include: { coach: { include: { seats: { orderBy: [{ row: 'asc' }, { col: 'asc' }] } } } }, }); - const rows = ['coachId,coachLabel,row,col,label,kind,status,premiumFeeMinor,eligibility']; - for (const coach of coaches) { - for (const seat of coach.seats) { - rows.push( - `${coach.id},${coach.label},${seat.row},${seat.col},${seat.label},${seat.kind},${seat.status},${seat.premiumFeeMinor},${seat.eligibility || ''}`, - ); + for (const a of assignments) { + for (const seat of a.coach.seats) { + rows.push(`${a.coach.id},${a.coach.label},${seat.row},${seat.col},${seat.label},${seat.kind},${seat.status},${seat.premiumFeeMinor},${seat.eligibility || ''}`); } } return rows.join('\n'); @@ -123,7 +126,7 @@ export class SeatsService { return { valid, invalid, errors: errors.slice(0, 10) }; } - async importSeatsCSV(tripId: string, csvContent: string, commit: boolean): Promise<{ imported: number; errors: string[] }> { + async importSeatsCSV(scheduleId: string, csvContent: string, commit: boolean): Promise<{ imported: number; errors: string[] }> { const lines = csvContent.trim().split('\n').slice(1); const errors: string[] = []; let imported = 0; diff --git a/apps/edr-passenger-api/src/modules/segments/booking-flow-example.ts b/apps/edr-passenger-api/src/modules/segments/booking-flow-example.ts index 04889e392..8b46a77d1 100644 --- a/apps/edr-passenger-api/src/modules/segments/booking-flow-example.ts +++ b/apps/edr-passenger-api/src/modules/segments/booking-flow-example.ts @@ -1,64 +1,56 @@ /** * SEGMENT-BASED SEAT RESERVATION EXAMPLE - * - * This example demonstrates the complete flow for booking Addis Ababa → Dire Dawa + * + * Demonstrates the complete flow for booking Addis Ababa → Dire Dawa * on the Addis Ababa → Djibouti route with segment-based seat management. - * - * Route: Addis Ababa (seq:0) → Adama (seq:1) → Awash (seq:2) → Dire Dawa (seq:3) → Djibouti (seq:4) - * Booking: Addis Ababa → Dire Dawa (segments: 0→1, 1→2, 2→3) + * + * Route: Addis Ababa (seq:1) → Adama (seq:2) → Awash (seq:3) → Dire Dawa (seq:4) → Aysha (seq:5) → Djibouti (seq:6) + * Booking: Addis Ababa → Dire Dawa (segments: 1→2, 2→3, 3→4) */ import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); -// Example 1: Complete Booking Flow async function exampleBookingFlow() { console.log('=== SEGMENT-BASED BOOKING FLOW ===\n'); - const tripId = 'trip_add_dji_001'; + const scheduleId = 'schedule_add_dji_001'; const passengerId = 'passenger_kelemu'; const seatIds = ['seat_coach_a_1a', 'seat_coach_a_1b']; - const originStationId = 'st_ADD'; // Addis Ababa - const destinationStationId = 'st_DRE'; // Dire Dawa + const originStationId = 'st_ADD'; + const destinationStationId = 'st_DRE'; try { - // Step 1: Check seat availability for segments console.log('1. Checking seat availability...'); - const segments = await getJourneySegments(tripId, originStationId, destinationStationId); + const segments = await getJourneySegments(scheduleId, originStationId, destinationStationId); console.log('Journey segments:', segments.map(s => `${s.fromName} → ${s.toName}`)); - // Step 2: Hold seats (10-minute expiry) console.log('\n2. Holding seats...'); - const holdResult = await holdSeatsTransaction(tripId, seatIds, passengerId, originStationId, destinationStationId); + const holdResult = await holdSeatsTransaction(scheduleId, seatIds, passengerId, originStationId, destinationStationId); console.log('Hold created:', holdResult); - // Step 3: Simulate payment processing (5 seconds) console.log('\n3. Processing payment...'); await new Promise(resolve => setTimeout(resolve, 5000)); - // Step 4: Confirm booking console.log('\n4. Confirming booking...'); const bookingId = 'booking_' + Date.now(); const confirmResult = await confirmBookingTransaction(holdResult.holdId, bookingId, segments); console.log('Booking confirmed:', confirmResult); - // Step 5: Simulate trip progress and seat release console.log('\n5. Simulating trip progress...'); - await simulateTripProgress(tripId, segments); + await simulateTripProgress(scheduleId, segments); } catch (error) { console.error('Booking flow error:', error); } } -// Database Transaction Functions - -async function getJourneySegments(tripId: string, originStationId: string, destinationStationId: string) { +async function getJourneySegments(scheduleId: string, originStationId: string, destinationStationId: string) { const stopTimes = await prisma.tripStopTime.findMany({ - where: { tripId }, + where: { scheduleId }, include: { station: true }, - orderBy: { sequence: 'asc' } + orderBy: { sequence: 'asc' }, }); const originStop = stopTimes.find(st => st.stationId === originStationId); @@ -72,7 +64,6 @@ async function getJourneySegments(tripId: string, originStationId: string, desti for (let i = originStop.sequence; i < destinationStop.sequence; i++) { const fromStop = stopTimes.find(st => st.sequence === i); const toStop = stopTimes.find(st => st.sequence === i + 1); - if (fromStop && toStop) { segments.push({ fromStationId: fromStop.stationId, @@ -80,27 +71,19 @@ async function getJourneySegments(tripId: string, originStationId: string, desti fromSequence: fromStop.sequence, toSequence: toStop.sequence, fromName: fromStop.station.name, - toName: toStop.station.name + toName: toStop.station.name, }); } } - return segments; } -async function holdSeatsTransaction(tripId: string, seatIds: string[], passengerId: string, originStationId: string, destinationStationId: string) { +async function holdSeatsTransaction(scheduleId: string, seatIds: string[], passengerId: string, originStationId: string, destinationStationId: string) { return prisma.$transaction(async (tx) => { console.log(' → Starting seat hold transaction...'); - // 1. Validate seats exist and are available - const seats = await tx.seat.findMany({ - where: { id: { in: seatIds } }, - include: { coach: true } - }); - - if (seats.length !== seatIds.length) { - throw new Error('Some seats not found'); - } + const seats = await tx.seat.findMany({ where: { id: { in: seatIds } }, include: { coach: true } }); + if (seats.length !== seatIds.length) throw new Error('Some seats not found'); for (const seat of seats) { if (seat.status !== 'AVAILABLE') { @@ -108,43 +91,15 @@ async function holdSeatsTransaction(tripId: string, seatIds: string[], passenger } } - // 2. Check for overlapping reservations - const segments = await getJourneySegments(tripId, originStationId, destinationStationId); - - for (const seatId of seatIds) { - const overlaps = await checkOverlappingReservations(tx, tripId, seatId, segments); - if (overlaps.length > 0) { - throw new Error(`Seat ${seatId} has overlapping reservations`); - } - } - - // 3. Create hold record - const expiresAt = new Date(Date.now() + 10 * 60 * 1000); // 10 minutes + const expiresAt = new Date(Date.now() + 10 * 60 * 1000); const seatHold = await tx.seatHold.create({ - data: { - tripId, - seatIds, - passengerId, - expiresAt - } + data: { scheduleId, seatIds, passengerId, expiresAt }, }); - // 4. Update seat status to HELD - await tx.seat.updateMany({ - where: { id: { in: seatIds } }, - data: { - status: 'HELD', - heldUntil: expiresAt - } - }); + await tx.seat.updateMany({ where: { id: { in: seatIds } }, data: { status: 'HELD', heldUntil: expiresAt } }); console.log(' → Seats held successfully'); - return { - holdId: seatHold.id, - expiresAt, - segments: segments.length, - seats: seatIds.length - }; + return { holdId: seatHold.id, expiresAt, seats: seatIds.length }; }); } @@ -152,157 +107,96 @@ async function confirmBookingTransaction(holdId: string, bookingId: string, segm return prisma.$transaction(async (tx) => { console.log(' → Starting booking confirmation transaction...'); - // 1. Validate hold const hold = await tx.seatHold.findUnique({ where: { id: holdId } }); - if (!hold || hold.expiresAt < new Date()) { - throw new Error('Hold expired or not found'); - } + if (!hold || hold.expiresAt < new Date()) throw new Error('Hold expired or not found'); - // 2. Create booking record (simplified) const booking = await tx.booking.create({ data: { id: bookingId, bookingRef: 'BK' + Date.now().toString().slice(-6), passengerId: hold.passengerId, - tripId: hold.tripId, - status: 'CONFIRMED', - totalMinor: 45000, // Example fare - currency: 'ETB' - } - }); - - // 3. Create journey record - const journey = await tx.journey.create({ - data: { - passengerId: hold.passengerId, + scheduleId: hold.scheduleId, status: 'CONFIRMED', totalMinor: 45000, - currency: 'ETB' - } + currency: 'ETB', + }, + }); + + const journey = await tx.journey.create({ + data: { passengerId: hold.passengerId, status: 'CONFIRMED', totalMinor: 45000, currency: 'ETB' }, }); - // 4. Create journey segments for each seat for (const seatId of hold.seatIds) { for (let i = 0; i < segments.length; i++) { await tx.journeySegment.create({ data: { journeyId: journey.id, - tripId: hold.tripId, + scheduleId: hold.scheduleId, segmentOrder: i + 1, seatId, departureStationId: segments[i].fromStationId, - arrivalStationId: segments[i].toStationId - } + arrivalStationId: segments[i].toStationId, + }, }); } } - // 5. Create booking seats for (const seatId of hold.seatIds) { - await tx.bookingSeat.create({ - data: { - bookingId, - seatId, - passengerName: 'Kelemu Ketsela' // Example - } - }); + await tx.bookingSeat.create({ data: { bookingId, seatId, passengerName: 'Kelemu Ketsela' } }); } - // 6. Update seat status to BOOKED - await tx.seat.updateMany({ - where: { id: { in: hold.seatIds } }, - data: { - status: 'BOOKED', - heldUntil: null - } - }); - - // 7. Delete hold + await tx.seat.updateMany({ where: { id: { in: hold.seatIds } }, data: { status: 'BOOKED', heldUntil: null } }); await tx.seatHold.delete({ where: { id: holdId } }); console.log(' → Booking confirmed successfully'); - return { - bookingId, - bookingRef: booking.bookingRef, - confirmedSeats: hold.seatIds.length, - segments: segments.length - }; + return { bookingId, bookingRef: booking.bookingRef, confirmedSeats: hold.seatIds.length, segments: segments.length }; }); } -async function simulateTripProgress(tripId: string, bookedSegments: any[]) { +async function simulateTripProgress(scheduleId: string, bookedSegments: any[]) { console.log(' → Simulating trip progress...'); - // Simulate train reaching each station for (const segment of bookedSegments) { console.log(` → Train approaching ${segment.toName}...`); - - // Update trip live status + await prisma.tripLiveStatus.upsert({ - where: { tripId }, - update: { - currentLocationLabel: segment.toName, - progressPercent: Math.round((segment.toSequence / 4) * 100), - updatedAt: new Date() - }, + where: { scheduleId }, + update: { currentLocationLabel: segment.toName, progressPercent: Math.round((segment.toSequence / 4) * 100) }, create: { - tripId, + scheduleId, state: 'EN_ROUTE', currentLocationLabel: segment.toName, progressPercent: Math.round((segment.toSequence / 4) * 100), delayMinutes: 0, - updatedAt: new Date() - } + }, }); - // Check if this is the final destination for any passengers if (segment.toName === 'Dire Dawa') { console.log(' → Passengers reached destination, releasing seats...'); - await releaseSeatsAtStation(tripId, segment.toStationId); + await releaseSeatsAtStation(scheduleId, segment.toStationId); } - await new Promise(resolve => setTimeout(resolve, 2000)); // 2 second delay + await new Promise(resolve => setTimeout(resolve, 2000)); } } -async function releaseSeatsAtStation(tripId: string, stationId: string) { +async function releaseSeatsAtStation(scheduleId: string, stationId: string) { return prisma.$transaction(async (tx) => { - // Find journey segments ending at this station const completedSegments = await tx.journeySegment.findMany({ - where: { - tripId, - arrivalStationId: stationId - }, - include: { - journey: { - include: { - journeySegments: { - where: { tripId } - } - } - } - } + where: { scheduleId, arrivalStationId: stationId }, + include: { journey: { include: { journeySegments: { where: { scheduleId } } } } }, }); - const seatsToRelease = []; + const seatsToRelease: string[] = []; - // Check if passenger's entire journey is complete for (const segment of completedSegments) { const passengerSegments = segment.journey.journeySegments.filter((js: any) => js.seatId === segment.seatId); const maxOrder = Math.max(...passengerSegments.map((js: any) => js.segmentOrder)); - - if (segment.segmentOrder === maxOrder) { - seatsToRelease.push(segment.seatId!); - } + if (segment.segmentOrder === maxOrder) seatsToRelease.push(segment.seatId!); } - // Release seats if (seatsToRelease.length > 0) { - await tx.seat.updateMany({ - where: { id: { in: seatsToRelease } }, - data: { status: 'AVAILABLE' } - }); - + await tx.seat.updateMany({ where: { id: { in: seatsToRelease } }, data: { status: 'AVAILABLE' } }); console.log(` → Released ${seatsToRelease.length} seats at station`); } @@ -310,73 +204,24 @@ async function releaseSeatsAtStation(tripId: string, stationId: string) { }); } -async function checkOverlappingReservations(tx: any, tripId: string, seatId: string, segments: any[]) { - // Check active holds +async function checkOverlappingReservations(tx: any, scheduleId: string, seatId: string, segments: any[]) { const activeHolds = await tx.seatHold.findMany({ - where: { - tripId, - seatIds: { has: seatId }, - expiresAt: { gt: new Date() } - } + where: { scheduleId, seatIds: { has: seatId }, expiresAt: { gt: new Date() } }, }); - // Check active bookings const activeBookings = await tx.journeySegment.findMany({ where: { - tripId, + scheduleId, seatId, - journey: { - status: { in: ['PENDING_PAYMENT', 'CONFIRMED'] } - } - } + journey: { status: { in: ['PENDING_PAYMENT', 'CONFIRMED'] } }, + }, }); return [...activeHolds, ...activeBookings]; } -// Example API Usage -async function exampleApiUsage() { - console.log('\n=== API ENDPOINT EXAMPLES ===\n'); - - const baseUrl = 'http://localhost:4000'; - - // 1. Check availability - console.log('GET /segments/seats/availability'); - console.log('Query: tripId=trip_001&originStationId=st_ADD&destinationStationId=st_DRE'); - console.log('Response: Available seats for Addis Ababa → Dire Dawa segments\n'); - - // 2. Hold seats - console.log('POST /segments/seats/hold'); - console.log('Body:', JSON.stringify({ - tripId: 'trip_001', - seatIds: ['seat_1', 'seat_2'], - passengerId: 'passenger_123', - originStationId: 'st_ADD', - destinationStationId: 'st_DRE' - }, null, 2)); - console.log('Response: Hold created with 10-minute expiry\n'); - - // 3. Confirm booking - console.log('POST /segments/seats/confirm'); - console.log('Body:', JSON.stringify({ - holdId: 'hold_123', - bookingId: 'booking_456' - }, null, 2)); - console.log('Response: Booking confirmed, seats reserved for segments\n'); - - // 4. Release seats (triggered by trip progress) - console.log('POST /segments/seats/release'); - console.log('Body:', JSON.stringify({ - tripId: 'trip_001', - currentStationId: 'st_DRE' - }, null, 2)); - console.log('Response: Seats released for passengers reaching Dire Dawa\n'); -} - -// Run examples if (require.main === module) { exampleBookingFlow() - .then(() => exampleApiUsage()) .then(() => console.log('\n=== EXAMPLES COMPLETED ===')) .catch(console.error) .finally(() => prisma.$disconnect()); @@ -388,5 +233,6 @@ export { holdSeatsTransaction, confirmBookingTransaction, simulateTripProgress, - releaseSeatsAtStation -}; \ No newline at end of file + releaseSeatsAtStation, + checkOverlappingReservations, +}; diff --git a/apps/edr-passenger-api/src/modules/segments/enhanced-seats.service.ts b/apps/edr-passenger-api/src/modules/segments/enhanced-seats.service.ts index 57b6f2d2f..275ab077f 100644 --- a/apps/edr-passenger-api/src/modules/segments/enhanced-seats.service.ts +++ b/apps/edr-passenger-api/src/modules/segments/enhanced-seats.service.ts @@ -4,7 +4,7 @@ import { SegmentsService, Segment } from '../segments/segments.service'; import { EventEmitter2 } from '@nestjs/event-emitter'; export interface SeatHoldRequest { - tripId: string; + scheduleId: string; seatIds: string[]; passengerId: string; originStationId: string; @@ -22,349 +22,177 @@ export class EnhancedSeatsService { constructor( private prisma: PrismaService, private segmentsService: SegmentsService, - private eventEmitter: EventEmitter2 + private eventEmitter: EventEmitter2, ) {} - /** - * Hold seats for specific segments with atomicity - */ async holdSeats(request: SeatHoldRequest) { return this.prisma.$transaction(async (tx) => { - // 1. Get journey segments - const segments = await this.segmentsService.getJourneySegments( - request.tripId, - request.originStationId, - request.destinationStationId - ); + const segments = await this.segmentsService.getJourneySegments(request.scheduleId, request.originStationId, request.destinationStationId); - // 2. Check seat availability for all requested seats for (const seatId of request.seatIds) { - const seat = await tx.seat.findUnique({ - where: { id: seatId }, - include: { coach: true } - }); - - if (!seat) { - throw new BadRequestException(`Seat ${seatId} not found`); - } - - if (seat.status === 'BLOCKED') { - throw new BadRequestException(`Seat ${seat.label} is blocked`); - } - - // Check for overlapping reservations - const overlaps = await this.segmentsService.getOverlappingReservations( - request.tripId, - seatId, - segments - ); - - if (overlaps.length > 0) { - throw new ConflictException(`Seat ${seat.label} is not available for the requested segments`); - } + const seat = await tx.seat.findUnique({ where: { id: seatId } }); + if (!seat) throw new BadRequestException(`Seat ${seatId} not found`); + if (seat.status === 'BLOCKED') throw new BadRequestException(`Seat ${seat.label} is blocked`); + const overlaps = await this.segmentsService.getOverlappingReservations(request.scheduleId, seatId, segments); + if (overlaps.length > 0) throw new ConflictException(`Seat ${seat.label} is not available for the requested segments`); } - // 3. Create seat hold - const expiresAt = new Date(Date.now() + 10 * 60 * 1000); // 10 minutes + const expiresAt = new Date(Date.now() + 10 * 60 * 1000); + // Encode origin/destination into fareQuoteId so confirmBooking can resolve the leg range + // Format: "leg:{originStationId}:{destinationStationId}" (or preserve actual fareQuoteId) + const legKey = request.fareQuoteId ?? `leg:${request.originStationId}:${request.destinationStationId}`; const seatHold = await tx.seatHold.create({ - data: { - tripId: request.tripId, - seatIds: request.seatIds, - passengerId: request.passengerId, - fareQuoteId: request.fareQuoteId, - expiresAt - } + data: { scheduleId: request.scheduleId, seatIds: request.seatIds, passengerId: request.passengerId, fareQuoteId: legKey, expiresAt }, }); - // 4. Update seat status to HELD - await tx.seat.updateMany({ - where: { id: { in: request.seatIds } }, - data: { - status: 'HELD', - heldUntil: expiresAt - } - }); + await tx.seat.updateMany({ where: { id: { in: request.seatIds } }, data: { status: 'HELD', heldUntil: expiresAt } }); - // 5. Emit event for real-time updates - this.eventEmitter.emit('seats.held', { - holdId: seatHold.id, - tripId: request.tripId, - seatIds: request.seatIds, - segments - }); + this.eventEmitter.emit('seats.held', { holdId: seatHold.id, scheduleId: request.scheduleId, seatIds: request.seatIds, segments }); - return { - holdId: seatHold.id, - expiresAt, - segments, - seats: request.seatIds - }; + return { holdId: seatHold.id, expiresAt, segments, seats: request.seatIds }; }); } - /** - * Confirm booking and convert hold to booking - */ async confirmBooking(request: BookingConfirmRequest) { return this.prisma.$transaction(async (tx) => { - // 1. Get and validate hold - const hold = await tx.seatHold.findUnique({ - where: { id: request.holdId } + const hold = await tx.seatHold.findUnique({ where: { id: request.holdId } }); + if (!hold) throw new BadRequestException('Seat hold not found'); + if (hold.expiresAt < new Date()) throw new BadRequestException('Seat hold has expired'); + + const booking = await tx.booking.findUnique({ where: { id: request.bookingId } }); + if (!booking) throw new BadRequestException('Booking not found'); + + const schedule = await tx.trainSchedule.findUnique({ + where: { id: hold.scheduleId }, + include: { stopTimes: { orderBy: { sequence: 'asc' } } }, }); + if (!schedule) throw new BadRequestException('Schedule not found'); - if (!hold) { - throw new BadRequestException('Seat hold not found'); + // Resolve the passenger's leg range from the hold's fareQuoteId (encoded as "leg:originId:destId") + const legKey = hold.fareQuoteId ?? ''; + let originStationId: string | undefined; + let destinationStationId: string | undefined; + if (legKey.startsWith('leg:')) { + const parts = legKey.split(':'); + originStationId = parts[1]; + destinationStationId = parts[2]; + } else { + // Fall back to booking's own origin/destination if available + originStationId = (booking as any).originStationId; + destinationStationId = (booking as any).destinationStationId; } - if (hold.expiresAt < new Date()) { - throw new BadRequestException('Seat hold has expired'); - } + const originStop = originStationId ? schedule.stopTimes.find(s => s.stationId === originStationId) : undefined; + const destStop = destinationStationId ? schedule.stopTimes.find(s => s.stationId === destinationStationId) : undefined; + const fromSeq = originStop?.sequence ?? schedule.stopTimes[0].sequence; + const toSeq = destStop?.sequence ?? schedule.stopTimes[schedule.stopTimes.length - 1].sequence; - // 2. Get booking - const booking = await tx.booking.findUnique({ - where: { id: request.bookingId } - }); - - if (!booking) { - throw new BadRequestException('Booking not found'); - } - - // 3. Get journey segments - we need to derive from trip stops - const trip = await tx.trip.findUnique({ - where: { id: hold.tripId }, - include: { - stopTimes: { - orderBy: { sequence: 'asc' } - } + const segments: Segment[] = []; + for (let i = fromSeq; i < toSeq; i++) { + const fromStop = schedule.stopTimes.find(s => s.sequence === i); + const toStop = schedule.stopTimes.find(s => s.sequence === i + 1); + if (fromStop && toStop) { + segments.push({ + fromStationId: fromStop.stationId, + toStationId: toStop.stationId, + fromSequence: fromStop.sequence, + toSequence: toStop.sequence, + fromName: '', + toName: '', + }); } - }); - - if (!trip) { - throw new BadRequestException('Trip not found'); } - // For now, create segments for the full trip (would need origin/destination from booking) - const segments = []; - for (let i = 0; i < trip.stopTimes.length - 1; i++) { - segments.push({ - fromStationId: trip.stopTimes[i].stationId, - toStationId: trip.stopTimes[i + 1].stationId, - fromSequence: trip.stopTimes[i].sequence, - toSequence: trip.stopTimes[i + 1].sequence - }); - } - - // 4. Create journey record const journey = await tx.journey.create({ - data: { - passengerId: hold.passengerId, - status: 'CONFIRMED', - totalMinor: booking.totalMinor, - currency: booking.currency - } + data: { passengerId: hold.passengerId, status: 'CONFIRMED', totalMinor: booking.totalMinor, currency: booking.currency }, }); - // 5. Create journey segments for each seat for (const seatId of hold.seatIds) { for (let i = 0; i < segments.length; i++) { await tx.journeySegment.create({ data: { journeyId: journey.id, - tripId: hold.tripId, + scheduleId: hold.scheduleId, segmentOrder: i + 1, seatId, departureStationId: segments[i].fromStationId, - arrivalStationId: segments[i].toStationId - } + arrivalStationId: segments[i].toStationId, + }, }); } } - // 6. Update seat status to BOOKED - await tx.seat.updateMany({ - where: { id: { in: hold.seatIds } }, - data: { - status: 'BOOKED', - heldUntil: null - } - }); + await tx.seat.updateMany({ where: { id: { in: hold.seatIds } }, data: { status: 'BOOKED', heldUntil: null } }); + await tx.seatHold.delete({ where: { id: request.holdId } }); - // 7. Delete the hold - await tx.seatHold.delete({ - where: { id: request.holdId } - }); + this.eventEmitter.emit('booking.confirmed', { bookingId: request.bookingId, scheduleId: hold.scheduleId, seatIds: hold.seatIds, segments }); - // 8. Emit confirmation event - this.eventEmitter.emit('booking.confirmed', { - bookingId: request.bookingId, - tripId: hold.tripId, - seatIds: hold.seatIds, - segments - }); - - return { - bookingId: request.bookingId, - confirmedSeats: hold.seatIds, - segments - }; + return { bookingId: request.bookingId, confirmedSeats: hold.seatIds, segments }; }); } - /** - * Release seats when passenger reaches destination - */ - async releaseSeats(tripId: string, currentStationId: string) { + async releaseSeats(scheduleId: string, currentStationId: string) { return this.prisma.$transaction(async (tx) => { - // 1. Find all journey segments ending at current station const completedSegments = await tx.journeySegment.findMany({ - where: { - tripId, - arrivalStationId: currentStationId - }, - include: { - journey: { - include: { - journeySegments: { - where: { tripId } - } - } - } - } + where: { scheduleId, arrivalStationId: currentStationId }, + include: { journey: { include: { journeySegments: { where: { scheduleId } } } } }, }); - const seatsToRelease = []; - - // 2. Check if passenger's entire journey is complete + const seatsToRelease: string[] = []; for (const segment of completedSegments) { const allSegments = segment.journey.journeySegments.filter((js: any) => js.seatId === segment.seatId); const maxSegmentOrder = Math.max(...allSegments.map((js: any) => js.segmentOrder)); - - // If this is the last segment for this seat, release it - if (segment.segmentOrder === maxSegmentOrder) { - seatsToRelease.push(segment.seatId!); - } + if (segment.segmentOrder === maxSegmentOrder) seatsToRelease.push(segment.seatId!); } - // 3. Update seat status to AVAILABLE if (seatsToRelease.length > 0) { - await tx.seat.updateMany({ - where: { id: { in: seatsToRelease } }, - data: { status: 'AVAILABLE' } - }); - - // 4. Mark journey segments as completed (optional - could add a completed field) - // For now, we'll leave the segments as they are for historical tracking - - // 5. Emit release event - this.eventEmitter.emit('seats.released', { - tripId, - stationId: currentStationId, - releasedSeats: seatsToRelease - }); + await tx.seat.updateMany({ where: { id: { in: seatsToRelease } }, data: { status: 'AVAILABLE' } }); + this.eventEmitter.emit('seats.released', { scheduleId, stationId: currentStationId, releasedSeats: seatsToRelease }); } - return { - releasedSeats: seatsToRelease, - stationId: currentStationId - }; + return { releasedSeats: seatsToRelease, stationId: currentStationId }; }); } - /** - * Expire old holds (background job) - */ async expireHolds() { return this.prisma.$transaction(async (tx) => { - const expiredHolds = await tx.seatHold.findMany({ - where: { - expiresAt: { lt: new Date() } - } - }); - - const expiredSeatIds = expiredHolds.flatMap(hold => hold.seatIds); + const expiredHolds = await tx.seatHold.findMany({ where: { expiresAt: { lt: new Date() } } }); + const expiredSeatIds = expiredHolds.flatMap(h => h.seatIds); if (expiredSeatIds.length > 0) { - // Release expired seats - await tx.seat.updateMany({ - where: { id: { in: expiredSeatIds } }, - data: { - status: 'AVAILABLE', - heldUntil: null - } - }); - - // Delete expired holds - await tx.seatHold.deleteMany({ - where: { - expiresAt: { lt: new Date() } - } - }); - - this.eventEmitter.emit('holds.expired', { - expiredHolds: expiredHolds.length, - releasedSeats: expiredSeatIds - }); + await tx.seat.updateMany({ where: { id: { in: expiredSeatIds } }, data: { status: 'AVAILABLE', heldUntil: null } }); + await tx.seatHold.deleteMany({ where: { expiresAt: { lt: new Date() } } }); + this.eventEmitter.emit('holds.expired', { expiredHolds: expiredHolds.length, releasedSeats: expiredSeatIds }); } - return { - expiredHolds: expiredHolds.length, - releasedSeats: expiredSeatIds - }; + return { expiredHolds: expiredHolds.length, releasedSeats: expiredSeatIds }; }); } - /** - * Get seat availability for specific segments - */ - async getSeatAvailability(tripId: string, originStationId: string, destinationStationId: string) { - const segments = await this.segmentsService.getJourneySegments( - tripId, - originStationId, - destinationStationId - ); + async getSeatAvailability(scheduleId: string, originStationId: string, destinationStationId: string) { + const segments = await this.segmentsService.getJourneySegments(scheduleId, originStationId, destinationStationId); - const trip = await this.prisma.trip.findUnique({ - where: { id: tripId }, - include: { - coaches: { - include: { - seats: true - } - } - } + const schedule = await this.prisma.trainSchedule.findUnique({ + where: { id: scheduleId }, + include: { coachAssignments: { include: { coach: { include: { seats: true, seatClass: true } } } } }, }); - - if (!trip) { - throw new BadRequestException('Trip not found'); - } + if (!schedule) throw new BadRequestException('Schedule not found'); const availableSeats = []; - - for (const coach of trip.coaches) { - for (const seat of coach.seats) { - const overlaps = await this.segmentsService.getOverlappingReservations( - tripId, - seat.id, - segments - ); - + for (const assignment of schedule.coachAssignments) { + for (const seat of assignment.coach.seats) { + const overlaps = await this.segmentsService.getOverlappingReservations(scheduleId, seat.id, segments); if (overlaps.length === 0 && seat.status === 'AVAILABLE') { availableSeats.push({ - id: seat.id, - label: seat.label, - coach: coach.label, - serviceClass: coach.serviceClass, - row: seat.row, - col: seat.col + id: seat.id, label: seat.label, + coach: assignment.coach.label, + seatClass: assignment.coach.seatClass.name, + row: seat.row, col: seat.col, }); } } } - return { - segments, - availableSeats, - totalAvailable: availableSeats.length - }; + return { segments, availableSeats, totalAvailable: availableSeats.length }; } -} \ No newline at end of file +} diff --git a/apps/edr-passenger-api/src/modules/segments/segments.controller.ts b/apps/edr-passenger-api/src/modules/segments/segments.controller.ts index f733195f3..5a45e38c5 100644 --- a/apps/edr-passenger-api/src/modules/segments/segments.controller.ts +++ b/apps/edr-passenger-api/src/modules/segments/segments.controller.ts @@ -32,12 +32,12 @@ export class SegmentSeatsController { @ApiResponse({ status: 409, description: 'Seats not available for requested segments' }) async holdSeats(@Body() dto: HoldSeatsDto) { return this.enhancedSeatsService.holdSeats({ - tripId: dto.tripId, + scheduleId: dto.scheduleId, seatIds: dto.seatIds, passengerId: dto.passengerId, originStationId: dto.originStationId, destinationStationId: dto.destinationStationId, - fareQuoteId: dto.fareQuoteId + fareQuoteId: dto.fareQuoteId, }); } @@ -82,7 +82,7 @@ export class SegmentSeatsController { } }) async releaseSeats(@Body() dto: ReleaseSeatsDto) { - return this.enhancedSeatsService.releaseSeats(dto.tripId, dto.currentStationId); + return this.enhancedSeatsService.releaseSeats(dto.scheduleId, dto.currentStationId); } @Get('availability') @@ -100,19 +100,15 @@ export class SegmentSeatsController { { fromName: 'Adama', toName: 'Awash', fromSequence: 1, toSequence: 2 } ], availableSeats: [ - { id: 'seat_1', label: '1A', coach: 'A', serviceClass: 'ECONOMY', row: 1, col: 'A' }, - { id: 'seat_2', label: '1B', coach: 'A', serviceClass: 'ECONOMY', row: 1, col: 'B' } + { id: 'seat_1', label: '1A', coach: 'A', seatClass: 'Economy Regular', row: 1, col: 'A' }, + { id: 'seat_2', label: '1B', coach: 'A', seatClass: 'Economy Regular', row: 1, col: 'B' } ], totalAvailable: 2 } } }) async getSeatAvailability(@Query() dto: SeatAvailabilityDto) { - return this.enhancedSeatsService.getSeatAvailability( - dto.tripId, - dto.originStationId, - dto.destinationStationId - ); + return this.enhancedSeatsService.getSeatAvailability(dto.scheduleId, dto.originStationId, dto.destinationStationId); } @Post('expire-holds') diff --git a/apps/edr-passenger-api/src/modules/segments/segments.dto.ts b/apps/edr-passenger-api/src/modules/segments/segments.dto.ts index b04ccf284..3cc335c11 100644 --- a/apps/edr-passenger-api/src/modules/segments/segments.dto.ts +++ b/apps/edr-passenger-api/src/modules/segments/segments.dto.ts @@ -1,64 +1,27 @@ -import { ApiProperty } from '@nestjs/swagger'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { IsString, IsArray, IsOptional } from 'class-validator'; export class HoldSeatsDto { - @ApiProperty({ example: 'trip_123' }) - @IsString() - tripId: string; - - @ApiProperty({ example: ['seat_1', 'seat_2'] }) - @IsArray() - @IsString({ each: true }) - seatIds: string[]; - - @ApiProperty({ example: 'passenger_123' }) - @IsString() - passengerId: string; - - @ApiProperty({ example: 'st_ADD' }) - @IsString() - originStationId: string; - - @ApiProperty({ example: 'st_DRE' }) - @IsString() - destinationStationId: string; - - @ApiProperty({ example: 'quote_123', required: false }) - @IsOptional() - @IsString() - fareQuoteId?: string; + @ApiProperty({ example: 'schedule-uuid' }) @IsString() scheduleId: string; + @ApiProperty({ example: ['seat_1', 'seat_2'] }) @IsArray() @IsString({ each: true }) seatIds: string[]; + @ApiProperty({ example: 'passenger-uuid' }) @IsString() passengerId: string; + @ApiProperty({ example: 'st_ADD' }) @IsString() originStationId: string; + @ApiProperty({ example: 'st_DJI' }) @IsString() destinationStationId: string; + @ApiPropertyOptional({ example: 'quote-uuid' }) @IsOptional() @IsString() fareQuoteId?: string; } export class ConfirmBookingDto { - @ApiProperty({ example: 'hold_123' }) - @IsString() - holdId: string; - - @ApiProperty({ example: 'booking_123' }) - @IsString() - bookingId: string; + @ApiProperty({ example: 'hold-uuid' }) @IsString() holdId: string; + @ApiProperty({ example: 'booking-uuid' }) @IsString() bookingId: string; } export class SeatAvailabilityDto { - @ApiProperty({ example: 'trip_123' }) - @IsString() - tripId: string; - - @ApiProperty({ example: 'st_ADD' }) - @IsString() - originStationId: string; - - @ApiProperty({ example: 'st_DRE' }) - @IsString() - destinationStationId: string; + @ApiProperty({ example: 'schedule-uuid' }) @IsString() scheduleId: string; + @ApiProperty({ example: 'st_ADD' }) @IsString() originStationId: string; + @ApiProperty({ example: 'st_DJI' }) @IsString() destinationStationId: string; } export class ReleaseSeatsDto { - @ApiProperty({ example: 'trip_123' }) - @IsString() - tripId: string; - - @ApiProperty({ example: 'st_DRE' }) - @IsString() - currentStationId: string; -} \ No newline at end of file + @ApiProperty({ example: 'schedule-uuid' }) @IsString() scheduleId: string; + @ApiProperty({ example: 'st_DJI' }) @IsString() currentStationId: string; +} diff --git a/apps/edr-passenger-api/src/modules/segments/segments.service.ts b/apps/edr-passenger-api/src/modules/segments/segments.service.ts index 9346e25b3..8fe525bcb 100644 --- a/apps/edr-passenger-api/src/modules/segments/segments.service.ts +++ b/apps/edr-passenger-api/src/modules/segments/segments.service.ts @@ -14,33 +14,31 @@ export interface Segment { export class SegmentsService { constructor(private prisma: PrismaService) {} - /** - * Derive all segments between origin and destination using TripStopTime.sequence - * Example: Addis → Dire Dawa = [Addis → Adama, Adama → Awash, Awash → Dire Dawa] - */ - async getJourneySegments(tripId: string, originStationId: string, destinationStationId: string): Promise { + async getJourneySegments( + scheduleId: string, + originStationId: string, + destinationStationId: string, + ): Promise { const stopTimes = await this.prisma.tripStopTime.findMany({ - where: { tripId }, + where: { scheduleId }, include: { station: true }, - orderBy: { sequence: 'asc' } + orderBy: { sequence: 'asc' }, }); const originStop = stopTimes.find(st => st.stationId === originStationId); - const destinationStop = stopTimes.find(st => st.stationId === destinationStationId); + const destStop = stopTimes.find(st => st.stationId === destinationStationId); - if (!originStop || !destinationStop) { - throw new BadRequestException('Origin or destination station not found on this trip'); + if (!originStop || !destStop) { + throw new BadRequestException('Origin or destination station not found on this schedule'); } - - if (originStop.sequence >= destinationStop.sequence) { + if (originStop.sequence >= destStop.sequence) { throw new BadRequestException('Origin must come before destination'); } const segments: Segment[] = []; - for (let i = originStop.sequence; i < destinationStop.sequence; i++) { + for (let i = originStop.sequence; i < destStop.sequence; i++) { const fromStop = stopTimes.find(st => st.sequence === i); const toStop = stopTimes.find(st => st.sequence === i + 1); - if (fromStop && toStop) { segments.push({ fromStationId: fromStop.stationId, @@ -48,97 +46,85 @@ export class SegmentsService { fromSequence: fromStop.sequence, toSequence: toStop.sequence, fromName: fromStop.station.name, - toName: toStop.station.name + toName: toStop.station.name, }); } } - return segments; } - /** - * Check if two segment ranges overlap - */ + /** True if two segment ranges overlap: [a.from, a.to) ∩ [b.from, b.to) ≠ ∅ */ segmentsOverlap(segments1: Segment[], segments2: Segment[]): boolean { - for (const seg1 of segments1) { - for (const seg2 of segments2) { - // Segments overlap if one starts before the other ends - if (seg1.fromSequence < seg2.toSequence && seg2.fromSequence < seg1.toSequence) { - return true; - } + for (const s1 of segments1) { + for (const s2 of segments2) { + if (s1.fromSequence < s2.toSequence && s2.fromSequence < s1.toSequence) return true; } } return false; } /** - * Get all existing bookings/holds that overlap with given segments + * Returns conflicts for a seat on a schedule for the requested segment range. + * Checks: + * 1. Active SeatHolds — resolved to sequence range via JourneySegment if available, + * otherwise treated as full-schedule block. + * 2. Active BookingSeats — resolved via JourneySegment sequence ranges. */ - async getOverlappingReservations(tripId: string, seatId: string, segments: Segment[]) { - // Get active holds + async getOverlappingReservations( + scheduleId: string, + seatId: string, + requestedSegments: Segment[], + ) { + const overlaps: { type: string; id: string }[] = []; + const reqFrom = Math.min(...requestedSegments.map(s => s.fromSequence)); + const reqTo = Math.max(...requestedSegments.map(s => s.toSequence)); + + // ── 1. Active holds ────────────────────────────────────────────────────── const activeHolds = await this.prisma.seatHold.findMany({ - where: { - tripId, - seatIds: { has: seatId }, - expiresAt: { gt: new Date() } - } + where: { scheduleId, seatIds: { has: seatId }, expiresAt: { gt: new Date() } }, }); - // Get active bookings with journey segments - const activeBookings = await this.prisma.bookingSeat.findMany({ - where: { - seatId, - booking: { - tripId, - status: { in: ['PENDING_PAYMENT', 'CONFIRMED'] } - } - }, - include: { - booking: true - } - }); - - const overlaps = []; - - // Check hold overlaps (assume full journey for holds) for (const hold of activeHolds) { - overlaps.push({ type: 'hold', id: hold.id }); - } - - // Check booking overlaps by querying journey segments separately - for (const booking of activeBookings) { - const journeySegments = await this.prisma.journeySegment.findMany({ - where: { - tripId, - seatId, - journeyId: booking.bookingId - } + // Resolve hold range from JourneySegments created at hold time + const holdSegs = await this.prisma.journeySegment.findMany({ + where: { scheduleId, seatId }, + include: { schedule: { include: { stopTimes: true } } }, }); - for (const journeySegment of journeySegments) { - // Get sequence numbers for this segment - const segmentStops = await this.prisma.tripStopTime.findMany({ - where: { - tripId, - stationId: { in: [journeySegment.departureStationId, journeySegment.arrivalStationId] } - } - }); + if (holdSegs.length === 0) { + // No journey segments yet — conservative: treat as full-schedule conflict + overlaps.push({ type: 'hold', id: hold.id }); + continue; + } - const fromSeq = segmentStops.find(s => s.stationId === journeySegment.departureStationId)?.sequence; - const toSeq = segmentStops.find(s => s.stationId === journeySegment.arrivalStationId)?.sequence; - - if (fromSeq !== undefined && toSeq !== undefined) { - // Check if any requested segment overlaps with this booking segment - for (const reqSeg of segments) { - if (reqSeg.fromSequence < toSeq && fromSeq < reqSeg.toSequence) { - overlaps.push({ type: 'booking', id: booking.booking.id }); - break; - } - } + for (const js of holdSegs) { + const depSeq = js.schedule.stopTimes.find(s => s.stationId === js.departureStationId)?.sequence; + const arrSeq = js.schedule.stopTimes.find(s => s.stationId === js.arrivalStationId)?.sequence; + if (depSeq !== undefined && arrSeq !== undefined && depSeq < reqTo && reqFrom < arrSeq) { + overlaps.push({ type: 'hold', id: hold.id }); + break; } } } + // ── 2. Active bookings via JourneySegment ──────────────────────────────── + const bookedSegments = await this.prisma.journeySegment.findMany({ + where: { + scheduleId, + seatId, + journey: { status: { in: ['CONFIRMED', 'PENDING_PAYMENT'] } }, + }, + include: { schedule: { include: { stopTimes: true } } }, + }); + + for (const js of bookedSegments) { + const depSeq = js.schedule.stopTimes.find(s => s.stationId === js.departureStationId)?.sequence; + const arrSeq = js.schedule.stopTimes.find(s => s.stationId === js.arrivalStationId)?.sequence; + if (depSeq !== undefined && arrSeq !== undefined && depSeq < reqTo && reqFrom < arrSeq) { + overlaps.push({ type: 'booking', id: js.journeyId }); + } + } + return overlaps; } -} \ No newline at end of file +} diff --git a/apps/edr-passenger-api/src/modules/segments/trip-progress.service.ts b/apps/edr-passenger-api/src/modules/segments/trip-progress.service.ts index 9bd974dac..f67808385 100644 --- a/apps/edr-passenger-api/src/modules/segments/trip-progress.service.ts +++ b/apps/edr-passenger-api/src/modules/segments/trip-progress.service.ts @@ -19,14 +19,14 @@ export class TripProgressService { return this.prisma.$transaction(async (tx) => { // 1. Update trip live status await tx.tripLiveStatus.upsert({ - where: { tripId }, + where: { scheduleId: tripId }, update: { currentLocationLabel: currentStationId, progressPercent, updatedAt: new Date() }, create: { - tripId, + scheduleId: tripId, state: 'EN_ROUTE', currentLocationLabel: currentStationId, progressPercent, @@ -69,7 +69,7 @@ export class TripProgressService { * Simulate trip progress (for testing/demo) */ async simulateTripProgress(tripId: string) { - const trip = await this.prisma.trip.findUnique({ + const trip = await this.prisma.trainSchedule.findUnique({ where: { id: tripId }, include: { stopTimes: { @@ -110,13 +110,17 @@ export class TripProgressService { @OnEvent('trip.completed') async handleTripCompleted(payload: { tripId: string }) { // Release all remaining seats for this trip - const trip = await this.prisma.trip.findUnique({ + const trip = await this.prisma.trainSchedule.findUnique({ where: { id: payload.tripId }, include: { - coaches: { + coachAssignments: { include: { - seats: { - where: { status: 'BOOKED' } + coach: { + include: { + seats: { + where: { status: 'BOOKED' } + } + } } } } @@ -124,8 +128,8 @@ export class TripProgressService { }); if (trip) { - const bookedSeatIds = trip.coaches.flatMap(coach => - coach.seats.map(seat => seat.id) + const bookedSeatIds = trip.coachAssignments.flatMap(assignment => + assignment.coach.seats.map(seat => seat.id) ); if (bookedSeatIds.length > 0) { @@ -161,7 +165,7 @@ export class TripProgressService { * Get current trip status with seat availability */ async getTripStatus(tripId: string) { - const trip = await this.prisma.trip.findUnique({ + const trip = await this.prisma.trainSchedule.findUnique({ where: { id: tripId }, include: { liveStatus: true, @@ -169,9 +173,11 @@ export class TripProgressService { include: { station: true }, orderBy: { sequence: 'asc' } }, - coaches: { + coachAssignments: { include: { - seats: true + coach: { + include: { seats: true } + } } } } @@ -189,8 +195,8 @@ export class TripProgressService { blocked: 0 }; - trip.coaches.forEach(coach => { - coach.seats.forEach(seat => { + trip.coachAssignments.forEach(assignment => { + assignment.coach.seats.forEach(seat => { seatSummary.total++; const status = seat.status.toLowerCase() as keyof typeof seatSummary; if (status in seatSummary) { diff --git a/apps/edr-passenger-api/src/modules/tickets/tickets.controller.ts b/apps/edr-passenger-api/src/modules/tickets/tickets.controller.ts index c4f6a4d38..7b871db3f 100644 --- a/apps/edr-passenger-api/src/modules/tickets/tickets.controller.ts +++ b/apps/edr-passenger-api/src/modules/tickets/tickets.controller.ts @@ -34,8 +34,8 @@ export class TicketsController { @Get('offline/export') @ApiOperation({ summary: 'Export tickets for offline validation' }) - exportOfflineData(@Query('tripId') tripId: string) { - return this.service.exportOfflineData(tripId); + exportOfflineData(@Query('scheduleId') scheduleId: string) { + return this.service.exportOfflineData(scheduleId); } @Post('validate/offline') diff --git a/apps/edr-passenger-api/src/modules/tickets/tickets.service.ts b/apps/edr-passenger-api/src/modules/tickets/tickets.service.ts index e2e2ff1f9..33971d3ec 100644 --- a/apps/edr-passenger-api/src/modules/tickets/tickets.service.ts +++ b/apps/edr-passenger-api/src/modules/tickets/tickets.service.ts @@ -16,7 +16,7 @@ export class TicketsService { async generate(bookingId: string) { const booking = await this.prisma.booking.findUnique({ where: { id: bookingId }, - include: { trip: { include: { originStation: true, destinationStation: true, service: true } }, seats: { include: { seat: { include: { coach: true } } } } }, + include: { schedule: { include: { originStation: true, destinationStation: true, train: true } }, seats: { include: { seat: { include: { coach: true } } } } }, }); if (!booking) throw new NotFoundException('Booking not found'); const qrPayload = await QRCode.toDataURL(`edr:tkt:${booking.id}:${booking.bookingRef}`); @@ -31,14 +31,14 @@ export class TicketsService { async getByRef(bookingRef: string) { const booking = await this.prisma.booking.findUnique({ where: { bookingRef }, - include: { trip: { include: { originStation: true, destinationStation: true, service: true } }, seats: { include: { seat: { include: { coach: true } } } }, ticket: true }, + include: { schedule: { include: { originStation: true, destinationStation: true, train: true } }, seats: { include: { seat: { include: { coach: true } } } }, ticket: true }, }); if (!booking?.ticket) throw new NotFoundException('Ticket not found'); const seat = booking.seats[0]; return { id: booking.ticket.id, bookingId: booking.id, bookingRef: booking.bookingRef, status: booking.status, - fromStationName: booking.trip.originStation.name, toStationName: booking.trip.destinationStation.name, - departureAt: booking.trip.departureAt, trainName: booking.trip.service.name, + fromStationName: booking.schedule.originStation.name, toStationName: booking.schedule.destinationStation.name, + departureAt: booking.schedule.departureAt, trainName: booking.schedule.train.name, coachLabel: seat?.seat.coach.label, seatLabel: seat?.seat.label, passengerName: seat?.passengerName, priceMinor: booking.totalMinor, currency: booking.currency, qrPayload: booking.ticket.qrPayload, barcodePayload: booking.ticket.barcodePayload @@ -72,7 +72,7 @@ export class TicketsService { async exportOfflineData(tripId: string) { const bookings = await this.prisma.booking.findMany({ - where: { tripId, status: 'CONFIRMED' }, + where: { scheduleId: tripId, status: 'CONFIRMED' }, include: { ticket: true, seats: { include: { seat: { include: { coach: true } } } }, From 672987cd1e9bae3d9345fe16e56d329cfe95d961 Mon Sep 17 00:00:00 2001 From: Stephanos A Date: Fri, 22 May 2026 15:05:20 +0300 Subject: [PATCH 22/38] Migrations update --- .../20260522115951_initial/migration.sql | 1352 +++++++++++++++++ apps/edr-passenger-api/prisma/schema.prisma | 1 - 2 files changed, 1352 insertions(+), 1 deletion(-) create mode 100644 apps/edr-passenger-api/prisma/migrations/20260522115951_initial/migration.sql diff --git a/apps/edr-passenger-api/prisma/migrations/20260522115951_initial/migration.sql b/apps/edr-passenger-api/prisma/migrations/20260522115951_initial/migration.sql new file mode 100644 index 000000000..cb6c033f5 --- /dev/null +++ b/apps/edr-passenger-api/prisma/migrations/20260522115951_initial/migration.sql @@ -0,0 +1,1352 @@ +-- CreateEnum +CREATE TYPE "UserRole" AS ENUM ('PASSENGER', 'AGENT', 'SUPERVISOR', 'ADMIN', 'STAFF'); + +-- CreateEnum +CREATE TYPE "TripStatus" AS ENUM ('SCHEDULED', 'BOARDING', 'EN_ROUTE', 'ARRIVED', 'CANCELLED', 'DELAYED'); + +-- CreateEnum +CREATE TYPE "SeatKind" AS ENUM ('STANDARD', 'PREMIUM', 'ACCESSIBLE'); + +-- CreateEnum +CREATE TYPE "SeatStatus" AS ENUM ('AVAILABLE', 'HELD', 'BOOKED', 'BLOCKED'); + +-- CreateEnum +CREATE TYPE "PassengerCategory" AS ENUM ('ADULT', 'CHILD'); + +-- CreateEnum +CREATE TYPE "IdDocumentType" AS ENUM ('NATIONAL_ID', 'PASSPORT', 'DRIVING_LICENSE', 'OTHER'); + +-- CreateEnum +CREATE TYPE "Currency" AS ENUM ('ETB', 'DJF', 'USD'); + +-- CreateEnum +CREATE TYPE "BookingStatus" AS ENUM ('DRAFT', 'PENDING_PAYMENT', 'CONFIRMED', 'CANCELLED', 'COMPLETED', 'NO_SHOW', 'REFUNDED'); + +-- CreateEnum +CREATE TYPE "PaymentMethodType" AS ENUM ('TELEBIRR', 'CBE_BIRR', 'EBIRR', 'CARD', 'WALLET'); + +-- CreateEnum +CREATE TYPE "PaymentIntentStatus" AS ENUM ('REQUIRES_ACTION', 'PROCESSING', 'SUCCEEDED', 'FAILED', 'CANCELLED', 'REFUNDED'); + +-- CreateEnum +CREATE TYPE "WalletLedgerType" AS ENUM ('CREDIT', 'DEBIT'); + +-- CreateEnum +CREATE TYPE "NotificationCategory" AS ENUM ('BOOKING', 'PAYMENT', 'DISRUPTION', 'PROMOTION', 'SYSTEM'); + +-- CreateEnum +CREATE TYPE "StopStatus" AS ENUM ('COMPLETED', 'APPROACHING', 'CURRENT', 'UPCOMING'); + +-- CreateEnum +CREATE TYPE "SupportConversationStatus" AS ENUM ('OPEN', 'RESOLVED', 'CLOSED'); + +-- CreateEnum +CREATE TYPE "SupportSender" AS ENUM ('USER', 'BOT', 'AGENT'); + +-- CreateEnum +CREATE TYPE "LoyaltyTier" AS ENUM ('BRONZE', 'SILVER', 'GOLD', 'PLATINUM'); + +-- CreateEnum +CREATE TYPE "LoyaltyLedgerReason" AS ENUM ('TRIP_COMPLETED', 'REWARD_REDEEMED', 'PROMO_BONUS', 'MANUAL_ADJUSTMENT', 'EXPIRY'); + +-- CreateEnum +CREATE TYPE "FoodOrderStatus" AS ENUM ('PENDING', 'PREPARING', 'READY', 'DELIVERED', 'CANCELLED'); + +-- CreateEnum +CREATE TYPE "DevicePlatform" AS ENUM ('IOS', 'ANDROID', 'WEB'); + +-- AlterTable +ALTER TABLE "SeatClass" ALTER COLUMN "updatedAt" DROP DEFAULT; + +-- CreateTable +CREATE TABLE "User" ( + "id" TEXT NOT NULL, + "email" TEXT NOT NULL, + "phone" TEXT NOT NULL, + "fullName" TEXT NOT NULL, + "passwordHash" TEXT NOT NULL, + "role" "UserRole" NOT NULL DEFAULT 'PASSENGER', + "nationality" TEXT, + "nationalityCode" TEXT, + "passportNumber" TEXT, + "nationalId" TEXT, + "failedLoginAttempts" INTEGER NOT NULL DEFAULT 0, + "lockedUntil" TIMESTAMP(3), + "blockedUntil" TIMESTAMP(3), + "lastLoginAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "User_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Session" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "token" TEXT NOT NULL, + "expiresAt" TIMESTAMP(3) NOT NULL, + "ipAddress" TEXT, + "userAgent" TEXT, + "lastActivityAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "Session_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Passenger" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "defaultTravelerProfileId" TEXT, + "preferredLanguage" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "Passenger_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "TravelerProfile" ( + "id" TEXT NOT NULL, + "passengerId" TEXT NOT NULL, + "fullName" TEXT NOT NULL, + "relationship" TEXT NOT NULL, + "dateOfBirth" TIMESTAMP(3), + "nationalId" TEXT, + "notes" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "TravelerProfile_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Station" ( + "id" TEXT NOT NULL, + "code" TEXT NOT NULL, + "name" TEXT NOT NULL, + "city" TEXT NOT NULL, + "countryCode" TEXT, + "isOperational" BOOLEAN NOT NULL DEFAULT true, + "timezone" TEXT NOT NULL DEFAULT 'Africa/Addis_Ababa', + "lat" DECIMAL(9,6) NOT NULL, + "lng" DECIMAL(9,6) NOT NULL, + + CONSTRAINT "Station_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Train" ( + "id" TEXT NOT NULL, + "number" TEXT NOT NULL, + "name" TEXT NOT NULL, + "operatorId" TEXT NOT NULL DEFAULT 'op_edr', + "operatorName" TEXT, + "description" TEXT, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Train_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "TrainSchedule" ( + "id" TEXT NOT NULL, + "trainId" TEXT NOT NULL, + "routeId" TEXT, + "originStationId" TEXT NOT NULL, + "destinationStationId" TEXT NOT NULL, + "departureAt" TIMESTAMP(3) NOT NULL, + "arrivalAt" TIMESTAMP(3) NOT NULL, + "durationMinutes" INTEGER NOT NULL, + "status" "TripStatus" NOT NULL DEFAULT 'SCHEDULED', + "stopsCount" INTEGER NOT NULL DEFAULT 0, + "reservedCount" INTEGER NOT NULL DEFAULT 0, + "onTimePercent" INTEGER NOT NULL DEFAULT 100, + "carbonRating" TEXT NOT NULL DEFAULT 'A', + "notes" TEXT, + + CONSTRAINT "TrainSchedule_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "TripStopTime" ( + "id" TEXT NOT NULL, + "scheduleId" TEXT NOT NULL, + "stationId" TEXT NOT NULL, + "sequence" INTEGER NOT NULL, + "plannedArrivalAt" TIMESTAMP(3), + "plannedDepartureAt" TIMESTAMP(3), + "actualArrivalAt" TIMESTAMP(3), + "status" "StopStatus" NOT NULL DEFAULT 'UPCOMING', + + CONSTRAINT "TripStopTime_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "TripLiveStatus" ( + "id" TEXT NOT NULL, + "scheduleId" TEXT NOT NULL, + "state" TEXT NOT NULL, + "currentLocationLabel" TEXT, + "progressPercent" INTEGER NOT NULL DEFAULT 0, + "delayMinutes" INTEGER NOT NULL DEFAULT 0, + "currentSpeedKph" INTEGER, + "platformLabel" TEXT, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "TripLiveStatus_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Coach" ( + "id" TEXT NOT NULL, + "coachNumber" TEXT NOT NULL, + "label" TEXT NOT NULL, + "seatClassId" TEXT NOT NULL, + "coachType" TEXT, + "mode" TEXT NOT NULL DEFAULT 'seat', + "seatArrangement" TEXT, + "bedArrangement" TEXT, + "amenities" JSONB, + "totalUnits" INTEGER NOT NULL DEFAULT 0, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Coach_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "CoachAssignment" ( + "id" TEXT NOT NULL, + "scheduleId" TEXT NOT NULL, + "coachId" TEXT NOT NULL, + "positionNumber" INTEGER NOT NULL, + "isOperational" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "CoachAssignment_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Seat" ( + "id" TEXT NOT NULL, + "coachId" TEXT NOT NULL, + "row" INTEGER NOT NULL, + "col" TEXT NOT NULL, + "label" TEXT NOT NULL, + "seatNumber" TEXT, + "kind" "SeatKind" NOT NULL DEFAULT 'STANDARD', + "status" "SeatStatus" NOT NULL DEFAULT 'AVAILABLE', + "heldUntil" TIMESTAMP(3), + "isWindow" BOOLEAN NOT NULL DEFAULT false, + "isAisle" BOOLEAN NOT NULL DEFAULT false, + "bedPosition" TEXT, + "premiumFeeMinor" INTEGER NOT NULL DEFAULT 0, + "eligibility" TEXT, + + CONSTRAINT "Seat_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "SeatHold" ( + "id" TEXT NOT NULL, + "scheduleId" TEXT NOT NULL, + "seatIds" TEXT[], + "fareQuoteId" TEXT, + "passengerId" TEXT NOT NULL, + "createdBy" TEXT, + "expiresAt" TIMESTAMP(3) NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "SeatHold_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "FareRule" ( + "id" TEXT NOT NULL, + "tripId" TEXT, + "route" TEXT, + "seatClassId" TEXT NOT NULL, + "baseFareMinor" INTEGER NOT NULL, + "currency" TEXT NOT NULL DEFAULT 'ETB', + "refundable" BOOLEAN NOT NULL DEFAULT true, + "validFrom" TIMESTAMP(3) NOT NULL, + "validUntil" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "FareRule_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Booking" ( + "id" TEXT NOT NULL, + "bookingRef" TEXT NOT NULL, + "passengerId" TEXT NOT NULL, + "scheduleId" TEXT NOT NULL, + "status" "BookingStatus" NOT NULL DEFAULT 'DRAFT', + "currency" TEXT NOT NULL DEFAULT 'ETB', + "totalMinor" INTEGER NOT NULL, + "adultCount" INTEGER NOT NULL DEFAULT 1, + "childCount" INTEGER NOT NULL DEFAULT 0, + "displayCurrency" "Currency", + "displayTotalMinor" INTEGER, + "bookingType" TEXT NOT NULL DEFAULT 'ONE_WAY', + "userAgent" TEXT, + "source" TEXT NOT NULL DEFAULT 'WEB', + "promoCode" TEXT, + "paidAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Booking_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "BookingSeat" ( + "id" TEXT NOT NULL, + "bookingId" TEXT NOT NULL, + "seatId" TEXT NOT NULL, + "passengerName" TEXT NOT NULL, + "dateOfBirth" TIMESTAMP(3), + "passengerCategory" "PassengerCategory" NOT NULL DEFAULT 'ADULT', + "idDocumentType" "IdDocumentType", + "idDocumentNumber" TEXT, + "passportNumber" TEXT, + "passportCountry" TEXT, + "verifaydaVerified" BOOLEAN NOT NULL DEFAULT false, + "verifaydaData" JSONB, + "seatLabelSnapshot" TEXT, + "fareMinor" INTEGER, + "displayCurrency" "Currency", + "displayFareMinor" INTEGER, + + CONSTRAINT "BookingSeat_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "PaymentMethod" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "type" "PaymentMethodType" NOT NULL, + "displayName" TEXT NOT NULL, + "maskedHint" TEXT, + "providerId" TEXT, + "isDefault" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "PaymentMethod_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "PaymentIntent" ( + "id" TEXT NOT NULL, + "bookingId" TEXT NOT NULL, + "amountMinor" INTEGER NOT NULL, + "currency" TEXT NOT NULL DEFAULT 'ETB', + "method" "PaymentMethodType" NOT NULL, + "provider" TEXT, + "status" "PaymentIntentStatus" NOT NULL DEFAULT 'REQUIRES_ACTION', + "providerRef" TEXT, + "clientAction" JSONB, + "merchantOrderId" TEXT, + "providerOrderId" TEXT, + "providerTxnId" TEXT, + "rawInitiation" JSONB, + "paidAt" TIMESTAMP(3), + "refundedAt" TIMESTAMP(3), + "captureMethod" TEXT, + "failureCode" TEXT, + "failureMessage" TEXT, + "expiresAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "PaymentIntent_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "PaymentWebhookEvent" ( + "id" TEXT NOT NULL, + "provider" "PaymentMethodType" NOT NULL, + "externalEventId" TEXT NOT NULL, + "merchantOrderId" TEXT, + "providerTxnId" TEXT, + "signatureValid" BOOLEAN NOT NULL, + "status" TEXT NOT NULL, + "payload" JSONB NOT NULL, + "receivedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "processedAt" TIMESTAMP(3), + "processingError" TEXT, + + CONSTRAINT "PaymentWebhookEvent_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "PaymentRefund" ( + "id" TEXT NOT NULL, + "paymentIntentId" TEXT NOT NULL, + "amountMinor" INTEGER NOT NULL, + "reason" TEXT, + "providerRefundId" TEXT, + "status" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "PaymentRefund_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Ticket" ( + "id" TEXT NOT NULL, + "bookingId" TEXT NOT NULL, + "bookingRef" TEXT NOT NULL, + "status" TEXT NOT NULL DEFAULT 'CONFIRMED', + "qrPayload" TEXT NOT NULL, + "barcodePayload" TEXT, + "pdfUrl" TEXT, + "deliveryChannel" TEXT NOT NULL DEFAULT 'EMAIL', + "issuedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "validatedAt" TIMESTAMP(3), + "validatorId" TEXT, + + CONSTRAINT "Ticket_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "LoyaltyAccount" ( + "id" TEXT NOT NULL, + "passengerId" TEXT NOT NULL, + "pointsBalance" INTEGER NOT NULL DEFAULT 0, + "lifetimePoints" INTEGER NOT NULL DEFAULT 0, + "tier" "LoyaltyTier" NOT NULL DEFAULT 'BRONZE', + "tierUpdatedAt" TIMESTAMP(3), + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "LoyaltyAccount_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "LoyaltyLedgerEntry" ( + "id" TEXT NOT NULL, + "accountId" TEXT NOT NULL, + "delta" INTEGER NOT NULL, + "reason" "LoyaltyLedgerReason" NOT NULL, + "bookingId" TEXT, + "balanceAfter" INTEGER NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "LoyaltyLedgerEntry_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "LoyaltyReward" ( + "id" TEXT NOT NULL, + "accountId" TEXT NOT NULL, + "title" TEXT NOT NULL, + "costPoints" INTEGER NOT NULL, + "available" BOOLEAN NOT NULL DEFAULT true, + "description" TEXT, + + CONSTRAINT "LoyaltyReward_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "WalletAccount" ( + "id" TEXT NOT NULL, + "passengerId" TEXT NOT NULL, + "balanceMinor" INTEGER NOT NULL DEFAULT 0, + "status" TEXT NOT NULL DEFAULT 'ACTIVE', + "holdMinor" INTEGER NOT NULL DEFAULT 0, + "currency" TEXT NOT NULL DEFAULT 'ETB', + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "WalletAccount_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "WalletLedgerEntry" ( + "id" TEXT NOT NULL, + "walletId" TEXT NOT NULL, + "type" "WalletLedgerType" NOT NULL, + "amountMinor" INTEGER NOT NULL, + "balanceAfterMinor" INTEGER NOT NULL, + "description" TEXT NOT NULL, + "relatedBookingId" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "WalletLedgerEntry_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Notification" ( + "id" TEXT NOT NULL, + "passengerId" TEXT NOT NULL, + "title" TEXT NOT NULL, + "body" TEXT NOT NULL, + "category" "NotificationCategory" NOT NULL, + "read" BOOLEAN NOT NULL DEFAULT false, + "deepLink" TEXT, + "metadata" JSONB, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "Notification_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Promotion" ( + "id" TEXT NOT NULL, + "title" TEXT NOT NULL, + "subtitle" TEXT, + "code" TEXT NOT NULL, + "percentOff" INTEGER, + "amountOffMinor" INTEGER, + "validUntil" TIMESTAMP(3) NOT NULL, + "ctaLabel" TEXT, + "deepLink" TEXT, + "active" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "Promotion_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "StationCrowdSignal" ( + "id" TEXT NOT NULL, + "stationId" TEXT NOT NULL, + "level" TEXT NOT NULL, + "label" TEXT NOT NULL, + "statusLabel" TEXT NOT NULL, + "confidence" INTEGER, + "observedAt" TIMESTAMP(3), + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "StationCrowdSignal_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "WeatherAlert" ( + "id" TEXT NOT NULL, + "region" TEXT NOT NULL, + "severity" TEXT NOT NULL, + "title" TEXT NOT NULL, + "message" TEXT NOT NULL, + "validUntil" TIMESTAMP(3) NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "WeatherAlert_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "MenuCategory" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + + CONSTRAINT "MenuCategory_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "MenuItem" ( + "id" TEXT NOT NULL, + "scheduleId" TEXT NOT NULL, + "categoryId" TEXT NOT NULL, + "name" TEXT NOT NULL, + "priceMinor" INTEGER NOT NULL, + "currency" TEXT NOT NULL DEFAULT 'ETB', + "available" BOOLEAN NOT NULL DEFAULT true, + "availableUntil" TIMESTAMP(3), + + CONSTRAINT "MenuItem_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "FoodOrder" ( + "id" TEXT NOT NULL, + "bookingId" TEXT NOT NULL, + "status" "FoodOrderStatus" NOT NULL DEFAULT 'PENDING', + "totalMinor" INTEGER NOT NULL, + "currency" TEXT NOT NULL DEFAULT 'ETB', + "specialInstructions" TEXT, + "estimatedReadyAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "FoodOrder_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "FoodOrderItem" ( + "id" TEXT NOT NULL, + "orderId" TEXT NOT NULL, + "menuItemId" TEXT NOT NULL, + "name" TEXT NOT NULL, + "quantity" INTEGER NOT NULL, + "unitPriceMinor" INTEGER, + "lineTotalMinor" INTEGER NOT NULL, + + CONSTRAINT "FoodOrderItem_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "FaqCategory" ( + "id" TEXT NOT NULL, + "title" TEXT NOT NULL, + "iconKey" TEXT, + + CONSTRAINT "FaqCategory_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "FaqArticle" ( + "id" TEXT NOT NULL, + "categoryId" TEXT NOT NULL, + "question" TEXT NOT NULL, + "answerMarkdown" TEXT NOT NULL, + "rank" INTEGER NOT NULL DEFAULT 0, + + CONSTRAINT "FaqArticle_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "SupportConversation" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "assignedAgentId" TEXT, + "status" "SupportConversationStatus" NOT NULL DEFAULT 'OPEN', + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "SupportConversation_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "SupportMessage" ( + "id" TEXT NOT NULL, + "conversationId" TEXT NOT NULL, + "sender" "SupportSender" NOT NULL, + "text" TEXT NOT NULL, + "attachments" JSONB, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "SupportMessage_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "UserPreferences" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "pushEnabled" BOOLEAN NOT NULL DEFAULT true, + "emailEnabled" BOOLEAN NOT NULL DEFAULT true, + "smsEnabled" BOOLEAN NOT NULL DEFAULT false, + "promosEnabled" BOOLEAN NOT NULL DEFAULT true, + "biometricEnabled" BOOLEAN NOT NULL DEFAULT false, + "twoFactorEnabled" BOOLEAN NOT NULL DEFAULT false, + "defaultPaymentMethodId" TEXT, + "autoDownloadTickets" BOOLEAN NOT NULL DEFAULT true, + "dataSharing" BOOLEAN NOT NULL DEFAULT false, + "locale" TEXT NOT NULL DEFAULT 'en', + "darkMode" BOOLEAN NOT NULL DEFAULT false, + "language" TEXT NOT NULL DEFAULT 'en', + + CONSTRAINT "UserPreferences_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Device" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "platform" "DevicePlatform" NOT NULL, + "name" TEXT NOT NULL, + "pushToken" TEXT, + "trusted" BOOLEAN NOT NULL DEFAULT false, + "lastSeenAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "Device_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "SavedRoute" ( + "id" TEXT NOT NULL, + "passengerId" TEXT NOT NULL, + "fromStationId" TEXT NOT NULL, + "toStationId" TEXT NOT NULL, + "fromName" TEXT NOT NULL, + "toName" TEXT NOT NULL, + "tripCount" INTEGER NOT NULL DEFAULT 0, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "SavedRoute_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Journey" ( + "id" TEXT NOT NULL, + "passengerId" TEXT NOT NULL, + "status" TEXT NOT NULL, + "totalMinor" INTEGER NOT NULL, + "currency" TEXT NOT NULL DEFAULT 'ETB', + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "Journey_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "JourneySegment" ( + "id" TEXT NOT NULL, + "journeyId" TEXT NOT NULL, + "scheduleId" TEXT NOT NULL, + "segmentOrder" INTEGER NOT NULL, + "seatId" TEXT, + "coachId" TEXT, + "departureStationId" TEXT NOT NULL, + "arrivalStationId" TEXT NOT NULL, + + CONSTRAINT "JourneySegment_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "OtpCode" ( + "id" TEXT NOT NULL, + "userId" TEXT, + "email" TEXT, + "phone" TEXT, + "code" TEXT NOT NULL, + "purpose" TEXT NOT NULL, + "expiresAt" TIMESTAMP(3) NOT NULL, + "verified" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "OtpCode_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "PasswordResetToken" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "token" TEXT NOT NULL, + "expiresAt" TIMESTAMP(3) NOT NULL, + "used" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "PasswordResetToken_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Route" ( + "id" TEXT NOT NULL, + "code" TEXT NOT NULL, + "name" TEXT NOT NULL, + "description" TEXT, + "effectiveFrom" TIMESTAMP(3) NOT NULL, + "effectiveUntil" TIMESTAMP(3), + "active" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "Route_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "RouteStop" ( + "id" TEXT NOT NULL, + "routeId" TEXT NOT NULL, + "stationId" TEXT NOT NULL, + "sequence" INTEGER NOT NULL, + "distanceKm" INTEGER, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "RouteStop_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "RouteFareRule" ( + "id" TEXT NOT NULL, + "routeId" TEXT NOT NULL, + "seatClassId" TEXT NOT NULL, + "passengerCategory" "PassengerCategory" NOT NULL DEFAULT 'ADULT', + "baseFareMinor" INTEGER NOT NULL, + "discountPercent" INTEGER, + "taxPercent" INTEGER, + "surchargeMinor" INTEGER, + "currency" TEXT NOT NULL DEFAULT 'ETB', + "validFrom" TIMESTAMP(3) NOT NULL, + "validUntil" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "RouteFareRule_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Agent" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "agentCode" TEXT NOT NULL, + "stationId" TEXT, + "commissionRate" INTEGER NOT NULL DEFAULT 5, + "active" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "Agent_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "AgentBooking" ( + "id" TEXT NOT NULL, + "agentId" TEXT NOT NULL, + "bookingId" TEXT NOT NULL, + "paymentMethod" TEXT NOT NULL, + "cashReceived" INTEGER, + "changeGiven" INTEGER, + "paperTicket" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "AgentBooking_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "AgentShift" ( + "id" TEXT NOT NULL, + "agentId" TEXT NOT NULL, + "openedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "closedAt" TIMESTAMP(3), + "openingBalance" INTEGER NOT NULL DEFAULT 0, + "closingBalance" INTEGER, + "reconciled" BOOLEAN NOT NULL DEFAULT false, + "notes" TEXT, + + CONSTRAINT "AgentShift_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "AgentCommission" ( + "id" TEXT NOT NULL, + "agentId" TEXT NOT NULL, + "bookingId" TEXT NOT NULL, + "amountMinor" INTEGER NOT NULL, + "rate" INTEGER NOT NULL, + "paidAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "AgentCommission_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "BookingModification" ( + "id" TEXT NOT NULL, + "bookingId" TEXT NOT NULL, + "modifiedBy" TEXT NOT NULL, + "modificationType" TEXT NOT NULL, + "oldData" JSONB NOT NULL, + "newData" JSONB NOT NULL, + "fareAdjustment" INTEGER NOT NULL DEFAULT 0, + "reason" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "BookingModification_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "BookingCancellation" ( + "id" TEXT NOT NULL, + "bookingId" TEXT NOT NULL, + "cancelledBy" TEXT NOT NULL, + "reason" TEXT, + "refundAmount" INTEGER NOT NULL, + "refundMethod" TEXT NOT NULL, + "refundStatus" TEXT NOT NULL, + "processedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "BookingCancellation_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "GateValidationLog" ( + "id" TEXT NOT NULL, + "ticketId" TEXT NOT NULL, + "validatorId" TEXT NOT NULL, + "gateId" TEXT, + "status" TEXT NOT NULL, + "reason" TEXT, + "validatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "GateValidationLog_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "BaggageAllowance" ( + "id" TEXT NOT NULL, + "seatClassId" TEXT NOT NULL, + "maxWeightKg" INTEGER NOT NULL, + "maxPiecesCount" INTEGER NOT NULL, + "excessFeePerKg" INTEGER NOT NULL, + "currency" TEXT NOT NULL DEFAULT 'ETB', + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "BaggageAllowance_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "BaggageBooking" ( + "id" TEXT NOT NULL, + "bookingId" TEXT NOT NULL, + "weightKg" INTEGER NOT NULL, + "piecesCount" INTEGER NOT NULL, + "excessFeeMinor" INTEGER NOT NULL DEFAULT 0, + "paid" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "BaggageBooking_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "AuditLog" ( + "id" TEXT NOT NULL, + "userId" TEXT, + "action" TEXT NOT NULL, + "entityType" TEXT NOT NULL, + "entityId" TEXT, + "oldData" JSONB, + "newData" JSONB, + "ipAddress" TEXT, + "userAgent" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "AuditLog_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "NotificationTemplate" ( + "id" TEXT NOT NULL, + "code" TEXT NOT NULL, + "channel" TEXT NOT NULL, + "subject" TEXT, + "bodyTemplate" TEXT NOT NULL, + "active" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "NotificationTemplate_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "SeatBlock" ( + "id" TEXT NOT NULL, + "seatId" TEXT NOT NULL, + "reason" TEXT NOT NULL, + "blockedBy" TEXT NOT NULL, + "approvedBy" TEXT, + "blockedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "unblockAt" TIMESTAMP(3), + + CONSTRAINT "SeatBlock_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "OperationalReport" ( + "id" TEXT NOT NULL, + "reportType" TEXT NOT NULL, + "dateFrom" TIMESTAMP(3) NOT NULL, + "dateTo" TIMESTAMP(3) NOT NULL, + "data" JSONB NOT NULL, + "generatedBy" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "OperationalReport_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "FraudRule" ( + "id" TEXT NOT NULL, + "type" TEXT NOT NULL, + "enabled" BOOLEAN NOT NULL DEFAULT true, + "threshold" DOUBLE PRECISION NOT NULL, + "config" JSONB, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "FraudRule_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "FraudAlert" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "eventType" TEXT NOT NULL, + "triggeredRules" TEXT[], + "context" JSONB NOT NULL, + "severity" TEXT NOT NULL DEFAULT 'MEDIUM', + "acknowledged" BOOLEAN NOT NULL DEFAULT false, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "FraudAlert_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "CurrencyExchangeRate" ( + "id" TEXT NOT NULL, + "fromCurrency" "Currency" NOT NULL, + "toCurrency" "Currency" NOT NULL, + "rate" DECIMAL(18,6) NOT NULL, + "effectiveDate" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "source" TEXT NOT NULL DEFAULT 'MANUAL', + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "CurrencyExchangeRate_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "VerifaydaVerification" ( + "id" TEXT NOT NULL, + "bookingId" TEXT, + "nationalId" TEXT NOT NULL, + "requestPayload" JSONB NOT NULL, + "responsePayload" JSONB, + "verified" BOOLEAN NOT NULL DEFAULT false, + "failureReason" TEXT, + "verifiedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "VerifaydaVerification_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_phone_key" ON "User"("phone"); + +-- CreateIndex +CREATE UNIQUE INDEX "Session_token_key" ON "Session"("token"); + +-- CreateIndex +CREATE UNIQUE INDEX "Passenger_userId_key" ON "Passenger"("userId"); + +-- CreateIndex +CREATE INDEX "Passenger_userId_idx" ON "Passenger"("userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Station_code_key" ON "Station"("code"); + +-- CreateIndex +CREATE INDEX "Station_city_countryCode_idx" ON "Station"("city", "countryCode"); + +-- CreateIndex +CREATE UNIQUE INDEX "Train_number_key" ON "Train"("number"); + +-- CreateIndex +CREATE INDEX "TrainSchedule_departureAt_originStationId_idx" ON "TrainSchedule"("departureAt", "originStationId"); + +-- CreateIndex +CREATE UNIQUE INDEX "TripStopTime_scheduleId_sequence_key" ON "TripStopTime"("scheduleId", "sequence"); + +-- CreateIndex +CREATE UNIQUE INDEX "TripLiveStatus_scheduleId_key" ON "TripLiveStatus"("scheduleId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Coach_coachNumber_key" ON "Coach"("coachNumber"); + +-- CreateIndex +CREATE INDEX "CoachAssignment_scheduleId_idx" ON "CoachAssignment"("scheduleId"); + +-- CreateIndex +CREATE UNIQUE INDEX "CoachAssignment_scheduleId_positionNumber_key" ON "CoachAssignment"("scheduleId", "positionNumber"); + +-- CreateIndex +CREATE UNIQUE INDEX "Seat_coachId_row_col_key" ON "Seat"("coachId", "row", "col"); + +-- CreateIndex +CREATE UNIQUE INDEX "Seat_coachId_seatNumber_key" ON "Seat"("coachId", "seatNumber"); + +-- CreateIndex +CREATE INDEX "SeatHold_expiresAt_idx" ON "SeatHold"("expiresAt"); + +-- CreateIndex +CREATE UNIQUE INDEX "Booking_bookingRef_key" ON "Booking"("bookingRef"); + +-- CreateIndex +CREATE INDEX "Booking_passengerId_status_idx" ON "Booking"("passengerId", "status"); + +-- CreateIndex +CREATE INDEX "PaymentMethod_userId_isDefault_idx" ON "PaymentMethod"("userId", "isDefault"); + +-- CreateIndex +CREATE UNIQUE INDEX "PaymentIntent_bookingId_key" ON "PaymentIntent"("bookingId"); + +-- CreateIndex +CREATE UNIQUE INDEX "PaymentIntent_merchantOrderId_key" ON "PaymentIntent"("merchantOrderId"); + +-- CreateIndex +CREATE INDEX "PaymentIntent_providerOrderId_idx" ON "PaymentIntent"("providerOrderId"); + +-- CreateIndex +CREATE INDEX "PaymentIntent_providerTxnId_idx" ON "PaymentIntent"("providerTxnId"); + +-- CreateIndex +CREATE INDEX "PaymentWebhookEvent_merchantOrderId_idx" ON "PaymentWebhookEvent"("merchantOrderId"); + +-- CreateIndex +CREATE UNIQUE INDEX "PaymentWebhookEvent_provider_externalEventId_key" ON "PaymentWebhookEvent"("provider", "externalEventId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Ticket_bookingId_key" ON "Ticket"("bookingId"); + +-- CreateIndex +CREATE UNIQUE INDEX "LoyaltyAccount_passengerId_key" ON "LoyaltyAccount"("passengerId"); + +-- CreateIndex +CREATE UNIQUE INDEX "WalletAccount_passengerId_key" ON "WalletAccount"("passengerId"); + +-- CreateIndex +CREATE INDEX "WalletAccount_passengerId_idx" ON "WalletAccount"("passengerId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Promotion_code_key" ON "Promotion"("code"); + +-- CreateIndex +CREATE UNIQUE INDEX "UserPreferences_userId_key" ON "UserPreferences"("userId"); + +-- CreateIndex +CREATE INDEX "OtpCode_email_phone_idx" ON "OtpCode"("email", "phone"); + +-- CreateIndex +CREATE UNIQUE INDEX "PasswordResetToken_token_key" ON "PasswordResetToken"("token"); + +-- CreateIndex +CREATE INDEX "PasswordResetToken_userId_idx" ON "PasswordResetToken"("userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Route_code_key" ON "Route"("code"); + +-- CreateIndex +CREATE INDEX "RouteStop_routeId_stationId_idx" ON "RouteStop"("routeId", "stationId"); + +-- CreateIndex +CREATE UNIQUE INDEX "RouteStop_routeId_sequence_key" ON "RouteStop"("routeId", "sequence"); + +-- CreateIndex +CREATE INDEX "RouteFareRule_routeId_seatClassId_idx" ON "RouteFareRule"("routeId", "seatClassId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Agent_userId_key" ON "Agent"("userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Agent_agentCode_key" ON "Agent"("agentCode"); + +-- CreateIndex +CREATE UNIQUE INDEX "AgentBooking_bookingId_key" ON "AgentBooking"("bookingId"); + +-- CreateIndex +CREATE INDEX "AgentShift_agentId_openedAt_idx" ON "AgentShift"("agentId", "openedAt"); + +-- CreateIndex +CREATE INDEX "AgentCommission_agentId_paidAt_idx" ON "AgentCommission"("agentId", "paidAt"); + +-- CreateIndex +CREATE INDEX "BookingModification_bookingId_idx" ON "BookingModification"("bookingId"); + +-- CreateIndex +CREATE UNIQUE INDEX "BookingCancellation_bookingId_key" ON "BookingCancellation"("bookingId"); + +-- CreateIndex +CREATE INDEX "GateValidationLog_ticketId_idx" ON "GateValidationLog"("ticketId"); + +-- CreateIndex +CREATE INDEX "GateValidationLog_validatorId_idx" ON "GateValidationLog"("validatorId"); + +-- CreateIndex +CREATE INDEX "BaggageBooking_bookingId_idx" ON "BaggageBooking"("bookingId"); + +-- CreateIndex +CREATE INDEX "AuditLog_userId_createdAt_idx" ON "AuditLog"("userId", "createdAt"); + +-- CreateIndex +CREATE INDEX "AuditLog_entityType_entityId_idx" ON "AuditLog"("entityType", "entityId"); + +-- CreateIndex +CREATE UNIQUE INDEX "NotificationTemplate_code_key" ON "NotificationTemplate"("code"); + +-- CreateIndex +CREATE INDEX "SeatBlock_seatId_idx" ON "SeatBlock"("seatId"); + +-- CreateIndex +CREATE INDEX "OperationalReport_reportType_dateFrom_idx" ON "OperationalReport"("reportType", "dateFrom"); + +-- CreateIndex +CREATE UNIQUE INDEX "FraudRule_type_key" ON "FraudRule"("type"); + +-- CreateIndex +CREATE INDEX "FraudAlert_userId_createdAt_idx" ON "FraudAlert"("userId", "createdAt"); + +-- CreateIndex +CREATE INDEX "FraudAlert_acknowledged_idx" ON "FraudAlert"("acknowledged"); + +-- CreateIndex +CREATE INDEX "CurrencyExchangeRate_fromCurrency_toCurrency_idx" ON "CurrencyExchangeRate"("fromCurrency", "toCurrency"); + +-- CreateIndex +CREATE UNIQUE INDEX "CurrencyExchangeRate_fromCurrency_toCurrency_effectiveDate_key" ON "CurrencyExchangeRate"("fromCurrency", "toCurrency", "effectiveDate"); + +-- CreateIndex +CREATE INDEX "VerifaydaVerification_nationalId_idx" ON "VerifaydaVerification"("nationalId"); + +-- CreateIndex +CREATE INDEX "VerifaydaVerification_bookingId_idx" ON "VerifaydaVerification"("bookingId"); + +-- AddForeignKey +ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Passenger" ADD CONSTRAINT "Passenger_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "TravelerProfile" ADD CONSTRAINT "TravelerProfile_passengerId_fkey" FOREIGN KEY ("passengerId") REFERENCES "Passenger"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "TrainSchedule" ADD CONSTRAINT "TrainSchedule_trainId_fkey" FOREIGN KEY ("trainId") REFERENCES "Train"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "TrainSchedule" ADD CONSTRAINT "TrainSchedule_originStationId_fkey" FOREIGN KEY ("originStationId") REFERENCES "Station"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "TrainSchedule" ADD CONSTRAINT "TrainSchedule_destinationStationId_fkey" FOREIGN KEY ("destinationStationId") REFERENCES "Station"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "TripStopTime" ADD CONSTRAINT "TripStopTime_scheduleId_fkey" FOREIGN KEY ("scheduleId") REFERENCES "TrainSchedule"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "TripStopTime" ADD CONSTRAINT "TripStopTime_stationId_fkey" FOREIGN KEY ("stationId") REFERENCES "Station"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "TripLiveStatus" ADD CONSTRAINT "TripLiveStatus_scheduleId_fkey" FOREIGN KEY ("scheduleId") REFERENCES "TrainSchedule"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Coach" ADD CONSTRAINT "Coach_seatClassId_fkey" FOREIGN KEY ("seatClassId") REFERENCES "SeatClass"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "CoachAssignment" ADD CONSTRAINT "CoachAssignment_scheduleId_fkey" FOREIGN KEY ("scheduleId") REFERENCES "TrainSchedule"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "CoachAssignment" ADD CONSTRAINT "CoachAssignment_coachId_fkey" FOREIGN KEY ("coachId") REFERENCES "Coach"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Seat" ADD CONSTRAINT "Seat_coachId_fkey" FOREIGN KEY ("coachId") REFERENCES "Coach"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "FareRule" ADD CONSTRAINT "FareRule_seatClassId_fkey" FOREIGN KEY ("seatClassId") REFERENCES "SeatClass"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Booking" ADD CONSTRAINT "Booking_passengerId_fkey" FOREIGN KEY ("passengerId") REFERENCES "Passenger"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Booking" ADD CONSTRAINT "Booking_scheduleId_fkey" FOREIGN KEY ("scheduleId") REFERENCES "TrainSchedule"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "BookingSeat" ADD CONSTRAINT "BookingSeat_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "BookingSeat" ADD CONSTRAINT "BookingSeat_seatId_fkey" FOREIGN KEY ("seatId") REFERENCES "Seat"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "PaymentIntent" ADD CONSTRAINT "PaymentIntent_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "PaymentRefund" ADD CONSTRAINT "PaymentRefund_paymentIntentId_fkey" FOREIGN KEY ("paymentIntentId") REFERENCES "PaymentIntent"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Ticket" ADD CONSTRAINT "Ticket_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "LoyaltyAccount" ADD CONSTRAINT "LoyaltyAccount_passengerId_fkey" FOREIGN KEY ("passengerId") REFERENCES "Passenger"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "LoyaltyLedgerEntry" ADD CONSTRAINT "LoyaltyLedgerEntry_accountId_fkey" FOREIGN KEY ("accountId") REFERENCES "LoyaltyAccount"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "LoyaltyReward" ADD CONSTRAINT "LoyaltyReward_accountId_fkey" FOREIGN KEY ("accountId") REFERENCES "LoyaltyAccount"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "WalletAccount" ADD CONSTRAINT "WalletAccount_passengerId_fkey" FOREIGN KEY ("passengerId") REFERENCES "Passenger"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "WalletLedgerEntry" ADD CONSTRAINT "WalletLedgerEntry_walletId_fkey" FOREIGN KEY ("walletId") REFERENCES "WalletAccount"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Notification" ADD CONSTRAINT "Notification_passengerId_fkey" FOREIGN KEY ("passengerId") REFERENCES "Passenger"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "StationCrowdSignal" ADD CONSTRAINT "StationCrowdSignal_stationId_fkey" FOREIGN KEY ("stationId") REFERENCES "Station"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "MenuItem" ADD CONSTRAINT "MenuItem_scheduleId_fkey" FOREIGN KEY ("scheduleId") REFERENCES "TrainSchedule"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "MenuItem" ADD CONSTRAINT "MenuItem_categoryId_fkey" FOREIGN KEY ("categoryId") REFERENCES "MenuCategory"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "FoodOrder" ADD CONSTRAINT "FoodOrder_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "FoodOrderItem" ADD CONSTRAINT "FoodOrderItem_orderId_fkey" FOREIGN KEY ("orderId") REFERENCES "FoodOrder"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "FaqArticle" ADD CONSTRAINT "FaqArticle_categoryId_fkey" FOREIGN KEY ("categoryId") REFERENCES "FaqCategory"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "SupportMessage" ADD CONSTRAINT "SupportMessage_conversationId_fkey" FOREIGN KEY ("conversationId") REFERENCES "SupportConversation"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "UserPreferences" ADD CONSTRAINT "UserPreferences_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Device" ADD CONSTRAINT "Device_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "SavedRoute" ADD CONSTRAINT "SavedRoute_passengerId_fkey" FOREIGN KEY ("passengerId") REFERENCES "Passenger"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "JourneySegment" ADD CONSTRAINT "JourneySegment_journeyId_fkey" FOREIGN KEY ("journeyId") REFERENCES "Journey"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "JourneySegment" ADD CONSTRAINT "JourneySegment_scheduleId_fkey" FOREIGN KEY ("scheduleId") REFERENCES "TrainSchedule"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "RouteStop" ADD CONSTRAINT "RouteStop_routeId_fkey" FOREIGN KEY ("routeId") REFERENCES "Route"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "RouteFareRule" ADD CONSTRAINT "RouteFareRule_routeId_fkey" FOREIGN KEY ("routeId") REFERENCES "Route"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "RouteFareRule" ADD CONSTRAINT "RouteFareRule_seatClassId_fkey" FOREIGN KEY ("seatClassId") REFERENCES "SeatClass"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Agent" ADD CONSTRAINT "Agent_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "AgentBooking" ADD CONSTRAINT "AgentBooking_agentId_fkey" FOREIGN KEY ("agentId") REFERENCES "Agent"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "AgentBooking" ADD CONSTRAINT "AgentBooking_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "AgentShift" ADD CONSTRAINT "AgentShift_agentId_fkey" FOREIGN KEY ("agentId") REFERENCES "Agent"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "AgentCommission" ADD CONSTRAINT "AgentCommission_agentId_fkey" FOREIGN KEY ("agentId") REFERENCES "Agent"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "BookingModification" ADD CONSTRAINT "BookingModification_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "BookingCancellation" ADD CONSTRAINT "BookingCancellation_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "GateValidationLog" ADD CONSTRAINT "GateValidationLog_ticketId_fkey" FOREIGN KEY ("ticketId") REFERENCES "Ticket"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "BaggageBooking" ADD CONSTRAINT "BaggageBooking_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "AuditLog" ADD CONSTRAINT "AuditLog_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "SeatBlock" ADD CONSTRAINT "SeatBlock_seatId_fkey" FOREIGN KEY ("seatId") REFERENCES "Seat"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "FraudAlert" ADD CONSTRAINT "FraudAlert_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/apps/edr-passenger-api/prisma/schema.prisma b/apps/edr-passenger-api/prisma/schema.prisma index 7b2df1e81..e8d4f5f72 100644 --- a/apps/edr-passenger-api/prisma/schema.prisma +++ b/apps/edr-passenger-api/prisma/schema.prisma @@ -5,7 +5,6 @@ generator client { datasource db { provider = "postgresql" url = env("DATABASE_URL") - schemas = ["edr_passenger"] } enum UserRole { From 2dad9137dd6ed273e40e8fa40dfb0760d5d47330 Mon Sep 17 00:00:00 2001 From: Stephanos A Date: Fri, 22 May 2026 16:21:24 +0300 Subject: [PATCH 23/38] Set schema to 'passenger' --- apps/edr-passenger-api/prisma/schema.prisma | 171 ++++++++++++++++++++ 1 file changed, 171 insertions(+) diff --git a/apps/edr-passenger-api/prisma/schema.prisma b/apps/edr-passenger-api/prisma/schema.prisma index e8d4f5f72..046faf2b1 100644 --- a/apps/edr-passenger-api/prisma/schema.prisma +++ b/apps/edr-passenger-api/prisma/schema.prisma @@ -5,6 +5,7 @@ generator client { datasource db { provider = "postgresql" url = env("DATABASE_URL") + schemas = ["passenger"] } enum UserRole { @@ -13,6 +14,8 @@ enum UserRole { SUPERVISOR ADMIN STAFF + + @@schema("passenger") } enum TripStatus { @@ -22,12 +25,16 @@ enum TripStatus { ARRIVED CANCELLED DELAYED + + @@schema("passenger") } enum SeatKind { STANDARD PREMIUM ACCESSIBLE + + @@schema("passenger") } enum SeatStatus { @@ -35,11 +42,15 @@ enum SeatStatus { HELD BOOKED BLOCKED + + @@schema("passenger") } enum PassengerCategory { ADULT CHILD + + @@schema("passenger") } enum IdDocumentType { @@ -47,12 +58,16 @@ enum IdDocumentType { PASSPORT DRIVING_LICENSE OTHER + + @@schema("passenger") } enum Currency { ETB DJF USD + + @@schema("passenger") } model SeatClass { @@ -66,6 +81,8 @@ model SeatClass { coaches Coach[] fareRules FareRule[] routeFareRules RouteFareRule[] + + @@schema("passenger") } enum BookingStatus { @@ -76,6 +93,8 @@ enum BookingStatus { COMPLETED NO_SHOW REFUNDED + + @@schema("passenger") } enum PaymentMethodType { @@ -84,6 +103,8 @@ enum PaymentMethodType { EBIRR CARD WALLET + + @@schema("passenger") } enum PaymentIntentStatus { @@ -93,11 +114,15 @@ enum PaymentIntentStatus { FAILED CANCELLED REFUNDED + + @@schema("passenger") } enum WalletLedgerType { CREDIT DEBIT + + @@schema("passenger") } enum NotificationCategory { @@ -106,6 +131,8 @@ enum NotificationCategory { DISRUPTION PROMOTION SYSTEM + + @@schema("passenger") } enum StopStatus { @@ -113,18 +140,24 @@ enum StopStatus { APPROACHING CURRENT UPCOMING + + @@schema("passenger") } enum SupportConversationStatus { OPEN RESOLVED CLOSED + + @@schema("passenger") } enum SupportSender { USER BOT AGENT + + @@schema("passenger") } enum LoyaltyTier { @@ -132,6 +165,8 @@ enum LoyaltyTier { SILVER GOLD PLATINUM + + @@schema("passenger") } enum LoyaltyLedgerReason { @@ -140,6 +175,8 @@ enum LoyaltyLedgerReason { PROMO_BONUS MANUAL_ADJUSTMENT EXPIRY + + @@schema("passenger") } enum FoodOrderStatus { @@ -148,12 +185,16 @@ enum FoodOrderStatus { READY DELIVERED CANCELLED + + @@schema("passenger") } enum DevicePlatform { IOS ANDROID WEB + + @@schema("passenger") } model User { @@ -180,6 +221,8 @@ model User { preferences UserPreferences? auditLogs AuditLog[] fraudAlerts FraudAlert[] + + @@schema("passenger") } model Session { @@ -192,6 +235,8 @@ model Session { lastActivityAt DateTime @default(now()) createdAt DateTime @default(now()) user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@schema("passenger") } model Passenger { @@ -208,6 +253,8 @@ model Passenger { travelerProfiles TravelerProfile[] savedRoutes SavedRoute[] @@index([userId]) + + @@schema("passenger") } model TravelerProfile { @@ -220,6 +267,8 @@ model TravelerProfile { notes String? createdAt DateTime @default(now()) passenger Passenger @relation(fields: [passengerId], references: [id]) + + @@schema("passenger") } model Station { @@ -237,6 +286,8 @@ model Station { stopTimes TripStopTime[] crowdSignals StationCrowdSignal[] @@index([city, countryCode]) + + @@schema("passenger") } model Train { @@ -250,6 +301,8 @@ model Train { createdAt DateTime @default(now()) updatedAt DateTime @updatedAt schedules TrainSchedule[] + + @@schema("passenger") } model TrainSchedule { @@ -277,6 +330,8 @@ model TrainSchedule { menuItems MenuItem[] journeySegments JourneySegment[] @@index([departureAt, originStationId]) + + @@schema("passenger") } model TripStopTime { @@ -291,6 +346,8 @@ model TripStopTime { schedule TrainSchedule @relation(fields: [scheduleId], references: [id]) station Station @relation(fields: [stationId], references: [id]) @@unique([scheduleId, sequence]) + + @@schema("passenger") } model TripLiveStatus { @@ -304,6 +361,8 @@ model TripLiveStatus { platformLabel String? updatedAt DateTime @updatedAt schedule TrainSchedule @relation(fields: [scheduleId], references: [id]) + + @@schema("passenger") } model Coach { @@ -323,6 +382,8 @@ model Coach { seatClass SeatClass @relation(fields: [seatClassId], references: [id]) seats Seat[] assignments CoachAssignment[] + + @@schema("passenger") } model CoachAssignment { @@ -336,6 +397,8 @@ model CoachAssignment { coach Coach @relation(fields: [coachId], references: [id]) @@unique([scheduleId, positionNumber]) @@index([scheduleId]) + + @@schema("passenger") } model Seat { @@ -358,6 +421,8 @@ model Seat { blocks SeatBlock[] @@unique([coachId, row, col]) @@unique([coachId, seatNumber]) + + @@schema("passenger") } model SeatHold { @@ -370,6 +435,8 @@ model SeatHold { expiresAt DateTime createdAt DateTime @default(now()) @@index([expiresAt]) + + @@schema("passenger") } model FareRule { @@ -384,6 +451,8 @@ model FareRule { validFrom DateTime validUntil DateTime? createdAt DateTime @default(now()) + + @@schema("passenger") } model Booking { @@ -416,6 +485,8 @@ model Booking { cancellation BookingCancellation? baggage BaggageBooking[] @@index([passengerId, status]) + + @@schema("passenger") } model BookingSeat { @@ -437,6 +508,8 @@ model BookingSeat { displayFareMinor Int? booking Booking @relation(fields: [bookingId], references: [id]) seat Seat @relation(fields: [seatId], references: [id]) + + @@schema("passenger") } model PaymentMethod { @@ -449,6 +522,8 @@ model PaymentMethod { isDefault Boolean @default(false) createdAt DateTime @default(now()) @@index([userId, isDefault]) + + @@schema("passenger") } model PaymentIntent { @@ -477,6 +552,8 @@ model PaymentIntent { refunds PaymentRefund[] @@index([providerOrderId]) @@index([providerTxnId]) + + @@schema("passenger") } model PaymentWebhookEvent { @@ -493,6 +570,8 @@ model PaymentWebhookEvent { processingError String? @@unique([provider, externalEventId]) @@index([merchantOrderId]) + + @@schema("passenger") } model PaymentRefund { @@ -504,6 +583,8 @@ model PaymentRefund { status String createdAt DateTime @default(now()) paymentIntent PaymentIntent @relation(fields: [paymentIntentId], references: [id]) + + @@schema("passenger") } model Ticket { @@ -520,6 +601,8 @@ model Ticket { validatorId String? booking Booking @relation(fields: [bookingId], references: [id]) validationLogs GateValidationLog[] + + @@schema("passenger") } model LoyaltyAccount { @@ -533,6 +616,8 @@ model LoyaltyAccount { passenger Passenger @relation(fields: [passengerId], references: [id]) ledger LoyaltyLedgerEntry[] rewards LoyaltyReward[] + + @@schema("passenger") } model LoyaltyLedgerEntry { @@ -544,6 +629,8 @@ model LoyaltyLedgerEntry { balanceAfter Int createdAt DateTime @default(now()) account LoyaltyAccount @relation(fields: [accountId], references: [id]) + + @@schema("passenger") } model LoyaltyReward { @@ -554,6 +641,8 @@ model LoyaltyReward { available Boolean @default(true) description String? account LoyaltyAccount @relation(fields: [accountId], references: [id]) + + @@schema("passenger") } model WalletAccount { @@ -567,6 +656,8 @@ model WalletAccount { passenger Passenger @relation(fields: [passengerId], references: [id]) ledger WalletLedgerEntry[] @@index([passengerId]) + + @@schema("passenger") } model WalletLedgerEntry { @@ -579,6 +670,8 @@ model WalletLedgerEntry { relatedBookingId String? createdAt DateTime @default(now()) wallet WalletAccount @relation(fields: [walletId], references: [id]) + + @@schema("passenger") } model Notification { @@ -592,6 +685,8 @@ model Notification { metadata Json? createdAt DateTime @default(now()) passenger Passenger @relation(fields: [passengerId], references: [id]) + + @@schema("passenger") } model Promotion { @@ -606,6 +701,8 @@ model Promotion { deepLink String? active Boolean @default(true) createdAt DateTime @default(now()) + + @@schema("passenger") } model StationCrowdSignal { @@ -618,6 +715,8 @@ model StationCrowdSignal { observedAt DateTime? updatedAt DateTime @updatedAt station Station @relation(fields: [stationId], references: [id]) + + @@schema("passenger") } model WeatherAlert { @@ -628,12 +727,16 @@ model WeatherAlert { message String validUntil DateTime createdAt DateTime @default(now()) + + @@schema("passenger") } model MenuCategory { id String @id @default(uuid()) name String items MenuItem[] + + @@schema("passenger") } model MenuItem { @@ -647,6 +750,8 @@ model MenuItem { availableUntil DateTime? schedule TrainSchedule @relation(fields: [scheduleId], references: [id]) category MenuCategory @relation(fields: [categoryId], references: [id]) + + @@schema("passenger") } model FoodOrder { @@ -660,6 +765,8 @@ model FoodOrder { createdAt DateTime @default(now()) booking Booking @relation(fields: [bookingId], references: [id]) items FoodOrderItem[] + + @@schema("passenger") } model FoodOrderItem { @@ -671,6 +778,8 @@ model FoodOrderItem { unitPriceMinor Int? lineTotalMinor Int order FoodOrder @relation(fields: [orderId], references: [id]) + + @@schema("passenger") } model FaqCategory { @@ -678,6 +787,8 @@ model FaqCategory { title String iconKey String? articles FaqArticle[] + + @@schema("passenger") } model FaqArticle { @@ -687,6 +798,8 @@ model FaqArticle { answerMarkdown String rank Int @default(0) category FaqCategory @relation(fields: [categoryId], references: [id]) + + @@schema("passenger") } model SupportConversation { @@ -696,6 +809,8 @@ model SupportConversation { status SupportConversationStatus @default(OPEN) createdAt DateTime @default(now()) messages SupportMessage[] + + @@schema("passenger") } model SupportMessage { @@ -706,6 +821,8 @@ model SupportMessage { attachments Json? createdAt DateTime @default(now()) conversation SupportConversation @relation(fields: [conversationId], references: [id]) + + @@schema("passenger") } model UserPreferences { @@ -724,6 +841,8 @@ model UserPreferences { darkMode Boolean @default(false) language String @default("en") user User @relation(fields: [userId], references: [id]) + + @@schema("passenger") } model Device { @@ -735,6 +854,8 @@ model Device { trusted Boolean @default(false) lastSeenAt DateTime @default(now()) user User @relation(fields: [userId], references: [id]) + + @@schema("passenger") } model SavedRoute { @@ -747,6 +868,8 @@ model SavedRoute { tripCount Int @default(0) createdAt DateTime @default(now()) passenger Passenger @relation(fields: [passengerId], references: [id]) + + @@schema("passenger") } model Journey { @@ -757,6 +880,8 @@ model Journey { currency String @default("ETB") createdAt DateTime @default(now()) journeySegments JourneySegment[] + + @@schema("passenger") } model JourneySegment { @@ -770,6 +895,8 @@ model JourneySegment { arrivalStationId String journey Journey @relation(fields: [journeyId], references: [id]) schedule TrainSchedule @relation(fields: [scheduleId], references: [id]) + + @@schema("passenger") } model OtpCode { @@ -783,6 +910,8 @@ model OtpCode { verified Boolean @default(false) createdAt DateTime @default(now()) @@index([email, phone]) + + @@schema("passenger") } model PasswordResetToken { @@ -793,6 +922,8 @@ model PasswordResetToken { used Boolean @default(false) createdAt DateTime @default(now()) @@index([userId]) + + @@schema("passenger") } model Route { @@ -806,6 +937,8 @@ model Route { createdAt DateTime @default(now()) stops RouteStop[] fareRules RouteFareRule[] + + @@schema("passenger") } model RouteStop { @@ -818,6 +951,8 @@ model RouteStop { route Route @relation(fields: [routeId], references: [id], onDelete: Cascade) @@unique([routeId, sequence]) @@index([routeId, stationId]) + + @@schema("passenger") } model RouteFareRule { @@ -836,6 +971,8 @@ model RouteFareRule { route Route @relation(fields: [routeId], references: [id], onDelete: Cascade) seatClass SeatClass @relation(fields: [seatClassId], references: [id]) @@index([routeId, seatClassId]) + + @@schema("passenger") } model Agent { @@ -850,6 +987,8 @@ model Agent { bookings AgentBooking[] shifts AgentShift[] commissions AgentCommission[] + + @@schema("passenger") } model AgentBooking { @@ -863,6 +1002,8 @@ model AgentBooking { createdAt DateTime @default(now()) agent Agent @relation(fields: [agentId], references: [id]) booking Booking @relation(fields: [bookingId], references: [id]) + + @@schema("passenger") } model AgentShift { @@ -876,6 +1017,8 @@ model AgentShift { notes String? agent Agent @relation(fields: [agentId], references: [id]) @@index([agentId, openedAt]) + + @@schema("passenger") } model AgentCommission { @@ -888,6 +1031,8 @@ model AgentCommission { createdAt DateTime @default(now()) agent Agent @relation(fields: [agentId], references: [id]) @@index([agentId, paidAt]) + + @@schema("passenger") } model BookingModification { @@ -902,6 +1047,8 @@ model BookingModification { createdAt DateTime @default(now()) booking Booking @relation(fields: [bookingId], references: [id]) @@index([bookingId]) + + @@schema("passenger") } model BookingCancellation { @@ -915,6 +1062,8 @@ model BookingCancellation { processedAt DateTime? createdAt DateTime @default(now()) booking Booking @relation(fields: [bookingId], references: [id]) + + @@schema("passenger") } model GateValidationLog { @@ -928,6 +1077,8 @@ model GateValidationLog { ticket Ticket @relation(fields: [ticketId], references: [id]) @@index([ticketId]) @@index([validatorId]) + + @@schema("passenger") } model BaggageAllowance { @@ -938,6 +1089,8 @@ model BaggageAllowance { excessFeePerKg Int currency String @default("ETB") createdAt DateTime @default(now()) + + @@schema("passenger") } model BaggageBooking { @@ -950,6 +1103,8 @@ model BaggageBooking { createdAt DateTime @default(now()) booking Booking @relation(fields: [bookingId], references: [id]) @@index([bookingId]) + + @@schema("passenger") } model AuditLog { @@ -966,6 +1121,8 @@ model AuditLog { user User? @relation(fields: [userId], references: [id]) @@index([userId, createdAt]) @@index([entityType, entityId]) + + @@schema("passenger") } model NotificationTemplate { @@ -976,6 +1133,8 @@ model NotificationTemplate { bodyTemplate String active Boolean @default(true) createdAt DateTime @default(now()) + + @@schema("passenger") } model SeatBlock { @@ -988,6 +1147,8 @@ model SeatBlock { unblockAt DateTime? seat Seat @relation(fields: [seatId], references: [id]) @@index([seatId]) + + @@schema("passenger") } model OperationalReport { @@ -999,6 +1160,8 @@ model OperationalReport { generatedBy String? createdAt DateTime @default(now()) @@index([reportType, dateFrom]) + + @@schema("passenger") } model FraudRule { @@ -1009,6 +1172,8 @@ model FraudRule { config Json? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt + + @@schema("passenger") } model FraudAlert { @@ -1023,6 +1188,8 @@ model FraudAlert { user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId, createdAt]) @@index([acknowledged]) + + @@schema("passenger") } model CurrencyExchangeRate { @@ -1035,6 +1202,8 @@ model CurrencyExchangeRate { createdAt DateTime @default(now()) @@unique([fromCurrency, toCurrency, effectiveDate]) @@index([fromCurrency, toCurrency]) + + @@schema("passenger") } model VerifaydaVerification { @@ -1049,4 +1218,6 @@ model VerifaydaVerification { createdAt DateTime @default(now()) @@index([nationalId]) @@index([bookingId]) + + @@schema("passenger") } From 6397572b475525caa2cd4b6b055d1ee904ed2e64 Mon Sep 17 00:00:00 2001 From: Abubeker Yasin Date: Sat, 23 May 2026 05:07:24 +0300 Subject: [PATCH 24/38] feat(payments): support web and mobile platform for Telebirr initiation --- .../src/modules/payments/payments.dto.ts | 15 ++++++++++++--- .../src/modules/payments/payments.service.ts | 8 +++++--- .../src/modules/payments/payments.types.ts | 10 ++++++---- .../payments/providers/telebirr.provider.ts | 13 +++++++++++-- 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/apps/edr-passenger-api/src/modules/payments/payments.dto.ts b/apps/edr-passenger-api/src/modules/payments/payments.dto.ts index adeee8b22..815569f24 100644 --- a/apps/edr-passenger-api/src/modules/payments/payments.dto.ts +++ b/apps/edr-passenger-api/src/modules/payments/payments.dto.ts @@ -1,13 +1,19 @@ -import { IsString, IsEnum, IsOptional } from 'class-validator'; +import { IsString, IsEnum, IsOptional, IsIn } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { PaymentIntentStatus } from '@prisma/client'; export enum PaymentMethodTypeEnum { TELEBIRR = 'TELEBIRR', CBE_BIRR = 'CBE_BIRR', EBIRR = 'EBIRR', CARD = 'CARD', WALLET = 'WALLET' } +export type PaymentPlatformDto = 'web' | 'mobile'; + export class InitiatePaymentDto { @ApiProperty() @IsString() bookingId: string; @ApiProperty({ enum: PaymentMethodTypeEnum }) @IsEnum(PaymentMethodTypeEnum) method: PaymentMethodTypeEnum; @ApiPropertyOptional() @IsOptional() @IsString() paymentMethodId?: string; + @ApiPropertyOptional({ enum: ['web', 'mobile'], default: 'web' }) + @IsOptional() + @IsIn(['web', 'mobile']) + platform?: PaymentPlatformDto; } export class RefundDto { @@ -23,8 +29,11 @@ export class AddPaymentMethodDto { } export class ClientActionDto { - @ApiProperty({ enum: ['REDIRECT'] }) type: 'REDIRECT'; - @ApiProperty() url: string; + @ApiProperty({ enum: ['REDIRECT', 'LAUNCH_APP'] }) type: 'REDIRECT' | 'LAUNCH_APP'; + @ApiPropertyOptional({ description: 'Set when type=REDIRECT (web flow)' }) url?: string; + @ApiPropertyOptional({ description: 'Set when type=LAUNCH_APP (mobile flow)' }) prepayId?: string; + @ApiPropertyOptional({ description: 'Set when type=LAUNCH_APP (mobile flow)' }) receiveCode?: string; + @ApiPropertyOptional({ description: 'Set when type=LAUNCH_APP (mobile flow)' }) shortCode?: string; } export class InitiateResponseDto { diff --git a/apps/edr-passenger-api/src/modules/payments/payments.service.ts b/apps/edr-passenger-api/src/modules/payments/payments.service.ts index 9f1ae5341..e6c179049 100644 --- a/apps/edr-passenger-api/src/modules/payments/payments.service.ts +++ b/apps/edr-passenger-api/src/modules/payments/payments.service.ts @@ -5,7 +5,7 @@ import { TicketsService } from '../tickets/tickets.service'; import { EventEmitter2 } from '@nestjs/event-emitter'; import { Prisma, PaymentIntentStatus, PaymentMethodType } from '@prisma/client'; import { InitiatePaymentDto, RefundDto, AddPaymentMethodDto, InitiateResponseDto, IntentStatusDto } from './payments.dto'; -import { PaymentProvider, ProviderStatus } from './payments.types'; +import { ClientAction, PaymentProvider, ProviderStatus } from './payments.types'; import { TelebirrProvider } from './providers/telebirr.provider'; import { CbeBirrProvider } from './providers/cbe-birr.provider'; import { EBirrProvider } from './providers/ebirr.provider'; @@ -66,7 +66,7 @@ export class PaymentsService { const provider = this.providers.get(method); if (provider) { - return this.initiateProviderPayment(booking, provider); + return this.initiateProviderPayment(booking, provider, dto.platform); } throw new BadRequestException(`Unsupported payment method: ${method}`); @@ -139,6 +139,7 @@ export class PaymentsService { private async initiateProviderPayment( booking: Prisma.BookingGetPayload<{ include: { seats: true } }>, provider: PaymentProvider, + platform: 'web' | 'mobile' | undefined, ): Promise { const merchantOrderId = createMerchantOrderId(); const result = await provider.initiate({ @@ -146,6 +147,7 @@ export class PaymentsService { bookingRef: booking.bookingRef, amountMinor: booking.totalMinor, currency: booking.currency, + platform, }); const intent = await this.prisma.paymentIntent.upsert({ @@ -184,7 +186,7 @@ export class PaymentsService { ): InitiateResponseDto { const clientAction = intent.clientAction && typeof intent.clientAction === 'object' - ? (intent.clientAction as unknown as { type: 'REDIRECT'; url: string }) + ? (intent.clientAction as unknown as ClientAction) : undefined; return { intentId: intent.id, diff --git a/apps/edr-passenger-api/src/modules/payments/payments.types.ts b/apps/edr-passenger-api/src/modules/payments/payments.types.ts index 336f4b511..e218c3e5c 100644 --- a/apps/edr-passenger-api/src/modules/payments/payments.types.ts +++ b/apps/edr-passenger-api/src/modules/payments/payments.types.ts @@ -1,15 +1,17 @@ import { PaymentIntentStatus, PaymentMethodType } from '@prisma/client'; -export interface ClientAction { - type: 'REDIRECT'; - url: string; -} +export type PaymentPlatform = 'web' | 'mobile'; + +export type ClientAction = + | { type: 'REDIRECT'; url: string } + | { type: 'LAUNCH_APP'; prepayId: string; receiveCode?: string; shortCode: string }; export interface ProviderInitiationInput { merchantOrderId: string; bookingRef: string; amountMinor: number; currency: string; + platform?: PaymentPlatform; } export interface ProviderInitiationResult { diff --git a/apps/edr-passenger-api/src/modules/payments/providers/telebirr.provider.ts b/apps/edr-passenger-api/src/modules/payments/providers/telebirr.provider.ts index 21980a175..9984b5842 100644 --- a/apps/edr-passenger-api/src/modules/payments/providers/telebirr.provider.ts +++ b/apps/edr-passenger-api/src/modules/payments/providers/telebirr.provider.ts @@ -58,12 +58,21 @@ export class TelebirrProvider implements PaymentProvider { ); } - const checkoutUrl = this.buildCheckoutUrl(prepayId); const expiresAt = this.computeExpiresAt(requestBody.biz_content.timeout_express); + const platform = input.platform ?? 'web'; + const clientAction = + platform === 'mobile' + ? { + type: 'LAUNCH_APP' as const, + prepayId, + receiveCode: response.biz_content?.receiveCode, + shortCode: this.merchantCode, + } + : { type: 'REDIRECT' as const, url: this.buildCheckoutUrl(prepayId) }; return { providerOrderId: prepayId, - clientAction: { type: 'REDIRECT', url: checkoutUrl }, + clientAction, expiresAt, rawInitiation: { request: this.sanitize(requestBody), From 7282e32c524ec8328c06bf9695c39bc7bde16ac0 Mon Sep 17 00:00:00 2001 From: "Eyob T." Date: Sat, 23 May 2026 08:59:57 +0300 Subject: [PATCH 25/38] Deployment failure fix --- apps/edr-passenger-api/src/main.ts | 1 + pnpm-lock.yaml | 14486 +++++++++++++++++---------- 2 files changed, 9214 insertions(+), 5273 deletions(-) diff --git a/apps/edr-passenger-api/src/main.ts b/apps/edr-passenger-api/src/main.ts index 7abf8092a..d28f94e11 100644 --- a/apps/edr-passenger-api/src/main.ts +++ b/apps/edr-passenger-api/src/main.ts @@ -5,6 +5,7 @@ import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger"; import { AppModule } from "./app.module"; import { HttpExceptionFilter } from "./common/filters/http-exception.filter"; import { ResponseTransformInterceptor } from "./common/interceptors/response-transform.interceptor"; +import { SessionActivityInterceptor } from "./common/interceptors/session-activity.interceptor"; async function bootstrap() { const app = await NestFactory.create(AppModule); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c4cc0af18..30f7e543d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -25,7 +25,7 @@ importers: version: 3.8.3 turbo: specifier: ^2.3.0 - version: 2.9.12 + version: 2.9.14 typescript: specifier: ^5.5.4 version: 5.9.3 @@ -40,31 +40,31 @@ importers: version: link:../../packages/types '@nestjs/common': specifier: ^11.0.0 - version: 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/config': specifier: ^4.0.0 - version: 4.0.4(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2) + version: 4.0.4(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2) '@nestjs/core': specifier: ^11.0.0 - version: 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.19)(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.23)(@nestjs/platform-express@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/microservices': specifier: ^11.0.0 - version: 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/platform-express': specifier: ^11.0.0 - version: 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19) + version: 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23) '@nestjs/swagger': specifier: ^11.4.2 - version: 11.4.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) + version: 11.4.4(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) '@nestjs/typeorm': specifier: ^11.0.1 - version: 11.0.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))) + version: 11.0.1(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))) '@tria-plc/api-common': specifier: ^0.1.0 - version: 0.1.4(42b11c4715772d7b83dab2dbc0ea2324) + version: 0.1.4(223e9245c5c33c83105d11e0b796f581) '@tria-plc/iamapi-common': specifier: ^0.1.0 - version: 0.1.6(7eaf302065296f503c6ce1ae1c9ee51c) + version: 0.1.6(5db95f48cc2d3ea262f734e8a77edcde) class-transformer: specifier: ^0.5.1 version: 0.5.1 @@ -73,7 +73,7 @@ importers: version: 0.14.4 pg: specifier: ^8.13.0 - version: 8.20.0 + version: 8.21.0 reflect-metadata: specifier: ^0.2.2 version: 0.2.2 @@ -82,7 +82,7 @@ importers: version: 7.8.2 typeorm: specifier: ^0.3.20 - version: 0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) + version: 0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) devDependencies: '@edr/eslint-config': specifier: workspace:* @@ -98,7 +98,7 @@ importers: version: 11.1.0(chokidar@4.0.3)(prettier@3.8.3)(typescript@5.9.3) '@nestjs/testing': specifier: ^11.0.0 - version: 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(@nestjs/microservices@11.1.19)(@nestjs/platform-express@11.1.19) + version: 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(@nestjs/microservices@11.1.23)(@nestjs/platform-express@11.1.23) '@types/express': specifier: ^5.0.0 version: 5.0.6 @@ -119,7 +119,7 @@ importers: version: 7.2.2 ts-jest: specifier: ^29.2.5 - version: 29.4.9(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.41)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.11(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.41)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)))(typescript@5.9.3) ts-loader: specifier: ^9.5.1 version: 9.5.7(typescript@5.9.3)(webpack@5.106.0) @@ -143,13 +143,13 @@ importers: version: link:../../../packages/ui-common '@tanstack/react-query': specifier: ^5.59.0 - version: 5.100.10(react@18.3.1) + version: 5.100.11(react@18.3.1) '@tria-plc/iamui-common': specifier: 1.0.3 - version: 1.0.3(b753628ac65312d9adb4ccd0069fe702) + version: 1.0.3(39b46189c29498b6b03bc65d0aed046a) axios: specifier: ^1.7.7 - version: 1.16.0 + version: 1.16.1 clsx: specifier: ^2.1.1 version: 2.1.1 @@ -164,7 +164,7 @@ importers: version: 6.30.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) zustand: specifier: ^5.0.0 - version: 5.0.13(@types/react@18.3.28)(immer@11.1.8)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) + version: 5.0.13(@types/react@18.3.29)(immer@11.1.8)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) devDependencies: '@edr/eslint-config': specifier: workspace:* @@ -174,22 +174,22 @@ importers: version: link:../../../packages/config/tsconfig '@types/react': specifier: ^18.3.11 - version: 18.3.28 + version: 18.3.29 '@types/react-dom': specifier: ^18.3.0 - version: 18.3.7(@types/react@18.3.28) + version: 18.3.7(@types/react@18.3.29) '@vitejs/plugin-react': specifier: ^4.3.2 - version: 4.7.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1)) + version: 4.7.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0)) autoprefixer: specifier: ^10.4.20 - version: 10.5.0(postcss@8.5.14) + version: 10.5.0(postcss@8.5.15) jsdom: specifier: ^25.0.1 version: 25.0.1 postcss: specifier: ^8.4.47 - version: 8.5.14 + version: 8.5.15 tailwindcss: specifier: ^3.4.13 version: 3.4.19(yaml@2.9.0) @@ -198,10 +198,10 @@ importers: version: 5.9.3 vite: specifier: ^5.4.8 - version: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1) + version: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0) vitest: specifier: ^2.1.2 - version: 2.1.9(@types/node@24.12.4)(jsdom@25.0.1)(lightningcss@1.32.0)(terser@5.47.1) + version: 2.1.9(@types/node@24.12.4)(jsdom@25.0.1)(lightningcss@1.32.0)(terser@5.48.0) apps/edr-freight-web/portal: dependencies: @@ -213,13 +213,13 @@ importers: version: link:../../../packages/ui-common '@tanstack/react-query': specifier: ^5.59.0 - version: 5.100.10(react@18.3.1) + version: 5.100.11(react@18.3.1) '@tria-plc/iamui-common': specifier: 1.0.3 - version: 1.0.3(9c106f46deace9660b1e6a7145f91ebf) + version: 1.0.3(29e1b902a5d7eebd7a61a744bc03492c) axios: specifier: ^1.7.7 - version: 1.16.0 + version: 1.16.1 clsx: specifier: ^2.1.1 version: 2.1.1 @@ -234,7 +234,7 @@ importers: version: 6.30.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) zustand: specifier: ^5.0.0 - version: 5.0.13(@types/react@18.3.28)(immer@11.1.8)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) + version: 5.0.13(@types/react@18.3.29)(immer@11.1.8)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) devDependencies: '@edr/eslint-config': specifier: workspace:* @@ -244,22 +244,22 @@ importers: version: link:../../../packages/config/tsconfig '@types/react': specifier: ^18.3.11 - version: 18.3.28 + version: 18.3.29 '@types/react-dom': specifier: ^18.3.0 - version: 18.3.7(@types/react@18.3.28) + version: 18.3.7(@types/react@18.3.29) '@vitejs/plugin-react': specifier: ^4.3.2 - version: 4.7.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1)) + version: 4.7.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0)) autoprefixer: specifier: ^10.4.20 - version: 10.5.0(postcss@8.5.14) + version: 10.5.0(postcss@8.5.15) jsdom: specifier: ^25.0.1 version: 25.0.1 postcss: specifier: ^8.4.47 - version: 8.5.14 + version: 8.5.15 tailwindcss: specifier: ^3.4.13 version: 3.4.19(yaml@2.9.0) @@ -268,49 +268,49 @@ importers: version: 5.9.3 vite: specifier: ^5.4.8 - version: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1) + version: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0) vitest: specifier: ^2.1.2 - version: 2.1.9(@types/node@24.12.4)(jsdom@25.0.1)(lightningcss@1.32.0)(terser@5.47.1) + version: 2.1.9(@types/node@24.12.4)(jsdom@25.0.1)(lightningcss@1.32.0)(terser@5.48.0) apps/edr-passenger-api: dependencies: '@nestjs/axios': specifier: ^4.0.1 - version: 4.0.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.16.0)(rxjs@7.8.2) + version: 4.0.1(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.16.1)(rxjs@7.8.2) '@nestjs/common': specifier: ^11.0.0 - version: 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/config': specifier: ^4.0.4 - version: 4.0.4(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2) + version: 4.0.4(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2) '@nestjs/core': specifier: ^11.1.19 - version: 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.19)(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.23)(@nestjs/platform-express@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/event-emitter': specifier: ^2.0.4 - version: 2.1.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19) + version: 2.1.1(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23) '@nestjs/jwt': specifier: ^10.2.0 - version: 10.2.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)) + version: 10.2.0(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)) '@nestjs/passport': specifier: ^10.0.3 - version: 10.0.3(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0) + version: 10.0.3(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0) '@nestjs/platform-express': specifier: ^11.1.19 - version: 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19) + version: 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23) '@nestjs/schedule': specifier: ^6.1.3 - version: 6.1.3(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19) + version: 6.1.3(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23) '@nestjs/swagger': specifier: ^7.4.0 - version: 7.4.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) + version: 7.4.2(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) '@sendgrid/mail': specifier: ^8.1.0 version: 8.1.6 axios: specifier: ^1.7.7 - version: 1.16.0 + version: 1.16.1 bcrypt: specifier: ^5.1.1 version: 5.1.1 @@ -356,7 +356,7 @@ importers: version: 11.1.0(chokidar@4.0.3)(prettier@3.8.3)(typescript@5.9.3) '@nestjs/testing': specifier: ^11.1.19 - version: 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(@nestjs/microservices@11.1.19)(@nestjs/platform-express@11.1.19) + version: 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(@nestjs/microservices@11.1.23)(@nestjs/platform-express@11.1.23) '@prisma/client': specifier: ^6.19.3 version: 6.19.3(prisma@6.19.3(typescript@5.9.3))(typescript@5.9.3) @@ -389,7 +389,7 @@ importers: version: 7.2.2 ts-jest: specifier: ^29.1.1 - version: 29.4.9(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.41)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.11(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.41)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)))(typescript@5.9.3) ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@20.19.41)(typescript@5.9.3) @@ -407,10 +407,10 @@ importers: version: link:../../../packages/ui-common '@tanstack/react-query': specifier: ^5.59.0 - version: 5.100.10(react@18.3.1) + version: 5.100.11(react@18.3.1) axios: specifier: ^1.7.7 - version: 1.16.0 + version: 1.16.1 clsx: specifier: ^2.1.1 version: 2.1.1 @@ -425,7 +425,7 @@ importers: version: 6.30.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) zustand: specifier: ^5.0.0 - version: 5.0.13(@types/react@18.3.28)(immer@11.1.8)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) + version: 5.0.13(@types/react@18.3.29)(immer@11.1.8)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) devDependencies: '@edr/eslint-config': specifier: workspace:* @@ -435,22 +435,22 @@ importers: version: link:../../../packages/config/tsconfig '@types/react': specifier: ^18.3.11 - version: 18.3.28 + version: 18.3.29 '@types/react-dom': specifier: ^18.3.0 - version: 18.3.7(@types/react@18.3.28) + version: 18.3.7(@types/react@18.3.29) '@vitejs/plugin-react': specifier: ^4.3.2 - version: 4.7.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1)) + version: 4.7.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0)) autoprefixer: specifier: ^10.4.20 - version: 10.5.0(postcss@8.5.14) + version: 10.5.0(postcss@8.5.15) jsdom: specifier: ^25.0.1 version: 25.0.1 postcss: specifier: ^8.4.47 - version: 8.5.14 + version: 8.5.15 tailwindcss: specifier: ^3.4.13 version: 3.4.19(yaml@2.9.0) @@ -459,10 +459,10 @@ importers: version: 5.9.3 vite: specifier: ^5.4.8 - version: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1) + version: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0) vitest: specifier: ^2.1.2 - version: 2.1.9(@types/node@24.12.4)(jsdom@25.0.1)(lightningcss@1.32.0)(terser@5.47.1) + version: 2.1.9(@types/node@24.12.4)(jsdom@25.0.1)(lightningcss@1.32.0)(terser@5.48.0) apps/edr-passenger-web/portal: dependencies: @@ -474,10 +474,10 @@ importers: version: link:../../../packages/ui-common '@tanstack/react-query': specifier: ^5.59.0 - version: 5.100.10(react@18.3.1) + version: 5.100.11(react@18.3.1) axios: specifier: ^1.7.7 - version: 1.16.0 + version: 1.16.1 clsx: specifier: ^2.1.1 version: 2.1.1 @@ -492,7 +492,7 @@ importers: version: 6.30.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) zustand: specifier: ^5.0.0 - version: 5.0.13(@types/react@18.3.28)(immer@11.1.8)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) + version: 5.0.13(@types/react@18.3.29)(immer@11.1.8)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) devDependencies: '@edr/eslint-config': specifier: workspace:* @@ -502,22 +502,22 @@ importers: version: link:../../../packages/config/tsconfig '@types/react': specifier: ^18.3.11 - version: 18.3.28 + version: 18.3.29 '@types/react-dom': specifier: ^18.3.0 - version: 18.3.7(@types/react@18.3.28) + version: 18.3.7(@types/react@18.3.29) '@vitejs/plugin-react': specifier: ^4.3.2 - version: 4.7.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1)) + version: 4.7.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0)) autoprefixer: specifier: ^10.4.20 - version: 10.5.0(postcss@8.5.14) + version: 10.5.0(postcss@8.5.15) jsdom: specifier: ^25.0.1 version: 25.0.1 postcss: specifier: ^8.4.47 - version: 8.5.14 + version: 8.5.15 tailwindcss: specifier: ^3.4.13 version: 3.4.19(yaml@2.9.0) @@ -526,10 +526,10 @@ importers: version: 5.9.3 vite: specifier: ^5.4.8 - version: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1) + version: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0) vitest: specifier: ^2.1.2 - version: 2.1.9(@types/node@24.12.4)(jsdom@25.0.1)(lightningcss@1.32.0)(terser@5.47.1) + version: 2.1.9(@types/node@24.12.4)(jsdom@25.0.1)(lightningcss@1.32.0)(terser@5.48.0) packages/api-common: dependencies: @@ -545,10 +545,10 @@ importers: version: link:../config/tsconfig '@nestjs/common': specifier: ^11.0.0 - version: 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/core': specifier: ^11.0.0 - version: 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.19)(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.23)(@nestjs/platform-express@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@types/node': specifier: ^20.14.0 version: 20.19.41 @@ -560,7 +560,7 @@ importers: version: 7.8.2 typeorm: specifier: ^0.3.20 - version: 0.3.29(babel-plugin-macros@3.1.0)(mysql2@3.15.3)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) + version: 0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) typescript: specifier: ^5.5.4 version: 5.9.3 @@ -569,10 +569,10 @@ importers: devDependencies: '@typescript-eslint/eslint-plugin': specifier: ^8.8.0 - version: 8.59.3(@typescript-eslint/parser@8.59.3(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3) + version: 8.59.4(@typescript-eslint/parser@8.59.4(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.8.0 - version: 8.59.3(eslint@8.57.1)(typescript@5.9.3) + version: 8.59.4(eslint@8.57.1)(typescript@5.9.3) eslint: specifier: ^8.57.0 version: 8.57.1 @@ -581,7 +581,7 @@ importers: version: 9.1.2(eslint@8.57.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.59.3(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1) + version: 2.32.0(@typescript-eslint/parser@8.59.4(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1) eslint-plugin-react: specifier: ^7.37.1 version: 7.37.5(eslint@8.57.1) @@ -625,10 +625,10 @@ importers: version: link:../config/tsconfig '@types/react': specifier: ^18.3.11 - version: 18.3.28 + version: 18.3.29 '@types/react-dom': specifier: ^18.3.0 - version: 18.3.7(@types/react@18.3.28) + version: 18.3.7(@types/react@18.3.29) react: specifier: ^18.3.1 version: 18.3.1 @@ -968,8 +968,8 @@ packages: resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} engines: {node: '>=18'} - '@date-fns/tz@1.4.1': - resolution: {integrity: sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==} + '@date-fns/tz@1.5.0': + resolution: {integrity: sha512-lwYN/vDPeNRULcepoE/LO2Pgx+7/RV+S9ARfbc9lr2DtGkOD7pAiruHvbR1RX3Qyf6ja47EWJDMsNK5vK08DJg==} '@emotion/babel-plugin@11.13.5': resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} @@ -1181,10 +1181,15 @@ packages: resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@humanwhocodes/config-array@0.13.0': - resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead + '@faker-js/faker@10.4.0': + resolution: {integrity: sha512-sDBWI3yLy8EcDzgobvJTWq1MJYzAkQdpjXuPukga9wXonhpMRvd1Izuo2Qgwey2OiEoRIBr35RMU9HJRoOHzpw==} + engines: {node: ^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0, npm: '>=10'} + + '@fast-csv/format@4.3.5': + resolution: {integrity: sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==} + + '@fast-csv/parse@4.3.6': + resolution: {integrity: sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==} '@floating-ui/core@1.7.5': resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} @@ -1374,6 +1379,12 @@ packages: '@types/node': optional: true + '@internationalized/date@3.12.0': + resolution: {integrity: sha512-/PyIMzK29jtXaGU23qTvNZxvBXRtKbNnGDFD+PY6CZw/Y8Ex8pFUzkuCJCG9aOqmShjqhS9mPqP6Dk5onQY8rQ==} + + '@internationalized/number@3.6.5': + resolution: {integrity: sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g==} + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -1759,8 +1770,8 @@ packages: '@swc/core': optional: true - '@nestjs/common@11.1.19': - resolution: {integrity: sha512-qeiTt2tv+e5QyDKqG8HlVZb2wx64FEaSGFJouqTSRs+kG44iTfl3xlz1XqVped+rihx4hmjWgL5gkhtdK3E6+Q==} + '@nestjs/common@11.1.23': + resolution: {integrity: sha512-qKgEqwQXHIVu8TwiISmgbTrGHAFBsseP86KNolBZwAiHQryinJ5FPiDpp0ZJBBryY+WEMnsqaCa4TSxVuQEWug==} peerDependencies: class-transformer: '>=0.4.1' class-validator: '>=0.13.2' @@ -1778,8 +1789,8 @@ packages: '@nestjs/common': ^10.0.0 || ^11.0.0 rxjs: ^7.1.0 - '@nestjs/core@11.1.19': - resolution: {integrity: sha512-6nJkWa2efrYi+XlU686J9y5L7OvxpLVjT0T/sxRKE7Jvpffiihelup4WSvLvRhdHDjj/5SuoWEwqReXAaaeHmw==} + '@nestjs/core@11.1.23': + resolution: {integrity: sha512-Yd+mVFUilw4A6PzV7tyfiW+zrG2wmRXnFZVmNQA+fl1N0k6km4bhhNboxjLu//dzl+XiZI5AsOHHOTegzvOgNQ==} engines: {node: '>= 20'} peerDependencies: '@nestjs/common': ^11.0.0 @@ -1820,8 +1831,21 @@ packages: class-validator: optional: true - '@nestjs/microservices@11.1.19': - resolution: {integrity: sha512-3Oja56ydTlSaui19/i7gYM0MMqz/w4UR2aqZeL4K8B+Fq0Ztg3zHb8et76atToJGpSCevJLEsoEMOMaGgzRwfg==} + '@nestjs/mapped-types@2.1.1': + resolution: {integrity: sha512-SCCoMEJ6jdeI5h/N+KCVF1+pmg/hmEkNA5nHTS8Gvww7T/LCl4o1gFLinw2iQ60w7slFkszHcGLKGdazVI4F8A==} + peerDependencies: + '@nestjs/common': ^10.0.0 || ^11.0.0 + class-transformer: ^0.4.0 || ^0.5.0 + class-validator: ^0.13.0 || ^0.14.0 || ^0.15.0 + reflect-metadata: ^0.1.12 || ^0.2.0 + peerDependenciesMeta: + class-transformer: + optional: true + class-validator: + optional: true + + '@nestjs/microservices@11.1.23': + resolution: {integrity: sha512-iVPp3u274Xx6XAEbKPWDCzUHP6wlt7L7RXUIyIpf3caJ3ldFh/dG3uyHva1lgjHG+ukz+XCXafl1cx352TPW0w==} peerDependencies: '@grpc/grpc-js': '*' '@nestjs/common': ^11.0.0 @@ -1862,8 +1886,8 @@ packages: '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 passport: ^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0 - '@nestjs/platform-express@11.1.19': - resolution: {integrity: sha512-Vpdv8jyCQdThfoTx+UTn+DRYr6H6X02YUqcpZ3qP6G3ZUwtVp7eS+hoQPGd4UuCnlnFG8Wqr2J9bGEzQdi1rIg==} + '@nestjs/platform-express@11.1.23': + resolution: {integrity: sha512-7TQ9v2Z9lej8btTYK1VUVB3nZr0lXFNFiyI/iOc0jAOg31dHdpAWtnMMm9iUvyAfq/ssw7dsBhjCHOmEJJKr0A==} peerDependencies: '@nestjs/common': ^11.0.0 '@nestjs/core': ^11.0.0 @@ -1883,6 +1907,23 @@ packages: prettier: optional: true + '@nestjs/swagger@11.4.4': + resolution: {integrity: sha512-VaIo1ruV2G7b+f2zPzkBSUNy9a/WQ9sg8TLKhWlrTfg4O6U10M/PA7Xi6XMXadOVhwOqoesijba8jH3i/3adrA==} + peerDependencies: + '@fastify/static': ^8.0.0 || ^9.0.0 + '@nestjs/common': ^11.0.1 + '@nestjs/core': ^11.0.1 + class-transformer: '*' + class-validator: '*' + reflect-metadata: ^0.1.12 || ^0.2.0 + peerDependenciesMeta: + '@fastify/static': + optional: true + class-transformer: + optional: true + class-validator: + optional: true + '@nestjs/swagger@7.4.2': resolution: {integrity: sha512-Mu6TEn1M/owIvAx2B4DUQObQXqo2028R2s9rSZ/hJEgBK95+doTwS0DjmVA2wTeZTyVtXOoN7CsoM5pONBzvKQ==} peerDependencies: @@ -1900,8 +1941,8 @@ packages: class-validator: optional: true - '@nestjs/testing@11.1.19': - resolution: {integrity: sha512-/UFNWXvPEdu4v4DlC5oWLbGKmD27LehLK06b8oLzs6D6lf4vAQTdST8LRAXBadyMUQnVEQWMuBo3CtAVtlfXtQ==} + '@nestjs/testing@11.1.23': + resolution: {integrity: sha512-cpE+WzbZiUxT9Wd4TvYvfDFJ7LAGlFE4qCubIfpuqXuSQkjNJfLGfVv2wif1/2Ery1zXGPVH0yz/TQcctL10aA==} peerDependencies: '@nestjs/common': ^11.0.0 '@nestjs/core': ^11.0.0 @@ -1913,6 +1954,26 @@ packages: '@nestjs/platform-express': optional: true + '@nestjs/throttler@6.5.0': + resolution: {integrity: sha512-9j0ZRfH0QE1qyrj9JjIRDz5gQLPqq9yVC2nHsrosDVAfI5HHw08/aUAWx9DZLSdQf4HDkmhTTEGLrRFHENvchQ==} + peerDependencies: + '@nestjs/common': ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 + '@nestjs/core': ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 + reflect-metadata: ^0.1.13 || ^0.2.0 + + '@nestjs/typeorm@11.0.1': + resolution: {integrity: sha512-8rw/nKT0S+L+MkzgE9F2/mox7mAgsPlwfzmW9gsESN1lmQtIrVEfiiBwC2O8+guS1jBfQehJIdcdUj2OAp4VUQ==} + peerDependencies: + '@nestjs/common': ^10.0.0 || ^11.0.0 + '@nestjs/core': ^10.0.0 || ^11.0.0 + reflect-metadata: ^0.1.13 || ^0.2.0 + rxjs: ^7.2.0 + typeorm: ^0.3.0 || ^1.0.0-dev + + '@noble/ciphers@1.3.0': + resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} + engines: {node: ^14.21.3 || >=16} + '@noble/hashes@1.8.0': resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} @@ -1934,9 +1995,13 @@ packages: engines: {node: ^14.18.0 || >=16.10.0, npm: '>=5.10.0'} hasBin: true - '@onlyoffice/document-editor-react@2.1.1': - resolution: {integrity: sha512-b0SnFPmT+OEyJons18PPHpwtFABVCI4nr3gPtAAImar1PhN9tNc9703Yo5KPYsHhIgVq+FqHSWgunI9GJnKa5w==} + '@onlyoffice/doceditor-types@9.3.1': + resolution: {integrity: sha512-2RZEyes+TA/1PbxSGKU8kMQn0upImDgmA3osqvFux+KrUfAW41yB26ZZmA9zKGR57jYiyOuUBtSvFQsXn8C2dw==} + + '@onlyoffice/document-editor-react@2.2.0': + resolution: {integrity: sha512-SPgeJ1lK+I5mpcCUi6Qz98QVtlZR6axxCArgHoKNNBfFqXNmb6iDOf5Z1QUiVQ0xr57oo84D0ptyXZaF8K51nA==} peerDependencies: + '@onlyoffice/doceditor-types': '>=9.3.1' react: ^16.9.0 || ^17 || ^18 || ^19 react-dom: ^16.9.0 || ^17 || ^18 || ^19 @@ -1946,10 +2011,17 @@ packages: '@paralleldrive/cuid2@2.3.1': resolution: {integrity: sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==} + '@phc/format@1.0.0': + resolution: {integrity: sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==} + engines: {node: '>=10'} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@popperjs/core@2.11.8': + resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + '@prisma/client@6.19.3': resolution: {integrity: sha512-mKq3jQFhjvko5LTJFHGilsuQs+W+T3Gm451NzuTDGQxwCzwXHYnIu2zGkRoW+Exq3Rob7yp2MfzSrdIiZVhrBg==} engines: {node: '>=18.18'} @@ -1980,9 +2052,11 @@ packages: '@prisma/get-platform@6.19.3': resolution: {integrity: sha512-xFj1VcJ1N3MKooOQAGO0W5tsd0W2QzIvW7DD7c/8H14Zmp4jseeWAITm+w2LLoLrlhoHdPPh0NMZ8mfL6puoHA==} - '@remix-run/router@1.23.2': - resolution: {integrity: sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==} - engines: {node: '>=14.0.0'} + '@radix-ui/number@1.1.1': + resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} + + '@radix-ui/primitive@1.1.3': + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} '@radix-ui/react-accordion@1.2.12': resolution: {integrity: sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==} @@ -2760,8 +2834,8 @@ packages: '@react-pdf/types@2.11.1': resolution: {integrity: sha512-i9xQgfaDU9QoeNnbp6rltXCWg1huEh195rpOuN8cE4BZ2FuLdQrsIcb2dhFF9aOxXf+XBA6LOSpIW051MDD/bw==} - '@reduxjs/toolkit@2.11.2': - resolution: {integrity: sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==} + '@reduxjs/toolkit@2.12.0': + resolution: {integrity: sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw==} peerDependencies: react: ^16.9.0 || ^17.0.0 || ^18 || ^19 react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 @@ -2778,141 +2852,141 @@ packages: '@rolldown/pluginutils@1.0.0-beta.27': resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} - '@rollup/rollup-android-arm-eabi@4.60.3': - resolution: {integrity: sha512-x35CNW/ANXG3hE/EZpRU8MXX1JDN86hBb2wMGAtltkz7pc6cxgjpy1OMMfDosOQ+2hWqIkag/fGok1Yady9nGw==} + '@rollup/rollup-android-arm-eabi@4.60.4': + resolution: {integrity: sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.60.3': - resolution: {integrity: sha512-xw3xtkDApIOGayehp2+Rz4zimfkaX65r4t47iy+ymQB2G4iJCBBfj0ogVg5jpvjpn8UWn/+q9tprxleYeNp3Hw==} + '@rollup/rollup-android-arm64@4.60.4': + resolution: {integrity: sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.60.3': - resolution: {integrity: sha512-vo6Y5Qfpx7/5EaamIwi0WqW2+zfiusVihKatLvtN1VFVy3D13uERk/6gZLU1UiHRL6fDXqj/ELIeVRGnvcTE1g==} + '@rollup/rollup-darwin-arm64@4.60.4': + resolution: {integrity: sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.60.3': - resolution: {integrity: sha512-D+0QGcZhBzTN82weOnsSlY7V7+RMmPuF1CkbxyMAGE8+ZHeUjyb76ZiWmBlCu//AQQONvxcqRbwZTajZKqjuOw==} + '@rollup/rollup-darwin-x64@4.60.4': + resolution: {integrity: sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.60.3': - resolution: {integrity: sha512-6HnvHCT7fDyj6R0Ph7A6x8dQS/S38MClRWeDLqc0MdfWkxjiu1HSDYrdPhqSILzjTIC/pnXbbJbo+ft+gy/9hQ==} + '@rollup/rollup-freebsd-arm64@4.60.4': + resolution: {integrity: sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.60.3': - resolution: {integrity: sha512-KHLgC3WKlUYW3ShFKnnosZDOJ0xjg9zp7au3sIm2bs/tGBeC2ipmvRh/N7JKi0t9Ue20C0dpEshi8WUubg+cnA==} + '@rollup/rollup-freebsd-x64@4.60.4': + resolution: {integrity: sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.60.3': - resolution: {integrity: sha512-DV6fJoxEYWJOvaZIsok7KrYl0tPvga5OZ2yvKHNNYyk/2roMLqQAbGhr78EQ5YhHpnhLKJD3S1WFusAkmUuV5g==} + '@rollup/rollup-linux-arm-gnueabihf@4.60.4': + resolution: {integrity: sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.60.3': - resolution: {integrity: sha512-mQKoJAzvuOs6F+TZybQO4GOTSMUu7v0WdxEk24krQ/uUxXoPTtHjuaUuPmFhtBcM4K0ons8nrE3JyhTuCFtT/w==} + '@rollup/rollup-linux-arm-musleabihf@4.60.4': + resolution: {integrity: sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.60.3': - resolution: {integrity: sha512-Whjj2qoiJ6+OOJMGptTYazaJvjOJm+iKHpXQM1P3LzGjt7Ff++Tp7nH4N8J/BUA7R9IHfDyx4DJIflifwnbmIA==} + '@rollup/rollup-linux-arm64-gnu@4.60.4': + resolution: {integrity: sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.60.3': - resolution: {integrity: sha512-4YTNHKqGng5+yiZt3mg77nmyuCfmNfX4fPmyUapBcIk+BdwSwmCWGXOUxhXbBEkFHtoN5boLj/5NON+u5QC9tg==} + '@rollup/rollup-linux-arm64-musl@4.60.4': + resolution: {integrity: sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.60.3': - resolution: {integrity: sha512-SU3kNlhkpI4UqlUc2VXPGK9o886ZsSeGfMAX2ba2b8DKmMXq4AL7KUrkSWVbb7koVqx41Yczx6dx5PNargIrEA==} + '@rollup/rollup-linux-loong64-gnu@4.60.4': + resolution: {integrity: sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.60.3': - resolution: {integrity: sha512-6lDLl5h4TXpB1mTf2rQWnAk/LcXrx9vBfu/DT5TIPhvMhRWaZ5MxkIc8u4lJAmBo6klTe1ywXIUHFjylW505sg==} + '@rollup/rollup-linux-loong64-musl@4.60.4': + resolution: {integrity: sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==} cpu: [loong64] os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.60.3': - resolution: {integrity: sha512-BMo8bOw8evlup/8G+cj5xWtPyp93xPdyoSN16Zy90Q2QZ0ZYRhCt6ZJSwbrRzG9HApFabjwj2p25TUPDWrhzqQ==} + '@rollup/rollup-linux-ppc64-gnu@4.60.4': + resolution: {integrity: sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.60.3': - resolution: {integrity: sha512-E0L8X1dZN1/Rph+5VPF6Xj2G7JJvMACVXtamTJIDrVI44Y3K+G8gQaMEAavbqCGTa16InptiVrX6eM6pmJ+7qA==} + '@rollup/rollup-linux-ppc64-musl@4.60.4': + resolution: {integrity: sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==} cpu: [ppc64] os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.60.3': - resolution: {integrity: sha512-oZJ/WHaVfHUiRAtmTAeo3DcevNsVvH8mbvodjZy7D5QKvCefO371SiKRpxoDcCxB3PTRTLayWBkvmDQKTcX/sw==} + '@rollup/rollup-linux-riscv64-gnu@4.60.4': + resolution: {integrity: sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.60.3': - resolution: {integrity: sha512-Dhbyh7j9FybM3YaTgaHmVALwA8AkUwTPccyCQ79TG9AJUsMQqgN1DDEZNr4+QUfwiWvLDumW5vdwzoeUF+TNxQ==} + '@rollup/rollup-linux-riscv64-musl@4.60.4': + resolution: {integrity: sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.60.3': - resolution: {integrity: sha512-cJd1X5XhHHlltkaypz1UcWLA8AcoIi1aWhsvaWDskD1oz2eKCypnqvTQ8ykMNI0RSmm7NkTdSqSSD7zM0xa6Ig==} + '@rollup/rollup-linux-s390x-gnu@4.60.4': + resolution: {integrity: sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.60.3': - resolution: {integrity: sha512-DAZDBHQfG2oQuhY7mc6I3/qB4LU2fQCjRvxbDwd/Jdvb9fypP4IJ4qmtu6lNjes6B531AI8cg1aKC2di97bUxA==} + '@rollup/rollup-linux-x64-gnu@4.60.4': + resolution: {integrity: sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.60.3': - resolution: {integrity: sha512-cRxsE8c13mZOh3vP+wLDxpQBRrOHDIGOWyDL93Sy0Ga8y515fBcC2pjUfFwUe5T7tqvTvWbCpg1URM/AXdWIXA==} + '@rollup/rollup-linux-x64-musl@4.60.4': + resolution: {integrity: sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.60.3': - resolution: {integrity: sha512-QaWcIgRxqEdQdhJqW4DJctsH6HCmo5vHxY0krHSX4jMtOqfzC+dqDGuHM87bu4H8JBeibWx7jFz+h6/4C8wA5Q==} + '@rollup/rollup-openbsd-x64@4.60.4': + resolution: {integrity: sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.60.3': - resolution: {integrity: sha512-AaXwSvUi3QIPtroAUw1t5yHGIyqKEXwH54WUocFolZhpGDruJcs8c+xPNDRn4XiQsS7MEwnYsHW2l0MBLDMkWg==} + '@rollup/rollup-openharmony-arm64@4.60.4': + resolution: {integrity: sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.60.3': - resolution: {integrity: sha512-65LAKM/bAWDqKNEelHlcHvm2V+Vfb8C6INFxQXRHCvaVN1rJfwr4NvdP4FyzUaLqWfaCGaadf6UbTm8xJeYfEg==} + '@rollup/rollup-win32-arm64-msvc@4.60.4': + resolution: {integrity: sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.60.3': - resolution: {integrity: sha512-EEM2gyhBF5MFnI6vMKdX1LAosE627RGBzIoGMdLloPZkXrUN0Ckqgr2Qi8+J3zip/8NVVro3/FjB+tjhZUgUHA==} + '@rollup/rollup-win32-ia32-msvc@4.60.4': + resolution: {integrity: sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.60.3': - resolution: {integrity: sha512-E5Eb5H/DpxaoXH++Qkv28RcUJboMopmdDUALBczvHMf7hNIxaDZqwY5lK12UK1BHacSmvupoEWGu+n993Z0y1A==} + '@rollup/rollup-win32-x64-gnu@4.60.4': + resolution: {integrity: sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.60.3': - resolution: {integrity: sha512-hPt/bgL5cE+Qp+/TPHBqptcAgPzgj46mPcg/16zNUmbQk0j+mOEQV/+Lqu8QRtDV3Ek95Q6FeFITpuhl6OTsAA==} + '@rollup/rollup-win32-x64-msvc@4.60.4': + resolution: {integrity: sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==} cpu: [x64] os: [win32] @@ -3064,20 +3138,20 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 || ^7 || ^8 - '@tanstack/query-core@5.100.10': - resolution: {integrity: sha512-8UR0yJR+GiQ40m3lPhUr0xbfAupe6GSQiksSBSa9SM2NjezFyxXCIA69/lz8cSoNKZLrw1/PktIyQBJcVeMi3w==} + '@tanstack/query-core@5.100.11': + resolution: {integrity: sha512-lmE0994apShXPj8CUxgx4ch5yUJhE9k/+tVwihBvPOyerACWdBocfFg24t8+0RhtlTd7tEgchDkhlCxNssvDxw==} - '@tanstack/query-devtools@5.100.10': - resolution: {integrity: sha512-3DmJf25hDPus5IpVvp6ujXv6bKV2zPzI9vpbAmpJigsL/H6DPvPjmf7/Q9yVKEke//8fgeQ45abjgnLuyYxAiw==} + '@tanstack/query-devtools@5.100.11': + resolution: {integrity: sha512-47rVBDuGMW/A4ekt3YQdz+q0JSIwktwGnWCYyQUvSs2/g/Oa+6Fi2/IQk4/Y4vf6u1uwI7hOogHslgMC8f3X/Q==} - '@tanstack/react-query-devtools@5.100.10': - resolution: {integrity: sha512-zes0+o9ef5rAZXJ9f/SeaLs2nufJaeVkZkl/Or9NGrWVF41kL9Od9ED9nCwtQlgiF2VGtrzhEw5AU/igAO+aAg==} + '@tanstack/react-query-devtools@5.100.11': + resolution: {integrity: sha512-75RFlJEG53Ed/Cxe5WLmgIpOElPNpgLZq7h0fLFnM5XwTYxSTk1rX/gC6MqGVXsSdrbP7zn7hPSJx9MinwiUHA==} peerDependencies: - '@tanstack/react-query': ^5.100.10 + '@tanstack/react-query': ^5.100.11 react: ^18 || ^19 - '@tanstack/react-query@5.100.10': - resolution: {integrity: sha512-FLaZf2RCrA/Zgp4aiu5tG3TyasTRO7aZ99skxQpr3Hg/zXOhu6yq5FZCYQ/tRaJtM9ylnoK8tFK7PolXQadv6Q==} + '@tanstack/react-query@5.100.11': + resolution: {integrity: sha512-J0f9s5x3LE1450nNNfYx+e/n0DMa0uOBdFJUy5r0RvmsXd4nB/n0rbHtHI1vYXhikNFan+wf51p6Tmp4c8ucrg==} peerDependencies: react: ^18 || ^19 @@ -3102,179 +3176,179 @@ packages: tinymce: optional: true - '@tiptap/core@3.23.1': - resolution: {integrity: sha512-8YvSGiJTeU5wPuGiYIIYgyiyaaT1CAx+kJL0bju0w871OvbJJj0T/ywhcmxGXW6pOal2T8X2xt9ZqE+vib0VJw==} + '@tiptap/core@3.23.6': + resolution: {integrity: sha512-MRB3pHz4Oxqmcawh0cQ5iOGdY5xtNYp/1CoK7hdTLzw5K0C6/gTC2VvanB1R4INaB6EpBkxG/GiWkVirDRnuXw==} peerDependencies: - '@tiptap/pm': 3.23.1 + '@tiptap/pm': 3.23.6 - '@tiptap/extension-blockquote@3.23.1': - resolution: {integrity: sha512-FdVZLZOkL06j3WLXOC2UeX7++Cj3qI2vfohruMJiz4vk1Q5UUH7G4+AykFzjzBJHrdEpkiRUkRpU1KZIWdbluw==} + '@tiptap/extension-blockquote@3.23.6': + resolution: {integrity: sha512-2RmnqNqTltZ2k1F7IfjoDNs935Uq4rRDR7d98mqkg3OlDktcQIyBpv0t9dTay6H5bkQeZUuS8ogK2S1E8Edjug==} peerDependencies: - '@tiptap/core': 3.23.1 + '@tiptap/core': 3.23.6 - '@tiptap/extension-bold@3.23.1': - resolution: {integrity: sha512-EAYdNzyOjlQh2VBY1EhdxtiTjVMaOAD6P0ezms60dKRjd4oj/8grfXfUqwgo4NVdFb11Ks85vXoHuXJSylfR4A==} + '@tiptap/extension-bold@3.23.6': + resolution: {integrity: sha512-1LMhjnytdbbhWHSoOwnLxZAOQZWPkKyXVCNmaIk0Mhi4tLPUXptG4qKS5sVYTCveE5H6IBPFrbgBFi5dMI6krA==} peerDependencies: - '@tiptap/core': 3.23.1 + '@tiptap/core': 3.23.6 - '@tiptap/extension-bubble-menu@3.23.1': - resolution: {integrity: sha512-1advMCpPkHD/3ucZhYmNau8B4tF0L6iRAFhUOglp5bBZDuq13+rYujh3cm4vFmjH9KqThzpcUDn+ZU2c+mTMyw==} + '@tiptap/extension-bubble-menu@3.23.6': + resolution: {integrity: sha512-Mwkyp9LkDHFbqmWRIkp63FinRxFu3ajC4qSb9t4mnHsb4kAdbNLLsGtbFg+le0SWk4CxGwAOwM7SzeJ+6UGqCA==} peerDependencies: - '@tiptap/core': 3.23.1 - '@tiptap/pm': 3.23.1 + '@tiptap/core': 3.23.6 + '@tiptap/pm': 3.23.6 - '@tiptap/extension-bullet-list@3.23.1': - resolution: {integrity: sha512-owWnBBI4t+jqVDY0naDjhsAmrNGldh4czouef2K+mEf032B7uGsDVCwKp1qaX1JZesyYDfvXOaIwT22hNID2mw==} + '@tiptap/extension-bullet-list@3.23.6': + resolution: {integrity: sha512-RMRgfXZykr/13X8UBOwvpgysVOo9KchwqMoEbvqQSj4YFfU56iIn59C8sbxiQ1sKfeltUf0wH4fPc0I4iwKqAA==} peerDependencies: - '@tiptap/extension-list': 3.23.1 + '@tiptap/extension-list': 3.23.6 - '@tiptap/extension-code-block@3.23.1': - resolution: {integrity: sha512-BdJGqM57CsKgYrQUZz78vIG8Yn7EpsE2pA7iKn5tYoSXpYtt0IaU4qB1heH7lwWD/vVCAm0YQVD7/0F+0++yhA==} + '@tiptap/extension-code-block@3.23.6': + resolution: {integrity: sha512-4kccgcn5yHThxrzsIhJny3EwfEZYIk+BjUCL4uIuzOyWvExtGhZ6JMHVCZeMhI8D1/bX1LNkkAKN5DXPzH4lXQ==} peerDependencies: - '@tiptap/core': 3.23.1 - '@tiptap/pm': 3.23.1 + '@tiptap/core': 3.23.6 + '@tiptap/pm': 3.23.6 - '@tiptap/extension-code@3.23.1': - resolution: {integrity: sha512-nGuhb4YghgTfkejwWHrD9GSpwcC5kkVmm2sN/UY4yceDw+PkyysYKJWZehRLTOC8GNgSAhq/EeQeq14Xwk6dyg==} + '@tiptap/extension-code@3.23.6': + resolution: {integrity: sha512-KG8KXFYyLrtYvT7AZ1WGV61ofx8pDe5g9pH658MERxqQGii+Pyfc6xkz04l7XeBts/7+571UQp/0O7i/z560TA==} peerDependencies: - '@tiptap/core': 3.23.1 + '@tiptap/core': 3.23.6 - '@tiptap/extension-color@3.23.1': - resolution: {integrity: sha512-OYk/fT3h8Bz4B6GUVTQDvKGpPnpI5d6QHkuqjVhdFsgH3oo58PdLE1TdIGgeavuYPLaFxgBtEXmm3oTY9jPWxw==} + '@tiptap/extension-color@3.23.6': + resolution: {integrity: sha512-2WxYc+X+OGFXbq/Ak0VXODEzfK1l5wz33oTWSuhdSw44HAQM7+SSyiDnMCXDQdqi063ANqMmQmlw5WngjQ6wCA==} peerDependencies: - '@tiptap/extension-text-style': 3.23.1 + '@tiptap/extension-text-style': 3.23.6 - '@tiptap/extension-document@3.23.1': - resolution: {integrity: sha512-NA5Rx59HRwG6Hb6LwLpC5lE7z6vCj6f90S7RNNsnE+CyiXNR/OhY2BcjuxiGnascHvsnsAbvxGU3ymKMDgvDVg==} + '@tiptap/extension-document@3.23.6': + resolution: {integrity: sha512-XDAIgG9KcKumFM9KJWUEUhXPbFIhhl47bfy5GknareWTRKke85rcoj/oxKKO9ihLZr8JfpbXjqnS4SCm5yhYPw==} peerDependencies: - '@tiptap/core': 3.23.1 + '@tiptap/core': 3.23.6 - '@tiptap/extension-dropcursor@3.23.1': - resolution: {integrity: sha512-WRN7e/h9m3uI5j9/+L6jcPhHbTL6aKxfFfQWZHNf5M8TqSL1P+/2h034td0XMj3n48i4fWyzjVUV9+sz6t2fDw==} + '@tiptap/extension-dropcursor@3.23.6': + resolution: {integrity: sha512-+XWEoRKf3lXxi7Le1aOM2xU1XHwxICGpXjT3m4QaYqUgIpsq8gQEuso6kVg8DnTD7biKQs6+oIQ0o2b/gTW9WA==} peerDependencies: - '@tiptap/extensions': 3.23.1 + '@tiptap/extensions': 3.23.6 - '@tiptap/extension-floating-menu@3.23.1': - resolution: {integrity: sha512-XrYHpLn1DpLFSGTko9F9xgbNamL6fGpWkK4wqgwPVbg/SJwQCDO/9p5D3DtJTwD+xgw4sQ9as4O6rt6jx8JT+Q==} + '@tiptap/extension-floating-menu@3.23.6': + resolution: {integrity: sha512-2kjuDcEq69lEcECl75xqY5MyzUSh2zcC5aLrpwP1WwhJz5bxsIFHiaps5AP6h9R4A+ZBj5b2haay2Y1wDUU3VA==} peerDependencies: '@floating-ui/dom': ^1.0.0 - '@tiptap/core': 3.23.1 - '@tiptap/pm': 3.23.1 + '@tiptap/core': 3.23.6 + '@tiptap/pm': 3.23.6 - '@tiptap/extension-gapcursor@3.23.1': - resolution: {integrity: sha512-E4hB0xquUpEXy7kboLBazrFyRCsN0j0fsTFR8udgQf5xetAVPhOexSTKuzOcU/n0kxsKJin7laYYEag/Fd2KNw==} + '@tiptap/extension-gapcursor@3.23.6': + resolution: {integrity: sha512-wbKmxXsszxWacEkrHucRpSQbiKjz4fmOebD6OVyL9AcrmlbxNk8vcM3iyh/8cVeRy09XY+morM165t/u7/z4IQ==} peerDependencies: - '@tiptap/extensions': 3.23.1 + '@tiptap/extensions': 3.23.6 - '@tiptap/extension-hard-break@3.23.1': - resolution: {integrity: sha512-XYkCKC5RVqMmmBk+nd22/6IDDx1OC54sdStH5VEHtfOrarriO0JztK8Mr0TijPPk9N4rKXsmndYZM2xyWZZytQ==} + '@tiptap/extension-hard-break@3.23.6': + resolution: {integrity: sha512-KeUm+tkUfIVSX9QM9XOIhaay0Fn36sLKUo5NVYjN3uJaxFvaZXZmTlxdO85OTdgF2P5sqh9LomrIgliaFRGk4w==} peerDependencies: - '@tiptap/core': 3.23.1 + '@tiptap/core': 3.23.6 - '@tiptap/extension-heading@3.23.1': - resolution: {integrity: sha512-1z9yCSp8fevgX3r/4kWXO3of0WFCQWfYjWfHANvoJ4JQTYBkARjXlj1tbk5rrAJBFDDfKRkUpZOurXKgGo+h+g==} + '@tiptap/extension-heading@3.23.6': + resolution: {integrity: sha512-A/0jPhxnUh9THSZymlu0OGPZe1wdFdwHAXnRCmqvYUCwJjrG7LCC/ahzmcj1tcNzI9hgHyuYPSfev8RXYrNu/w==} peerDependencies: - '@tiptap/core': 3.23.1 + '@tiptap/core': 3.23.6 - '@tiptap/extension-highlight@3.23.1': - resolution: {integrity: sha512-Bf5u5KBb6SLveKzPgUEbHoU5uWTUcEvSSZr/mpQZpvCpE6MlXZbvengmFj1OkKnrNZWg0Um2p9e6zKnZHH07sA==} + '@tiptap/extension-highlight@3.23.6': + resolution: {integrity: sha512-GWv6R4iZzVrNeB33qtJDBt/BfVjuc5S/sUF/VDFAtK8h86bg4cEm1tGLEsui4T3+vij/t+P+eoGhkzF6NGogdg==} peerDependencies: - '@tiptap/core': 3.23.1 + '@tiptap/core': 3.23.6 - '@tiptap/extension-horizontal-rule@3.23.1': - resolution: {integrity: sha512-30XUHXdEZxcz1FCWjz9HW2EEq06NQcAye6rXGnvHo6Y60iJ6MRsrX5byvceFNF9DTVtOIcUFBQ/psIiRcoi0KA==} + '@tiptap/extension-horizontal-rule@3.23.6': + resolution: {integrity: sha512-hEUlz4H+I64r+TH6LCuNCRgO7JTHncXGmx9+WbU69EOfY8O0ZurcgeJc8HeiAKL+r9YuC1e5YHfFxgCaaC0jlg==} peerDependencies: - '@tiptap/core': 3.23.1 - '@tiptap/pm': 3.23.1 + '@tiptap/core': 3.23.6 + '@tiptap/pm': 3.23.6 - '@tiptap/extension-image@3.23.1': - resolution: {integrity: sha512-rAyfh8HS0PfXS8PKl1VQUiDFzXtF5SlrILpOPmz+4Oc4pmI+/vN+ain4z8k6HRxWM03YVpvLvyeQ0OFwi/fq3A==} + '@tiptap/extension-image@3.23.6': + resolution: {integrity: sha512-vvNGxArvD2dW+XvV0KdYovRVUzCy8QVNulc2r5pV7umnG1E6cCmMkiHiif8J2ePJu2KtysAvJQe0iF+UqueGMw==} peerDependencies: - '@tiptap/core': 3.23.1 + '@tiptap/core': 3.23.6 - '@tiptap/extension-italic@3.23.1': - resolution: {integrity: sha512-lZB9YCjoVNDoPMguya66nBvaS/2YpGN5iAcjAGx/JQkCAZeOAtl9+ALMzbWPKH6tQP6m98YtkY1T7RXr++T0bA==} + '@tiptap/extension-italic@3.23.6': + resolution: {integrity: sha512-wol5KdwCPAvpiYhH9PLlvO8ZnJHwZtIboVevrfOGgBcKlXRA3dedR4OAMXHnUtkkzu9KtliLg1+TYzEx4JZG9Q==} peerDependencies: - '@tiptap/core': 3.23.1 + '@tiptap/core': 3.23.6 - '@tiptap/extension-link@3.23.1': - resolution: {integrity: sha512-uOeyLqYQI0WG62agpFG24kVHSn3Z48gD8Y0uLLJbtzh/nDFC3d9So2sQGWlSVyMzsgkJ4k/9jNnxxsVO8qgJOg==} + '@tiptap/extension-link@3.23.6': + resolution: {integrity: sha512-KNZz7z7P2/qbQsx5bPAbSPjrKDg1VHsedGlLHJCr8U2VRD5VgmDLkMpkouP1CsDg15qgyUKv/nDib5KgPpLNWA==} peerDependencies: - '@tiptap/core': 3.23.1 - '@tiptap/pm': 3.23.1 + '@tiptap/core': 3.23.6 + '@tiptap/pm': 3.23.6 - '@tiptap/extension-list-item@3.23.1': - resolution: {integrity: sha512-Fk/884un5OSLCFxe2TbOmfp3sLMB5b76CnMjaSrvgfiaZnsV2WlJZGPXxCAPbxNIATTykNlSBsVuMBO7we64Vg==} + '@tiptap/extension-list-item@3.23.6': + resolution: {integrity: sha512-3zzyhdkUWcHVpXuvy6KiIwjh29rbH6gEDEqPQqHLrl1XGnO9pnShC7pSHctlCDjmcx3O4n9cd4QMtVBlUerbiA==} peerDependencies: - '@tiptap/extension-list': 3.23.1 + '@tiptap/extension-list': 3.23.6 - '@tiptap/extension-list-keymap@3.23.1': - resolution: {integrity: sha512-sHbE5sxiJzhgGn94GUAzD4qKM9SyImBrOlAGS/EIe+pausjqQE7xi+YW0gRo2jG+gXhSYl4/oAGXQXzmSInSUQ==} + '@tiptap/extension-list-keymap@3.23.6': + resolution: {integrity: sha512-x8bPcLViGzg/RAmQM/XtmfqIwQ/Pv9Q8mkd+OgfUiTqjeJqKwVQmiqbLFNa7zw81+H61M+HDU+qGAaQ3vRIMjw==} peerDependencies: - '@tiptap/extension-list': 3.23.1 + '@tiptap/extension-list': 3.23.6 - '@tiptap/extension-list@3.23.1': - resolution: {integrity: sha512-v1AeXPpagslgRZdOp7WdjCoO4TjjNP8RM2R6Gqx0/inGaNXnM8zCMshOxZlAb03Ad7kq/4RGJmkpM/Jjsi6dEQ==} + '@tiptap/extension-list@3.23.6': + resolution: {integrity: sha512-z6vj9+Qht2sjdQkyyHcUpsC/yCIZqTrQiyHDhs/HGKrfvoANyAZGpqdNeKf1wSyjIso+27tQuIH5NDfk8ygyNw==} peerDependencies: - '@tiptap/core': 3.23.1 - '@tiptap/pm': 3.23.1 + '@tiptap/core': 3.23.6 + '@tiptap/pm': 3.23.6 - '@tiptap/extension-ordered-list@3.23.1': - resolution: {integrity: sha512-3GG7YFhVJWw/HWmRxvMMUC296x7TPBQRLsH4ryEC1SMAmVJnbTIvetyvIcLqLEXGW7Rj41S7SO8qjOXVceSOTA==} + '@tiptap/extension-ordered-list@3.23.6': + resolution: {integrity: sha512-1m/wWB/ZtXcmG2vNdiUkCqsOgqv5vBjCv/mVaHhF9OvV+zQS8YDjoWE7zEuT/GgELdT77Xq8lHrn4nCDudB3/A==} peerDependencies: - '@tiptap/extension-list': 3.23.1 + '@tiptap/extension-list': 3.23.6 - '@tiptap/extension-paragraph@3.23.1': - resolution: {integrity: sha512-GC7b6yAjASl1q9sNkPmukZmVYMfxx03EEhpMMrLYJY9GBz82Ald927yYQsOqf2aKA/Rjo/aZMYCGtjXkGk6aBA==} + '@tiptap/extension-paragraph@3.23.6': + resolution: {integrity: sha512-+7m58LUSncodjrIyXks4RZ3tLNYrvgT77wRR4l3HnM5OABY3GDsDTqi7c1t1yI29NVOSk/DUacqy6UwYAj1DGg==} peerDependencies: - '@tiptap/core': 3.23.1 + '@tiptap/core': 3.23.6 - '@tiptap/extension-strike@3.23.1': - resolution: {integrity: sha512-+R5LG0ZW9SDZc4weA79uq6uUduVsCEph9tRcoQCRA82IVIiPYSTxTLew9odalmk/Mc7vdZvOK5jjtO5jUVw/rg==} + '@tiptap/extension-strike@3.23.6': + resolution: {integrity: sha512-oF7FEZ37f15aCe5kPgzGDYf/m+hr7VdQ/Ko/Hds/UM9pX7AG1fdtmRrl6wqkRqDM/incZaC/AQR2/Dpo2VCNGQ==} peerDependencies: - '@tiptap/core': 3.23.1 + '@tiptap/core': 3.23.6 - '@tiptap/extension-text-align@3.23.1': - resolution: {integrity: sha512-ap4ZN31v57mVX2P+0OoW5iO+ehsUNe0C5MgF/Ta2F/HRmTCc1M1mFqYUCk8zJYX1TFRV18vqK2j6STRBk0R8ng==} + '@tiptap/extension-text-align@3.23.6': + resolution: {integrity: sha512-pE+gDmvnrSMWHADDnDSzaO7YUi9kOywQkyrqZ9bEPLddZred7ICoJ4NtD2DqLjDSur+HijaJuByResWb78c6FA==} peerDependencies: - '@tiptap/core': 3.23.1 + '@tiptap/core': 3.23.6 - '@tiptap/extension-text-style@3.23.1': - resolution: {integrity: sha512-q3GQQo+lBhrtNkqdbhYWnv/byG/RYAxVnNhYPQMubRzavGdXBU8NhpJ/47YYjPimG1sahzcs2aqy7amVd8ri/A==} + '@tiptap/extension-text-style@3.23.6': + resolution: {integrity: sha512-Auasgj469wkQ5ip+Zi2gaRzvqxx9qKG58+1mkT8yPE3QAGnOIg/AaKyQ7pTV77UyL3FHvLnU+KsWCad+qcobww==} peerDependencies: - '@tiptap/core': 3.23.1 + '@tiptap/core': 3.23.6 - '@tiptap/extension-text@3.23.1': - resolution: {integrity: sha512-k1Ki9bBV6mLz1mFP+Laqh1YHJ2MY0P8XzaMqpkgMndEBIJQ3XcpWQc5bfAlRnYcOI9ZXDbAgQ8CwgArxHmQWCQ==} + '@tiptap/extension-text@3.23.6': + resolution: {integrity: sha512-ipoC2TkIAIOTiF5ByiGgvQB1DqDyfP90wrUB3mohBcgvp7lQnwHszCDGv8dNnmcUek8uXV/uoLu2VXeVQlxjPA==} peerDependencies: - '@tiptap/core': 3.23.1 + '@tiptap/core': 3.23.6 - '@tiptap/extension-underline@3.23.1': - resolution: {integrity: sha512-+PvHyVozHyxJ9oWCIQx5JHBZ7LAa/sFJUOFaKyfmel4gL9AbP52MmvrciXARlZHd1WCULJtdbLan0+x5/D/9hQ==} + '@tiptap/extension-underline@3.23.6': + resolution: {integrity: sha512-P55wGIZGYTVH92Fq0cgI4/O9AhLCaJC3hhxg15RSERP5/YegM9eJHDK/GQ1EE/DvYA+xpYGOV6agKwAUqfA/Iw==} peerDependencies: - '@tiptap/core': 3.23.1 + '@tiptap/core': 3.23.6 - '@tiptap/extensions@3.23.1': - resolution: {integrity: sha512-7UIn+idaVTVhdlP0KmgzBh8Csmwck357Dq4te5DuAxhSkN1gsXHlq39mpx907UYKJdSOgd+GMFeyOziPwSmbOQ==} + '@tiptap/extensions@3.23.6': + resolution: {integrity: sha512-X09/Db1teB+ifXzDGVVFmOeQRx7wTAayE9/280spxpsHkHZvJ5bHRvWIzUzviMIjbBz+NPDIKYPK7gMfh9iaig==} peerDependencies: - '@tiptap/core': 3.23.1 - '@tiptap/pm': 3.23.1 + '@tiptap/core': 3.23.6 + '@tiptap/pm': 3.23.6 - '@tiptap/pm@3.23.1': - resolution: {integrity: sha512-8G+TkNsUHHAAJYREpA6fw+Dw/m2Y3Go4/QMQM8RYepid+wTeE1wSv7sBA/CBrphhYmJSWeTyCPtgQIxnTJXMCA==} + '@tiptap/pm@3.23.6': + resolution: {integrity: sha512-in5CaMaWlJcH2A1q6GJKFtrodE8WLS3M9tIi/f89jPmIVHJShpodC0KZDNyJkrVBQomYk0DEh86Utm6ASXzQww==} - '@tiptap/react@3.23.1': - resolution: {integrity: sha512-43zUwKOcsxRIcgiDbcEUagojhPIez2OIryaNG/uiDcRzkrUteiTu2wSJndkQqwouwh3wJEm+KOw8xybNYvU+qA==} + '@tiptap/react@3.23.6': + resolution: {integrity: sha512-Tw9KZkYqFMk3vaJAEQKqEYIO/iq3cSJe7OUEGBul4k4GaMQeLItLf5EYhUd0GIPXci1WVVPNntKJsHfX25M37w==} peerDependencies: - '@tiptap/core': 3.23.1 - '@tiptap/pm': 3.23.1 + '@tiptap/core': 3.23.6 + '@tiptap/pm': 3.23.6 '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 '@types/react-dom': ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tiptap/starter-kit@3.23.1': - resolution: {integrity: sha512-CURePHQagBaZIDJrHH3of4Nmi0VYGpZ6yBlkdFxFHBxY9aeG2/h5kn+oHo8GbzkSFsRV+9olzRgDTOULVgs8pQ==} + '@tiptap/starter-kit@3.23.6': + resolution: {integrity: sha512-gykwtGWrnWCmtql1hid3opac/KV8zQvOAnu3bTqIqcHrn1FusbUwKmNzavSbfGvcktHM3hFjb35W48JyVLyu/A==} '@tokenizer/inflate@0.4.1': resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} @@ -3335,33 +3409,33 @@ packages: '@tsconfig/node16@1.0.4': resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - '@turbo/darwin-64@2.9.12': - resolution: {integrity: sha512-eu3eFRmE9NjgZ0wPdRJ44l+LGSeIky+tz5ZQd8zQkw/Yqi+BM7wq+8nbabeoiVUcICi/IZweMOKl/MCmkrd1+g==} + '@turbo/darwin-64@2.9.14': + resolution: {integrity: sha512-t7QiPflaEyBE4oayeZtSmu4mEfjgIrcNlNNl1z1dmIVPqEdtA7+CfTf8d7KXsOGPh6aNgWjKxyvQg9uGfDQF+A==} cpu: [x64] os: [darwin] - '@turbo/darwin-arm64@2.9.12': - resolution: {integrity: sha512-RUkAE404z/J8NsyrUosMcBaXT6M4bRFxTQrmkDQBLQVXaC8Jl0e9bMvYDSX0GW7Ffm2m3j9y7RXgR1foeUAM9w==} + '@turbo/darwin-arm64@2.9.14': + resolution: {integrity: sha512-d23147mC9BsCPA9mJ0h/ubcpbRgcJBXbcG3+Vq7YLhjz3IXuvQsJ1UXH8f4MD76ZjJ4m/E4aRdJV+MW88CDfbw==} cpu: [arm64] os: [darwin] - '@turbo/linux-64@2.9.12': - resolution: {integrity: sha512-InIUtH7cw/vqXNX1Gr7QgWfmw3ct08pV5CpfdEOR48z2u2rzdmpIuk00B/Q2xCb0PMWtKgiMQynfuphmEuUyTQ==} + '@turbo/linux-64@2.9.14': + resolution: {integrity: sha512-P3ZKB5tuUDdDQWuAsACGUR1qv9W7BNWxdxqVJ0kZNuNNPRaVYTPPikLcp79+GiEcW3npsR+KyP38lnQiBc5aSA==} cpu: [x64] os: [linux] - '@turbo/linux-arm64@2.9.12': - resolution: {integrity: sha512-lC6nD//Xh67fmJM0LKaLsg74Wry0aYrgMklpiNgCbUaMdPIOqj0A00iri3NU7Lb7pZHx8ViisgpeDKlpSgFUCA==} + '@turbo/linux-arm64@2.9.14': + resolution: {integrity: sha512-ZRTlzcUMrrPv9ZuDzRF9n60Ym13bKeG9jDB8WjxyLhWNzV+AJQN+zdpIk3NJYf2zQsGUm1mNar2P0elRzLw25g==} cpu: [arm64] os: [linux] - '@turbo/windows-64@2.9.12': - resolution: {integrity: sha512-conYri8VUl72JOdYnLDPYwzqbPcY5ECoHmo9FWoKznemhaAIilj4maHqs9Uar0aKfNoZIULniy+6iWaLtLO34A==} + '@turbo/windows-64@2.9.14': + resolution: {integrity: sha512-exanwN6sIduZwykYeiTQj8kCmOhazP5WOz3bvXMcYtjhL6Z3iRWLewKrXCBq0bqwSP3iBMb/AerRCnHI4lx46A==} cpu: [x64] os: [win32] - '@turbo/windows-arm64@2.9.12': - resolution: {integrity: sha512-XoR4bsg62/L/esRVcmoMESEiNZ36+YmyjYGLpoqk8nwMgXzzVjNOgX0lRSz5w/U/ajLGv3nhMsS0Q2QOdvp2AQ==} + '@turbo/windows-arm64@2.9.14': + resolution: {integrity: sha512-fVdCsnmYoKICsycbWuuGp6Jvi51/3G/UluFWuAUCvR8PIW5IJkAk5BM9UF8PSm0Q2IphWHFZjYEgjHsh3B9y/g==} cpu: [arm64] os: [win32] @@ -3533,8 +3607,8 @@ packages: peerDependencies: '@types/react': '*' - '@types/react@18.3.28': - resolution: {integrity: sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==} + '@types/react@18.3.29': + resolution: {integrity: sha512-ch0qJdr2JY0r04NXSprbK6TXOgnaJ1Tz23fm5W+z0/CBah6BSBc3n96h7K9GOtwh0HrilNWHIBzE1Ko4Dcw/Wg==} '@types/send@1.2.1': resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} @@ -3548,8 +3622,8 @@ packages: '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} - '@types/superagent@8.1.9': - resolution: {integrity: sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==} + '@types/superagent@8.1.10': + resolution: {integrity: sha512-nbt4IWXABhW0jGmmpRzCFNlbmwCTzZ2gTUsNIr+X+ItdqPms+PAJZbWsNzpS2USqXjcoNLQcO6nXo60zcPQiIg==} '@types/supertest@6.0.3': resolution: {integrity: sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==} @@ -3572,63 +3646,63 @@ packages: '@types/yargs@17.0.35': resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} - '@typescript-eslint/eslint-plugin@8.59.3': - resolution: {integrity: sha512-PwFvSKsXGShKGW6n5bZOhGHEcCZXM8HofLK9fNsEwZXzFRjoY+XT1Vsf1zgyXdwTr0ZYz1/2tkZ0DBTT9jZjhw==} + '@typescript-eslint/eslint-plugin@8.59.4': + resolution: {integrity: sha512-PegsU+XfyJJNjd4+u/k6f9yTyp0lEXXiPopUNobZcIAUJFGICFLN+sP0Rb3JehVmiij1Ph0dFGYqODoRo/2+6A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.59.3 + '@typescript-eslint/parser': ^8.59.4 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.59.3': - resolution: {integrity: sha512-HPwA+hVkfcriajbNvTmZv4VRauibay+cWArYUYq7u7W7PmGShMxbPxLvrwDme55a6d5alG3nrYfhyJ/G28XlLg==} + '@typescript-eslint/parser@8.59.4': + resolution: {integrity: sha512-zORHqO/tuhxY1zWuTvMUqddRxpiFJ72xVfcNoWpqdLjs6lfPbuQBJuW4pk+49/uBMy7Ssr4bzgjiKmmDB1UbZQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.59.3': - resolution: {integrity: sha512-ECiUWa/KYRGDFUqTNehaRgzDshnJfkTABJxVemHk4ko22gcr0ukloKjWvyQ64g8YCV/UI47kN1dbmjf/GaQYng==} + '@typescript-eslint/project-service@8.59.4': + resolution: {integrity: sha512-Ly00Vu4oAacfDeHp2Zg85ioNG6l8HG+tN1D7J+xTHSxu9y0awYKJ2zH1rFBn8ZSfuGK+7FxK3Cgl3uAz0aZZLg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.59.3': - resolution: {integrity: sha512-t2LvZnoEfzKtnPjgeEu41xw5gxq9mQVfYy4OoZ4Vlt0sk3JwxmhCca/AR7DwOiHrjWgjAj6as4AhRLKSDfvZIA==} + '@typescript-eslint/scope-manager@8.59.4': + resolution: {integrity: sha512-mUeR/3H1WrTAddJrwut8OoPjfauaztMQmRwV5fQTUyNVJCLiUXXe4lGEyYIL2oFDpP7UtgbGJXCt72wT0z2S3Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.59.3': - resolution: {integrity: sha512-PcIJHjmaREXLgIAIzLnSY9VucEzz8FKXsRgFa1DmdGCK/5tJpW03TKJF01Q6VZd1lLdz2sIKPWaDUZN9dp//dw==} + '@typescript-eslint/tsconfig-utils@8.59.4': + resolution: {integrity: sha512-DLCpnKgD4alVxTBSKulK+gU1KCqOgUXfDRDXh2mZgzokQKa/70ax93I2uVO3m/LLvIAtWZIFoiifudmIqAxpMA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.59.3': - resolution: {integrity: sha512-g71d8QD8UaiHGvrJwyIS1hCX5r63w6Jll+4VEYhEAHXTDIqX1JgxhTAbEHtKntL9kuc4jRo7/GWw5xfCepSccQ==} + '@typescript-eslint/type-utils@8.59.4': + resolution: {integrity: sha512-uonTuPAAKr9XaBGqJ3LjYTh72zy5DyGesljO9gtmk/eFW0W1fRHjnwVYKB35Lm8d5Q5CluEW3gPHjTvZTmgrfA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.59.3': - resolution: {integrity: sha512-ePFoH0g4ludssdRFqqDxQePCxU4WQyRa9+XVwjm7yLn0FKhMeoetC+qBEEI1Eyb1pGSDveTIT09Bvw2WhlGayg==} + '@typescript-eslint/types@8.59.4': + resolution: {integrity: sha512-F1o7WJcCq+bc8dwcO/YsSEOudAH8RDtaOhM6wcAQhcUsFhnWQl81JKy48q1hoxAU0qrzM89+31GYh1515Zde3Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.59.3': - resolution: {integrity: sha512-CbRjVRAf7Lr9Kr8RopKcbY45p2VfmmHrm0ygOCYFi7oU8q19m0Fs/6iHS7kNOmwpp+ob07ZVcAqlxUod9lYdmg==} + '@typescript-eslint/typescript-estree@8.59.4': + resolution: {integrity: sha512-F+RuOmcDXo4+TPdfd/TCLS3m2nw8gE9XXyZLrA3JBfaA5tz9TtdkyD3YJFmPxulyc2cKbEok/CvFE3MgSLWnag==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.59.3': - resolution: {integrity: sha512-JAvT14goBzRzzzZyqq3P9BLArIxTtQURUtFgQ/V7FO+eU+Gg6ES+5ymOPP1wRxXcxAYeivCk4uS3jCKWI1K8Zg==} + '@typescript-eslint/utils@8.59.4': + resolution: {integrity: sha512-cYXeNAUsG4lJo5dbc1FcKm+JwIWrj1/UpTORsC6tGMjEZ81DYcvIr9/ueikhMa/Y/gDQYGp+YX9/xQrXje5BJw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.59.3': - resolution: {integrity: sha512-f1UQF7ggd42YiwI5wGrRaPsa+P0CINBlrkLPmGfpq/u/I/oVtecoEIfFR9ag/oa1sLOsRNZ6xehf6qMZhQGBDg==} + '@typescript-eslint/visitor-keys@8.59.4': + resolution: {integrity: sha512-U3gxVaDVnuZKhSspW/MzMxE1kq7zOdc072FcSNoqA1I9p8HyKbBFfEHoWckBAMgNMph4MamwS5iTVzFmrnt8TQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.3.1': @@ -4431,8 +4505,8 @@ packages: aws4@1.13.2: resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} - axios@1.16.0: - resolution: {integrity: sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==} + axios@1.16.1: + resolution: {integrity: sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==} babel-jest@29.7.0: resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} @@ -4485,8 +4559,8 @@ packages: resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==} engines: {node: '>=0.10.0'} - baseline-browser-mapping@2.10.29: - resolution: {integrity: sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ==} + baseline-browser-mapping@2.10.31: + resolution: {integrity: sha512-MujYO3eP72uvmSE0i4wltsodRfIpZATP3jvzRNRGGxgzId7aVocVJJV3nf01qnzzKFGxQVC9bpWxl5cjxTr/7Q==} engines: {node: '>=6.0.0'} hasBin: true @@ -4658,6 +4732,14 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} + c12@3.1.0: + resolution: {integrity: sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==} + peerDependencies: + magicast: ^0.3.5 + peerDependenciesMeta: + magicast: + optional: true + cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -4714,8 +4796,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001792: - resolution: {integrity: sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==} + caniuse-lite@1.0.30001793: + resolution: {integrity: sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==} canvg@3.0.11: resolution: {integrity: sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==} @@ -4788,6 +4870,12 @@ packages: resolution: {integrity: sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==} engines: {node: '>= 0.10'} + citty@0.1.6: + resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + + citty@0.2.2: + resolution: {integrity: sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==} + cjs-module-lexer@1.4.3: resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} @@ -4951,6 +5039,9 @@ packages: concat-with-sourcemaps@1.1.0: resolution: {integrity: sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==} + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} + connect-history-api-fallback@1.6.0: resolution: {integrity: sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==} engines: {node: '>=0.8'} @@ -4980,6 +5071,10 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} + content-type@2.0.0: + resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} + engines: {node: '>=18'} + conventional-changelog-angular@7.0.0: resolution: {integrity: sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==} engines: {node: '>=16'} @@ -5214,8 +5309,8 @@ packages: date-fns-jalali@4.1.0-0: resolution: {integrity: sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==} - date-fns@4.1.0: - resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} + date-fns@4.2.1: + resolution: {integrity: sha512-37RhSdxaG1suen6VDCza6rNrQfooyQh57HFVPwQGEq2QWliVLzPQZ8Oa017weOu+HZCnzI7N3Pf/wyoBKfEqrA==} date.js@0.3.3: resolution: {integrity: sha512-HgigOS3h3k6HnW011nAb43c5xx5rBXk8P2v/WIT9Zv4koIaVXiH2BURguI78VVp+5Qc076T7OR378JViCnZtBw==} @@ -5293,6 +5388,10 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + deepmerge-ts@7.1.5: + resolution: {integrity: sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==} + engines: {node: '>=16.0.0'} + deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} @@ -5324,6 +5423,9 @@ packages: resolution: {integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==} engines: {node: '>=0.10.0'} + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + del@3.0.0: resolution: {integrity: sha512-7yjqSoVSlJzA4t/VUwazuEagGeANEKB3f/aNI//06pfKgwoCb7f6Q1gETN1sZzYaj6chTQ0AhIwDiPdfOjko4A==} engines: {node: '>=4'} @@ -5436,8 +5538,8 @@ packages: resolution: {integrity: sha512-l32Xp/TLgWb8ReqbVJAFIvXmY7go4nTxxlWiAFyhoQw9RKEOHBZNnyGvJWqDVSPmq3Y9HlM4npqF/T6VMOXhww==} deprecated: dommatrix is no longer maintained. Please use @thednp/dommatrix. - dompurify@3.4.2: - resolution: {integrity: sha512-lHeS9SA/IKeIFFyYciHBr2n0v1VMPlSj843HdLOwjb2OxNwdq9Xykxqhk+FE42MzAdHvInbAolSE4mhahPpjXA==} + dompurify@3.4.5: + resolution: {integrity: sha512-OrwIBKsdNSVEeubdJ1HBv/wNENRM9ytAVCv7YXt//A3vPdVMNuACRqK9mXCGCBW2ln7BT/A4X0jXHo2Gu89miA==} domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} @@ -5483,8 +5585,11 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.353: - resolution: {integrity: sha512-kOrWphBi8TOZyiJZqsgqIle0lw+tzmnQK83pV9dZUd01Nm2POECSyFQMAuarzZdYqQW7FH9RaYOuaRo3h+bQ3w==} + effect@3.21.0: + resolution: {integrity: sha512-PPN80qRokCd1f015IANNhrwOnLO7GrrMQfk4/lnZRE/8j7UPWrNNjPV0uBrZutI/nHzernbW+J0hdqQysHiSnQ==} + + electron-to-chromium@1.5.360: + resolution: {integrity: sha512-GkcBt6YYAw9SxFWn+xVar4cLVGlXVuswwtRLBozi2zp0GjXs4ZnOrqV4zbXzg35n7w81hCkyJNYicgXlVHAmBA==} elliptic@6.6.1: resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} @@ -5509,6 +5614,10 @@ packages: resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} engines: {node: '>= 4'} + empathic@2.0.0: + resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} + engines: {node: '>=14'} + encodeurl@2.0.0: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} @@ -5516,8 +5625,8 @@ packages: end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} - engine.io-client@6.6.4: - resolution: {integrity: sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw==} + engine.io-client@6.6.5: + resolution: {integrity: sha512-QCwxUDULPlXv8F6tqMMKx5dNkTe6OaBYRMPYeXKBlyOoKvAmE0ac6pW7fFhSscJ/5SI7666/U/B+MElbsrJlIg==} engine.io-parser@5.2.3: resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} @@ -5527,8 +5636,8 @@ packages: resolution: {integrity: sha512-ZaAux1rigq1e2nQrztHn4h2ugvpzZxs64qneNah+8Mh/K0CRqJFJc+UoXnUsq+1yX+DmQFPPdVqboKAJ89e0Iw==} engines: {node: '>=4.3.0 <5.0.0 || >=5.10'} - enhanced-resolve@5.21.3: - resolution: {integrity: sha512-QyL119InA+XXEkNLNTPCXPugSvOfhwv0JOlGNzvxs0hZaiHLNvXSpudUWsOlsXGWJh8G6ckCScEkVHfX3kw/2Q==} + enhanced-resolve@5.21.6: + resolution: {integrity: sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==} engines: {node: '>=10.13.0'} ent@2.2.2: @@ -5592,6 +5701,10 @@ packages: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + es-set-tostringtag@2.1.0: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} @@ -5848,6 +5961,9 @@ packages: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + ext@1.7.0: resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} @@ -5874,6 +5990,10 @@ packages: resolution: {integrity: sha512-lxEuefF5MBIVDmE6XeqCdM4BWk1+vYmGZtkbKZ/VFcg6uBBw6fXNEbWmxCjDdQlFc9hy450nkiWwM3VAW6G1qg==} engines: {node: '>=0.10.0'} + fast-check@3.23.2: + resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} + engines: {node: '>=8.0.0'} + fast-csv@4.3.6: resolution: {integrity: sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==} engines: {node: '>=10.0.0'} @@ -5935,8 +6055,8 @@ packages: picomatch: optional: true - fflate@0.8.2: - resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} + fflate@0.8.3: + resolution: {integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==} file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} @@ -6079,8 +6199,8 @@ packages: resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==} engines: {node: '>=0.10.0'} - framer-motion@12.38.0: - resolution: {integrity: sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g==} + framer-motion@12.40.0: + resolution: {integrity: sha512-uaBd3qC1v3KQqBEjwTUd183K6PbS+j0yR9w9VmEOLWA/tnUcSn8Xa3uck7t4dgpDoUss8xQTcj8W2L07lrnLFg==} peerDependencies: '@emotion/is-prop-valid': '*' react: ^18.0.0 || ^19.0.0 @@ -6219,6 +6339,10 @@ packages: getpass@0.1.7: resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} + giget@2.0.0: + resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} + hasBin: true + git-raw-commits@4.0.0: resolution: {integrity: sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==} engines: {node: '>=16'} @@ -6515,8 +6639,8 @@ packages: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} - idb-keyval@6.2.2: - resolution: {integrity: sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==} + idb-keyval@6.2.4: + resolution: {integrity: sha512-D/NzHWUmYJGXi++z67aMSrnisb9A3621CyRK5G89JyTlN13C8xf0g04DLxUKMufPem3e3L2JAXR6Z00OWy183Q==} ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -7108,2415 +7232,12 @@ packages: jquery@3.7.1: resolution: {integrity: sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==} - js-cookie@3.0.5: - resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} - engines: {node: '>=14'} - - '@rollup/rollup-linux-arm-musleabihf@4.60.3': - resolution: {integrity: sha512-mQKoJAzvuOs6F+TZybQO4GOTSMUu7v0WdxEk24krQ/uUxXoPTtHjuaUuPmFhtBcM4K0ons8nrE3JyhTuCFtT/w==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.60.3': - resolution: {integrity: sha512-Whjj2qoiJ6+OOJMGptTYazaJvjOJm+iKHpXQM1P3LzGjt7Ff++Tp7nH4N8J/BUA7R9IHfDyx4DJIflifwnbmIA==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.60.3': - resolution: {integrity: sha512-4YTNHKqGng5+yiZt3mg77nmyuCfmNfX4fPmyUapBcIk+BdwSwmCWGXOUxhXbBEkFHtoN5boLj/5NON+u5QC9tg==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-loong64-gnu@4.60.3': - resolution: {integrity: sha512-SU3kNlhkpI4UqlUc2VXPGK9o886ZsSeGfMAX2ba2b8DKmMXq4AL7KUrkSWVbb7koVqx41Yczx6dx5PNargIrEA==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-loong64-musl@4.60.3': - resolution: {integrity: sha512-6lDLl5h4TXpB1mTf2rQWnAk/LcXrx9vBfu/DT5TIPhvMhRWaZ5MxkIc8u4lJAmBo6klTe1ywXIUHFjylW505sg==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-ppc64-gnu@4.60.3': - resolution: {integrity: sha512-BMo8bOw8evlup/8G+cj5xWtPyp93xPdyoSN16Zy90Q2QZ0ZYRhCt6ZJSwbrRzG9HApFabjwj2p25TUPDWrhzqQ==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-ppc64-musl@4.60.3': - resolution: {integrity: sha512-E0L8X1dZN1/Rph+5VPF6Xj2G7JJvMACVXtamTJIDrVI44Y3K+G8gQaMEAavbqCGTa16InptiVrX6eM6pmJ+7qA==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.60.3': - resolution: {integrity: sha512-oZJ/WHaVfHUiRAtmTAeo3DcevNsVvH8mbvodjZy7D5QKvCefO371SiKRpxoDcCxB3PTRTLayWBkvmDQKTcX/sw==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-riscv64-musl@4.60.3': - resolution: {integrity: sha512-Dhbyh7j9FybM3YaTgaHmVALwA8AkUwTPccyCQ79TG9AJUsMQqgN1DDEZNr4+QUfwiWvLDumW5vdwzoeUF+TNxQ==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.60.3': - resolution: {integrity: sha512-cJd1X5XhHHlltkaypz1UcWLA8AcoIi1aWhsvaWDskD1oz2eKCypnqvTQ8ykMNI0RSmm7NkTdSqSSD7zM0xa6Ig==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.60.3': - resolution: {integrity: sha512-DAZDBHQfG2oQuhY7mc6I3/qB4LU2fQCjRvxbDwd/Jdvb9fypP4IJ4qmtu6lNjes6B531AI8cg1aKC2di97bUxA==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.60.3': - resolution: {integrity: sha512-cRxsE8c13mZOh3vP+wLDxpQBRrOHDIGOWyDL93Sy0Ga8y515fBcC2pjUfFwUe5T7tqvTvWbCpg1URM/AXdWIXA==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-openbsd-x64@4.60.3': - resolution: {integrity: sha512-QaWcIgRxqEdQdhJqW4DJctsH6HCmo5vHxY0krHSX4jMtOqfzC+dqDGuHM87bu4H8JBeibWx7jFz+h6/4C8wA5Q==} - cpu: [x64] - os: [openbsd] - - '@rollup/rollup-openharmony-arm64@4.60.3': - resolution: {integrity: sha512-AaXwSvUi3QIPtroAUw1t5yHGIyqKEXwH54WUocFolZhpGDruJcs8c+xPNDRn4XiQsS7MEwnYsHW2l0MBLDMkWg==} - cpu: [arm64] - os: [openharmony] - - '@rollup/rollup-win32-arm64-msvc@4.60.3': - resolution: {integrity: sha512-65LAKM/bAWDqKNEelHlcHvm2V+Vfb8C6INFxQXRHCvaVN1rJfwr4NvdP4FyzUaLqWfaCGaadf6UbTm8xJeYfEg==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.60.3': - resolution: {integrity: sha512-EEM2gyhBF5MFnI6vMKdX1LAosE627RGBzIoGMdLloPZkXrUN0Ckqgr2Qi8+J3zip/8NVVro3/FjB+tjhZUgUHA==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-gnu@4.60.3': - resolution: {integrity: sha512-E5Eb5H/DpxaoXH++Qkv28RcUJboMopmdDUALBczvHMf7hNIxaDZqwY5lK12UK1BHacSmvupoEWGu+n993Z0y1A==} - cpu: [x64] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.60.3': - resolution: {integrity: sha512-hPt/bgL5cE+Qp+/TPHBqptcAgPzgj46mPcg/16zNUmbQk0j+mOEQV/+Lqu8QRtDV3Ek95Q6FeFITpuhl6OTsAA==} - cpu: [x64] - os: [win32] - - '@rtsao/scc@1.1.0': - resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - - '@scarf/scarf@1.4.0': - resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==} - - '@sendgrid/client@8.1.6': - resolution: {integrity: sha512-/BHu0hqwXNHr2aLhcXU7RmmlVqrdfrbY9KpaNj00KZHlVOVoRxRVrpOCabIB+91ISXJ6+mLM9vpaVUhK6TwBWA==} - engines: {node: '>=12.*'} - - '@sendgrid/helpers@8.0.0': - resolution: {integrity: sha512-Ze7WuW2Xzy5GT5WRx+yEv89fsg/pgy3T1E3FS0QEx0/VvRmigMZ5qyVGhJz4SxomegDkzXv/i0aFPpHKN8qdAA==} - engines: {node: '>= 12.0.0'} - - '@sendgrid/mail@8.1.6': - resolution: {integrity: sha512-/ZqxUvKeEztU9drOoPC/8opEPOk+jLlB2q4+xpx6HVLq6aFu3pMpalkTpAQz8XfRfpLp8O25bh6pGPcHDCYpqg==} - engines: {node: '>=12.*'} - - '@sinclair/typebox@0.27.10': - resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==} - - '@sinonjs/commons@3.0.1': - resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} - - '@sinonjs/fake-timers@10.3.0': - resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} - - '@sqltools/formatter@1.2.5': - resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==} - - '@standard-schema/spec@1.1.0': - resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - - '@tanstack/query-core@5.100.10': - resolution: {integrity: sha512-8UR0yJR+GiQ40m3lPhUr0xbfAupe6GSQiksSBSa9SM2NjezFyxXCIA69/lz8cSoNKZLrw1/PktIyQBJcVeMi3w==} - - '@tanstack/react-query@5.100.10': - resolution: {integrity: sha512-FLaZf2RCrA/Zgp4aiu5tG3TyasTRO7aZ99skxQpr3Hg/zXOhu6yq5FZCYQ/tRaJtM9ylnoK8tFK7PolXQadv6Q==} - peerDependencies: - react: 18.3.1 - - '@tokenizer/inflate@0.4.1': - resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} - engines: {node: '>=18'} - - '@tokenizer/token@0.3.0': - resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} - - '@tsconfig/node10@1.0.12': - resolution: {integrity: sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==} - - '@tsconfig/node12@1.0.11': - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} - - '@tsconfig/node14@1.0.3': - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} - - '@tsconfig/node16@1.0.4': - resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - - '@turbo/darwin-64@2.9.12': - resolution: {integrity: sha512-eu3eFRmE9NjgZ0wPdRJ44l+LGSeIky+tz5ZQd8zQkw/Yqi+BM7wq+8nbabeoiVUcICi/IZweMOKl/MCmkrd1+g==} - cpu: [x64] - os: [darwin] - - '@turbo/darwin-arm64@2.9.12': - resolution: {integrity: sha512-RUkAE404z/J8NsyrUosMcBaXT6M4bRFxTQrmkDQBLQVXaC8Jl0e9bMvYDSX0GW7Ffm2m3j9y7RXgR1foeUAM9w==} - cpu: [arm64] - os: [darwin] - - '@turbo/linux-64@2.9.12': - resolution: {integrity: sha512-InIUtH7cw/vqXNX1Gr7QgWfmw3ct08pV5CpfdEOR48z2u2rzdmpIuk00B/Q2xCb0PMWtKgiMQynfuphmEuUyTQ==} - cpu: [x64] - os: [linux] - - '@turbo/linux-arm64@2.9.12': - resolution: {integrity: sha512-lC6nD//Xh67fmJM0LKaLsg74Wry0aYrgMklpiNgCbUaMdPIOqj0A00iri3NU7Lb7pZHx8ViisgpeDKlpSgFUCA==} - cpu: [arm64] - os: [linux] - - '@turbo/windows-64@2.9.12': - resolution: {integrity: sha512-conYri8VUl72JOdYnLDPYwzqbPcY5ECoHmo9FWoKznemhaAIilj4maHqs9Uar0aKfNoZIULniy+6iWaLtLO34A==} - cpu: [x64] - os: [win32] - - '@turbo/windows-arm64@2.9.12': - resolution: {integrity: sha512-XoR4bsg62/L/esRVcmoMESEiNZ36+YmyjYGLpoqk8nwMgXzzVjNOgX0lRSz5w/U/ajLGv3nhMsS0Q2QOdvp2AQ==} - cpu: [arm64] - os: [win32] - - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - - '@types/babel__generator@7.27.0': - resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} - - '@types/babel__template@7.4.4': - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - - '@types/babel__traverse@7.28.0': - resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} - - '@types/bcrypt@5.0.2': - resolution: {integrity: sha512-6atioO8Y75fNcbmj0G7UjI9lXN2pQ/IGJ2FWT4a/btd0Lk9lQalHLKhkgKVZ3r+spnmWUKfbMi1GEe9wyHQfNQ==} - - '@types/body-parser@1.19.6': - resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} - - '@types/connect@3.4.38': - resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} - - '@types/conventional-commits-parser@5.0.2': - resolution: {integrity: sha512-BgT2szDXnVypgpNxOK8aL5SGjUdaQbC++WZNjF1Qge3Og2+zhHj+RWhmehLhYyvQwqAmvezruVfOf8+3m74W+g==} - - '@types/cookiejar@2.1.5': - resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==} - - '@types/eslint-scope@3.7.7': - resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} - - '@types/eslint@9.6.1': - resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} - - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - - '@types/estree@1.0.9': - resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} - - lightningcss-linux-arm64-gnu@1.32.0: - resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - lightningcss-linux-arm64-musl@1.32.0: - resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [musl] - - lightningcss-linux-x64-gnu@1.32.0: - resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [glibc] - - lightningcss-linux-x64-musl@1.32.0: - resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [musl] - - '@types/istanbul-lib-coverage@2.0.6': - resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} - - '@types/istanbul-lib-report@3.0.3': - resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} - - '@types/istanbul-reports@3.0.4': - resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} - - '@types/jest@29.5.14': - resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} - - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - - '@types/json5@0.0.29': - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - - '@types/jsonwebtoken@9.0.10': - resolution: {integrity: sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==} - - '@types/jsonwebtoken@9.0.5': - resolution: {integrity: sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==} - - '@types/luxon@3.7.1': - resolution: {integrity: sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg==} - - '@types/methods@1.1.4': - resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==} - - '@types/ms@2.1.0': - resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - - '@types/node@20.19.41': - resolution: {integrity: sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ==} - - '@types/node@24.12.4': - resolution: {integrity: sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==} - - '@types/parse-json@4.0.2': - resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} - - '@types/passport-jwt@4.0.1': - resolution: {integrity: sha512-Y0Ykz6nWP4jpxgEUYq8NoVZeCQPo1ZndJLfapI249g1jHChvRfZRO/LS3tqu26YgAS/laI1qx98sYGz0IalRXQ==} - - '@types/passport-strategy@0.2.38': - resolution: {integrity: sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA==} - - '@types/passport@1.0.17': - resolution: {integrity: sha512-aciLyx+wDwT2t2/kJGJR2AEeBz0nJU4WuRX04Wu9Dqc5lSUtwu0WERPHYsLhF9PtseiAMPBGNUOtFjxZ56prsg==} - - '@types/prop-types@15.7.15': - resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} - - '@types/qrcode@1.5.6': - resolution: {integrity: sha512-te7NQcV2BOvdj2b1hCAHzAoMNuj65kNBMz0KBaxM6c3VGBOhU0dURQKOtH8CFNI/dsKkwlv32p26qYQTWoB5bw==} - - '@types/qs@6.15.1': - resolution: {integrity: sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==} - - '@types/range-parser@1.2.7': - resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - - '@types/react-dom@18.3.7': - resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} - peerDependencies: - '@types/react': ^18.0.0 - - '@types/react@18.3.28': - resolution: {integrity: sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==} - - '@types/send@1.2.1': - resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} - - '@types/serve-static@2.2.0': - resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} - - '@types/stack-utils@2.0.3': - resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} - - '@types/superagent@8.1.9': - resolution: {integrity: sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==} - - '@types/supertest@6.0.3': - resolution: {integrity: sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==} - - '@types/validator@13.15.10': - resolution: {integrity: sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==} - - '@types/yargs-parser@21.0.3': - resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - - '@types/yargs@17.0.35': - resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} - - '@typescript-eslint/eslint-plugin@8.59.3': - resolution: {integrity: sha512-PwFvSKsXGShKGW6n5bZOhGHEcCZXM8HofLK9fNsEwZXzFRjoY+XT1Vsf1zgyXdwTr0ZYz1/2tkZ0DBTT9jZjhw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.59.3 - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/parser@8.59.3': - resolution: {integrity: sha512-HPwA+hVkfcriajbNvTmZv4VRauibay+cWArYUYq7u7W7PmGShMxbPxLvrwDme55a6d5alG3nrYfhyJ/G28XlLg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/project-service@8.59.3': - resolution: {integrity: sha512-ECiUWa/KYRGDFUqTNehaRgzDshnJfkTABJxVemHk4ko22gcr0ukloKjWvyQ64g8YCV/UI47kN1dbmjf/GaQYng==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/scope-manager@8.59.3': - resolution: {integrity: sha512-t2LvZnoEfzKtnPjgeEu41xw5gxq9mQVfYy4OoZ4Vlt0sk3JwxmhCca/AR7DwOiHrjWgjAj6as4AhRLKSDfvZIA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/tsconfig-utils@8.59.3': - resolution: {integrity: sha512-PcIJHjmaREXLgIAIzLnSY9VucEzz8FKXsRgFa1DmdGCK/5tJpW03TKJF01Q6VZd1lLdz2sIKPWaDUZN9dp//dw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/type-utils@8.59.3': - resolution: {integrity: sha512-g71d8QD8UaiHGvrJwyIS1hCX5r63w6Jll+4VEYhEAHXTDIqX1JgxhTAbEHtKntL9kuc4jRo7/GWw5xfCepSccQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/types@8.59.3': - resolution: {integrity: sha512-ePFoH0g4ludssdRFqqDxQePCxU4WQyRa9+XVwjm7yLn0FKhMeoetC+qBEEI1Eyb1pGSDveTIT09Bvw2WhlGayg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/typescript-estree@8.59.3': - resolution: {integrity: sha512-CbRjVRAf7Lr9Kr8RopKcbY45p2VfmmHrm0ygOCYFi7oU8q19m0Fs/6iHS7kNOmwpp+ob07ZVcAqlxUod9lYdmg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/utils@8.59.3': - resolution: {integrity: sha512-JAvT14goBzRzzzZyqq3P9BLArIxTtQURUtFgQ/V7FO+eU+Gg6ES+5ymOPP1wRxXcxAYeivCk4uS3jCKWI1K8Zg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/visitor-keys@8.59.3': - resolution: {integrity: sha512-f1UQF7ggd42YiwI5wGrRaPsa+P0CINBlrkLPmGfpq/u/I/oVtecoEIfFR9ag/oa1sLOsRNZ6xehf6qMZhQGBDg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@ungap/structured-clone@1.3.1': - resolution: {integrity: sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==} - - '@vitejs/plugin-react@4.7.0': - resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - - '@vitest/expect@2.1.9': - resolution: {integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==} - - '@vitest/mocker@2.1.9': - resolution: {integrity: sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==} - peerDependencies: - msw: ^2.4.9 - vite: ^5.0.0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true - - '@vitest/pretty-format@2.1.9': - resolution: {integrity: sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==} - - '@vitest/runner@2.1.9': - resolution: {integrity: sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==} - - '@vitest/snapshot@2.1.9': - resolution: {integrity: sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==} - - '@vitest/spy@2.1.9': - resolution: {integrity: sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==} - - '@vitest/utils@2.1.9': - resolution: {integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==} - - '@webassemblyjs/ast@1.14.1': - resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} - - '@webassemblyjs/floating-point-hex-parser@1.13.2': - resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} - - '@webassemblyjs/helper-api-error@1.13.2': - resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} - - '@webassemblyjs/helper-buffer@1.14.1': - resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} - - '@webassemblyjs/helper-numbers@1.13.2': - resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} - - '@webassemblyjs/helper-wasm-bytecode@1.13.2': - resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} - - '@webassemblyjs/helper-wasm-section@1.14.1': - resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} - - '@webassemblyjs/ieee754@1.13.2': - resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} - - '@webassemblyjs/leb128@1.13.2': - resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} - - '@webassemblyjs/utf8@1.13.2': - resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} - - '@webassemblyjs/wasm-edit@1.14.1': - resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} - - '@webassemblyjs/wasm-gen@1.14.1': - resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} - - '@webassemblyjs/wasm-opt@1.14.1': - resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} - - '@webassemblyjs/wasm-parser@1.14.1': - resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} - - '@webassemblyjs/wast-printer@1.14.1': - resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} - - '@xtuc/ieee754@1.2.0': - resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} - - '@xtuc/long@4.2.2': - resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} - - JSONStream@1.3.5: - resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} - hasBin: true - - abbrev@1.1.1: - resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} - - accepts@2.0.0: - resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} - engines: {node: '>= 0.6'} - - acorn-import-phases@1.0.4: - resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} - engines: {node: '>=10.13.0'} - peerDependencies: - react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - luxon@3.7.2: - resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==} - engines: {node: '>=12'} - - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - acorn-walk@8.3.5: - resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==} - engines: {node: '>=0.4.0'} - - acorn@8.16.0: - resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} - engines: {node: '>=0.4.0'} - hasBin: true - - agent-base@6.0.2: - resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} - engines: {node: '>= 6.0.0'} - - agent-base@7.1.4: - resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} - engines: {node: '>= 14'} - - ajv-formats@2.1.1: - resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - - ajv-formats@3.0.1: - resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - - ajv-keywords@3.5.2: - resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} - peerDependencies: - ajv: ^6.9.1 - - ajv-keywords@5.1.0: - resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} - peerDependencies: - ajv: ^8.8.2 - - ajv@6.15.0: - resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} - - ajv@8.18.0: - resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} - - ajv@8.20.0: - resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} - - ansi-colors@4.1.3: - resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} - engines: {node: '>=6'} - - ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} - - ansi-escapes@7.3.0: - resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} - engines: {node: '>=18'} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-regex@6.2.2: - resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} - engines: {node: '>=12'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - - ansi-styles@6.2.3: - resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} - engines: {node: '>=12'} - - ansis@4.2.0: - resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} - engines: {node: '>=14'} - - ansis@4.3.0: - resolution: {integrity: sha512-44mvgtPvohuU/70DdY5Oz2AIrLJ9k6/5x4KmoSvPwO+5Moijo0+N9D0fKbbYZQWP1hNm5CpOf+E01jhxG/r8xg==} - engines: {node: '>=14'} - - any-promise@1.3.0: - resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - - app-root-path@3.1.0: - resolution: {integrity: sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==} - engines: {node: '>= 6.0.0'} - - append-field@1.0.0: - resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} - - aproba@2.1.0: - resolution: {integrity: sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==} - - are-we-there-yet@2.0.0: - resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} - engines: {node: '>=10'} - deprecated: This package is no longer supported. - - arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - - arg@5.0.2: - resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} - - argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - array-buffer-byte-length@1.0.2: - resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} - engines: {node: '>= 0.4'} - - array-ify@1.0.0: - resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} - - array-includes@3.1.9: - resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} - engines: {node: '>= 0.4'} - - array-timsort@1.0.3: - resolution: {integrity: sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==} - - array.prototype.findlast@1.2.5: - resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} - engines: {node: '>= 0.4'} - - array.prototype.findlastindex@1.2.6: - resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} - engines: {node: '>= 0.4'} - - array.prototype.flat@1.3.3: - resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} - engines: {node: '>= 0.4'} - - array.prototype.flatmap@1.3.3: - resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} - engines: {node: '>= 0.4'} - - array.prototype.tosorted@1.1.4: - resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} - engines: {node: '>= 0.4'} - - arraybuffer.prototype.slice@1.0.4: - resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} - engines: {node: '>= 0.4'} - - minimalistic-assert@1.0.1: - resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - - async-function@1.0.0: - resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} - engines: {node: '>= 0.4'} - - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - - autoprefixer@10.5.0: - resolution: {integrity: sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==} - engines: {node: ^10 || ^12 || >=14} - hasBin: true - peerDependencies: - postcss: ^8.1.0 - - available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} - - aws-ssl-profiles@1.1.2: - resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} - engines: {node: '>= 6.0.0'} - - axios@1.16.0: - resolution: {integrity: sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==} - - babel-jest@29.7.0: - resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.8.0 - - babel-plugin-istanbul@6.1.1: - resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} - engines: {node: '>=8'} - - babel-plugin-jest-hoist@29.6.3: - resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - babel-plugin-macros@3.1.0: - resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} - engines: {node: '>=10', npm: '>=6'} - - babel-preset-current-node-syntax@1.2.0: - resolution: {integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==} - peerDependencies: - '@babel/core': ^7.0.0 || ^8.0.0-0 - - babel-preset-jest@29.6.3: - resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.0.0 - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - balanced-match@4.0.4: - resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} - engines: {node: 18 || 20 || >=22} - - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - - baseline-browser-mapping@2.10.29: - resolution: {integrity: sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ==} - engines: {node: '>=6.0.0'} - hasBin: true - - bcrypt@5.1.1: - resolution: {integrity: sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==} - engines: {node: '>= 10.0.0'} - - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - - bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - - body-parser@2.2.2: - resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} - engines: {node: '>=18'} - - brace-expansion@1.1.14: - resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} - - mui-ethiopian-datepicker@0.3.2: - resolution: {integrity: sha512-I8TZ8lvloAxhFNl8tDl7NmgT7RPJslfnArNMpT2Sd9GbpfsdRrOwH/JBMcOhLQyaNUee9due0W6J85io1WLjlg==} - peerDependencies: - '@emotion/react': ^11.11.0 - '@emotion/styled': ^11.11.0 - '@mui/icons-material': ^5.11.16 - '@mui/material': ^5.13.3 - '@mui/x-date-pickers': ^6.7.0 - date-fns: ^2.30.0 - react: ^18.2.0 - react-dom: ^18.2.0 - - brace-expansion@5.0.6: - resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} - engines: {node: 18 || 20 || >=22} - - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - - browserslist@4.28.2: - resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - - bs-logger@0.2.6: - resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} - engines: {node: '>= 6'} - - bser@2.1.1: - resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} - - buffer-equal-constant-time@1.0.1: - resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} - - buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - - buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - - buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - - busboy@1.6.0: - resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} - engines: {node: '>=10.16.0'} - - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - - c12@3.1.0: - resolution: {integrity: sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==} - peerDependencies: - magicast: ^0.3.5 - peerDependenciesMeta: - magicast: - optional: true - - cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} - - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - next-themes@0.4.6: - resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} - peerDependencies: - react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} - - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - - camelcase-css@2.0.1: - resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} - engines: {node: '>= 6'} - - camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} - - camelcase@6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} - - caniuse-lite@1.0.30001792: - resolution: {integrity: sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw==} - - canvas@2.11.2: - resolution: {integrity: sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==} - engines: {node: '>=6'} - - chai@5.3.3: - resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} - engines: {node: '>=18'} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - chalk@5.6.2: - resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - - char-regex@1.0.2: - resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} - engines: {node: '>=10'} - - chardet@2.1.1: - resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} - - check-error@2.1.3: - resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} - engines: {node: '>= 16'} - - chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} - - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} - - chownr@2.0.0: - resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} - engines: {node: '>=10'} - - chrome-trace-event@1.0.4: - resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} - engines: {node: '>=6.0'} - - ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - - citty@0.1.6: - resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} - - citty@0.2.2: - resolution: {integrity: sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==} - - cjs-module-lexer@1.4.3: - resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} - - class-transformer@0.5.1: - resolution: {integrity: sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==} - - class-validator@0.14.4: - resolution: {integrity: sha512-AwNusCCam51q703dW82x95tOqQp6oC9HNUl724KxJJOfnKscI8dOloXFgyez7LbTTKWuRBA37FScqVbJEoq8Yw==} - - cli-cursor@3.1.0: - resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} - engines: {node: '>=8'} - - cli-cursor@5.0.0: - resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} - engines: {node: '>=18'} - - cli-spinners@2.9.2: - resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} - engines: {node: '>=6'} - - cli-table3@0.6.5: - resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} - engines: {node: 10.* || >= 12.*} - - cli-truncate@4.0.0: - resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} - engines: {node: '>=18'} - - cli-width@4.1.0: - resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} - engines: {node: '>= 12'} - - cliui@6.0.0: - resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} - - cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - - clone@1.0.4: - resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} - engines: {node: '>=0.8'} - - clsx@2.1.1: - resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} - engines: {node: '>=6'} - - co@4.6.0: - resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} - engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} - - collect-v8-coverage@1.0.3: - resolution: {integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - color-support@1.1.3: - resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} - hasBin: true - - colorette@2.0.20: - resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - - commander@13.1.0: - resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} - engines: {node: '>=18'} - - commander@2.20.3: - resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - - commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} - - comment-json@5.0.0: - resolution: {integrity: sha512-uiqLcOiVDJtBP8WGkZHEP+FZIhTzP1dxvn59EfoYUi9gqupjrBWVQkO2atDrbnKPwLeotFYDsuNb26uBMqB+hw==} - engines: {node: '>= 6'} - - compare-func@2.0.0: - resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} - - component-emitter@1.3.1: - resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - concat-stream@2.0.0: - resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} - engines: {'0': node >= 6.0} - - confbox@0.2.4: - resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} - - consola@3.4.2: - resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} - engines: {node: ^14.18.0 || >=16.10.0} - - console-control-strings@1.1.0: - resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} - - content-disposition@1.1.0: - resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} - engines: {node: '>=18'} - - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - - conventional-changelog-angular@7.0.0: - resolution: {integrity: sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==} - engines: {node: '>=16'} - - conventional-changelog-conventionalcommits@7.0.2: - resolution: {integrity: sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==} - engines: {node: '>=16'} - - conventional-commits-parser@5.0.0: - resolution: {integrity: sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==} - engines: {node: '>=16'} - hasBin: true - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - - cookie-signature@1.2.2: - resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} - engines: {node: '>=6.6.0'} - - cookie@0.7.2: - resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} - engines: {node: '>= 0.6'} - - cookiejar@2.1.4: - resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==} - - cors@2.8.6: - resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} - engines: {node: '>= 0.10'} - - cosmiconfig-typescript-loader@6.3.0: - resolution: {integrity: sha512-Akr82WH1Wfqatyiqpj8HDkO2o2KmJRu1FhKfSNJP3K4IdXwHfEyL7MOb62i1AGQVLtIQM+iCE9CGOtrfhR+mmA==} - engines: {node: '>=v18'} - peerDependencies: - '@types/node': '*' - cosmiconfig: '>=9' - typescript: '>=5' - - cosmiconfig@7.1.0: - resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} - engines: {node: '>=10'} - - cosmiconfig@8.3.6: - resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} - engines: {node: '>=14'} - peerDependencies: - typescript: '>=4.9.5' - peerDependenciesMeta: - typescript: - optional: true - - cosmiconfig@9.0.1: - resolution: {integrity: sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==} - engines: {node: '>=14'} - peerDependencies: - typescript: '>=4.9.5' - peerDependenciesMeta: - typescript: - optional: true - - create-jest@29.7.0: - resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - - create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - - cron@4.4.0: - resolution: {integrity: sha512-fkdfq+b+AHI4cKdhZlppHveI/mgz2qpiYxcm+t5E5TsxX7QrLS1VE0+7GENEk9z0EeGPcpSciGv6ez24duWhwQ==} - engines: {node: '>=18.x'} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true - - cssstyle@4.6.0: - resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==} - engines: {node: '>=18'} - - csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - - dargs@8.1.0: - resolution: {integrity: sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==} - engines: {node: '>=12'} - - data-urls@5.0.0: - resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} - engines: {node: '>=18'} - - data-view-buffer@1.0.2: - resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} - engines: {node: '>= 0.4'} - - data-view-byte-length@1.0.2: - resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} - engines: {node: '>= 0.4'} - - data-view-byte-offset@1.0.1: - resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} - engines: {node: '>= 0.4'} - - dayjs@1.11.20: - resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} - - debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - decamelize@1.2.0: - resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} - engines: {node: '>=0.10.0'} - - decimal.js@10.6.0: - resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - - decompress-response@4.2.1: - resolution: {integrity: sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==} - engines: {node: '>=8'} - - dedent@1.7.2: - resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} - peerDependencies: - babel-plugin-macros: ^3.1.0 - peerDependenciesMeta: - babel-plugin-macros: - optional: true - - deep-eql@5.0.2: - resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} - engines: {node: '>=6'} - - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - - deepmerge-ts@7.1.5: - resolution: {integrity: sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==} - engines: {node: '>=16.0.0'} - - deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} - - defaults@1.0.4: - resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} - - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} - - define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} - - defu@6.1.7: - resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} - - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - - delegates@1.0.0: - resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} - - denque@2.1.0: - resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} - engines: {node: '>=0.10'} - - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - - destr@2.0.5: - resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} - - detect-libc@2.1.2: - resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} - engines: {node: '>=8'} - - detect-newline@3.1.0: - resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} - engines: {node: '>=8'} - - dezalgo@1.0.4: - resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} - - didyoumean@1.2.2: - resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - - diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - diff@4.0.4: - resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} - engines: {node: '>=0.3.1'} - - dijkstrajs@1.0.3: - resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} - - dlv@1.1.3: - resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - - doctrine@2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} - engines: {node: '>=0.10.0'} - - doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - - path@0.12.7: - resolution: {integrity: sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==} - - dotenv@16.6.1: - resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} - engines: {node: '>=12'} - - dotenv@17.4.1: - resolution: {integrity: sha512-k8DaKGP6r1G30Lx8V4+pCsLzKr8vLmV2paqEj1Y55GdAgJuIqpRp5FfajGF8KtwMxCz9qJc6wUIJnm053d/WCw==} - engines: {node: '>=12'} - - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - - eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - - pdfjs-dist@2.16.105: - resolution: {integrity: sha512-J4dn41spsAwUxCpEoVf6GVoz908IAA3mYiLmNxg8J9kfRXc2jxpbUepcP0ocp0alVNLFthTAM8DZ1RaHh8sU0A==} - peerDependencies: - worker-loader: ^3.0.8 - peerDependenciesMeta: - worker-loader: - optional: true - - pdfjs-dist@5.4.296: - resolution: {integrity: sha512-DlOzet0HO7OEnmUmB6wWGJrrdvbyJKftI1bhMitK7O2N8W2gc757yyYBbINy9IDafXAV9wmKr9t7xsTaNKRG5Q==} - engines: {node: '>=20.16.0 || >=22.3.0'} - - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - - effect@3.21.0: - resolution: {integrity: sha512-PPN80qRokCd1f015IANNhrwOnLO7GrrMQfk4/lnZRE/8j7UPWrNNjPV0uBrZutI/nHzernbW+J0hdqQysHiSnQ==} - - electron-to-chromium@1.5.353: - resolution: {integrity: sha512-kOrWphBi8TOZyiJZqsgqIle0lw+tzmnQK83pV9dZUd01Nm2POECSyFQMAuarzZdYqQW7FH9RaYOuaRo3h+bQ3w==} - - emittery@0.13.1: - resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} - engines: {node: '>=12'} - - emoji-regex@10.6.0: - resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - - empathic@2.0.0: - resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} - engines: {node: '>=14'} - - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - - enhanced-resolve@5.21.3: - resolution: {integrity: sha512-QyL119InA+XXEkNLNTPCXPugSvOfhwv0JOlGNzvxs0hZaiHLNvXSpudUWsOlsXGWJh8G6ckCScEkVHfX3kw/2Q==} - engines: {node: '>=10.13.0'} - - entities@6.0.1: - resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} - engines: {node: '>=0.12'} - - env-paths@2.2.1: - resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} - engines: {node: '>=6'} - - environment@1.1.0: - resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} - engines: {node: '>=18'} - - error-ex@1.3.4: - resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} - - es-abstract@1.24.2: - resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==} - engines: {node: '>= 0.4'} - - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-iterator-helpers@1.3.2: - resolution: {integrity: sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw==} - engines: {node: '>= 0.4'} - - es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - - es-module-lexer@2.1.0: - resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} - - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - - es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} - - es-shim-unscopables@1.1.0: - resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} - engines: {node: '>= 0.4'} - - es-to-primitive@1.3.0: - resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} - engines: {node: '>= 0.4'} - - esbuild@0.21.5: - resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} - engines: {node: '>=12'} - hasBin: true - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - - escape-string-regexp@2.0.0: - resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} - engines: {node: '>=8'} - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - eslint-config-prettier@9.1.2: - resolution: {integrity: sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==} - hasBin: true - peerDependencies: - eslint: '>=7.0.0' - - eslint-import-resolver-node@0.3.10: - resolution: {integrity: sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==} - - eslint-module-utils@2.12.1: - resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - - eslint-plugin-import@2.32.0: - resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - - eslint-plugin-react-hooks@4.6.2: - resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==} - engines: {node: '>=10'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - - eslint-plugin-react-refresh@0.4.26: - resolution: {integrity: sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ==} - peerDependencies: - eslint: '>=8.40' - - eslint-plugin-react@7.37.5: - resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} - engines: {node: '>=4'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - - eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} - - eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@5.0.1: - resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - eslint@8.57.1: - resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. - hasBin: true - - espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - - esquery@1.7.0: - resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} - engines: {node: '>=0.10'} - - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - - estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - - eventemitter2@6.4.9: - resolution: {integrity: sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==} - - eventemitter3@5.0.4: - resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} - - events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} - - execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} - - execa@8.0.1: - resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} - engines: {node: '>=16.17'} - - exit@0.1.2: - resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} - engines: {node: '>= 0.8.0'} - - expect-type@1.3.0: - resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} - engines: {node: '>=12.0.0'} - - expect@29.7.0: - resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - express@5.2.1: - resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} - engines: {node: '>= 18'} - - exsolve@1.0.8: - resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} - - fast-check@3.23.2: - resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} - engines: {node: '>=8.0.0'} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - - fast-safe-stringify@2.1.1: - resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} - - fast-uri@3.1.2: - resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} - - fastq@1.20.1: - resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} - - fb-watchman@2.0.2: - resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} - - file-type@21.3.4: - resolution: {integrity: sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==} + js-cookie@3.0.7: + resolution: {integrity: sha512-z/wZZgDrkNV1eA0ULjM/F9/50Ya8fbzgKneSpoPsXSGd0KnpdtHfOZWK+GcwLk+EZbS4F9RBhU+K2RgzuDaItw==} engines: {node: '>=20'} - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - finalhandler@2.1.1: - resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} - engines: {node: '>= 18.0.0'} - - find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - find-up@7.0.0: - resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==} - engines: {node: '>=18'} - - flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} - - flatted@3.4.2: - resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} - - follow-redirects@1.16.0: - resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - - for-each@0.3.5: - resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} - engines: {node: '>= 0.4'} - - foreground-child@3.3.1: - resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} - engines: {node: '>=14'} - - fork-ts-checker-webpack-plugin@9.1.0: - resolution: {integrity: sha512-mpafl89VFPJmhnJ1ssH+8wmM2b50n+Rew5x42NeI2U78aRWgtkEtGmctp7iT16UjquJTjorEmIfESj3DxdW84Q==} - engines: {node: '>=14.21.3'} - peerDependencies: - react: '>= 16.3.0' - - react-datepicker@8.10.0: - resolution: {integrity: sha512-JIXuA+g+qP3c4MVJpx24o7n1gnv3WV/8A/D6964HucY1FlSEc30+ITPNUfbKZXYHl5rruCtxYCwi2lzn7gaz7g==} - peerDependencies: - react: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc - react-dom: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc - - react-day-picker@9.14.0: - resolution: {integrity: sha512-tBaoDWjPwe0M5pGrum4H0SR6Lyk+BO9oHnp9JbKpGKW2mlraNPgP9BMfsg5pWpwrssARmeqk7YBl2oXutZTaHA==} - engines: {node: '>=18'} - peerDependencies: - react: '>=16.8.0' - - react-dom@16.14.0: - resolution: {integrity: sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==} - peerDependencies: - react: ^16.14.0 - - react-dom@18.3.1: - resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} - peerDependencies: - react: ^18.3.1 - - react-dom@19.2.6: - resolution: {integrity: sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==} - peerDependencies: - react: ^19.2.6 - - react-dropzone@14.4.1: - resolution: {integrity: sha512-QDuV76v3uKbHiH34SpwifZ+gOLi1+RdsCO1kl5vxMT4wW8R82+sthjvBw4th3NHF/XX6FBsqDYZVNN+pnhaw0g==} - engines: {node: '>= 10.13'} - peerDependencies: - react: '>= 16.8 || 18.0.0' - - react-floater@0.7.9: - resolution: {integrity: sha512-NXqyp9o8FAXOATOEo0ZpyaQ2KPb4cmPMXGWkx377QtJkIXHlHRAGer7ai0r0C1kG5gf+KJ6Gy+gdNIiosvSicg==} - peerDependencies: - react: 15 - 18 - react-dom: 15 - 18 - - react-hook-form@7.75.0: - resolution: {integrity: sha512-Ovv94H+0p3sJ7B9B5QxPuCP1u8V/cHuVGyH55cSwodYDtoJwK+fqk3vjfIgSX59I2U/bU4z0nRJ9HMLpNiWEmw==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^16.8.0 || ^17 || ^18 || ^19 - - react-i18next@15.7.4: - resolution: {integrity: sha512-nyU8iKNrI5uDJch0z9+Y5XEr34b0wkyYj3Rp+tfbahxtlswxSCjcUL9H0nqXo9IR3/t5Y5PKIA3fx3MfUyR9Xw==} - peerDependencies: - i18next: '>= 23.4.0' - react: '>= 16.8.0' - react-dom: '*' - react-native: '*' - typescript: ^5 - peerDependenciesMeta: - react-dom: - optional: true - react-native: - optional: true - typescript: - optional: true - - react-icons@5.6.0: - resolution: {integrity: sha512-RH93p5ki6LfOiIt0UtDyNg/cee+HLVR6cHHtW3wALfo+eOHTp8RnU2kRkI6E+H19zMIs03DyxUG/GfZMOGvmiA==} - peerDependencies: - react: '*' - - react-image-crop@11.0.10: - resolution: {integrity: sha512-+5FfDXUgYLLqBh1Y/uQhIycpHCbXkI50a+nbfkB1C0xXXUTwkisHDo2QCB1SQJyHCqIuia4FeyReqXuMDKWQTQ==} - peerDependencies: - react: '>=16.13.1' - - react-innertext@1.1.5: - resolution: {integrity: sha512-PWAqdqhxhHIv80dT9znP2KvS+hfkbRovFp4zFYHFFlOoQLRiawIic81gKb3U1wEyJZgMwgs3JoLtwryASRWP3Q==} - peerDependencies: - '@types/react': '>=0.0.0 <=99' - react: '>=0.0.0 <=99' - - react-intersection-observer@9.16.0: - resolution: {integrity: sha512-w9nJSEp+DrW9KmQmeWHQyfaP6b03v+TdXynaoA964Wxt7mdR3An11z4NNCQgL4gKSK7y1ver2Fq+JKH6CWEzUA==} - peerDependencies: - react: ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - react-dom: - optional: true - - function.prototype.name@1.1.8: - resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} - engines: {node: '>= 0.4'} - - functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - - gauge@3.0.2: - resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} - engines: {node: '>=10'} - deprecated: This package is no longer supported. - - react-joyride@2.9.3: - resolution: {integrity: sha512-1+Mg34XK5zaqJ63eeBhqdbk7dlGCFp36FXwsEvgpjqrtyywX2C6h9vr3jgxP0bGHCw8Ilsp/nRDzNVq6HJ3rNw==} - peerDependencies: - react: 15 - 18 - react-dom: 15 - 18 - - react-number-format@5.4.5: - resolution: {integrity: sha512-y8O2yHHj3w0aE9XO8d2BCcUOOdQTRSVq+WIuMlLVucAm5XNjJAy+BoOJiuQMldVYVOKTMyvVNfnbl2Oqp+YxGw==} - peerDependencies: - react: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - react-pdf-html@2.1.5: - resolution: {integrity: sha512-KhmiTUcnUNbLVdZbxMcV/+Rp+PyBt+eVJHu425eNwjSsDUtytvcwS/SBdBbbpM0c4+MnnOQBOs3AiColUesM8A==} - engines: {node: '>=16.0.0'} - peerDependencies: - '@react-pdf/renderer': '>=3.4.4' - react: '>=16' - - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - react-pdf@10.4.1: - resolution: {integrity: sha512-kS/35staVCBqS29verTQJQZXw7RfsRCPO3fdJoW1KXylcv7A9dw6DZ3vJXC2w+bIBgLw5FN4pOFvKSQtkQhPfA==} - peerDependencies: - '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - react-redux@9.2.0: - resolution: {integrity: sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==} - peerDependencies: - '@types/react': ^18.2.25 || ^19 - react: ^18.0 || ^19 - redux: ^5.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - redux: - optional: true - - get-package-type@0.1.0: - resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} - engines: {node: '>=8.0.0'} - - react-remove-scroll-bar@2.3.8: - resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - react-resizable-panels@3.0.6: - resolution: {integrity: sha512-b3qKHQ3MLqOgSS+FRYKapNkJZf5EQzuf6+RLiq1/IlTHw99YrZ2NJZLk4hQIzTnnIkRg2LUqyVinu6YWWpUYew==} - peerDependencies: - react: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - - react-router-dom@6.30.3: - resolution: {integrity: sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==} - engines: {node: '>=14.0.0'} - peerDependencies: - react: '>=16.8' - react-dom: '>=16.8' - - react-router-dom@7.15.0: - resolution: {integrity: sha512-VcrVg64Fo8nwBvDscajG8gRTLIuTC6N50nb22l2HOOV4PTOHgoGp8mUjy9wLiHYoYTSYI36tUnXZgasSRFZorQ==} - engines: {node: '>=20.0.0'} - peerDependencies: - react: '>=18' - react-dom: '>=18' - - react-router@6.30.3: - resolution: {integrity: sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==} - engines: {node: '>=14.0.0'} - peerDependencies: - react: '>=16.8' - - react-router@7.15.0: - resolution: {integrity: sha512-HW9vYwuM8f4yx66Izy8xfrzCM+SBJluoZcCbww9A1TySax11S5Vgw6fi3ZjMONw9J4gQwngL7PzkyIpJJpJ7RQ==} - engines: {node: '>=20.0.0'} - peerDependencies: - react: '>=18' - react-dom: '>=18' - peerDependenciesMeta: - react-dom: - optional: true - - react-signature-canvas@1.1.0-alpha.2: - resolution: {integrity: sha512-tKUNk3Gmh04Ug4K8p5g8Is08BFUKvbXxi0PyetQ/f8OgCBzcx4vqNf9+OArY/TdNdfHtswXQNRwZD6tyELjkjQ==} - peerDependencies: - '@types/prop-types': ^15.7.3 - '@types/react': 0.14 - 19 - prop-types: ^15.5.8 - react: 0.14 - 19 - react-dom: 0.14 - 19 - peerDependenciesMeta: - '@types/prop-types': - optional: true - '@types/react': - optional: true - - react-style-singleton@2.2.3: - resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - react-textarea-autosize@8.5.9: - resolution: {integrity: sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A==} - engines: {node: '>=10'} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - react-transition-group@4.4.5: - resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} - peerDependencies: - react: '>=16.6.0' - react-dom: '>=16.6.0' - - react@16.14.0: - resolution: {integrity: sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==} - engines: {node: '>=0.10.0'} - - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - - react@19.2.6: - resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} - engines: {node: '>=0.10.0'} - - read-cache@1.0.0: - resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} - - globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} - - globalthis@1.0.4: - resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} - engines: {node: '>= 0.4'} - - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - - graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - - handlebars@4.7.9: - resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==} - engines: {node: '>=0.4.7'} - hasBin: true - - has-bigints@1.1.0: - resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} - engines: {node: '>= 0.4'} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - - has-proto@1.2.0: - resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} - engines: {node: '>= 0.4'} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - - has-unicode@2.0.1: - resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} - - hasown@2.0.3: - resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} - engines: {node: '>= 0.4'} - - html-encoding-sniffer@4.0.0: - resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} - engines: {node: '>=18'} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-is: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - html-escaper@2.0.2: - resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - - http-errors@2.0.1: - resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} - engines: {node: '>= 0.8'} - - http-proxy-agent@7.0.2: - resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} - engines: {node: '>= 14'} - - https-proxy-agent@5.0.1: - resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} - engines: {node: '>= 6'} - - https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} - - human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} - - human-signals@5.0.0: - resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} - engines: {node: '>=16.17.0'} - - husky@9.1.7: - resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} - engines: {node: '>=18'} - hasBin: true - - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - - iconv-lite@0.7.2: - resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} - engines: {node: '>=0.10.0'} - - ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} - engines: {node: '>= 4'} - - immer@11.1.8: - resolution: {integrity: sha512-/tbkHMW7y10Lx6i1crLjD4/OhNkRG+Fo7byZHtah0547nIeXYcpIXaUh0IAQY6gO5459qpGGYapcEOHtFXkIuA==} - - import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} - - import-local@3.2.0: - resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} - engines: {node: '>=8'} - hasBin: true - - import-meta-resolve@4.2.0: - resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - inflight@1.0.6: - resolution: {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. - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - ini@4.1.1: - resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - internal-slot@1.1.0: - resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} - engines: {node: '>= 0.4'} - - ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} - - is-array-buffer@3.0.5: - resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} - engines: {node: '>= 0.4'} - - is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - - is-async-function@2.1.1: - resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} - engines: {node: '>= 0.4'} - - is-bigint@1.1.0: - resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} - engines: {node: '>= 0.4'} - - is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - - is-boolean-object@1.2.2: - resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} - engines: {node: '>= 0.4'} - - is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - - is-core-module@2.16.2: - resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} - engines: {node: '>= 0.4'} - - is-data-view@1.0.2: - resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} - engines: {node: '>= 0.4'} - - is-date-object@1.1.0: - resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} - engines: {node: '>= 0.4'} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-finalizationregistry@1.1.1: - resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} - engines: {node: '>= 0.4'} - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - is-fullwidth-code-point@4.0.0: - resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} - engines: {node: '>=12'} - - is-fullwidth-code-point@5.1.0: - resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} - engines: {node: '>=18'} - - is-generator-fn@2.1.0: - resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} - engines: {node: '>=6'} - - is-generator-function@1.1.2: - resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} - engines: {node: '>= 0.4'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-interactive@1.0.0: - resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} - engines: {node: '>=8'} - - is-map@2.0.3: - resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} - engines: {node: '>= 0.4'} - - is-negative-zero@2.0.3: - resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} - engines: {node: '>= 0.4'} - - is-number-object@1.1.1: - resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} - engines: {node: '>= 0.4'} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-obj@2.0.0: - resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} - engines: {node: '>=8'} - - is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - - is-potential-custom-element-name@1.0.1: - resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - - is-promise@4.0.0: - resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} - - is-property@1.0.2: - resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} - - is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} - - is-set@2.0.3: - resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} - engines: {node: '>= 0.4'} - - is-shared-array-buffer@1.0.4: - resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} - engines: {node: '>= 0.4'} - - is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - - is-stream@3.0.0: - resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - is-string@1.1.1: - resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} - engines: {node: '>= 0.4'} - - is-symbol@1.1.1: - resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} - engines: {node: '>= 0.4'} - - is-text-path@2.0.0: - resolution: {integrity: sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==} - engines: {node: '>=8'} - - is-typed-array@1.1.15: - resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} - engines: {node: '>= 0.4'} - - is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} - - is-weakmap@2.0.2: - resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} - engines: {node: '>= 0.4'} - - is-weakref@1.1.1: - resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} - engines: {node: '>= 0.4'} - - is-weakset@2.0.4: - resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} - engines: {node: '>= 0.4'} - - isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - istanbul-lib-coverage@3.2.2: - resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} - engines: {node: '>=8'} - - scheduler@0.19.1: - resolution: {integrity: sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==} - - scheduler@0.23.2: - resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} - - istanbul-lib-instrument@6.0.3: - resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} - engines: {node: '>=10'} - - scheduler@0.27.0: - resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - - schema-utils@3.3.0: - resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} - engines: {node: '>= 10.13.0'} - - istanbul-lib-source-maps@4.0.1: - resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} - engines: {node: '>=10'} - - istanbul-reports@3.2.0: - resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} - engines: {node: '>=8'} - - iterare@1.2.1: - resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==} - engines: {node: '>=6'} - - iterator.prototype@1.1.5: - resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} - engines: {node: '>= 0.4'} - - jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - - jest-changed-files@29.7.0: - resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-circus@29.7.0: - resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-cli@29.7.0: - resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - - jest-config@29.7.0: - resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@types/node': '*' - ts-node: '>=9.0.0' - peerDependenciesMeta: - '@types/node': - optional: true - ts-node: - optional: true - - jest-diff@29.7.0: - resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-docblock@29.7.0: - resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-each@29.7.0: - resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-environment-node@29.7.0: - resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-get-type@29.6.3: - resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-haste-map@29.7.0: - resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-leak-detector@29.7.0: - resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-matcher-utils@29.7.0: - resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-message-util@29.7.0: - resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-mock@29.7.0: - resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-pnp-resolver@1.2.3: - resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} - engines: {node: '>=6'} - peerDependencies: - jest-resolve: '*' - peerDependenciesMeta: - jest-resolve: - optional: true - - jest-regex-util@29.6.3: - resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-resolve-dependencies@29.7.0: - resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-resolve@29.7.0: - resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-runner@29.7.0: - resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-runtime@29.7.0: - resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-snapshot@29.7.0: - resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-util@29.7.0: - resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-validate@29.7.0: - resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-watcher@29.7.0: - resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-worker@27.5.1: - resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} - engines: {node: '>= 10.13.0'} - - jest-worker@29.7.0: - resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest@29.7.0: - resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - - jiti@1.21.7: - resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} - hasBin: true - - jiti@2.6.1: - resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} - hasBin: true + js-md5@0.8.3: + resolution: {integrity: sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ==} js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -9533,8 +7254,28 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true - sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + jsbn@0.1.1: + resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} + + jsdom@25.0.1: + resolution: {integrity: sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==} + engines: {node: '>=18'} + peerDependencies: + canvas: ^2.11.2 + peerDependenciesMeta: + canvas: + optional: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-loader@0.5.7: + resolution: {integrity: sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==} json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} @@ -9545,9 +7286,25 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json-stream@1.0.0: + resolution: {integrity: sha512-H/ZGY0nIAg3QcOwE1QN/rK/Fa7gJn7Ii5obwp6zyPO4xiPNwpIMjqy2gwjBEGqzkF/vSWEIBQCBuN19hYiL6Qg==} + + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + + json3@3.3.3: + resolution: {integrity: sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==} + + json5@0.5.1: + resolution: {integrity: sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==} + hasBin: true + json5@1.0.2: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true @@ -9575,11 +7332,19 @@ packages: resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} engines: {node: '>=12', npm: '>=6'} - sonner@2.0.7: - resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} - peerDependencies: - react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc - react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + jspdf@3.0.4: + resolution: {integrity: sha512-dc6oQ8y37rRcHn316s4ngz/nOjayLF/FFxBF4V9zamQKRqXxyiH1zagkCdktdWhtoQId5K20xt1lB90XzkB+hQ==} + + jsprim@1.4.2: + resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==} + engines: {node: '>=0.6.0'} + + jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + + jszip@3.10.1: + resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} jwa@1.4.2: resolution: {integrity: sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==} @@ -9596,10 +7361,45 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + killable@1.0.1: + resolution: {integrity: sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==} + + kind-of@3.2.2: + resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} + engines: {node: '>=0.10.0'} + + kind-of@4.0.0: + resolution: {integrity: sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==} + engines: {node: '>=0.10.0'} + + kind-of@5.1.0: + resolution: {integrity: sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==} + engines: {node: '>=0.10.0'} + + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} + lazy-cache@1.0.4: + resolution: {integrity: sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==} + engines: {node: '>=0.10.0'} + + lazy-cache@2.0.2: + resolution: {integrity: sha512-7vp2Acd2+Kz4XkzxGxaB1FWOi8KjWIWsgdfD5MCb86DWvlLqhRPM+d6Pro3iNEL5VT9mstz5hKAlcd+QR6H3aA==} + engines: {node: '>=0.10.0'} + + lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + + lcid@1.0.0: + resolution: {integrity: sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==} + engines: {node: '>=0.10.0'} + leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -9608,8 +7408,18 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - libphonenumber-js@1.13.1: - resolution: {integrity: sha512-GEw0GLL7YUUA6nv21IsCvVjtI5Ejn84sjbdfQ9KxdbqEVOk1PZh7xejn01EEiniKw+dBeCfim+8MGeuvVuE2BA==} + libphonenumber-js@1.13.2: + resolution: {integrity: sha512-S3kmBrptp3yRTm83NUcHy9g1vbwiWMzI8WvY22+koBJ6zkRteLnedBL2VX0MIAGwx2yiyxX4J85pceZyQ6ffgg==} + + libphonenumber-js@1.13.3: + resolution: {integrity: sha512-xMkdAMqcyG7iN2WZZmGIfWbYxW4orRkny+0/AXIbwL0xll2zkDX0Vzo/BXFa6+7mh2UvJl9MbcTtHk0YXkFtBA==} + + libreoffice-convert@1.8.1: + resolution: {integrity: sha512-iZ1DD/EMTlPvol8G++QQ/0w4pVecSwRuhMLXRm7nRim/gcaSscSXuTO9Tgbkieyw5UdJg7UXD+lkFT8SCi51Dw==} + engines: {node: '>=6'} + + lie@3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} lightningcss-android-arm64@1.32.0: resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} @@ -9646,24 +7456,28 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.32.0: resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.32.0: resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.32.0: resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.32.0: resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} @@ -9685,14 +7499,23 @@ packages: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} + linebreak@1.1.0: + resolution: {integrity: sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==} + lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + linkifyjs@4.3.3: + resolution: {integrity: sha512-P8aEP5U/D1/IlTY2OeYsErdwh9bGuLE30NcXtKEjgdHcahveQoQwM2yZNsioQHsWFz0P7KKudisbrzCgR0sDHg==} + lint-staged@15.5.2: resolution: {integrity: sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==} engines: {node: '>=18.12.0'} hasBin: true + listenercount@1.0.1: + resolution: {integrity: sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==} + listr2@8.3.3: resolution: {integrity: sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==} engines: {node: '>=18.0.0'} @@ -9701,10 +7524,34 @@ packages: resolution: {integrity: sha512-v5xlu8eHD1+6r8EHTg6hfmO97LN8ugKtiXcy5e6oN72iD2r6u0RPfLl6fxM+7Wnh2ZRq15o0russMst44WauPA==} engines: {node: '>=13.2.0'} + load-json-file@1.1.0: + resolution: {integrity: sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==} + engines: {node: '>=0.10.0'} + + load-json-file@2.0.0: + resolution: {integrity: sha512-3p6ZOGNbiX4CdvEd1VcE6yi78UrGNpjHO33noGwHCnT/o2fyllJDepsm8+mFFv/DvtwFHht5HIHSyOy5a+ChVQ==} + engines: {node: '>=4'} + + loadash@1.0.0: + resolution: {integrity: sha512-xlX5HBsXB3KG0FJbJJG/3kYWCfsCyCSus3T+uHVu6QL6YxAdggmm3QeyLgn54N2yi5/UE6xxL5ZWJAAiHzHYEg==} + deprecated: Package is unsupport. Please use the lodash package instead. + + loader-runner@2.4.0: + resolution: {integrity: sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==} + engines: {node: '>=4.3.0 <5.0.0 || >=5.10'} + loader-runner@4.3.2: resolution: {integrity: sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==} engines: {node: '>=6.11.5'} + loader-utils@1.4.2: + resolution: {integrity: sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==} + engines: {node: '>=4.0.0'} + + locate-path@2.0.0: + resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} + engines: {node: '>=4'} + locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -9717,18 +7564,50 @@ packages: resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + locter@2.2.1: + resolution: {integrity: sha512-Cc7mowptFl7ug5he6Iuos7aGRd9xbwTfnx1ng4AX/7F4iqemPaXAIJDi13IBwQZrKgli9OPEYXm6uCKr7ynxUQ==} + engines: {node: '>=22.0.0'} + + lodash._reinterpolate@3.0.0: + resolution: {integrity: sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==} + lodash.camelcase@4.3.0: resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + lodash.defaults@4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + + lodash.difference@4.5.0: + resolution: {integrity: sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==} + + lodash.escaperegexp@4.1.2: + resolution: {integrity: sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==} + + lodash.flatten@4.4.0: + resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} + + lodash.groupby@4.6.0: + resolution: {integrity: sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==} + lodash.includes@4.3.0: resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} lodash.isboolean@3.0.3: resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} + lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. + + lodash.isfunction@3.0.9: + resolution: {integrity: sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==} + lodash.isinteger@4.0.4: resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} + lodash.isnil@4.0.0: + resolution: {integrity: sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==} + lodash.isnumber@3.0.3: resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} @@ -9738,6 +7617,9 @@ packages: lodash.isstring@4.0.1: resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + lodash.isundefined@3.0.1: + resolution: {integrity: sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==} + lodash.kebabcase@4.1.1: resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==} @@ -9759,6 +7641,16 @@ packages: lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + lodash.template@4.18.1: + resolution: {integrity: sha512-5urZrLnV/VD6zHK5KsVtZgt7H19v51mIzoS0aBNH8yp3I8tbswrEjOABOPY8m8uB7NuibubLrMX+Y0PXsU9X+w==} + deprecated: This package is deprecated. Use https://socket.dev/npm/package/eta instead. + + lodash.templatesettings@4.2.0: + resolution: {integrity: sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==} + + lodash.union@4.6.0: + resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==} + lodash.uniq@4.5.0: resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} @@ -9771,6 +7663,10 @@ packages: lodash@4.18.1: resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} + log-ok@0.1.1: + resolution: {integrity: sha512-cc8VrkS6C+9TFuYAwuHpshrcrGRAv7d0tUJ0GdM72ZBlKXtlgjUZF84O+OhQUdiVHoF7U/nVxwpjOdwUJ8d3Vg==} + engines: {node: '>=0.10.0'} + log-symbols@4.1.0: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} @@ -9779,29 +7675,56 @@ packages: resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} engines: {node: '>=18'} - long@5.3.2: - resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + log-utils@0.2.1: + resolution: {integrity: sha512-udyegKoMz9eGfpKAX//Khy7sVAZ8b1F7oLDnepZv/1/y8xTvsyPgqQrM94eG8V0vcc2BieYI2kVW4+aa6m+8Qw==} + engines: {node: '>=0.10.0'} + + logging-helpers@1.0.0: + resolution: {integrity: sha512-qyIh2goLt1sOgQQrrIWuwkRjUx4NUcEqEGAcYqD8VOnOC6ItwkrVE8/tA4smGpjzyp4Svhc6RodDp9IO5ghpyA==} + engines: {node: '>=0.10.0'} + + loglevel@1.9.2: + resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} + engines: {node: '>= 0.6.0'} + + longest@1.0.1: + resolution: {integrity: sha512-k+yt5n3l48JU4k8ftnKG6V7u32wyH2NfKzeMto9F/QRE0amxy/LayxwlvjjkZEIzqR+19IrtFO8p5kB9QaYUFg==} + engines: {node: '>=0.10.0'} loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true + lottie-web@5.13.0: + resolution: {integrity: sha512-+gfBXl6sxXMPe8tKQm7qzLnUy5DUPJPKIyRHwtpCpyUEYjHYRJC/5gjUvdkuO2c3JllrPtHXH5UJJK8LRYl5yQ==} + + loud-rejection@1.6.0: + resolution: {integrity: sha512-RPNliZOFkqFumDhvYqOaNY4Uz9oJM2K9tC6JWsJJsNdhuONW4LQHRBpb0qf4pJApVffI5N39SwzWZJuEhfd7eQ==} + engines: {node: '>=0.10.0'} + loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.3.6: - resolution: {integrity: sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==} + lru-cache@11.5.0: + resolution: {integrity: sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA==} engines: {node: 20 || >=22} + lru-cache@4.1.5: + resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lru.min@1.1.4: - resolution: {integrity: sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==} - engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} + lucide-react@0.513.0: + resolution: {integrity: sha512-CJZKq2g8Y8yN4Aq002GahSXbG2JpFv9kXwyiOAMvUBv7pxeOFHUWKB0mO7MiY4ZVFCV4aNjv2BJFq/z3DgKPQg==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 luxon@3.7.2: resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==} @@ -9813,6 +7736,9 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + make-cancellable-promise@2.0.0: + resolution: {integrity: sha512-3SEQqTpV9oqVsIWqAcmDuaNeo7yBO3tqPtqGRcKkEo0lrzD3wqbKG9mkxO65KoOgXqj+zH2phJ2LiAsdzlogSw==} + make-dir@3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} @@ -9824,13 +7750,37 @@ packages: make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + make-event-props@2.0.0: + resolution: {integrity: sha512-G/hncXrl4Qt7mauJEXSg3AcdYzmpkIITTNl5I+rH9sog5Yw0kK6vseJjCaPfOXqOqQuPUP89Rkhfz5kPS8ijtw==} + makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + map-cache@0.2.2: + resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} + engines: {node: '>=0.10.0'} + + map-obj@1.0.1: + resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} + engines: {node: '>=0.10.0'} + + map-visit@1.0.0: + resolution: {integrity: sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==} + engines: {node: '>=0.10.0'} + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + md5.js@1.3.5: + resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} + + mdn-data@2.0.14: + resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==} + + media-engine@1.0.3: + resolution: {integrity: sha512-aa5tG6sDoK+k70B9iEX1NeyfT8ObCKhNDs6lJVpwF6r8vhUfuKMslIcirq6HIUYuuUYLefcEQOn9bSBOvawtwg==} + media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} @@ -9839,18 +7789,40 @@ packages: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} + mem@1.1.0: + resolution: {integrity: sha512-nOBDrc/wgpkd3X/JOhMqYR+/eLqlfLP4oQfoBA6QExIxEl+GU01oyEkwWyueyO8110pUKijtiHGhEmYoOn88oQ==} + engines: {node: '>=4'} + memfs@3.5.3: resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==} engines: {node: '>= 4.0.0'} + memory-fs@0.4.1: + resolution: {integrity: sha512-cda4JKCxReDXFXRqOHPQscuIYg1PvxbE2S2GP45rnwfEK+vZaXC8C1OFvdHIbgw0DLzowXGVoxLaAmlgRy14GQ==} + meow@12.1.1: resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} engines: {node: '>=16.10'} + meow@3.7.0: + resolution: {integrity: sha512-TNdwZs0skRlpPpCUK25StC4VH+tP5GgeY1HQOOGP+lQ2xtdkN2VtT/5tiX9k3IWpkBPV9b3LsAWXn4GGi/PrSA==} + engines: {node: '>=0.10.0'} + + merge-descriptors@1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + merge-descriptors@2.0.0: resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} engines: {node: '>=18'} + merge-refs@2.0.0: + resolution: {integrity: sha512-3+B21mYK2IqUWnd2EivABLT7ueDhb0b8/dGK8LoFQPrU61YITeCMn14F7y7qZafWNZhUEKb24cJdiT5Wxs3prg==} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -9862,10 +7834,18 @@ packages: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} + micromatch@3.1.10: + resolution: {integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==} + engines: {node: '>=0.10.0'} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + miller-rabin@4.0.1: + resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} + hasBin: true + mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -9882,11 +7862,23 @@ packages: resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} engines: {node: '>=18'} + mime@1.2.11: + resolution: {integrity: sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==} + + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + mime@2.6.0: resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} engines: {node: '>=4.0.0'} hasBin: true + mimic-fn@1.2.0: + resolution: {integrity: sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==} + engines: {node: '>=4'} + mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -9899,9 +7891,11 @@ packages: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} - mimic-response@2.1.0: - resolution: {integrity: sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==} - engines: {node: '>=8'} + minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + + minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} minimatch@10.2.5: resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} @@ -9910,6 +7904,10 @@ packages: minimatch@3.1.5: resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} + engines: {node: '>=10'} + minimatch@9.0.9: resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} @@ -9917,6 +7915,10 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minio@7.1.3: + resolution: {integrity: sha512-xPrLjWkTT5E7H7VnzOjF//xBp9I40jYB4aWhb2xTFopXXfw+Wo82DDWngdUju7Doy3Wk7R8C4LAgwhLHHnf0wA==} + engines: {node: ^16 || ^18 || >=20} + minipass@3.3.6: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} engines: {node: '>=8'} @@ -9933,44 +7935,87 @@ packages: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} engines: {node: '>= 8'} + mixin-deep@1.3.2: + resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==} + engines: {node: '>=0.10.0'} + + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} hasBin: true + moment@2.30.1: + resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} + + motion-dom@12.40.0: + resolution: {integrity: sha512-HxU3ZaBwNPVQUBQf1xxgq+7JrPNZvjLVxgbpEZL7RrWJnsxOf0/OM+yrHG9ogLQ31Do/r57Oz2gQWPK+6q62mg==} + + motion-utils@12.39.0: + resolution: {integrity: sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==} + + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mui-ethiopian-datepicker@0.3.2: + resolution: {integrity: sha512-I8TZ8lvloAxhFNl8tDl7NmgT7RPJslfnArNMpT2Sd9GbpfsdRrOwH/JBMcOhLQyaNUee9due0W6J85io1WLjlg==} + peerDependencies: + '@emotion/react': ^11.11.0 + '@emotion/styled': ^11.11.0 + '@mui/icons-material': ^5.11.16 + '@mui/material': ^5.13.3 + '@mui/x-date-pickers': ^6.7.0 + date-fns: ^2.30.0 + react: ^18.2.0 + react-dom: ^18.2.0 + multer@2.1.1: resolution: {integrity: sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==} engines: {node: '>= 10.16.0'} + multicast-dns-service-types@1.1.0: + resolution: {integrity: sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==} + + multicast-dns@7.2.5: + resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==} + hasBin: true + mute-stream@2.0.0: resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} engines: {node: ^18.17.0 || >=20.5.0} - mysql2@3.15.3: - resolution: {integrity: sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==} - engines: {node: '>= 8.0'} - mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - named-placeholders@1.1.6: - resolution: {integrity: sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==} - engines: {node: '>=8.0.0'} - - nan@2.26.2: - resolution: {integrity: sha512-0tTvBTYkt3tdGw22nrAy50x7gpbGCCFH3AFcyS5WiUu7Eu4vWlri1woE6qHBSfy11vksDqkiwjOnlR7WV8G1Hw==} + nan@2.27.0: + resolution: {integrity: sha512-hC+0LidcL3XE4rp1C4H54KujgXKzbfyTngZTwBByQxsOxCEKZT0MPQ4hOKUH2jU1OYstqdDH4onyHPDzcV0XdQ==} nanoid@3.3.12: resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanomatch@1.2.13: + resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==} + engines: {node: '>=0.10.0'} + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + + negotiator@0.6.4: + resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} + engines: {node: '>= 0.6'} + negotiator@1.0.0: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} @@ -9978,12 +8023,34 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + nestjs-minio-client@2.2.0: + resolution: {integrity: sha512-mz1vfJq/7YfSyVCIeZwOCfIfBz+msI9QynHS2QGO9GB+tVNnQOYta8PxFsH9tMxN7gNrjrf5jXsEIpgBB1oTeA==} + peerDependencies: + '@nestjs/common': '>=9.0.0' + '@nestjs/core': '>=9.0.0' + + next-themes@0.4.6: + resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} + peerDependencies: + react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + + next-tick@1.1.0: + resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} + + no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + node-abort-controller@3.1.1: resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} node-addon-api@5.1.0: resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==} + node-addon-api@8.7.0: + resolution: {integrity: sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==} + engines: {node: ^18 || ^20 || >= 21} + node-emoji@1.11.0: resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} @@ -10003,21 +8070,50 @@ packages: encoding: optional: true + node-forge@0.10.0: + resolution: {integrity: sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==} + engines: {node: '>= 6.0.0'} + + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + + node-html-parser@6.1.13: + resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==} + node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - node-releases@2.0.44: - resolution: {integrity: sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==} + node-libs-browser@2.2.1: + resolution: {integrity: sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==} + + node-releases@2.0.45: + resolution: {integrity: sha512-iIbHXV9eBB2nB0wa7oTsrrXq+qQt+9SIlx9AX3T96YgobtEQfis5n6TJ6vV+3QP8DwdriEAcGhARaFCu37peBg==} + engines: {node: '>=18'} nopt@5.0.0: resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} engines: {node: '>=6'} hasBin: true + normalize-package-data@2.5.0: + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + + normalize-path@2.1.1: + resolution: {integrity: sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==} + engines: {node: '>=0.10.0'} + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} + normalize-svg-path@1.1.0: + resolution: {integrity: sha512-r9KHKG2UUeB5LoTouwDzBy2VxXlHsiM6fyLQvnJa0S5hrhzqElH/CH7TUGhT1fVvIYBIKf3OpY4YJ4CK+iaqHg==} + + npm-run-path@2.0.2: + resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==} + engines: {node: '>=4'} + npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} @@ -10030,6 +8126,13 @@ packages: resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} deprecated: This package is no longer supported. + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + number-is-nan@1.0.1: + resolution: {integrity: sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==} + engines: {node: '>=0.10.0'} + nwsapi@2.2.23: resolution: {integrity: sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==} @@ -10038,10 +8141,17 @@ packages: engines: {node: '>=18'} hasBin: true + oauth-sign@0.9.0: + resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==} + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + object-copy@0.1.0: + resolution: {integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==} + engines: {node: '>=0.10.0'} + object-hash@3.0.0: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} @@ -10050,10 +8160,18 @@ packages: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} + object-is@1.1.6: + resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} + engines: {node: '>= 0.4'} + object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} + object-visit@1.0.1: + resolution: {integrity: sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==} + engines: {node: '>=0.10.0'} + object.assign@4.1.7: resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} engines: {node: '>= 0.4'} @@ -10070,10 +8188,17 @@ packages: resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} engines: {node: '>= 0.4'} + object.pick@1.3.0: + resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==} + engines: {node: '>=0.10.0'} + object.values@1.2.1: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} + obuf@1.1.2: + resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + ohash@2.0.11: resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} @@ -10081,6 +8206,10 @@ packages: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} + on-headers@1.1.0: + resolution: {integrity: sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==} + engines: {node: '>= 0.8'} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -10096,6 +8225,14 @@ packages: resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} engines: {node: '>=18'} + opencollective-postinstall@2.0.3: + resolution: {integrity: sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==} + hasBin: true + + opn@5.5.0: + resolution: {integrity: sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==} + engines: {node: '>=4'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -10104,10 +8241,35 @@ packages: resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} engines: {node: '>=10'} + orderedmap@2.1.1: + resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==} + + original@1.0.2: + resolution: {integrity: sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==} + + os-browserify@0.3.0: + resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==} + + os-locale@1.4.0: + resolution: {integrity: sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==} + engines: {node: '>=0.10.0'} + + os-locale@2.1.0: + resolution: {integrity: sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==} + engines: {node: '>=4'} + own-keys@1.0.1: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} + p-finally@1.0.0: + resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} + engines: {node: '>=4'} + + p-limit@1.3.0: + resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} + engines: {node: '>=4'} + p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -10120,6 +8282,10 @@ packages: resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + p-locate@2.0.0: + resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} + engines: {node: '>=4'} + p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} @@ -10132,6 +8298,14 @@ packages: resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + p-map@1.2.0: + resolution: {integrity: sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==} + engines: {node: '>=4'} + + p-try@1.0.0: + resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} + engines: {node: '>=4'} + p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -10139,14 +8313,34 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + pako@0.2.9: + resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} + + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + + pako@2.1.0: + resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-asn1@5.1.9: + resolution: {integrity: sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==} + engines: {node: '>= 0.10'} + + parse-json@2.2.0: + resolution: {integrity: sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==} + engines: {node: '>=0.10.0'} + parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse-svg-path@0.1.2: + resolution: {integrity: sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==} + parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} @@ -10154,6 +8348,13 @@ packages: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} + pascal-case@3.1.2: + resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} + + pascalcase@0.1.1: + resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==} + engines: {node: '>=0.10.0'} + passport-jwt@4.0.1: resolution: {integrity: sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==} @@ -10165,6 +8366,20 @@ packages: resolution: {integrity: sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==} engines: {node: '>= 0.4.0'} + path-browserify@0.0.1: + resolution: {integrity: sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==} + + path-dirname@1.0.2: + resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==} + + path-exists@2.1.0: + resolution: {integrity: sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==} + engines: {node: '>=0.10.0'} + + path-exists@3.0.0: + resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} + engines: {node: '>=4'} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -10177,6 +8392,13 @@ packages: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} + path-is-inside@1.0.2: + resolution: {integrity: sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==} + + path-key@2.0.1: + resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==} + engines: {node: '>=4'} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -10196,16 +8418,30 @@ packages: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} + path-to-regexp@0.1.13: + resolution: {integrity: sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==} + path-to-regexp@3.3.0: resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==} path-to-regexp@8.4.2: resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + path-type@1.1.0: + resolution: {integrity: sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==} + engines: {node: '>=0.10.0'} + + path-type@2.0.0: + resolution: {integrity: sha512-dUnb5dXUf+kzhC/W/F4e5/SkluXIFf5VUHolW1Eg1irn1hGWjPGdsRcvYJ1nD6lhk8Ir7VM0bHJKsYTx8Jx9OQ==} + engines: {node: '>=4'} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + path@0.12.7: + resolution: {integrity: sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==} + pathe@1.1.2: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} @@ -10219,33 +8455,59 @@ packages: pause@0.0.1: resolution: {integrity: sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==} + pbkdf2@3.1.5: + resolution: {integrity: sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==} + engines: {node: '>= 0.10'} + + pdfjs-dist@2.16.105: + resolution: {integrity: sha512-J4dn41spsAwUxCpEoVf6GVoz908IAA3mYiLmNxg8J9kfRXc2jxpbUepcP0ocp0alVNLFthTAM8DZ1RaHh8sU0A==} + peerDependencies: + worker-loader: ^3.0.8 + peerDependenciesMeta: + worker-loader: + optional: true + + pdfjs-dist@5.4.296: + resolution: {integrity: sha512-DlOzet0HO7OEnmUmB6wWGJrrdvbyJKftI1bhMitK7O2N8W2gc757yyYBbINy9IDafXAV9wmKr9t7xsTaNKRG5Q==} + engines: {node: '>=20.16.0 || >=22.3.0'} + + peek-readable@5.4.2: + resolution: {integrity: sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg==} + engines: {node: '>=14.16'} + perfect-debounce@1.0.0: resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} - pg-cloudflare@1.3.0: - resolution: {integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==} + perfect-freehand@1.2.3: + resolution: {integrity: sha512-bHZSfqDHGNlPpgH2yxXgPHlQSPpEbo+qg7li0M78J9vNAi2yjwLeA4x79BEQhX44lEWpCLSFCeRZwpw0niiXPA==} - pg-connection-string@2.12.0: - resolution: {integrity: sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==} + performance-now@2.1.0: + resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} + + pg-cloudflare@1.4.0: + resolution: {integrity: sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A==} + + pg-connection-string@2.13.0: + resolution: {integrity: sha512-EMnU9E2fSULdsbErBbMaXJvFeD9B4+nPcM3f+4lsiCR0BHLPrLVjv3DbyM2hgQQviKJaTWIRRTjKjWlHg3p2ig==} pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} - pg-pool@3.13.0: - resolution: {integrity: sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==} + pg-pool@3.14.0: + resolution: {integrity: sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==} peerDependencies: pg: '>=8.0' - pg-protocol@1.13.0: - resolution: {integrity: sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==} + pg-protocol@1.14.0: + resolution: {integrity: sha512-n5taZ1kO3s9ngDTVxsEznOqCyToTgz0FLuPq0B33COy5pPpuWJpY3/2oRBVETuOgzdqRXfWpM9HIhp2LBBT1BA==} pg-types@2.2.0: resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} engines: {node: '>=4'} - pg@8.20.0: - resolution: {integrity: sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==} + pg@8.21.0: + resolution: {integrity: sha512-AUP1EYJuHraQGsVoCQVIcM7TEJVGtDzxWtGFZd8rds9d+CCXlU5Js1rYgfLNvxy9iJrpHjGrRjoi/3BT9fRyiA==} engines: {node: '>= 16.0.0'} peerDependencies: pg-native: '>=3.0.1' @@ -10276,10 +8538,26 @@ packages: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} + pify@3.0.0: + resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} + engines: {node: '>=4'} + + pinkie-promise@2.0.1: + resolution: {integrity: sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==} + engines: {node: '>=0.10.0'} + + pinkie@2.0.4: + resolution: {integrity: sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==} + engines: {node: '>=0.10.0'} + pirates@4.0.7: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} + pkg-dir@2.0.0: + resolution: {integrity: sha512-ojakdnUgL5pzJYWw2AIDEupaQCX5OPbM688ZevubICjdIX01PRSYKqm33fJoCOJBRseYCTUlQRnBNX+Pchaejw==} + engines: {node: '>=4'} + pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} @@ -10291,10 +8569,25 @@ packages: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} + png-js@2.0.0: + resolution: {integrity: sha512-GdzJuUMc6ZSpxFJWVxtOH1bzYHym+TOnveqUjb+VJIbZWbZzyiRGFiKhbiielfpYbgMlhHVhsJ0FTazfuRFkMA==} + pngjs@5.0.0: resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} engines: {node: '>=10.13.0'} + popper.js@1.16.1: + resolution: {integrity: sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==} + deprecated: You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1 + + portfinder@1.0.38: + resolution: {integrity: sha512-rEwq/ZHlJIKw++XtLAO8PPuOQA/zaPJOZJ37BVuN97nLpMJeuDVLVGRwbFoBgLudgdTMP2hdRJP++H+8QOA3vg==} + engines: {node: '>= 10.12'} + + posix-character-classes@0.1.1: + resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} + engines: {node: '>=0.10.0'} + possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} @@ -10342,8 +8635,8 @@ packages: postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.5.14: - resolution: {integrity: sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==} + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} engines: {node: ^10 || ^12 || >=14} postgres-array@2.0.0: @@ -10358,6 +8651,1791 @@ packages: resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} engines: {node: '>=0.10.0'} + postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier@3.8.3: + resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} + engines: {node: '>=14'} + hasBin: true + + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + prisma@6.19.3: + resolution: {integrity: sha512-++ZJ0ijLrDJF6hNB4t4uxg2br3fC4H9Yc9tcbjr2fcNFP3rh/SBNrAgjhsqBU4Ght8JPrVofG/ZkXfnSfnYsFg==} + engines: {node: '>=18.18'} + hasBin: true + peerDependencies: + typescript: '>=5.1.0' + peerDependenciesMeta: + typescript: + optional: true + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + prosemirror-changeset@2.4.1: + resolution: {integrity: sha512-96WBLhOaYhJ+kPhLg3uW359Tz6I/MfcrQfL4EGv4SrcqKEMC1gmoGrXHecPE8eOwTVCJ4IwgfzM8fFad25wNfw==} + + prosemirror-commands@1.7.1: + resolution: {integrity: sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==} + + prosemirror-dropcursor@1.8.2: + resolution: {integrity: sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==} + + prosemirror-gapcursor@1.4.1: + resolution: {integrity: sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==} + + prosemirror-history@1.5.0: + resolution: {integrity: sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==} + + prosemirror-keymap@1.2.3: + resolution: {integrity: sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==} + + prosemirror-model@1.25.7: + resolution: {integrity: sha512-A79aN8QEFUwI6cax8Yq4Rpcx1TJZ3Kagn+ii7qLo4/V8H3mMiHrhFyhTyHHvpSnOgMPpWiDGSwM3etwrxE50ug==} + + prosemirror-schema-list@1.5.1: + resolution: {integrity: sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==} + + prosemirror-state@1.4.4: + resolution: {integrity: sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==} + + prosemirror-tables@1.8.5: + resolution: {integrity: sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==} + + prosemirror-transform@1.12.0: + resolution: {integrity: sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w==} + + prosemirror-view@1.41.8: + resolution: {integrity: sha512-TnKDdohEatgyZNGCDWIdccOHXhYloJwbwU+phw/a23KBvJIR9lWQWW7WHHK3vBdOLDNuF7TaX98GObUZOWkOnA==} + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + proxy-compare@3.0.1: + resolution: {integrity: sha512-V9plBAt3qjMlS1+nC8771KNf6oJ12gExvaxnNzN/9yVRLdTv/lc+oJlnSzrdYDAvBfTStPCoiaCOTmTs0adv7Q==} + + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + + proxy-memoize@3.0.1: + resolution: {integrity: sha512-VDdG/VYtOgdGkWJx7y0o7p+zArSf2383Isci8C+BP3YXgMYDoPd3cCBjw0JdWb6YBb9sFiOPbAADDVTPJnh+9g==} + + prr@1.0.1: + resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + + pseudomap@1.0.2: + resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} + + psl@1.15.0: + resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} + + public-encrypt@4.0.3: + resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} + + punycode@1.4.1: + resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + + qrcode@1.5.4: + resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==} + engines: {node: '>=10.13.0'} + hasBin: true + + qs@6.15.2: + resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==} + engines: {node: '>=0.6'} + + qs@6.5.5: + resolution: {integrity: sha512-mzR4sElr1bfCaPJe7m8ilJ6ZXdDaGoObcYR0ZHSsktM/Lt21MVHj5De30GQH2eiZ1qGRTO7LCAzQsUeXTNexWQ==} + engines: {node: '>=0.6'} + + query-string@7.1.3: + resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} + engines: {node: '>=6'} + + querystring-es3@0.2.1: + resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} + engines: {node: '>=0.4.x'} + + querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + queue@6.0.2: + resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} + + raf@3.4.1: + resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==} + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + randomfill@1.0.4: + resolution: {integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + rapiq@0.9.0: + resolution: {integrity: sha512-k4oT4RarFBrlLMJ49xUTeQpa/us0uU4I70D/UEnK3FWQ4GENzei01rEQAmvPKAIzACo4NMW+YcYJ7EVfSa7EFg==} + + raw-body@2.5.3: + resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==} + engines: {node: '>= 0.8'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + + rc9@2.1.2: + resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} + + react-cookie@8.1.2: + resolution: {integrity: sha512-S45Z1y1dHyYfLEI4bFKQICuP+SwJqTPWbdc2ZpE6aQSdjSVJAjUDfwTPq8B7BWieIsgyyEWMb/QOrudtwJMjXA==} + peerDependencies: + react: '>= 16.3.0' + + react-datepicker@8.10.0: + resolution: {integrity: sha512-JIXuA+g+qP3c4MVJpx24o7n1gnv3WV/8A/D6964HucY1FlSEc30+ITPNUfbKZXYHl5rruCtxYCwi2lzn7gaz7g==} + peerDependencies: + react: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.9.0 || ^17 || ^18 || ^19 || ^19.0.0-rc + + react-day-picker@9.14.0: + resolution: {integrity: sha512-tBaoDWjPwe0M5pGrum4H0SR6Lyk+BO9oHnp9JbKpGKW2mlraNPgP9BMfsg5pWpwrssARmeqk7YBl2oXutZTaHA==} + engines: {node: '>=18'} + peerDependencies: + react: '>=16.8.0' + + react-dom@16.14.0: + resolution: {integrity: sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==} + peerDependencies: + react: ^16.14.0 + + react-dom@18.3.1: + resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} + peerDependencies: + react: ^18.3.1 + + react-dom@19.2.6: + resolution: {integrity: sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==} + peerDependencies: + react: ^19.2.6 + + react-dropzone@14.4.1: + resolution: {integrity: sha512-QDuV76v3uKbHiH34SpwifZ+gOLi1+RdsCO1kl5vxMT4wW8R82+sthjvBw4th3NHF/XX6FBsqDYZVNN+pnhaw0g==} + engines: {node: '>= 10.13'} + peerDependencies: + react: '>= 16.8 || 18.0.0' + + react-floater@0.7.9: + resolution: {integrity: sha512-NXqyp9o8FAXOATOEo0ZpyaQ2KPb4cmPMXGWkx377QtJkIXHlHRAGer7ai0r0C1kG5gf+KJ6Gy+gdNIiosvSicg==} + peerDependencies: + react: 15 - 18 + react-dom: 15 - 18 + + react-hook-form@7.76.0: + resolution: {integrity: sha512-eKtLGgFeSgkHqQD8J59AMZ9a4uD1D83iSIzt4YlTGD7liDen5rrjcUO1rVIGd9yC1gofryjtHbv+4ny4hkLWlw==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 || ^19 + + react-i18next@15.7.4: + resolution: {integrity: sha512-nyU8iKNrI5uDJch0z9+Y5XEr34b0wkyYj3Rp+tfbahxtlswxSCjcUL9H0nqXo9IR3/t5Y5PKIA3fx3MfUyR9Xw==} + peerDependencies: + i18next: '>= 23.4.0' + react: '>= 16.8.0' + react-dom: '*' + react-native: '*' + typescript: ^5 + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + typescript: + optional: true + + react-icons@5.6.0: + resolution: {integrity: sha512-RH93p5ki6LfOiIt0UtDyNg/cee+HLVR6cHHtW3wALfo+eOHTp8RnU2kRkI6E+H19zMIs03DyxUG/GfZMOGvmiA==} + peerDependencies: + react: '*' + + react-image-crop@11.0.10: + resolution: {integrity: sha512-+5FfDXUgYLLqBh1Y/uQhIycpHCbXkI50a+nbfkB1C0xXXUTwkisHDo2QCB1SQJyHCqIuia4FeyReqXuMDKWQTQ==} + peerDependencies: + react: '>=16.13.1' + + react-innertext@1.1.5: + resolution: {integrity: sha512-PWAqdqhxhHIv80dT9znP2KvS+hfkbRovFp4zFYHFFlOoQLRiawIic81gKb3U1wEyJZgMwgs3JoLtwryASRWP3Q==} + peerDependencies: + '@types/react': '>=0.0.0 <=99' + react: '>=0.0.0 <=99' + + react-intersection-observer@9.16.0: + resolution: {integrity: sha512-w9nJSEp+DrW9KmQmeWHQyfaP6b03v+TdXynaoA964Wxt7mdR3An11z4NNCQgL4gKSK7y1ver2Fq+JKH6CWEzUA==} + peerDependencies: + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + react-dom: + optional: true + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react-is@19.2.6: + resolution: {integrity: sha512-XjBR15BhXuylgWGuslhDKqlSayuqvqBX91BP8pauG8kd1zY8kotkNWbXksTCNRarse4kuGbe2kIY05ARtwNIvw==} + + react-joyride@2.9.3: + resolution: {integrity: sha512-1+Mg34XK5zaqJ63eeBhqdbk7dlGCFp36FXwsEvgpjqrtyywX2C6h9vr3jgxP0bGHCw8Ilsp/nRDzNVq6HJ3rNw==} + peerDependencies: + react: 15 - 18 + react-dom: 15 - 18 + + react-number-format@5.4.5: + resolution: {integrity: sha512-y8O2yHHj3w0aE9XO8d2BCcUOOdQTRSVq+WIuMlLVucAm5XNjJAy+BoOJiuQMldVYVOKTMyvVNfnbl2Oqp+YxGw==} + peerDependencies: + react: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + react-pdf-html@2.1.5: + resolution: {integrity: sha512-KhmiTUcnUNbLVdZbxMcV/+Rp+PyBt+eVJHu425eNwjSsDUtytvcwS/SBdBbbpM0c4+MnnOQBOs3AiColUesM8A==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@react-pdf/renderer': '>=3.4.4' + react: '>=16' + + react-pdf-viewer@0.1.0: + resolution: {integrity: sha512-JO0bZEA6EMtljhTrLNyn9T03nIOXY6/tzK8guOdwfYpImdOpYfACy47G9AKXrVrtob9bEW2d1jR3MkC0NEGajw==} + + react-pdf@10.4.1: + resolution: {integrity: sha512-kS/35staVCBqS29verTQJQZXw7RfsRCPO3fdJoW1KXylcv7A9dw6DZ3vJXC2w+bIBgLw5FN4pOFvKSQtkQhPfA==} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-redux@9.3.0: + resolution: {integrity: sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==} + peerDependencies: + '@types/react': ^18.2.25 || ^19 + react: ^18.0 || ^19 + redux: ^5.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + redux: + optional: true + + react-refresh@0.17.0: + resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} + engines: {node: '>=0.10.0'} + + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.2: + resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-resizable-panels@3.0.6: + resolution: {integrity: sha512-b3qKHQ3MLqOgSS+FRYKapNkJZf5EQzuf6+RLiq1/IlTHw99YrZ2NJZLk4hQIzTnnIkRg2LUqyVinu6YWWpUYew==} + peerDependencies: + react: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + + react-router-dom@6.30.3: + resolution: {integrity: sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + + react-router-dom@7.15.1: + resolution: {integrity: sha512-AzF62gjY6U9rkMq4RfP/r2EVtQ7DMfNMjyOp/flLTCrtRylLiK4wT4pSq6O8rOXZ2eXdZYJPEYe+ifomiv+Igg==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + + react-router@6.30.3: + resolution: {integrity: sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==} + engines: {node: '>=14.0.0'} + peerDependencies: + react: '>=16.8' + + react-router@7.15.1: + resolution: {integrity: sha512-R8rl9HhgikFYoPJymnUtPXWbnDb3oget6lQnfIoupbt61aT9aOhRkDsY2XRhZRyX1Z/8a5sL74fXmFNm3NRK5A==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + + react-signature-canvas@1.1.0-alpha.2: + resolution: {integrity: sha512-tKUNk3Gmh04Ug4K8p5g8Is08BFUKvbXxi0PyetQ/f8OgCBzcx4vqNf9+OArY/TdNdfHtswXQNRwZD6tyELjkjQ==} + peerDependencies: + '@types/prop-types': ^15.7.3 + '@types/react': 0.14 - 19 + prop-types: ^15.5.8 + react: 0.14 - 19 + react-dom: 0.14 - 19 + peerDependenciesMeta: + '@types/prop-types': + optional: true + '@types/react': + optional: true + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-textarea-autosize@8.5.9: + resolution: {integrity: sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A==} + engines: {node: '>=10'} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + react-transition-group@4.4.5: + resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} + peerDependencies: + react: '>=16.6.0' + react-dom: '>=16.6.0' + + react@16.14.0: + resolution: {integrity: sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==} + engines: {node: '>=0.10.0'} + + react@18.3.1: + resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} + engines: {node: '>=0.10.0'} + + react@19.2.6: + resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} + engines: {node: '>=0.10.0'} + + read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + + read-pkg-up@1.0.1: + resolution: {integrity: sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==} + engines: {node: '>=0.10.0'} + + read-pkg-up@2.0.0: + resolution: {integrity: sha512-1orxQfbWGUiTn9XsPlChs6rLie/AV9jwZTGmu2NZw/CUDJQchXJFYE0Fq5j7+n558T1JhDWLdhyd1Zj+wLY//w==} + engines: {node: '>=4'} + + read-pkg@1.1.0: + resolution: {integrity: sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==} + engines: {node: '>=0.10.0'} + + read-pkg@2.0.0: + resolution: {integrity: sha512-eFIBOPW7FGjzBuk3hdXEuNSiTZS/xEMlH49HxMyzb0hyPfu4EhVjT2DH32K1hSSmVq4sebAWnZuuY5auISUTGA==} + engines: {node: '>=4'} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readable-stream@4.7.0: + resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + readable-web-to-node-stream@3.0.4: + resolution: {integrity: sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw==} + engines: {node: '>=8'} + + readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + + readdirp@2.2.1: + resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==} + engines: {node: '>=0.10'} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + recharts@3.8.1: + resolution: {integrity: sha512-mwzmO1s9sFL0TduUpwndxCUNoXsBw3u3E/0+A+cLcrSfQitSG62L32N69GhqUrrT5qKcAE3pCGVINC6pqkBBQg==} + engines: {node: '>=18'} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-is: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + redent@1.0.0: + resolution: {integrity: sha512-qtW5hKzGQZqKoh6JNSD+4lfitfPKGz42e6QwiRmPM5mmKtR0N41AbJRYu0xJi7nhOJ4WDgRkKvAk6tw4WIwR4g==} + engines: {node: '>=0.10.0'} + + redux-thunk@3.1.0: + resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==} + peerDependencies: + redux: ^5.0.0 + + redux@5.0.1: + resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} + + reflect-metadata@0.1.14: + resolution: {integrity: sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==} + + reflect-metadata@0.2.2: + resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + + regenerator-runtime@0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + + regex-not@1.0.2: + resolution: {integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==} + engines: {node: '>=0.10.0'} + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + + relative@3.0.2: + resolution: {integrity: sha512-Q5W2qeYtY9GbiR8z1yHNZ1DGhyjb4AnLEjt8iE6XfcC1QIu+FAtj3HQaO0wH28H1mX6cqNLvAqWhP402dxJGyA==} + engines: {node: '>= 0.8.0'} + + remarkable@1.7.4: + resolution: {integrity: sha512-e6NKUXgX95whv7IgddywbeN/ItCkWbISmc2DiqHJb0wTrqZIexqdco5b8Z3XZoo/48IdNVKM9ZCvTPJ4F5uvhg==} + engines: {node: '>= 0.10.0'} + hasBin: true + + remove-trailing-separator@1.1.0: + resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} + + repeat-element@1.1.4: + resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==} + engines: {node: '>=0.10.0'} + + repeat-string@1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + + repeating@2.0.1: + resolution: {integrity: sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A==} + engines: {node: '>=0.10.0'} + + request@2.88.2: + resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==} + engines: {node: '>= 6'} + deprecated: request has been deprecated, see https://github.com/request/request/issues/3142 + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + require-main-filename@1.0.1: + resolution: {integrity: sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==} + + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + + requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + + reselect@5.1.1: + resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==} + + reselect@5.2.0: + resolution: {integrity: sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==} + + resolve-cwd@2.0.0: + resolution: {integrity: sha512-ccu8zQTrzVr954472aUVPLEcB3YpKSYR3cg/3lo1okzobPBM+1INXBbBZlDbnI/hbEocnf8j0QVo43hQKrbchg==} + engines: {node: '>=4'} + + resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + + resolve-from@3.0.0: + resolution: {integrity: sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==} + engines: {node: '>=4'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve-url@0.2.1: + resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==} + deprecated: https://github.com/lydell/resolve-url#deprecated + + resolve.exports@2.0.3: + resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} + engines: {node: '>=10'} + + resolve@1.22.12: + resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} + engines: {node: '>= 0.4'} + hasBin: true + + resolve@2.0.0-next.7: + resolution: {integrity: sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==} + engines: {node: '>= 0.4'} + hasBin: true + + restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + + restructure@3.0.2: + resolution: {integrity: sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==} + + ret@0.1.15: + resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==} + engines: {node: '>=0.12'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + + rgbcolor@1.0.1: + resolution: {integrity: sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==} + engines: {node: '>= 0.8.15'} + + right-align@0.1.3: + resolution: {integrity: sha512-yqINtL/G7vs2v+dFIZmFUDbnVyFUJFKd6gK22Kgo6R4jfJGFtisKyncWDDULgjfqf4ASQuIQyjJ7XZ+3aWpsAg==} + engines: {node: '>=0.10.0'} + + rimraf@2.7.1: + resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + ripemd160@2.0.3: + resolution: {integrity: sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==} + engines: {node: '>= 0.8'} + + rollup@4.60.4: + resolution: {integrity: sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + rope-sequence@1.3.4: + resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} + + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + rrweb-cssom@0.7.1: + resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==} + + rrweb-cssom@0.8.0: + resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + + safe-array-concat@1.1.4: + resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} + engines: {node: '>=0.4'} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + safe-regex@1.1.0: + resolution: {integrity: sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sax@1.6.0: + resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==} + engines: {node: '>=11.0.0'} + + saxes@5.0.1: + resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==} + engines: {node: '>=10'} + + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + + scheduler@0.19.1: + resolution: {integrity: sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==} + + scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + + scheduler@0.25.0-rc-603e6108-20241029: + resolution: {integrity: sha512-pFwF6H1XrSdYYNLfOcGlM28/j8CGLu8IvdrxqhjWULe2bPcKiKW4CV+OWqR/9fT52mywx65l7ysNkjLKBda7eA==} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + schema-utils@3.3.0: + resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} + engines: {node: '>= 10.13.0'} + + schema-utils@4.3.3: + resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} + engines: {node: '>= 10.13.0'} + + scroll@3.0.1: + resolution: {integrity: sha512-pz7y517OVls1maEzlirKO5nPYle9AXsFzTMNJrRGmT951mzpIBy7sNHOg5o/0MQd/NqliCiWnAi0kZneMPFLcg==} + + scrollparent@2.1.0: + resolution: {integrity: sha512-bnnvJL28/Rtz/kz2+4wpBjHzWoEzXhVg/TE8BeVGJHUqE8THNIRnDxDWMktwM+qahvlRdvlLdsQfYe+cuqfZeA==} + + select-hose@2.0.0: + resolution: {integrity: sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==} + + self-closing-tags@1.0.1: + resolution: {integrity: sha512-7t6hNbYMxM+VHXTgJmxwgZgLGktuXtVVD5AivWzNTdJBM4DBjnDKDzkf2SrNjihaArpeJYNjxkELBu1evI4lQA==} + engines: {node: '>=0.12.0'} + + selfsigned@1.10.14: + resolution: {integrity: sha512-lkjaiAye+wBZDCBsu5BGi0XiLRxeUlsGod5ZP924CRSEoGuZAw/f7y9RKu28rwTfiHVhdavhB0qH0INV6P1lEA==} + + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.8.1: + resolution: {integrity: sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==} + engines: {node: '>=10'} + hasBin: true + + send@0.19.2: + resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} + engines: {node: '>= 0.8.0'} + + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + serve-index@1.9.2: + resolution: {integrity: sha512-KDj11HScOaLmrPxl70KYNW1PksP4Nb/CLL2yvC+Qd2kHMPEEpfc4Re2e4FOay+bC/+XQl/7zAcWON3JVo5v3KQ==} + engines: {node: '>= 0.8.0'} + + serve-static@1.16.3: + resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} + engines: {node: '>= 0.8.0'} + + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-getter@0.1.1: + resolution: {integrity: sha512-9sVWOy+gthr+0G9DzqqLaYNA7+5OKkSmcqjL9cBpDEaZrr3ShQlyX2cZ/O/ozE41oxn/Tt0LGEM/w4Rub3A3gw==} + engines: {node: '>=0.10.0'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + set-value@2.0.1: + resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==} + engines: {node: '>=0.10.0'} + + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + sha.js@2.4.12: + resolution: {integrity: sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==} + engines: {node: '>= 0.10'} + hasBin: true + + shebang-command@1.2.0: + resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} + engines: {node: '>=0.10.0'} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@1.0.0: + resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} + engines: {node: '>=0.10.0'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + signature_pad@2.3.2: + resolution: {integrity: sha512-peYXLxOsIY6MES2TrRLDiNg2T++8gGbpP2yaC+6Ohtxr+a2dzoaqWosWDY9sWqTAAk6E/TyQO+LJw9zQwyu5kA==} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + + slice-ansi@7.1.2: + resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} + engines: {node: '>=18'} + + smob@1.6.2: + resolution: {integrity: sha512-RQsvleCbF8cVHEv+xuDGaA4pOizFqJ0GgjtMSRo6oP8pnN7WsigHgVGey6aILRBKv4W2YOMHLqbKdnB6hpB9fw==} + engines: {node: '>=20.0.0'} + + snapdragon-node@2.1.1: + resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==} + engines: {node: '>=0.10.0'} + + snapdragon-util@3.0.1: + resolution: {integrity: sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==} + engines: {node: '>=0.10.0'} + + snapdragon@0.8.2: + resolution: {integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==} + engines: {node: '>=0.10.0'} + + socket.io-client@4.8.3: + resolution: {integrity: sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==} + engines: {node: '>=10.0.0'} + + socket.io-parser@4.2.6: + resolution: {integrity: sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg==} + engines: {node: '>=10.0.0'} + + sockjs-client@1.1.5: + resolution: {integrity: sha512-PmPRkAYIeuRgX+ZSieViT4Z3Q23bLS2Itm/ck1tSf5P0/yVuFDiI5q9mcnpXoMdToaPSRS9MEyUx/aaBxrFzyw==} + + sockjs@0.3.19: + resolution: {integrity: sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==} + + sonner@2.0.7: + resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + + source-list-map@2.0.1: + resolution: {integrity: sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map-resolve@0.5.3: + resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==} + deprecated: See https://github.com/lydell/source-map-resolve#deprecated + + source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map-url@0.4.1: + resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==} + deprecated: See https://github.com/lydell/source-map-url#deprecated + + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + + spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + + spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + + spdx-license-ids@3.0.23: + resolution: {integrity: sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==} + + spdy-transport@3.0.0: + resolution: {integrity: sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==} + + spdy@4.0.2: + resolution: {integrity: sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==} + engines: {node: '>=6.0.0'} + + split-on-first@1.1.0: + resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==} + engines: {node: '>=6'} + + split-string@3.1.0: + resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==} + engines: {node: '>=0.10.0'} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + sql-highlight@6.1.0: + resolution: {integrity: sha512-ed7OK4e9ywpE7pgRMkMQmZDPKSVdm0oX5IEtZiKnFucSF0zu6c80GZBe38UqHuVhTWJ9xsKgSMjCG2bml86KvA==} + engines: {node: '>=14'} + + ssf@0.11.2: + resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==} + engines: {node: '>=0.8'} + + sshpk@1.18.0: + resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==} + engines: {node: '>=0.10.0'} + hasBin: true + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + stackblur-canvas@2.7.0: + resolution: {integrity: sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==} + engines: {node: '>=0.1.14'} + + static-extend@0.1.2: + resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==} + engines: {node: '>=0.10.0'} + + statuses@1.5.0: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + + stream-browserify@2.0.2: + resolution: {integrity: sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==} + + stream-http@2.8.3: + resolution: {integrity: sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==} + + streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + + strict-uri-encode@2.0.0: + resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} + engines: {node: '>=4'} + + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + + string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + + string-width@1.0.2: + resolution: {integrity: sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==} + engines: {node: '>=0.10.0'} + + string-width@2.1.1: + resolution: {integrity: sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==} + engines: {node: '>=4'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + engines: {node: '>= 0.4'} + + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@3.0.1: + resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} + engines: {node: '>=0.10.0'} + + strip-ansi@4.0.0: + resolution: {integrity: sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==} + engines: {node: '>=4'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + + strip-bom@2.0.0: + resolution: {integrity: sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==} + engines: {node: '>=0.10.0'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + + strip-eof@1.0.0: + resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==} + engines: {node: '>=0.10.0'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + strip-indent@1.0.1: + resolution: {integrity: sha512-I5iQq6aFMM62fBEAIB/hXzwJD6EEZ0xEGCX2t7oXqaKPIRgt4WruAQ285BISgdkP+HLGWyeGmNJcpIwFeRYRUA==} + engines: {node: '>=0.10.0'} + hasBin: true + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + striptags@3.2.0: + resolution: {integrity: sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw==} + + strnum@1.1.2: + resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==} + + strtok3@10.3.5: + resolution: {integrity: sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==} + engines: {node: '>=18'} + + strtok3@7.1.1: + resolution: {integrity: sha512-mKX8HA/cdBqMKUr0MMZAFssCkIGoZeSCMXgnt79yKxNFguMLVFgRe6wB+fsL0NmoHDbeyZXczy7vEPSoo3rkzg==} + engines: {node: '>=16'} + + style-object-to-css-string@1.1.3: + resolution: {integrity: sha512-bISQoUsir/qGfo7vY8rw00ia9nnyE1jvYt3zZ2jhdkcXZ6dAEi74inMzQ6On57vFI+I4Fck6wOv5UI9BEwJDgw==} + + stylis@4.2.0: + resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} + + success-symbol@0.1.0: + resolution: {integrity: sha512-7S6uOTxPklNGxOSbDIg4KlVLBQw1UiGVyfCUYgYxrZUKRblUkmGj7r8xlfQoFudvqLv6Ap5gd76/IIFfI9JG2A==} + engines: {node: '>=0.10.0'} + + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + superagent@10.3.0: + resolution: {integrity: sha512-B+4Ik7ROgVKrQsXTV0Jwp2u+PXYLSlqtDAhYnkkD+zn3yg8s/zjA2MeGayPoY/KICrbitwneDHrjSotxKL+0XQ==} + engines: {node: '>=14.18.0'} + + supertest@7.2.2: + resolution: {integrity: sha512-oK8WG9diS3DlhdUkcFn4tkNIiIbBx9lI2ClF8K+b2/m8Eyv47LSawxUzZQSNKUrVb2KsqeTDCcjAAVPYaSLVTA==} + engines: {node: '>=14.18.0'} + + supports-color@4.5.0: + resolution: {integrity: sha512-ycQR/UbvI9xIlEdQT1TQqwoXtEldExbCEAJgRo5YXlmSKjv6ThHnP9/vwGa1gr19Gfw+LkFd7KqYMhzrRC5JYw==} + engines: {node: '>=4'} + + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + svg-arc-to-cubic-bezier@3.2.0: + resolution: {integrity: sha512-djbJ/vZKZO+gPoSDThGNpKDO+o+bAeA4XQKovvkNCqnIS2t+S4qnLAGQhyyrulhCFRl1WWzAp0wUDV8PpTVU3g==} + + svg-pathdata@6.0.3: + resolution: {integrity: sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==} + engines: {node: '>=12.0.0'} + + swagger-ui-dist@5.17.14: + resolution: {integrity: sha512-CVbSfaLpstV65OnSjbXfVd6Sta3q3F7Cj/yYuvHMp1P90LztOLs6PfUnKEVAeiIVQt9u2SaPwv0LiH/OyMjHRw==} + + swagger-ui-dist@5.32.6: + resolution: {integrity: sha512-75ttZNaYCLoFPnozPZcTUU6mS3wKT8l7WLjU5zJSHFeJa23i5vtnze6IiCl4jDMPeQTXVXIgovq4M11NNfQvSA==} + + swagger-ui-express@5.0.1: + resolution: {integrity: sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==} + engines: {node: '>= v0.10.32'} + peerDependencies: + express: '>=4.0.0 || >=5.0.0-beta' + + symbol-observable@4.0.0: + resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} + engines: {node: '>=0.10'} + + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + + tabbable@6.4.0: + resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} + + tailwind-merge@3.6.0: + resolution: {integrity: sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==} + + tailwind-scrollbar-hide@4.0.0: + resolution: {integrity: sha512-gobtvVcThB2Dxhy0EeYSS1RKQJ5baDFkamkhwBvzvevwX6L4XQfpZ3me9s25Ss1ecFVT5jPYJ50n+7xTBJG9WQ==} + peerDependencies: + tailwindcss: '>=3.0.0 || >= 4.0.0 || >= 4.0.0-beta.8 || >= 4.0.0-alpha.20' + + tailwindcss-animate@1.0.7: + resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + + tailwindcss@3.4.19: + resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==} + engines: {node: '>=14.0.0'} + hasBin: true + + tailwindcss@4.3.0: + resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==} + + tapable@0.2.9: + resolution: {integrity: sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==} + engines: {node: '>=0.6'} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + + tar@6.2.1: + resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} + engines: {node: '>=10'} + deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + + terser-webpack-plugin@5.6.0: + resolution: {integrity: sha512-Eum+5ajkaOhf5KbM26osvv21kLD7BaGqQ1UA4Ami4arYwylmGUQTgHFpHDdmJod1q4QXa66p0to/FBKID+J1vA==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@minify-html/node': '*' + '@swc/core': '*' + '@swc/css': '*' + '@swc/html': '*' + clean-css: '*' + cssnano: '*' + csso: '*' + esbuild: '*' + html-minifier-terser: '*' + lightningcss: '*' + postcss: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@minify-html/node': + optional: true + '@swc/core': + optional: true + '@swc/css': + optional: true + '@swc/html': + optional: true + clean-css: + optional: true + cssnano: + optional: true + csso: + optional: true + esbuild: + optional: true + html-minifier-terser: + optional: true + lightningcss: + optional: true + postcss: + optional: true + uglify-js: + optional: true + + terser@5.48.0: + resolution: {integrity: sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==} + engines: {node: '>=10'} + hasBin: true + + tesseract.js-core@7.0.0: + resolution: {integrity: sha512-WnNH518NzmbSq9zgTPeoF8c+xmilS8rFIl1YKbk/ptuuc7p6cLNELNuPAzcmsYw450ca6bLa8j3t0VAtq435Vw==} + + tesseract.js@7.0.0: + resolution: {integrity: sha512-exPBkd+z+wM1BuMkx/Bjv43OeLBxhL5kKWsz/9JY+DXcXdiBjiAch0V49QR3oAJqCaL5qURE0vx9Eo+G5YE7mA==} + + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + + text-extensions@2.4.0: + resolution: {integrity: sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==} + engines: {node: '>=8'} + + text-segmentation@1.0.3: + resolution: {integrity: sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + through2@2.0.5: + resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} + + through2@4.0.2: + resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} + + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + + thunky@1.1.0: + resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==} + + time-stamp@1.1.0: + resolution: {integrity: sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==} + engines: {node: '>=0.10.0'} + + time-stamp@2.2.0: + resolution: {integrity: sha512-zxke8goJQpBeEgD82CXABeMh0LSJcj7CXEd0OHOg45HgcofF7pxNwZm9+RknpxpDhwN4gFpySkApKfFYfRQnUA==} + engines: {node: '>=0.10.0'} + + timers-browserify@2.0.12: + resolution: {integrity: sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==} + engines: {node: '>=0.6.0'} + + tiny-inflate@1.0.3: + resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} + + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyexec@1.1.2: + resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} + engines: {node: '>=18'} + + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + engines: {node: '>=12.0.0'} + + tinymce@7.9.3: + resolution: {integrity: sha512-Mtm54U5YJ6Pyo/GaAx+JSHXTGEuxrg2AowVWCD9zy1eBolp5Ub7S1rTtsyQdxhPegfhLuR3VLiTKGw1tacv09g==} + + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@1.2.0: + resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} + engines: {node: '>=14.0.0'} + + tinyspy@3.0.2: + resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} + engines: {node: '>=14.0.0'} + + tldts-core@6.1.86: + resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} + + tldts@6.1.86: + resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} + hasBin: true + + tmp@0.2.5: + resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} + engines: {node: '>=14.14'} + + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + + to-arraybuffer@1.0.1: + resolution: {integrity: sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==} + + to-buffer@1.2.2: + resolution: {integrity: sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==} + engines: {node: '>= 0.4'} + + to-gfm-code-block@0.1.1: + resolution: {integrity: sha512-LQRZWyn8d5amUKnfR9A9Uu7x9ss7Re8peuWR2gkh1E+ildOfv2aF26JpuDg8JtvCduu5+hOrMIH+XstZtnagqg==} + engines: {node: '>=0.10.0'} + + to-object-path@0.3.0: + resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==} + engines: {node: '>=0.10.0'} + + to-regex-range@2.1.1: + resolution: {integrity: sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==} + engines: {node: '>=0.10.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + to-regex@3.0.2: + resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==} + engines: {node: '>=0.10.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + token-types@5.0.1: + resolution: {integrity: sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==} + engines: {node: '>=14.16'} + + token-types@6.1.2: + resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} + engines: {node: '>=14.16'} + + tough-cookie@2.5.0: + resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==} + engines: {node: '>=0.8'} + + tough-cookie@5.1.2: + resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} + engines: {node: '>=16'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + tr46@5.1.1: + resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} + engines: {node: '>=18'} + + traverse@0.3.9: + resolution: {integrity: sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==} + + tree-changes@0.11.3: + resolution: {integrity: sha512-r14mvDZ6tqz8PRQmlFKjhUVngu4VZ9d92ON3tp0EGpFBE6PAHOq8Bx8m8ahbNoGE3uI/npjYcJiqVydyOiYXag==} + + tree-changes@0.9.3: + resolution: {integrity: sha512-vvvS+O6kEeGRzMglTKbc19ltLWNtmNt1cpBoSYLj/iEcPVvpJasemKOlxBrmZaCtDJoF+4bwv3m01UKYi8mukQ==} + + trim-canvas@0.1.2: + resolution: {integrity: sha512-nd4Ga3iLFV94mdhW9JFMLpQbHUyCQuhFOD71PEAt1NjtMD5wbZctzhX8c3agHNybMR5zXD1XTGoIEWk995E6pQ==} + + trim-newlines@1.0.0: + resolution: {integrity: sha512-Nm4cF79FhSTzrLKGDMi3I4utBtFv8qKy4sq1enftf2gMdpqI8oVQTAfySkTz5r49giVzDj88SVZXP4CeYQwjaw==} + engines: {node: '>=0.10.0'} + + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + ts-jest@29.4.11: + resolution: {integrity: sha512-IrFl7l9AuB/qrNw5quqvAv/hmKMb8dhWOH4jQOGo0Oq8tCeo1O86/iTFG1FaRimgUkF13l4PcepO8ATFT6Ns4g==} + engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@jest/transform': ^29.0.0 || ^30.0.0 + '@jest/types': ^29.0.0 || ^30.0.0 + babel-jest: ^29.0.0 || ^30.0.0 + esbuild: '*' + jest: ^29.0.0 || ^30.0.0 + jest-util: ^29.0.0 || ^30.0.0 + typescript: '>=4.3 <7' + peerDependenciesMeta: + '@babel/core': + optional: true + '@jest/transform': + optional: true + '@jest/types': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + jest-util: + optional: true + + ts-loader@9.5.7: + resolution: {integrity: sha512-/ZNrKgA3K3PtpMYOC71EeMWIloGw3IYEa5/t1cyz2r5/PyUwTXGzYJvcD3kfUvmhlfpz1rhV8B2O6IVTQ0avsg==} + engines: {node: '>=12.0.0'} + peerDependencies: + typescript: '*' + webpack: ^5.0.0 + + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + + tsconfig-paths-webpack-plugin@4.2.0: + resolution: {integrity: sha512-zbem3rfRS8BgeNK50Zz5SIQgXzLafiHjOwUAvk/38/o1jHn/V5QAgVUcz884or7WYcPaH3N2CIfUc2u0ul7UcA==} + engines: {node: '>=10.13.0'} + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tsconfig-paths@4.2.0: + resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} + engines: {node: '>=6'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tty-browserify@0.0.0: + resolution: {integrity: sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==} + + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + + turbo@2.9.14: + resolution: {integrity: sha512-BQqXRr4UoWI3UPFrtznCLykYHxwxWh53iCB57x092jPMjIlW1wnm3N895g5irpiXmnxUhREBB0n6+y8BHhs4nw==} + hasBin: true + + tweetnacl@0.14.5: + resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + + type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + + type-is@2.1.0: + resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} + engines: {node: '>= 18'} + + type@2.7.3: + resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + + typedarray@0.0.6: + resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} + + typeof-article@0.1.1: + resolution: {integrity: sha512-Vn42zdX3FhmUrzEmitX3iYyLb+Umwpmv8fkZRIknYh84lmdrwqZA5xYaoKiIj2Rc5i/5wcDrpUmZcbk1U51vTw==} + engines: {node: '>=4'} + + typeorm-extension@3.9.0: + resolution: {integrity: sha512-LCVo/7zEh59/+Ig+WsXFbuu1gvU7EilIOH1vwxTG2eAiKmteaTQlID9c1x/PQH2IyZ+Lk4htbWf1d9QieKrpPQ==} + engines: {node: ^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@faker-js/faker': '>=8.4.1' + typeorm: ~0.3.0 + + typeorm@0.3.30: + resolution: {integrity: sha512-8T35PzjefOdqc2ZR9mwLQj0pUGp6lQhMbK2EvVMwJVJWlaoHm0v/Q6dThNOZkFchD+0yMg8gwjKM28ePiLSXSQ==} + engines: {node: '>=16.13.0'} + hasBin: true + peerDependencies: + '@google-cloud/spanner': ^5.18.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + '@sap/hana-client': ^2.14.22 + better-sqlite3: ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0 + ioredis: ^5.0.4 + mongodb: ^5.8.0 || ^6.0.0 + mssql: ^9.1.1 || ^10.0.0 || ^11.0.0 || ^12.0.0 + mysql2: ^2.2.5 || ^3.0.1 + oracledb: ^6.3.0 + pg: ^8.5.1 + pg-native: ^3.0.0 + pg-query-stream: ^4.0.0 + redis: ^3.1.1 || ^4.0.0 || ^5.0.14 + sql.js: ^1.4.0 + sqlite3: ^5.0.3 + ts-node: ^10.7.0 + typeorm-aurora-data-api-driver: ^2.0.0 || ^3.0.0 + peerDependenciesMeta: + '@google-cloud/spanner': + optional: true + '@sap/hana-client': + optional: true + better-sqlite3: + optional: true + ioredis: + optional: true + mongodb: + optional: true + mssql: + optional: true + mysql2: + optional: true + oracledb: + optional: true + pg: + optional: true + pg-native: + optional: true + pg-query-stream: + optional: true + redis: + optional: true + sql.js: + optional: true + sqlite3: + optional: true + ts-node: + optional: true + typeorm-aurora-data-api-driver: + optional: true + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + uglify-js@2.8.29: + resolution: {integrity: sha512-qLq/4y2pjcU3vhlhseXGGJ7VbFO4pBANu0kwl8VCa9KEI0V8VfZIx2Fy3w01iSTA/pGwKZSmu/+I4etLNDdt5w==} + engines: {node: '>=0.8.0'} + hasBin: true + + uglify-js@3.19.3: + resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} + engines: {node: '>=0.8.0'} + hasBin: true + + uglify-to-browserify@1.0.2: + resolution: {integrity: sha512-vb2s1lYx2xBtUgy+ta+b2J/GLVUR+wmpINwHePmPRhOsIVCG2wDzKJ0n14GslH1BifsqVzSOwQhRaCAsZ/nI4Q==} + + uglifyjs-webpack-plugin@0.4.6: + resolution: {integrity: sha512-TNM20HMW67kxHRNCZdvLyiwE1ST6WyY5Ae+TG55V81NpvNwJ9+V4/po4LHA1R9afV/WrqzfedG2UJCk2+swirw==} + engines: {node: '>=4.3.0 <5.0.0 || >=5.10'} + peerDependencies: + webpack: ^1.9 || ^2 || ^2.1.0-beta || ^2.2.0-rc || ^3.0.0 + + uid@2.0.2: + resolution: {integrity: sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==} + engines: {node: '>=8'} + + uint8array-extras@1.5.0: + resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} + engines: {node: '>=18'} + + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + + unicode-properties@1.4.1: + resolution: {integrity: sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==} + + unicode-trie@2.0.0: + resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==} + + unicorn-magic@0.1.0: + resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} + engines: {node: '>=18'} + + union-value@1.0.1: + resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} + engines: {node: '>=0.10.0'} + + universal-cookie@8.1.2: + resolution: {integrity: sha512-kcKzTGNsxVytujrYOvQbvh//QyFrA53HrzCGyzh6i9ujCww5gfPrLK0tG+jJD40SIIldiEjBNPPSR8fBMS21GA==} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + unset-value@1.0.0: + resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==} + engines: {node: '>=0.10.0'} + + unzipper@0.10.14: + resolution: {integrity: sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==} + + upath@1.2.0: + resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} + engines: {node: '>=4'} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uqr@0.1.2: + resolution: {integrity: sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + urix@0.1.0: + resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==} + deprecated: Please see https://github.com/lydell/urix#deprecated + + url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + + url@0.11.4: + resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==} + engines: {node: '>= 0.4'} + use-callback-ref@1.3.3: resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} engines: {node: '>=10'} @@ -10395,15 +10473,14 @@ packages: '@types/react': optional: true - prisma@6.19.3: - resolution: {integrity: sha512-++ZJ0ijLrDJF6hNB4t4uxg2br3fC4H9Yc9tcbjr2fcNFP3rh/SBNrAgjhsqBU4Ght8JPrVofG/ZkXfnSfnYsFg==} - engines: {node: '>=18.18'} - hasBin: true + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} peerDependencies: '@types/react': '*' react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc peerDependenciesMeta: - typescript: + '@types/react': optional: true use-sync-external-store@1.6.0: @@ -10424,124 +10501,171 @@ packages: util@0.11.1: resolution: {integrity: sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==} - prop-types@15.8.1: - resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} - proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} + utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} - proxy-from-env@2.1.0: - resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} - engines: {node: '>=10'} + utrie@1.0.2: + resolution: {integrity: sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==} - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - pure-rand@6.1.0: - resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} - - qrcode@1.5.4: - resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==} - engines: {node: '>=10.13.0'} + uuid@11.1.1: + resolution: {integrity: sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==} hasBin: true - qs@6.15.1: - resolution: {integrity: sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==} - engines: {node: '>=0.6'} + uuid@3.4.0: + resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). + hasBin: true - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). + hasBin: true - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - raw-body@3.0.2: - resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + v8-to-istanbul@9.3.0: + resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} + engines: {node: '>=10.12.0'} + + validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + + validator@13.15.35: + resolution: {integrity: sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==} engines: {node: '>= 0.10'} - rc9@2.1.2: - resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} - react-dom@18.3.1: - resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} + vaul@1.1.2: + resolution: {integrity: sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==} peerDependencies: react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc - react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + verror@1.10.0: + resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} + engines: {'0': node >=0.6.0} - react-is@18.3.1: - resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + victory-vendor@37.3.6: + resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==} - react-refresh@0.17.0: - resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} - engines: {node: '>=0.10.0'} - - react-router-dom@6.30.3: - resolution: {integrity: sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==} - engines: {node: '>=14.0.0'} - peerDependencies: - react: 18.3.1 - react-dom: 18.3.1 - - react-router@6.30.3: - resolution: {integrity: sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==} - engines: {node: '>=14.0.0'} - peerDependencies: - react: 18.3.1 - - react@18.3.1: - resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} - engines: {node: '>=0.10.0'} - - read-cache@1.0.0: - resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} - - readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + vite-compatible-readable-stream@3.6.1: + resolution: {integrity: sha512-t20zYkrSf868+j/p31cRIGN28Phrjm3nRSLR2fyc2tiWi4cZGVdv68yNlwnIINTkMTmPoMiSlc0OadaO7DXZaQ==} engines: {node: '>= 6'} - readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} + vite-node@2.1.9: + resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} + vite@5.4.21: + resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true - reflect-metadata@0.2.2: - resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + vitest@2.1.9: + resolution: {integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 2.1.9 + '@vitest/ui': 2.1.9 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true - reflect.getprototypeof@1.0.10: - resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} - engines: {node: '>= 0.4'} + vm-browserify@1.1.2: + resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==} - regexp.prototype.flags@1.5.4: - resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} - engines: {node: '>= 0.4'} - - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + void-elements@3.1.0: + resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} engines: {node: '>=0.10.0'} - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + + warning-symbol@0.1.0: + resolution: {integrity: sha512-1S0lwbHo3kNUKA4VomBAhqn4DPjQkIKSdbOin5K7EFUQNwyIKx+wZMGXKI53RUjla8V2B8ouQduUlgtx8LoSMw==} engines: {node: '>=0.10.0'} - require-main-filename@2.0.0: - resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + warning@4.0.3: + resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} - resolve-cwd@3.0.0: - resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} - engines: {node: '>=8'} + wasm-feature-detect@1.8.0: + resolution: {integrity: sha512-zksaLKM2fVlnB5jQQDqKXXwYHLQUVH9es+5TOOHwGOVJOCeRBCiPjwSg+3tN2AdTCzjgli4jijCH290kXb/zWQ==} - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} + watchpack-chokidar2@2.0.1: + resolution: {integrity: sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==} + + watchpack@1.7.5: + resolution: {integrity: sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==} + + watchpack@2.5.1: + resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} + engines: {node: '>=10.13.0'} + + wbuf@1.7.3: + resolution: {integrity: sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==} + + wcwidth@1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + + web-encoding@1.1.5: + resolution: {integrity: sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==} web-streams-polyfill@3.3.3: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} @@ -10550,299 +10674,316 @@ packages: webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - resolve.exports@2.0.3: - resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} - engines: {node: '>=10'} + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} - resolve@1.22.12: - resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} - engines: {node: '>= 0.4'} + webpack-dev-middleware@1.12.2: + resolution: {integrity: sha512-FCrqPy1yy/sN6U/SaEZcHKRXGlqU0DUaEBL45jkUYoB8foVb6wCnbIJ1HKIx+qUFTW+3JpVcCJCxZ8VATL4e+A==} + engines: {node: '>=0.6'} + peerDependencies: + webpack: ^1.0.0 || ^2.0.0 || ^3.0.0 + + webpack-dev-server@2.11.5: + resolution: {integrity: sha512-7TdOKKt7G3sWEhPKV0zP+nD0c4V9YKUJ3wDdBwQsZNo58oZIRoVIu66pg7PYkBW8A74msP9C2kLwmxGHndz/pw==} + engines: {node: '>=4.7'} hasBin: true + peerDependencies: + webpack: ^2.2.0 || ^3.0.0 + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true - resolve@2.0.0-next.6: - resolution: {integrity: sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==} - engines: {node: '>= 0.4'} + webpack-node-externals@3.0.0: + resolution: {integrity: sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==} + engines: {node: '>=6'} + + webpack-sources@1.4.3: + resolution: {integrity: sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==} + + webpack-sources@3.4.1: + resolution: {integrity: sha512-eACpxRN02yaawnt+uUNIF7Qje6A9zArxBbcAJjK1PK3S9Ycg5jIuJ8pW4q8EMnwNZCEGltcjkRx1QzOxOkKD8A==} + engines: {node: '>=10.13.0'} + + webpack@3.12.0: + resolution: {integrity: sha512-Sw7MdIIOv/nkzPzee4o0EdvCuPmxT98+vVpIvwtcwcF1Q4SDSNp92vwcKc4REe7NItH9f1S4ra9FuQ7yuYZ8bQ==} + engines: {node: '>=4.3.0 <5.0.0 || >=5.10'} hasBin: true + peerDependencies: + webpack-cli: '*' + webpack-command: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + webpack-command: + optional: true - restore-cursor@3.1.0: - resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} - engines: {node: '>=8'} + webpack@5.106.0: + resolution: {integrity: sha512-Pkx5joZ9RrdgO5LBkyX1L2ZAJeK/Taz3vqZ9CbcP0wS5LEMx5QkKsEwLl29QJfihZ+DKRBFldzy1O30pJ1MDpA==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true - restore-cursor@5.1.0: - resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + websocket-driver@0.7.4: + resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==} + engines: {node: '>=0.8.0'} + + websocket-extensions@0.1.4: + resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==} + engines: {node: '>=0.8.0'} + + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} engines: {node: '>=18'} - reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + whatwg-url@14.2.0: + resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} + engines: {node: '>=18'} - rfdc@1.4.1: - resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-module@1.0.0: + resolution: {integrity: sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==} + + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + + which-typed-array@1.1.20: + resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} + engines: {node: '>= 0.4'} + + which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true - rollup@4.60.3: - resolution: {integrity: sha512-pAQK9HalE84QSm4Po3EmWIZPd3FnjkShVkiMlz1iligWYkWQ7wHYd1PF/T7QZ5TVSD6uSTon5gBVMSM4JfBV+A==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} hasBin: true - router@2.2.0: - resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} - engines: {node: '>= 18'} + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true - rrweb-cssom@0.7.1: - resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==} + wide-align@1.1.5: + resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} - rrweb-cssom@0.8.0: - resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} + window-size@0.1.0: + resolution: {integrity: sha512-1pTPQDKTdd61ozlKGNCjhNRd+KPmgLSGa3mZTHoOliaGcESD8G1PXhh7c1fgiPjVbNVfgy2Faw4BI8/m0cC8Mg==} + engines: {node: '>= 0.8.0'} - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + wmf@1.0.2: + resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==} + engines: {node: '>=0.8'} - rxjs@7.8.1: - resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} - rxjs@7.8.2: - resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + word@0.3.0: + resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==} + engines: {node: '>=0.8'} - safe-array-concat@1.1.4: - resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} + wordwrap@0.0.2: + resolution: {integrity: sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q==} + engines: {node: '>=0.4.0'} + + wordwrap@1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + + wrap-ansi@2.1.0: + resolution: {integrity: sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==} + engines: {node: '>=0.10.0'} + + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrap-ansi@9.0.2: + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} + engines: {node: '>=18'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + write-file-atomic@4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + ws@8.20.1: + resolution: {integrity: sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==} + 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 + + xlsx@0.18.5: + resolution: {integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==} + engines: {node: '>=0.8'} + hasBin: true + + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + + xml2js@0.5.0: + resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} + engines: {node: '>=4.0.0'} + + xml@1.0.1: + resolution: {integrity: sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==} + + xmlbuilder@11.0.1: + resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} + engines: {node: '>=4.0'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + + xmlhttprequest-ssl@2.1.2: + resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==} + engines: {node: '>=0.4.0'} + + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + y18n@3.2.2: + resolution: {integrity: sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==} - safe-push-apply@1.0.0: - resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} - engines: {node: '>= 0.4'} + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} - safe-regex-test@1.1.0: - resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} - engines: {node: '>= 0.4'} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - saxes@6.0.0: - resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} - engines: {node: '>=v12.22.7'} - - scheduler@0.23.2: - resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} - - schema-utils@3.3.0: - resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} - engines: {node: '>= 10.13.0'} - - schema-utils@4.3.3: - resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} - engines: {node: '>= 10.13.0'} - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - semver@7.8.0: - resolution: {integrity: sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==} + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} + + yallist@2.1.2: + resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yaml@1.10.3: + resolution: {integrity: sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==} + engines: {node: '>= 6'} + + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} hasBin: true - send@1.2.1: - resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} - engines: {node: '>= 18'} + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} - seq-queue@0.0.5: - resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} - - serve-static@2.2.1: - resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} - engines: {node: '>= 18'} - - set-blocking@2.0.0: - resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - - set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} - - set-function-name@2.0.2: - resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} - engines: {node: '>= 0.4'} - - set-proto@1.0.0: - resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} - engines: {node: '>= 0.4'} - - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - - sha.js@2.4.12: - resolution: {integrity: sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==} - engines: {node: '>= 0.10'} - hasBin: true - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - side-channel-list@1.0.1: - resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - - siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - - signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - simple-concat@1.0.1: - resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} - - simple-get@3.1.1: - resolution: {integrity: sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==} - - sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - - slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - - slice-ansi@5.0.0: - resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} - slice-ansi@7.1.2: - resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + + yargs-parser@4.2.1: + resolution: {integrity: sha512-+QQWqC2xeL0N5/TE+TY6OGEqyNRM+g2/r712PDNYgiCdXYCApXf1vzfmDSLBxfGRwV+moTq/V8FnMI24JCm2Yg==} + + yargs-parser@7.0.0: + resolution: {integrity: sha512-WhzC+xgstid9MbVUktco/bf+KJG+Uu6vMX0LN1sLJvwmbCQVxb4D8LzogobonKycNasCZLdOzTAk1SK7+K7swg==} + + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yargs@18.0.0: + resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + + yargs@3.10.0: + resolution: {integrity: sha512-QFzUah88GAGy9lyDKGBqZdkYApt63rCXYBGYnEP4xDJPXNqXXnBDACnbrXnViV6jRSqAePwrATi2i8mfYm4L1A==} + + yargs@6.6.0: + resolution: {integrity: sha512-6/QWTdisjnu5UHUzQGst+UOEuEVwIzFVGBjq3jMTFNs5WJQsH/X6nMURSaScIdF5txylr1Ao9bvbWiKi2yXbwA==} + + yargs@8.0.2: + resolution: {integrity: sha512-3RiZrpLpjrzIAKgGdPktBcMP/eG5bDFlkI+PHle1qwzyVXyDQL+pD/eZaMoOOO0Y7LLBfjpucObuUm/icvbpKQ==} + + year@0.2.1: + resolution: {integrity: sha512-9GnJUZ0QM4OgXuOzsKNzTJ5EOkums1Xc+3YQXp+Q+UxFjf7zLucp9dQ8QMIft0Szs1E1hUiXFim1OYfEKFq97w==} + engines: {node: '>=0.8'} + + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + + yoctocolors-cjs@2.1.3: + resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} engines: {node: '>=18'} - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} + yoga-layout@3.2.1: + resolution: {integrity: sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==} - source-map-support@0.5.13: - resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + zip-stream@4.1.1: + resolution: {integrity: sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==} + engines: {node: '>= 10'} - source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + zlibjs@0.3.1: + resolution: {integrity: sha512-+J9RrgTKOmlxFSDHo0pI1xM6BLVUv+o0ZT9ANtCxGkjIVCCUdx9alUF8Gm+dGLKbkkkidWIHFDZHDMpfITt4+w==} - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - - source-map@0.7.4: - resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} - engines: {node: '>= 8'} - - split2@4.2.0: - resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} - engines: {node: '>= 10.x'} - - sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - - sql-highlight@6.1.0: - resolution: {integrity: sha512-ed7OK4e9ywpE7pgRMkMQmZDPKSVdm0oX5IEtZiKnFucSF0zu6c80GZBe38UqHuVhTWJ9xsKgSMjCG2bml86KvA==} - engines: {node: '>=14'} - - sqlstring@2.3.3: - resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} - engines: {node: '>= 0.6'} - - stack-utils@2.0.6: - resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} - engines: {node: '>=10'} - - stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - - statuses@2.0.2: - resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} - engines: {node: '>= 0.8'} - - std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} - - stop-iteration-iterator@1.1.0: - resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} - engines: {node: '>= 0.4'} - - streamsearch@1.1.0: - resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} - engines: {node: '>=10.0.0'} - - string-argv@0.3.2: - resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} - engines: {node: '>=0.6.19'} - - string-length@4.0.2: - resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} - engines: {node: '>=10'} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - - string-width@7.2.0: - resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} - engines: {node: '>=18'} - - string.prototype.matchall@4.0.12: - resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} - engines: {node: '>= 0.4'} - - string.prototype.repeat@1.0.0: - resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} - - string.prototype.trim@1.2.10: - resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} - engines: {node: '>= 0.4'} - - string.prototype.trimend@1.0.9: - resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} - engines: {node: '>= 0.4'} - - string.prototype.trimstart@1.0.8: - resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} - engines: {node: '>= 0.4'} - - string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-ansi@7.2.0: - resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} - engines: {node: '>=12'} + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} zustand@5.0.13: resolution: {integrity: sha512-efI2tVaVQPqtOh114loML/Z80Y4NP3yc+Ff0fYiZJPauNeWZeIp/bRFD7I9bfmCOYBh/PHxlglQ9+wvlwnPikQ==} @@ -10862,25 +11003,42 @@ packages: use-sync-external-store: optional: true - strip-bom@4.0.0: - resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} - engines: {node: '>=8'} +snapshots: - strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} + '@alloc/quick-lru@5.2.0': {} - strip-final-newline@3.0.0: - resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} - engines: {node: '>=12'} + '@angular-devkit/core@19.2.24(chokidar@4.0.3)': + dependencies: + ajv: 8.18.0 + ajv-formats: 3.0.1(ajv@8.18.0) + jsonc-parser: 3.3.1 + picomatch: 4.0.4 + rxjs: 7.8.1 + source-map: 0.7.4 + optionalDependencies: + chokidar: 4.0.3 - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} + '@angular-devkit/schematics-cli@19.2.24(@types/node@20.19.41)(chokidar@4.0.3)': + dependencies: + '@angular-devkit/core': 19.2.24(chokidar@4.0.3) + '@angular-devkit/schematics': 19.2.24(chokidar@4.0.3) + '@inquirer/prompts': 7.3.2(@types/node@20.19.41) + ansi-colors: 4.1.3 + symbol-observable: 4.0.0 + yargs-parser: 21.1.1 + transitivePeerDependencies: + - '@types/node' + - chokidar - strtok3@10.3.5: - resolution: {integrity: sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==} - engines: {node: '>=18'} + '@angular-devkit/schematics@19.2.24(chokidar@4.0.3)': + dependencies: + '@angular-devkit/core': 19.2.24(chokidar@4.0.3) + jsonc-parser: 3.3.1 + magic-string: 0.30.17 + ora: 5.4.1 + rxjs: 7.8.1 + transitivePeerDependencies: + - chokidar '@ark-ui/react@5.36.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: @@ -10954,839 +11112,6 @@ packages: react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - superagent@10.3.0: - resolution: {integrity: sha512-B+4Ik7ROgVKrQsXTV0Jwp2u+PXYLSlqtDAhYnkkD+zn3yg8s/zjA2MeGayPoY/KICrbitwneDHrjSotxKL+0XQ==} - engines: {node: '>=14.18.0'} - - supertest@7.2.2: - resolution: {integrity: sha512-oK8WG9diS3DlhdUkcFn4tkNIiIbBx9lI2ClF8K+b2/m8Eyv47LSawxUzZQSNKUrVb2KsqeTDCcjAAVPYaSLVTA==} - engines: {node: '>=14.18.0'} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - '@babel/core@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.29.2 - '@babel/parser': 7.29.3 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3(supports-color@5.5.0) - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - swagger-ui-dist@5.17.14: - resolution: {integrity: sha512-CVbSfaLpstV65OnSjbXfVd6Sta3q3F7Cj/yYuvHMp1P90LztOLs6PfUnKEVAeiIVQt9u2SaPwv0LiH/OyMjHRw==} - - swagger-ui-dist@5.32.4: - resolution: {integrity: sha512-0AADFFQNJzExEN49SrD/34Nn9cxNxVLiydYl2MBwSZFPVXNkVwC/EFAjoezGGqE8oDegiDC+p47t8lKObCinMQ==} - - swagger-ui-express@5.0.1: - resolution: {integrity: sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==} - engines: {node: '>= v0.10.32'} - peerDependencies: - express: '>=4.0.0 || >=5.0.0-beta' - - symbol-observable@4.0.0: - resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} - engines: {node: '>=0.10'} - - symbol-tree@3.2.4: - resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - - tailwindcss@3.4.19: - resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==} - engines: {node: '>=14.0.0'} - hasBin: true - - tapable@2.3.3: - resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} - engines: {node: '>=6'} - - tar@6.2.1: - resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} - engines: {node: '>=10'} - deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - - terser-webpack-plugin@5.6.0: - resolution: {integrity: sha512-Eum+5ajkaOhf5KbM26osvv21kLD7BaGqQ1UA4Ami4arYwylmGUQTgHFpHDdmJod1q4QXa66p0to/FBKID+J1vA==} - engines: {node: '>= 10.13.0'} - peerDependencies: - '@minify-html/node': '*' - '@swc/core': '*' - '@swc/css': '*' - '@swc/html': '*' - clean-css: '*' - cssnano: '*' - csso: '*' - esbuild: '*' - html-minifier-terser: '*' - lightningcss: '*' - postcss: '*' - uglify-js: '*' - webpack: ^5.1.0 - peerDependenciesMeta: - '@minify-html/node': - optional: true - '@swc/core': - optional: true - '@swc/css': - optional: true - '@swc/html': - optional: true - clean-css: - optional: true - cssnano: - optional: true - csso: - optional: true - esbuild: - optional: true - html-minifier-terser: - optional: true - lightningcss: - optional: true - postcss: - optional: true - uglify-js: - optional: true - - terser@5.47.1: - resolution: {integrity: sha512-tPbLXTI6ohPASb/1YViL428oEHu6/qv1OxqYnfaonVCFHqx4+wCd95pHrQWsL5X4pl90CTyW9piSAsS2L0VoMw==} - engines: {node: '>=10'} - hasBin: true - - test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} - - text-extensions@2.4.0: - resolution: {integrity: sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==} - engines: {node: '>=8'} - - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - - thenify-all@1.6.0: - resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} - engines: {node: '>=0.8'} - - thenify@3.3.1: - resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - - through@2.3.8: - resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - - tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - - tinyexec@0.3.2: - resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - - tinyexec@1.1.2: - resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} - engines: {node: '>=18'} - - tinyglobby@0.2.16: - resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} - engines: {node: '>=12.0.0'} - - tinypool@1.1.1: - resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} - engines: {node: ^18.0.0 || >=20.0.0} - - tinyrainbow@1.2.0: - resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} - engines: {node: '>=14.0.0'} - - tinyspy@3.0.2: - resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} - engines: {node: '>=14.0.0'} - - tldts-core@6.1.86: - resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} - - tldts@6.1.86: - resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} - hasBin: true - - tmpl@1.0.5: - resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - - to-buffer@1.2.2: - resolution: {integrity: sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==} - engines: {node: '>= 0.4'} - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - - token-types@6.1.2: - resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} - engines: {node: '>=14.16'} - - tough-cookie@5.1.2: - resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} - engines: {node: '>=16'} - - '@babel/traverse@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.3 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - debug: 4.4.3(supports-color@5.5.0) - transitivePeerDependencies: - - supports-color - - tr46@5.1.1: - resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} - engines: {node: '>=18'} - - ts-api-utils@2.5.0: - resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} - engines: {node: '>=18.12'} - peerDependencies: - typescript: '>=4.8.4' - - ts-interface-checker@0.1.13: - resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - - '@chakra-ui/react@3.35.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@ark-ui/react': 5.36.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@emotion/is-prop-valid': 1.4.0 - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@19.2.6) - '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.6) - '@emotion/utils': 1.4.2 - '@pandacss/is-valid-prop': 1.11.1 - csstype: 3.2.3 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - - ts-node@10.9.2: - resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - - tsconfig-paths-webpack-plugin@4.2.0: - resolution: {integrity: sha512-zbem3rfRS8BgeNK50Zz5SIQgXzLafiHjOwUAvk/38/o1jHn/V5QAgVUcz884or7WYcPaH3N2CIfUc2u0ul7UcA==} - engines: {node: '>=10.13.0'} - - tsconfig-paths@3.15.0: - resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} - - tsconfig-paths@4.2.0: - resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} - engines: {node: '>=6'} - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - turbo@2.9.12: - resolution: {integrity: sha512-lCPgus1NuTiBdaITWqzSH/Ff6HVL8HHGBtOXHg1dHRfcshN79XkygSdh0M6g8b0td91ILLG5MTkLOkp5UvyPJw==} - hasBin: true - - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - - type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - - type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - - type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} - - type-fest@4.41.0: - resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} - engines: {node: '>=16'} - - type-is@1.6.18: - resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} - engines: {node: '>= 0.6'} - - type-is@2.0.1: - resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} - engines: {node: '>= 0.6'} - - typed-array-buffer@1.0.3: - resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} - engines: {node: '>= 0.4'} - - typed-array-byte-length@1.0.3: - resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} - engines: {node: '>= 0.4'} - - typed-array-byte-offset@1.0.4: - resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} - engines: {node: '>= 0.4'} - - typed-array-length@1.0.7: - resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} - engines: {node: '>= 0.4'} - - typedarray@0.0.6: - resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - - typeorm@0.3.29: - resolution: {integrity: sha512-wwPEX/df4l72gCmOsrs0otJZYLGA9lLQkUZCkukbsymEycV4zXv2KM7wU7v2r8L01TaCgY9ApSSqHQWBOUhEoQ==} - engines: {node: '>=16.13.0'} - hasBin: true - peerDependencies: - '@google-cloud/spanner': ^5.18.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - '@sap/hana-client': ^2.14.22 - better-sqlite3: ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0 - ioredis: ^5.0.4 - mongodb: ^5.8.0 || ^6.0.0 - mssql: ^9.1.1 || ^10.0.0 || ^11.0.0 || ^12.0.0 - mysql2: ^2.2.5 || ^3.0.1 - oracledb: ^6.3.0 - pg: ^8.5.1 - pg-native: ^3.0.0 - pg-query-stream: ^4.0.0 - redis: ^3.1.1 || ^4.0.0 || ^5.0.14 - sql.js: ^1.4.0 - sqlite3: ^5.0.3 - ts-node: ^10.7.0 - typeorm-aurora-data-api-driver: ^2.0.0 || ^3.0.0 - peerDependenciesMeta: - '@google-cloud/spanner': - optional: true - '@sap/hana-client': - optional: true - better-sqlite3: - optional: true - ioredis: - optional: true - mongodb: - optional: true - mssql: - optional: true - mysql2: - optional: true - oracledb: - optional: true - pg: - optional: true - pg-native: - optional: true - pg-query-stream: - optional: true - redis: - optional: true - sql.js: - optional: true - sqlite3: - optional: true - ts-node: - optional: true - typeorm-aurora-data-api-driver: - optional: true - - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true - - uglify-js@3.19.3: - resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} - engines: {node: '>=0.8.0'} - hasBin: true - - uid@2.0.2: - resolution: {integrity: sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==} - engines: {node: '>=8'} - - uint8array-extras@1.5.0: - resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} - engines: {node: '>=18'} - - unbox-primitive@1.1.0: - resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} - engines: {node: '>= 0.4'} - - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - - undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - - unicorn-magic@0.1.0: - resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} - engines: {node: '>=18'} - - universalify@2.0.1: - resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} - engines: {node: '>= 10.0.0'} - - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - - update-browserslist-db@1.2.3: - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - '@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1)': - dependencies: - '@babel/runtime': 7.29.2 - '@emotion/babel-plugin': 11.13.5 - '@emotion/cache': 11.14.0 - '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.6) - '@emotion/utils': 1.4.2 - '@emotion/weak-memoize': 0.4.0 - hoist-non-react-statics: 3.3.2 - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.28 - transitivePeerDependencies: - - supports-color - - '@emotion/react@11.14.0(@types/react@18.3.28)(react@19.2.6)': - dependencies: - '@babel/runtime': 7.29.2 - '@emotion/babel-plugin': 11.13.5 - '@emotion/cache': 11.14.0 - '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.6) - '@emotion/utils': 1.4.2 - '@emotion/weak-memoize': 0.4.0 - hoist-non-react-statics: 3.3.2 - react: 19.2.6 - optionalDependencies: - '@types/react': 18.3.28 - transitivePeerDependencies: - - supports-color - - '@emotion/serialize@1.3.3': - dependencies: - '@emotion/hash': 0.9.2 - '@emotion/memoize': 0.9.0 - '@emotion/unitless': 0.10.0 - '@emotion/utils': 1.4.2 - csstype: 3.2.3 - - utils-merge@1.0.1: - resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} - engines: {node: '>= 0.4.0'} - - uuid@11.1.1: - resolution: {integrity: sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==} - hasBin: true - - '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@19.2.6)': - dependencies: - '@babel/runtime': 7.29.2 - '@emotion/babel-plugin': 11.13.5 - '@emotion/is-prop-valid': 1.4.0 - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@19.2.6) - '@emotion/serialize': 1.3.3 - '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.6) - '@emotion/utils': 1.4.2 - react: 19.2.6 - optionalDependencies: - '@types/react': 18.3.28 - transitivePeerDependencies: - - supports-color - - '@emotion/unitless@0.10.0': {} - - v8-to-istanbul@9.3.0: - resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} - engines: {node: '>=10.12.0'} - - '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.6)': - dependencies: - react: 19.2.6 - - '@emotion/utils@1.4.2': {} - - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - - vite-node@2.1.9: - resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - - vite@5.4.21: - resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || >=20.0.0 - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - - vitest@2.1.9: - resolution: {integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 2.1.9 - '@vitest/ui': 2.1.9 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@types/node': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - - w3c-xmlserializer@5.0.0: - resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} - engines: {node: '>=18'} - - walker@1.0.8: - resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} - - watchpack@2.5.1: - resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} - engines: {node: '>=10.13.0'} - - wcwidth@1.0.1: - resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} - - webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - - webidl-conversions@7.0.0: - resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} - engines: {node: '>=12'} - - webpack-node-externals@3.0.0: - resolution: {integrity: sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==} - engines: {node: '>=6'} - - webpack-sources@3.4.1: - resolution: {integrity: sha512-eACpxRN02yaawnt+uUNIF7Qje6A9zArxBbcAJjK1PK3S9Ycg5jIuJ8pW4q8EMnwNZCEGltcjkRx1QzOxOkKD8A==} - engines: {node: '>=10.13.0'} - - webpack@5.106.0: - resolution: {integrity: sha512-Pkx5joZ9RrdgO5LBkyX1L2ZAJeK/Taz3vqZ9CbcP0wS5LEMx5QkKsEwLl29QJfihZ+DKRBFldzy1O30pJ1MDpA==} - engines: {node: '>=10.13.0'} - hasBin: true - peerDependencies: - webpack-cli: '*' - peerDependenciesMeta: - webpack-cli: - optional: true - - whatwg-encoding@3.1.1: - resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} - engines: {node: '>=18'} - deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation - - whatwg-mimetype@4.0.0: - resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} - engines: {node: '>=18'} - - whatwg-url@14.2.0: - resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} - engines: {node: '>=18'} - - whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - - which-boxed-primitive@1.1.1: - resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} - engines: {node: '>= 0.4'} - - which-builtin-type@1.2.1: - resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} - engines: {node: '>= 0.4'} - - which-collection@1.0.2: - resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} - engines: {node: '>= 0.4'} - - which-module@2.0.1: - resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} - - which-typed-array@1.1.20: - resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} - engines: {node: '>= 0.4'} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} - hasBin: true - - wide-align@1.1.5: - resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} - - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - - '@eslint/eslintrc@2.1.4': - dependencies: - ajv: 6.15.0 - debug: 4.4.3(supports-color@5.5.0) - espree: 9.6.1 - globals: 13.24.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.1 - minimatch: 3.1.5 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - wrap-ansi@6.2.0: - resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} - engines: {node: '>=8'} - - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} - - wrap-ansi@9.0.2: - resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} - engines: {node: '>=18'} - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - write-file-atomic@4.0.2: - resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - - ws@8.20.0: - resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} - 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 - - xml-name-validator@5.0.0: - resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} - engines: {node: '>=18'} - - '@floating-ui/react-dom@2.1.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@floating-ui/dom': 1.7.6 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - - '@floating-ui/react@0.27.19(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@floating-ui/react-dom': 2.1.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@floating-ui/utils': 0.2.11 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - tabbable: 6.4.0 - - xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - - y18n@4.0.3: - resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} - - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - - '@hookform/resolvers@5.2.2(react-hook-form@7.75.0(react@19.2.6))': - dependencies: - '@standard-schema/utils': 0.3.0 - react-hook-form: 7.75.0(react@19.2.6) - - '@humanwhocodes/config-array@0.13.0': - dependencies: - '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.3(supports-color@5.5.0) - minimatch: 3.1.5 - transitivePeerDependencies: - - supports-color - - yaml@1.10.3: - resolution: {integrity: sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==} - engines: {node: '>= 6'} - - yaml@2.9.0: - resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} - engines: {node: '>= 14.6'} - hasBin: true - - yargs-parser@18.1.3: - resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} - engines: {node: '>=6'} - - yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - - yargs@15.4.1: - resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} - engines: {node: '>=8'} - - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} - - yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - - yocto-queue@1.2.2: - resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} - engines: {node: '>=12.20'} - - yoctocolors-cjs@2.1.3: - resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} - engines: {node: '>=18'} - - zustand@5.0.13: - resolution: {integrity: sha512-efI2tVaVQPqtOh114loML/Z80Y4NP3yc+Ff0fYiZJPauNeWZeIp/bRFD7I9bfmCOYBh/PHxlglQ9+wvlwnPikQ==} - engines: {node: '>=12.20.0'} - peerDependencies: - '@types/react': '>=18.0.0' - immer: '>=9.0.6' - react: 18.3.1 - use-sync-external-store: '>=1.2.0' - peerDependenciesMeta: - '@types/react': - optional: true - immer: - optional: true - react: - optional: true - use-sync-external-store: - optional: true - -snapshots: - - '@alloc/quick-lru@5.2.0': {} - - '@angular-devkit/core@19.2.24(chokidar@4.0.3)': - dependencies: - ajv: 8.18.0 - ajv-formats: 3.0.1(ajv@8.18.0) - jsonc-parser: 3.3.1 - picomatch: 4.0.4 - rxjs: 7.8.1 - source-map: 0.7.4 - optionalDependencies: - chokidar: 4.0.3 - - '@angular-devkit/schematics-cli@19.2.24(@types/node@20.19.41)(chokidar@4.0.3)': - dependencies: - '@angular-devkit/core': 19.2.24(chokidar@4.0.3) - '@angular-devkit/schematics': 19.2.24(chokidar@4.0.3) - '@inquirer/prompts': 7.3.2(@types/node@20.19.41) - ansi-colors: 4.1.3 - symbol-observable: 4.0.0 - yargs-parser: 21.1.1 - transitivePeerDependencies: - - '@types/node' - - chokidar - - '@angular-devkit/schematics@19.2.24(chokidar@4.0.3)': - dependencies: - '@angular-devkit/core': 19.2.24(chokidar@4.0.3) - jsonc-parser: 3.3.1 - magic-string: 0.30.17 - ora: 5.4.1 - rxjs: 7.8.1 - transitivePeerDependencies: - - chokidar - '@asamuzakjp/css-color@3.2.0': dependencies: '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) @@ -11816,7 +11141,7 @@ snapshots: '@babel/types': 7.29.0 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -11959,39 +11284,23 @@ snapshots: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 - '@lottiefiles/react-lottie-player@3.6.0(react@19.2.6)': + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': dependencies: - lottie-web: 5.13.0 - react: 19.2.6 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@lukeed/csprng@1.1.0': {} - - '@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@19.2.6))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': dependencies: - '@floating-ui/react': 0.27.19(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@mantine/hooks': 8.3.18(react@19.2.6) - clsx: 2.1.1 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - react-number-format: 5.4.5(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@19.2.6) - react-textarea-autosize: 8.5.9(@types/react@18.3.28)(react@19.2.6) - type-fest: 4.41.0 - transitivePeerDependencies: - - '@types/react' + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@mantine/dates@8.3.18(@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@19.2.6))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@8.3.18(react@19.2.6))(dayjs@1.11.20)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@mantine/core': 8.3.18(@mantine/hooks@8.3.18(react@19.2.6))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@mantine/hooks': 8.3.18(react@19.2.6) - clsx: 2.1.1 - dayjs: 1.11.20 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) + '@babel/runtime@7.29.2': {} - '@mantine/hooks@8.3.18(react@19.2.6)': + '@babel/template@7.28.6': dependencies: - react: 19.2.6 + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 '@babel/traverse@7.29.0': dependencies: @@ -12001,7 +11310,7 @@ snapshots: '@babel/parser': 7.29.3 '@babel/template': 7.28.6 '@babel/types': 7.29.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -12014,26 +11323,21 @@ snapshots: '@borewit/text-codec@0.2.2': {} - '@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@chakra-ui/react@3.35.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@babel/runtime': 7.29.2 - '@mui/core-downloads-tracker': 5.18.0 - '@mui/system': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) - '@mui/types': 7.2.24(@types/react@18.3.28) - '@mui/utils': 5.17.1(@types/react@18.3.28)(react@18.3.1) - '@popperjs/core': 2.11.8 - '@types/react-transition-group': 4.4.12(@types/react@18.3.28) - clsx: 2.1.1 + '@ark-ui/react': 5.36.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@emotion/is-prop-valid': 1.4.0 + '@emotion/react': 11.14.0(@types/react@18.3.29)(react@19.2.6) + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.6) + '@emotion/utils': 1.4.2 + '@pandacss/is-valid-prop': 1.11.1 csstype: 3.2.3 - prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-is: 19.2.6 - react-transition-group: 4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - optionalDependencies: - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@19.2.6) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@19.2.6) - '@types/react': 18.3.28 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + + '@colors/colors@1.5.0': + optional: true '@commitlint/cli@19.8.1(@types/node@24.12.4)(typescript@5.9.3)': dependencies: @@ -12050,35 +11354,13 @@ snapshots: '@commitlint/config-conventional@19.8.1': dependencies: - '@babel/runtime': 7.29.2 - '@emotion/cache': 11.14.0 - '@emotion/serialize': 1.3.3 - csstype: 3.2.3 - prop-types: 15.8.1 - react: 18.3.1 - optionalDependencies: - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@19.2.6) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@19.2.6) + '@commitlint/types': 19.8.1 + conventional-changelog-conventionalcommits: 7.0.2 '@commitlint/config-validator@19.8.1': dependencies: - '@babel/runtime': 7.29.2 - '@mui/private-theming': 5.17.1(@types/react@18.3.28)(react@18.3.1) - '@mui/styled-engine': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(react@18.3.1) - '@mui/types': 7.2.24(@types/react@18.3.28) - '@mui/utils': 5.17.1(@types/react@18.3.28)(react@18.3.1) - clsx: 2.1.1 - csstype: 3.2.3 - prop-types: 15.8.1 - react: 18.3.1 - optionalDependencies: - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@19.2.6) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@19.2.6) - '@types/react': 18.3.28 - - '@mui/types@7.2.24(@types/react@18.3.28)': - optionalDependencies: - '@types/react': 18.3.28 + '@commitlint/types': 19.8.1 + ajv: 8.20.0 '@commitlint/ensure@19.8.1': dependencies: @@ -12096,100 +11378,12 @@ snapshots: '@commitlint/types': 19.8.1 chalk: 5.6.2 - '@mui/x-date-pickers@6.20.2(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(date-fns@4.1.0)(dayjs@1.11.20)(luxon@3.7.2)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@commitlint/is-ignored@19.8.1': dependencies: - '@babel/runtime': 7.29.2 - '@mui/base': 5.0.0-beta.70(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/material': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/system': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) - '@mui/utils': 5.17.1(@types/react@18.3.28)(react@18.3.1) - '@types/react-transition-group': 4.4.12(@types/react@18.3.28) - clsx: 2.1.1 - prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-transition-group: 4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - optionalDependencies: - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@19.2.6) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@19.2.6) - date-fns: 4.1.0 - dayjs: 1.11.20 - luxon: 3.7.2 - moment: 2.30.1 - transitivePeerDependencies: - - '@types/react' + '@commitlint/types': 19.8.1 + semver: 7.8.1 - '@mui/x-date-pickers@6.20.2(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(dayjs@1.11.20)(luxon@3.7.2)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@babel/runtime': 7.29.2 - '@mui/base': 5.0.0-beta.70(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/material': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/system': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) - '@mui/utils': 5.17.1(@types/react@18.3.28)(react@18.3.1) - '@types/react-transition-group': 4.4.12(@types/react@18.3.28) - clsx: 2.1.1 - prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-transition-group: 4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - optionalDependencies: - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@18.3.1) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) - dayjs: 1.11.20 - luxon: 3.7.2 - moment: 2.30.1 - transitivePeerDependencies: - - '@types/react' - - '@napi-rs/canvas-android-arm64@0.1.100': - optional: true - - '@napi-rs/canvas-darwin-arm64@0.1.100': - optional: true - - '@napi-rs/canvas-darwin-x64@0.1.100': - optional: true - - '@napi-rs/canvas-linux-arm-gnueabihf@0.1.100': - optional: true - - '@napi-rs/canvas-linux-arm64-gnu@0.1.100': - optional: true - - '@napi-rs/canvas-linux-arm64-musl@0.1.100': - optional: true - - '@napi-rs/canvas-linux-riscv64-gnu@0.1.100': - optional: true - - '@napi-rs/canvas-linux-x64-gnu@0.1.100': - optional: true - - '@napi-rs/canvas-linux-x64-musl@0.1.100': - optional: true - - '@napi-rs/canvas-win32-arm64-msvc@0.1.100': - optional: true - - '@napi-rs/canvas-win32-x64-msvc@0.1.100': - optional: true - - '@napi-rs/canvas@0.1.100': - optionalDependencies: - '@napi-rs/canvas-android-arm64': 0.1.100 - '@napi-rs/canvas-darwin-arm64': 0.1.100 - '@napi-rs/canvas-darwin-x64': 0.1.100 - '@napi-rs/canvas-linux-arm-gnueabihf': 0.1.100 - '@napi-rs/canvas-linux-arm64-gnu': 0.1.100 - '@napi-rs/canvas-linux-arm64-musl': 0.1.100 - '@napi-rs/canvas-linux-riscv64-gnu': 0.1.100 - '@napi-rs/canvas-linux-x64-gnu': 0.1.100 - '@napi-rs/canvas-linux-x64-musl': 0.1.100 - '@napi-rs/canvas-win32-arm64-msvc': 0.1.100 - '@napi-rs/canvas-win32-x64-msvc': 0.1.100 - optional: true - - '@nestjs/axios@4.0.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.16.0)(rxjs@7.8.2)': + '@commitlint/lint@19.8.1': dependencies: '@commitlint/is-ignored': 19.8.1 '@commitlint/parse': 19.8.1 @@ -12279,6 +11473,126 @@ snapshots: '@csstools/css-tokenizer@3.0.4': {} + '@date-fns/tz@1.5.0': {} + + '@emotion/babel-plugin@11.13.5': + dependencies: + '@babel/helper-module-imports': 7.28.6 + '@babel/runtime': 7.29.2 + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/serialize': 1.3.3 + babel-plugin-macros: 3.1.0 + convert-source-map: 1.9.0 + escape-string-regexp: 4.0.0 + find-root: 1.1.0 + source-map: 0.5.7 + stylis: 4.2.0 + transitivePeerDependencies: + - supports-color + + '@emotion/cache@11.14.0': + dependencies: + '@emotion/memoize': 0.9.0 + '@emotion/sheet': 1.4.0 + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + stylis: 4.2.0 + + '@emotion/hash@0.9.2': {} + + '@emotion/is-prop-valid@1.4.0': + dependencies: + '@emotion/memoize': 0.9.0 + + '@emotion/memoize@0.9.0': {} + + '@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.29.2 + '@emotion/babel-plugin': 11.13.5 + '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.6) + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + hoist-non-react-statics: 3.3.2 + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.29 + transitivePeerDependencies: + - supports-color + + '@emotion/react@11.14.0(@types/react@18.3.29)(react@19.2.6)': + dependencies: + '@babel/runtime': 7.29.2 + '@emotion/babel-plugin': 11.13.5 + '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.6) + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + hoist-non-react-statics: 3.3.2 + react: 19.2.6 + optionalDependencies: + '@types/react': 18.3.29 + transitivePeerDependencies: + - supports-color + + '@emotion/serialize@1.3.3': + dependencies: + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/unitless': 0.10.0 + '@emotion/utils': 1.4.2 + csstype: 3.2.3 + + '@emotion/sheet@1.4.0': {} + + '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.29.2 + '@emotion/babel-plugin': 11.13.5 + '@emotion/is-prop-valid': 1.4.0 + '@emotion/react': 11.14.0(@types/react@18.3.29)(react@18.3.1) + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@18.3.1) + '@emotion/utils': 1.4.2 + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.29 + transitivePeerDependencies: + - supports-color + + '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@19.2.6)': + dependencies: + '@babel/runtime': 7.29.2 + '@emotion/babel-plugin': 11.13.5 + '@emotion/is-prop-valid': 1.4.0 + '@emotion/react': 11.14.0(@types/react@18.3.29)(react@19.2.6) + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.6) + '@emotion/utils': 1.4.2 + react: 19.2.6 + optionalDependencies: + '@types/react': 18.3.29 + transitivePeerDependencies: + - supports-color + + '@emotion/unitless@0.10.0': {} + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@18.3.1)': + dependencies: + react: 18.3.1 + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.6)': + dependencies: + react: 19.2.6 + + '@emotion/utils@1.4.2': {} + + '@emotion/weak-memoize@0.4.0': {} + '@esbuild/aix-ppc64@0.21.5': optional: true @@ -12318,11 +11632,8 @@ snapshots: '@esbuild/linux-mips64el@0.21.5': optional: true - '@onlyoffice/document-editor-react@2.1.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - lodash: 4.17.21 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) + '@esbuild/linux-ppc64@0.21.5': + optional: true '@esbuild/linux-riscv64@0.21.5': optional: true @@ -12361,7 +11672,7 @@ snapshots: '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.15.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) espree: 9.6.1 globals: 13.24.0 ignore: 5.3.2 @@ -12374,10 +11685,71 @@ snapshots: '@eslint/js@8.57.1': {} + '@faker-js/faker@10.4.0': {} + + '@fast-csv/format@4.3.5': + dependencies: + '@types/node': 14.18.63 + lodash.escaperegexp: 4.1.2 + lodash.isboolean: 3.0.3 + lodash.isequal: 4.5.0 + lodash.isfunction: 3.0.9 + lodash.isnil: 4.0.0 + + '@fast-csv/parse@4.3.6': + dependencies: + '@types/node': 14.18.63 + lodash.escaperegexp: 4.1.2 + lodash.groupby: 4.6.0 + lodash.isfunction: 3.0.9 + lodash.isnil: 4.0.0 + lodash.isundefined: 3.0.1 + lodash.uniq: 4.5.0 + + '@floating-ui/core@1.7.5': + dependencies: + '@floating-ui/utils': 0.2.11 + + '@floating-ui/dom@1.7.6': + dependencies: + '@floating-ui/core': 1.7.5 + '@floating-ui/utils': 0.2.11 + + '@floating-ui/react-dom@2.1.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@floating-ui/dom': 1.7.6 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + + '@floating-ui/react-dom@2.1.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@floating-ui/dom': 1.7.6 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + + '@floating-ui/react@0.27.19(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@floating-ui/utils': 0.2.11 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + tabbable: 6.4.0 + + '@floating-ui/utils@0.2.11': {} + + '@gilbarbara/deep-equal@0.1.2': {} + + '@gilbarbara/deep-equal@0.3.1': {} + + '@hookform/resolvers@5.2.2(react-hook-form@7.76.0(react@19.2.6))': + dependencies: + '@standard-schema/utils': 0.3.0 + react-hook-form: 7.76.0(react@19.2.6) + '@humanwhocodes/config-array@0.13.0': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) minimatch: 3.1.5 transitivePeerDependencies: - supports-color @@ -12386,659 +11758,1595 @@ snapshots: '@humanwhocodes/object-schema@2.0.3': {} - '@radix-ui/react-accordion@1.2.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@inquirer/ansi@1.0.2': {} - '@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@inquirer/checkbox@4.3.2(@types/node@20.19.41)': dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@20.19.41) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@20.19.41) + yoctocolors-cjs: 2.1.3 optionalDependencies: '@types/node': 20.19.41 - '@radix-ui/react-arrow@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@inquirer/confirm@5.1.21(@types/node@20.19.41)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) + '@inquirer/core': 10.3.2(@types/node@20.19.41) + '@inquirer/type': 3.0.10(@types/node@20.19.41) optionalDependencies: '@types/node': 20.19.41 - '@radix-ui/react-avatar@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@inquirer/core@10.3.2(@types/node@20.19.41)': dependencies: - '@radix-ui/react-context': 1.1.3(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@inquirer/ansi': 1.0.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@20.19.41) + cli-width: 4.1.0 + mute-stream: 2.0.0 + signal-exit: 4.1.0 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 20.19.41 + + '@inquirer/editor@4.2.23(@types/node@20.19.41)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@20.19.41) + '@inquirer/external-editor': 1.0.3(@types/node@20.19.41) + '@inquirer/type': 3.0.10(@types/node@20.19.41) + optionalDependencies: + '@types/node': 20.19.41 + + '@inquirer/expand@4.0.23(@types/node@20.19.41)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@20.19.41) + '@inquirer/type': 3.0.10(@types/node@20.19.41) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 20.19.41 + + '@inquirer/external-editor@1.0.3(@types/node@20.19.41)': + dependencies: + chardet: 2.1.1 + iconv-lite: 0.7.2 + optionalDependencies: + '@types/node': 20.19.41 + + '@inquirer/figures@1.0.15': {} + + '@inquirer/input@4.3.1(@types/node@20.19.41)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@20.19.41) + '@inquirer/type': 3.0.10(@types/node@20.19.41) + optionalDependencies: + '@types/node': 20.19.41 + + '@inquirer/number@3.0.23(@types/node@20.19.41)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@20.19.41) + '@inquirer/type': 3.0.10(@types/node@20.19.41) + optionalDependencies: + '@types/node': 20.19.41 + + '@inquirer/password@4.0.23(@types/node@20.19.41)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@20.19.41) + '@inquirer/type': 3.0.10(@types/node@20.19.41) + optionalDependencies: + '@types/node': 20.19.41 + + '@inquirer/prompts@7.10.1(@types/node@20.19.41)': + dependencies: + '@inquirer/checkbox': 4.3.2(@types/node@20.19.41) + '@inquirer/confirm': 5.1.21(@types/node@20.19.41) + '@inquirer/editor': 4.2.23(@types/node@20.19.41) + '@inquirer/expand': 4.0.23(@types/node@20.19.41) + '@inquirer/input': 4.3.1(@types/node@20.19.41) + '@inquirer/number': 3.0.23(@types/node@20.19.41) + '@inquirer/password': 4.0.23(@types/node@20.19.41) + '@inquirer/rawlist': 4.1.11(@types/node@20.19.41) + '@inquirer/search': 3.2.2(@types/node@20.19.41) + '@inquirer/select': 4.4.2(@types/node@20.19.41) + optionalDependencies: + '@types/node': 20.19.41 + + '@inquirer/prompts@7.3.2(@types/node@20.19.41)': + dependencies: + '@inquirer/checkbox': 4.3.2(@types/node@20.19.41) + '@inquirer/confirm': 5.1.21(@types/node@20.19.41) + '@inquirer/editor': 4.2.23(@types/node@20.19.41) + '@inquirer/expand': 4.0.23(@types/node@20.19.41) + '@inquirer/input': 4.3.1(@types/node@20.19.41) + '@inquirer/number': 3.0.23(@types/node@20.19.41) + '@inquirer/password': 4.0.23(@types/node@20.19.41) + '@inquirer/rawlist': 4.1.11(@types/node@20.19.41) + '@inquirer/search': 3.2.2(@types/node@20.19.41) + '@inquirer/select': 4.4.2(@types/node@20.19.41) + optionalDependencies: + '@types/node': 20.19.41 + + '@inquirer/rawlist@4.1.11(@types/node@20.19.41)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@20.19.41) + '@inquirer/type': 3.0.10(@types/node@20.19.41) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 20.19.41 + + '@inquirer/search@3.2.2(@types/node@20.19.41)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@20.19.41) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@20.19.41) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 20.19.41 + + '@inquirer/select@4.4.2(@types/node@20.19.41)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@20.19.41) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@20.19.41) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 20.19.41 + + '@inquirer/type@3.0.10(@types/node@20.19.41)': + optionalDependencies: + '@types/node': 20.19.41 + + '@internationalized/date@3.12.0': + dependencies: + '@swc/helpers': 0.5.21 + + '@internationalized/number@3.6.5': + dependencies: + '@swc/helpers': 0.5.21 + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.2.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@istanbuljs/load-nyc-config@1.1.0': + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.2 + resolve-from: 5.0.0 + + '@istanbuljs/schema@0.1.6': {} + + '@jest/console@29.7.0': + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.19.41 + chalk: 4.1.2 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + + '@jest/core@29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))': + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.19.41 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@20.19.41)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + + '@jest/environment@29.7.0': + dependencies: + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.19.41 + jest-mock: 29.7.0 + + '@jest/expect-utils@29.7.0': + dependencies: + jest-get-type: 29.6.3 + + '@jest/expect@29.7.0': + dependencies: + expect: 29.7.0 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + + '@jest/fake-timers@29.7.0': + dependencies: + '@jest/types': 29.6.3 + '@sinonjs/fake-timers': 10.3.0 + '@types/node': 20.19.41 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + '@jest/globals@29.7.0': + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/types': 29.6.3 + jest-mock: 29.7.0 + transitivePeerDependencies: + - supports-color + + '@jest/reporters@29.7.0': + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.31 + '@types/node': 20.19.41 + chalk: 4.1.2 + collect-v8-coverage: 1.0.3 + exit: 0.1.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.3 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.2.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + jest-worker: 29.7.0 + slash: 3.0.0 + string-length: 4.0.2 + strip-ansi: 6.0.1 + v8-to-istanbul: 9.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.10 + + '@jest/source-map@29.6.3': + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + callsites: 3.1.0 + graceful-fs: 4.2.11 + + '@jest/test-result@29.7.0': + dependencies: + '@jest/console': 29.7.0 + '@jest/types': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + collect-v8-coverage: 1.0.3 + + '@jest/test-sequencer@29.7.0': + dependencies: + '@jest/test-result': 29.7.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + slash: 3.0.0 + + '@jest/transform@29.7.0': + dependencies: + '@babel/core': 7.29.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.31 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + micromatch: 4.0.8 + pirates: 4.0.7 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 20.19.41 + '@types/yargs': 17.0.35 + chalk: 4.1.2 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@leichtgewicht/ip-codec@2.0.5': {} + + '@lottiefiles/react-lottie-player@3.6.0(react@19.2.6)': + dependencies: + lottie-web: 5.13.0 + react: 19.2.6 + + '@lukeed/csprng@1.1.0': {} + + '@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@18.3.1))(@types/react@18.3.29)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@floating-ui/react': 0.27.19(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@mantine/hooks': 8.3.18(react@19.2.6) + clsx: 2.1.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-number-format: 5.4.5(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-remove-scroll: 2.7.2(@types/react@18.3.29)(react@19.2.6) + react-textarea-autosize: 8.5.9(@types/react@18.3.29)(react@19.2.6) + type-fest: 4.41.0 + transitivePeerDependencies: + - '@types/react' + + '@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@19.2.6))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@floating-ui/react': 0.27.19(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@mantine/hooks': 8.3.18(react@19.2.6) + clsx: 2.1.1 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + react-number-format: 5.4.5(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-remove-scroll: 2.7.2(@types/react@18.3.29)(react@19.2.6) + react-textarea-autosize: 8.5.9(@types/react@18.3.29)(react@19.2.6) + type-fest: 4.41.0 + transitivePeerDependencies: + - '@types/react' - '@radix-ui/react-checkbox@1.3.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@mantine/dates@8.3.18(@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@18.3.1))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@8.3.18(react@18.3.1))(dayjs@1.11.20)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@mantine/core': 8.3.18(@mantine/hooks@8.3.18(react@18.3.1))(@types/react@18.3.29)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mantine/hooks': 8.3.18(react@19.2.6) + clsx: 2.1.1 + dayjs: 1.11.20 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + + '@mantine/dates@8.3.18(@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@19.2.6))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@8.3.18(react@19.2.6))(dayjs@1.11.20)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@mantine/core': 8.3.18(@mantine/hooks@8.3.18(react@19.2.6))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@mantine/hooks': 8.3.18(react@19.2.6) + clsx: 2.1.1 + dayjs: 1.11.20 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + + '@mantine/hooks@8.3.18(react@19.2.6)': + dependencies: + react: 19.2.6 + + '@mapbox/node-pre-gyp@1.0.11': + dependencies: + detect-libc: 2.1.2 + https-proxy-agent: 5.0.1 + make-dir: 3.1.0 + node-fetch: 2.7.0 + nopt: 5.0.0 + npmlog: 5.0.1 + rimraf: 3.0.2 + semver: 7.8.1 + tar: 6.2.1 + transitivePeerDependencies: + - encoding + - supports-color + + '@microsoft/tsdoc@0.15.1': {} + + '@microsoft/tsdoc@0.16.0': {} + + '@mui/base@5.0.0-beta.70(@types/react@18.3.29)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.29.2 + '@floating-ui/react-dom': 2.1.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/types': 7.2.24(@types/react@18.3.29) + '@mui/utils': 6.4.9(@types/react@18.3.29)(react@18.3.1) + '@popperjs/core': 2.11.8 + clsx: 2.1.1 + prop-types: 15.8.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.29 + + '@mui/core-downloads-tracker@5.18.0': {} + + '@mui/icons-material@5.18.0(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.29)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.29.2 + '@mui/material': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.29 + + '@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.29.2 + '@mui/core-downloads-tracker': 5.18.0 + '@mui/system': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1) + '@mui/types': 7.2.24(@types/react@18.3.29) + '@mui/utils': 5.17.1(@types/react@18.3.29)(react@18.3.1) + '@popperjs/core': 2.11.8 + '@types/react-transition-group': 4.4.12(@types/react@18.3.29) + clsx: 2.1.1 + csstype: 3.2.3 + prop-types: 15.8.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-is: 19.2.6 + react-transition-group: 4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + optionalDependencies: + '@emotion/react': 11.14.0(@types/react@18.3.29)(react@19.2.6) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@19.2.6) + '@types/react': 18.3.29 + + '@mui/private-theming@5.17.1(@types/react@18.3.29)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.29.2 + '@mui/utils': 5.17.1(@types/react@18.3.29)(react@18.3.1) + prop-types: 15.8.1 + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.29 + + '@mui/styled-engine@5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.29.2 + '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 + csstype: 3.2.3 + prop-types: 15.8.1 + react: 18.3.1 + optionalDependencies: + '@emotion/react': 11.14.0(@types/react@18.3.29)(react@19.2.6) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@19.2.6) + + '@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.29.2 + '@mui/private-theming': 5.17.1(@types/react@18.3.29)(react@18.3.1) + '@mui/styled-engine': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(react@18.3.1) + '@mui/types': 7.2.24(@types/react@18.3.29) + '@mui/utils': 5.17.1(@types/react@18.3.29)(react@18.3.1) + clsx: 2.1.1 + csstype: 3.2.3 + prop-types: 15.8.1 + react: 18.3.1 + optionalDependencies: + '@emotion/react': 11.14.0(@types/react@18.3.29)(react@19.2.6) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@19.2.6) + '@types/react': 18.3.29 + + '@mui/types@7.2.24(@types/react@18.3.29)': + optionalDependencies: + '@types/react': 18.3.29 + + '@mui/utils@5.17.1(@types/react@18.3.29)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.29.2 + '@mui/types': 7.2.24(@types/react@18.3.29) + '@types/prop-types': 15.7.15 + clsx: 2.1.1 + prop-types: 15.8.1 + react: 18.3.1 + react-is: 19.2.6 + optionalDependencies: + '@types/react': 18.3.29 + + '@mui/utils@6.4.9(@types/react@18.3.29)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.29.2 + '@mui/types': 7.2.24(@types/react@18.3.29) + '@types/prop-types': 15.7.15 + clsx: 2.1.1 + prop-types: 15.8.1 + react: 18.3.1 + react-is: 19.2.6 + optionalDependencies: + '@types/react': 18.3.29 + + '@mui/x-date-pickers@6.20.2(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(date-fns@4.2.1)(dayjs@1.11.20)(luxon@3.7.2)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.29.2 + '@mui/base': 5.0.0-beta.70(@types/react@18.3.29)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/material': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/system': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1) + '@mui/utils': 5.17.1(@types/react@18.3.29)(react@18.3.1) + '@types/react-transition-group': 4.4.12(@types/react@18.3.29) + clsx: 2.1.1 + prop-types: 15.8.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-transition-group: 4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + optionalDependencies: + '@emotion/react': 11.14.0(@types/react@18.3.29)(react@19.2.6) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@19.2.6) + date-fns: 4.2.1 + dayjs: 1.11.20 + luxon: 3.7.2 + moment: 2.30.1 + transitivePeerDependencies: + - '@types/react' + + '@mui/x-date-pickers@6.20.2(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(dayjs@1.11.20)(luxon@3.7.2)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.29.2 + '@mui/base': 5.0.0-beta.70(@types/react@18.3.29)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/material': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/system': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1) + '@mui/utils': 5.17.1(@types/react@18.3.29)(react@18.3.1) + '@types/react-transition-group': 4.4.12(@types/react@18.3.29) + clsx: 2.1.1 + prop-types: 15.8.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-transition-group: 4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + optionalDependencies: + '@emotion/react': 11.14.0(@types/react@18.3.29)(react@18.3.1) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1) + dayjs: 1.11.20 + luxon: 3.7.2 + moment: 2.30.1 + transitivePeerDependencies: + - '@types/react' + + '@napi-rs/canvas-android-arm64@0.1.100': + optional: true + + '@napi-rs/canvas-darwin-arm64@0.1.100': + optional: true + + '@napi-rs/canvas-darwin-x64@0.1.100': + optional: true + + '@napi-rs/canvas-linux-arm-gnueabihf@0.1.100': + optional: true + + '@napi-rs/canvas-linux-arm64-gnu@0.1.100': + optional: true + + '@napi-rs/canvas-linux-arm64-musl@0.1.100': + optional: true + + '@napi-rs/canvas-linux-riscv64-gnu@0.1.100': + optional: true + + '@napi-rs/canvas-linux-x64-gnu@0.1.100': + optional: true + + '@napi-rs/canvas-linux-x64-musl@0.1.100': + optional: true + + '@napi-rs/canvas-win32-arm64-msvc@0.1.100': + optional: true + + '@napi-rs/canvas-win32-x64-msvc@0.1.100': + optional: true + + '@napi-rs/canvas@0.1.100': + optionalDependencies: + '@napi-rs/canvas-android-arm64': 0.1.100 + '@napi-rs/canvas-darwin-arm64': 0.1.100 + '@napi-rs/canvas-darwin-x64': 0.1.100 + '@napi-rs/canvas-linux-arm-gnueabihf': 0.1.100 + '@napi-rs/canvas-linux-arm64-gnu': 0.1.100 + '@napi-rs/canvas-linux-arm64-musl': 0.1.100 + '@napi-rs/canvas-linux-riscv64-gnu': 0.1.100 + '@napi-rs/canvas-linux-x64-gnu': 0.1.100 + '@napi-rs/canvas-linux-x64-musl': 0.1.100 + '@napi-rs/canvas-win32-arm64-msvc': 0.1.100 + '@napi-rs/canvas-win32-x64-msvc': 0.1.100 + optional: true + + '@nestjs/axios@4.0.1(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.16.1)(rxjs@7.8.2)': + dependencies: + '@nestjs/common': 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + axios: 1.16.1 + rxjs: 7.8.2 + + '@nestjs/cli@11.0.21(@types/node@20.19.41)(prettier@3.8.3)': + dependencies: + '@angular-devkit/core': 19.2.24(chokidar@4.0.3) + '@angular-devkit/schematics': 19.2.24(chokidar@4.0.3) + '@angular-devkit/schematics-cli': 19.2.24(@types/node@20.19.41)(chokidar@4.0.3) + '@inquirer/prompts': 7.10.1(@types/node@20.19.41) + '@nestjs/schematics': 11.1.0(chokidar@4.0.3)(prettier@3.8.3)(typescript@5.9.3) + ansis: 4.2.0 + chokidar: 4.0.3 + cli-table3: 0.6.5 + commander: 4.1.1 + fork-ts-checker-webpack-plugin: 9.1.0(typescript@5.9.3)(webpack@5.106.0) + glob: 13.0.6 + node-emoji: 1.11.0 + ora: 5.4.1 + tsconfig-paths: 4.2.0 + tsconfig-paths-webpack-plugin: 4.2.0 + typescript: 5.9.3 + webpack: 5.106.0 + webpack-node-externals: 3.0.0 + transitivePeerDependencies: + - '@minify-html/node' + - '@swc/css' + - '@swc/html' + - '@types/node' + - clean-css + - cssnano + - csso + - esbuild + - html-minifier-terser + - lightningcss + - postcss + - prettier + - uglify-js + - webpack-cli + + '@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + dependencies: + file-type: 21.3.4 + iterare: 1.2.1 + load-esm: 1.0.3 + reflect-metadata: 0.2.2 + rxjs: 7.8.2 + tslib: 2.8.1 + uid: 2.0.2 + optionalDependencies: + class-transformer: 0.5.1 + class-validator: 0.14.4 + transitivePeerDependencies: + - supports-color + + '@nestjs/config@4.0.4(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2)': + dependencies: + '@nestjs/common': 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + dotenv: 17.4.1 + dotenv-expand: 12.0.3 + lodash: 4.18.1 + rxjs: 7.8.2 + + '@nestjs/core@11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.23)(@nestjs/platform-express@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + dependencies: + '@nestjs/common': 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nuxt/opencollective': 0.4.1 + fast-safe-stringify: 2.1.1 + iterare: 1.2.1 + path-to-regexp: 8.4.2 + reflect-metadata: 0.2.2 + rxjs: 7.8.2 + tslib: 2.8.1 + uid: 2.0.2 + optionalDependencies: + '@nestjs/microservices': 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/platform-express': 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23) + + '@nestjs/event-emitter@2.1.1(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)': + dependencies: + '@nestjs/common': 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.23)(@nestjs/platform-express@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2) + eventemitter2: 6.4.9 + + '@nestjs/jwt@10.2.0(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))': + dependencies: + '@nestjs/common': 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@types/jsonwebtoken': 9.0.5 + jsonwebtoken: 9.0.2 + + '@nestjs/mapped-types@2.0.5(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)': + dependencies: + '@nestjs/common': 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + reflect-metadata: 0.2.2 + optionalDependencies: + class-transformer: 0.5.1 + class-validator: 0.14.4 + + '@nestjs/mapped-types@2.1.1(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)': + dependencies: + '@nestjs/common': 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + reflect-metadata: 0.2.2 + optionalDependencies: + class-transformer: 0.5.1 + class-validator: 0.14.4 + + '@nestjs/microservices@11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + dependencies: + '@nestjs/common': 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.23)(@nestjs/platform-express@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2) + iterare: 1.2.1 + reflect-metadata: 0.2.2 + rxjs: 7.8.2 + tslib: 2.8.1 + + '@nestjs/passport@10.0.3(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0)': + dependencies: + '@nestjs/common': 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + passport: 0.7.0 + + '@nestjs/platform-express@11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)': + dependencies: + '@nestjs/common': 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.23)(@nestjs/platform-express@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2) + cors: 2.8.6 + express: 5.2.1 + multer: 2.1.1 + path-to-regexp: 8.4.2 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@nestjs/schedule@6.1.3(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)': + dependencies: + '@nestjs/common': 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.23)(@nestjs/platform-express@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2) + cron: 4.4.0 + + '@nestjs/schematics@11.1.0(chokidar@4.0.3)(prettier@3.8.3)(typescript@5.9.3)': + dependencies: + '@angular-devkit/core': 19.2.24(chokidar@4.0.3) + '@angular-devkit/schematics': 19.2.24(chokidar@4.0.3) + comment-json: 5.0.0 + jsonc-parser: 3.3.1 + pluralize: 8.0.0 + typescript: 5.9.3 + optionalDependencies: + prettier: 3.8.3 + transitivePeerDependencies: + - chokidar + + '@nestjs/swagger@11.4.4(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)': + dependencies: + '@microsoft/tsdoc': 0.16.0 + '@nestjs/common': 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.23)(@nestjs/platform-express@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/mapped-types': 2.1.1(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) + js-yaml: 4.1.1 + lodash: 4.18.1 + path-to-regexp: 8.4.2 + reflect-metadata: 0.2.2 + swagger-ui-dist: 5.32.6 + optionalDependencies: + class-transformer: 0.5.1 + class-validator: 0.14.4 + + '@nestjs/swagger@7.4.2(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)': + dependencies: + '@microsoft/tsdoc': 0.15.1 + '@nestjs/common': 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.23)(@nestjs/platform-express@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/mapped-types': 2.0.5(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) + js-yaml: 4.1.0 + lodash: 4.17.21 + path-to-regexp: 3.3.0 + reflect-metadata: 0.2.2 + swagger-ui-dist: 5.17.14 + optionalDependencies: + class-transformer: 0.5.1 + class-validator: 0.14.4 + + '@nestjs/testing@11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(@nestjs/microservices@11.1.23)(@nestjs/platform-express@11.1.23)': + dependencies: + '@nestjs/common': 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.23)(@nestjs/platform-express@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2) + tslib: 2.8.1 + optionalDependencies: + '@nestjs/microservices': 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/platform-express': 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23) + + '@nestjs/throttler@6.5.0(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(reflect-metadata@0.2.2)': + dependencies: + '@nestjs/common': 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.23)(@nestjs/platform-express@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2) + reflect-metadata: 0.2.2 + + '@nestjs/typeorm@11.0.1(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)))': + dependencies: + '@nestjs/common': 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.23)(@nestjs/platform-express@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2) + reflect-metadata: 0.2.2 + rxjs: 7.8.2 + typeorm: 0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) + + '@noble/ciphers@1.3.0': {} + + '@noble/hashes@1.8.0': {} + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + + '@nuxt/opencollective@0.4.1': + dependencies: + consola: 3.4.2 + + '@onlyoffice/doceditor-types@9.3.1': {} + + '@onlyoffice/document-editor-react@2.2.0(@onlyoffice/doceditor-types@9.3.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@onlyoffice/doceditor-types': 9.3.1 + lodash: 4.18.1 + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + + '@pandacss/is-valid-prop@1.11.1': {} + + '@paralleldrive/cuid2@2.3.1': + dependencies: + '@noble/hashes': 1.8.0 + + '@phc/format@1.0.0': {} + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@popperjs/core@2.11.8': {} + + '@prisma/client@6.19.3(prisma@6.19.3(typescript@5.9.3))(typescript@5.9.3)': + optionalDependencies: + prisma: 6.19.3(typescript@5.9.3) + typescript: 5.9.3 + + '@prisma/config@6.19.3': + dependencies: + c12: 3.1.0 + deepmerge-ts: 7.1.5 + effect: 3.21.0 + empathic: 2.0.0 + transitivePeerDependencies: + - magicast + + '@prisma/debug@6.19.3': {} + + '@prisma/engines-version@7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7': {} + + '@prisma/engines@6.19.3': + dependencies: + '@prisma/debug': 6.19.3 + '@prisma/engines-version': 7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7 + '@prisma/fetch-engine': 6.19.3 + '@prisma/get-platform': 6.19.3 + + '@prisma/fetch-engine@6.19.3': + dependencies: + '@prisma/debug': 6.19.3 + '@prisma/engines-version': 7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7 + '@prisma/get-platform': 6.19.3 + + '@prisma/get-platform@6.19.3': + dependencies: + '@prisma/debug': 6.19.3 + + '@radix-ui/number@1.1.1': {} + + '@radix-ui/primitive@1.1.3': {} + + '@radix-ui/react-accordion@1.2.12(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-collapsible@1.1.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/node': 20.19.41 + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-collection@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-arrow@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/node': 20.19.41 + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-compose-refs@1.1.2(@types/react@18.3.28)(react@19.2.6)': + '@radix-ui/react-avatar@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: + '@radix-ui/react-context': 1.1.3(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/node': 20.19.41 + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-context-menu@2.2.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-checkbox@1.3.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/node': 20.19.41 + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-context@1.1.2(@types/react@18.3.28)(react@19.2.6)': - dependencies: - react: 19.2.6 - optionalDependencies: - '@types/react': 18.3.28 - - '@radix-ui/react-context@1.1.3(@types/react@18.3.28)(react@19.2.6)': - dependencies: - react: 19.2.6 - optionalDependencies: - '@types/react': 18.3.28 - - '@radix-ui/react-dialog@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-collapsible@1.1.12(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.29)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + optionalDependencies: + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) + + '@radix-ui/react-collection@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.29)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + optionalDependencies: + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) + + '@radix-ui/react-compose-refs@1.1.2(@types/react@18.3.29)(react@19.2.6)': + dependencies: + react: 19.2.6 + optionalDependencies: + '@types/react': 18.3.29 + + '@radix-ui/react-context-menu@2.2.16(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.29)(react@19.2.6) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + optionalDependencies: + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) + + '@radix-ui/react-context@1.1.2(@types/react@18.3.29)(react@19.2.6)': + dependencies: + react: 19.2.6 + optionalDependencies: + '@types/react': 18.3.29 + + '@radix-ui/react-context@1.1.3(@types/react@18.3.29)(react@19.2.6)': + dependencies: + react: 19.2.6 + optionalDependencies: + '@types/react': 18.3.29 + + '@radix-ui/react-dialog@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.29)(react@19.2.6) aria-hidden: 1.2.6 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@19.2.6) + react-remove-scroll: 2.7.2(@types/react@18.3.29)(react@19.2.6) optionalDependencies: - '@types/node': 20.19.41 + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-direction@1.1.1(@types/react@18.3.28)(react@19.2.6)': + '@radix-ui/react-direction@1.1.1(@types/react@18.3.29)(react@19.2.6)': dependencies: react: 19.2.6 optionalDependencies: - '@types/node': 20.19.41 + '@types/react': 18.3.29 - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/node': 20.19.41 + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/node': 20.19.41 + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-focus-guards@1.1.3(@types/react@18.3.28)(react@19.2.6)': + '@radix-ui/react-focus-guards@1.1.3(@types/react@18.3.29)(react@19.2.6)': dependencies: react: 19.2.6 optionalDependencies: - '@types/node': 20.19.41 + '@types/react': 18.3.29 - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-hover-card@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-hover-card@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/node': 20.19.41 + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-id@1.1.1(@types/react@18.3.28)(react@19.2.6)': + '@radix-ui/react-id@1.1.1(@types/react@18.3.29)(react@19.2.6)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 optionalDependencies: - '@types/node': 20.19.41 + '@types/react': 18.3.29 - '@radix-ui/react-label@2.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-label@2.1.8(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-menu@2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-menu@2.1.16(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.29)(react@19.2.6) aria-hidden: 1.2.6 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@19.2.6) + react-remove-scroll: 2.7.2(@types/react@18.3.29)(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-navigation-menu@1.2.14(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-navigation-menu@1.2.14(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-popover@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-popover@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.29)(react@19.2.6) aria-hidden: 1.2.6 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@19.2.6) + react-remove-scroll: 2.7.2(@types/react@18.3.29)(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-popper@1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-popper@1.2.8(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@floating-ui/react-dom': 2.1.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-rect': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-rect': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.29)(react@19.2.6) '@radix-ui/rect': 1.1.1 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/node': 20.19.41 + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-portal@1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-portal@1.1.9(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-presence@1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-presence@1.1.5(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-primitive@2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-primitive@2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-primitive@2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-primitive@2.1.4(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-slot': 1.2.4(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-slot': 1.2.4(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-progress@1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-progress@1.1.8(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-context': 1.1.3(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-context': 1.1.3(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-radio-group@1.3.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-radio-group@1.3.8(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/number': 1.1.1 '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-select@2.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-select@2.2.6(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/number': 1.1.1 '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) aria-hidden: 1.2.6 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - react-remove-scroll: 2.7.2(@types/react@18.3.28)(react@19.2.6) + react-remove-scroll: 2.7.2(@types/react@18.3.29)(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-separator@1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-separator@1.1.8(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-slider@1.3.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-slider@1.3.6(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/number': 1.1.1 '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-slot@1.2.3(@types/react@18.3.28)(react@19.2.6)': + '@radix-ui/react-slot@1.2.3(@types/react@18.3.29)(react@19.2.6)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 - '@radix-ui/react-slot@1.2.4(@types/react@18.3.28)(react@19.2.6)': + '@radix-ui/react-slot@1.2.4(@types/react@18.3.29)(react@19.2.6)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 - '@radix-ui/react-switch@1.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-switch@1.2.6(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-tabs@1.1.13(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-tabs@1.1.13(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-toast@1.2.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-toast@1.2.15(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-toggle-group@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-toggle-group@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-toggle': 1.1.10(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-toggle': 1.1.10(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-toggle@1.1.10(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-toggle@1.1.10(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-tooltip@1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-tooltip@1.2.8(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@18.3.28)(react@19.2.6)': + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@18.3.29)(react@19.2.6)': dependencies: react: 19.2.6 optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@18.3.28)(react@19.2.6)': + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@18.3.29)(react@19.2.6)': dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 - '@radix-ui/react-use-effect-event@0.0.2(@types/react@18.3.28)(react@19.2.6)': + '@radix-ui/react-use-effect-event@0.0.2(@types/react@18.3.29)(react@19.2.6)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@18.3.28)(react@19.2.6)': + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@18.3.29)(react@19.2.6)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 - '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@18.3.28)(react@19.2.6)': + '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@18.3.29)(react@19.2.6)': dependencies: react: 19.2.6 use-sync-external-store: 1.6.0(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@18.3.28)(react@19.2.6)': + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@18.3.29)(react@19.2.6)': dependencies: react: 19.2.6 optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 - '@radix-ui/react-use-previous@1.1.1(@types/react@18.3.28)(react@19.2.6)': + '@radix-ui/react-use-previous@1.1.1(@types/react@18.3.29)(react@19.2.6)': dependencies: react: 19.2.6 optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 - '@radix-ui/react-use-rect@1.1.1(@types/react@18.3.28)(react@19.2.6)': + '@radix-ui/react-use-rect@1.1.1(@types/react@18.3.29)(react@19.2.6)': dependencies: '@radix-ui/rect': 1.1.1 react: 19.2.6 optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 - '@radix-ui/react-use-size@1.1.1(@types/react@18.3.28)(react@19.2.6)': + '@radix-ui/react-use-size@1.1.1(@types/react@18.3.29)(react@19.2.6)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.28)(react@19.2.6) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.29)(react@19.2.6) react: 19.2.6 optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 - '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) - '@lukeed/csprng@1.1.0': {} + '@radix-ui/rect@1.1.1': {} '@react-pdf-viewer/attachment@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: @@ -13046,8 +13354,7 @@ snapshots: react: 19.2.6 react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - - encoding - - supports-color + - pdfjs-dist '@react-pdf-viewer/bookmark@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: @@ -13073,20 +13380,7 @@ snapshots: react: 19.2.6 react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - - '@minify-html/node' - - '@swc/css' - - '@swc/html' - - '@types/node' - - clean-css - - cssnano - - csso - - esbuild - - html-minifier-terser - - lightningcss - - postcss - - prettier - - uglify-js - - webpack-cli + - pdfjs-dist '@react-pdf-viewer/full-screen@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: @@ -13094,7 +13388,7 @@ snapshots: react: 19.2.6 react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - - supports-color + - pdfjs-dist '@react-pdf-viewer/get-file@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: @@ -13158,7 +13452,7 @@ snapshots: react: 19.2.6 react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - - supports-color + - pdfjs-dist '@react-pdf-viewer/selection-mode@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: @@ -13174,7 +13468,7 @@ snapshots: react: 19.2.6 react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: - - chokidar + - pdfjs-dist '@react-pdf-viewer/thumbnail@3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: @@ -13212,30 +13506,47 @@ snapshots: transitivePeerDependencies: - pdfjs-dist - '@noble/hashes@1.8.0': {} + '@react-pdf/fns@3.1.3': {} - '@nodelib/fs.scandir@2.1.5': + '@react-pdf/font@4.0.8': dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 + '@react-pdf/pdfkit': 5.1.1 + '@react-pdf/types': 2.11.1 + fontkit: 2.0.4 + is-url: 1.2.4 - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': + '@react-pdf/image@3.1.0': dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.20.1 + '@react-pdf/svg': 1.1.0 + jay-peg: 1.1.1 + png-js: 2.0.0 - '@nuxt/opencollective@0.4.1': + '@react-pdf/layout@4.6.1': dependencies: - consola: 3.4.2 + '@react-pdf/fns': 3.1.3 + '@react-pdf/image': 3.1.0 + '@react-pdf/primitives': 4.3.0 + '@react-pdf/stylesheet': 6.2.1 + '@react-pdf/textkit': 6.3.0 + '@react-pdf/types': 2.11.1 + emoji-regex-xs: 1.0.0 + queue: 6.0.2 + yoga-layout: 3.2.1 - '@paralleldrive/cuid2@2.3.1': + '@react-pdf/pdfkit@5.1.1': dependencies: + '@babel/runtime': 7.29.2 + '@noble/ciphers': 1.3.0 '@noble/hashes': 1.8.0 + browserify-zlib: 0.2.0 + fontkit: 2.0.4 + jay-peg: 1.1.1 + js-md5: 0.8.3 + linebreak: 1.1.0 + png-js: 2.0.0 + vite-compatible-readable-stream: 3.6.1 - '@pkgjs/parseargs@0.11.0': - optional: true + '@react-pdf/primitives@4.3.0': {} '@react-pdf/reconciler@2.0.0(react@19.2.6)': dependencies: @@ -13273,112 +13584,121 @@ snapshots: queue: 6.0.2 react: 19.2.6 - '@prisma/debug@6.19.3': {} - - '@prisma/engines-version@7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7': {} - - '@prisma/engines@6.19.3': + '@react-pdf/stylesheet@6.2.1': dependencies: - '@prisma/debug': 6.19.3 - '@prisma/engines-version': 7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7 - '@prisma/fetch-engine': 6.19.3 - '@prisma/get-platform': 6.19.3 + '@react-pdf/fns': 3.1.3 + '@react-pdf/types': 2.11.1 + color-string: 2.1.4 + hsl-to-hex: 1.0.0 + media-engine: 1.0.3 + postcss-value-parser: 4.2.0 - '@prisma/fetch-engine@6.19.3': + '@react-pdf/svg@1.1.0': dependencies: - '@prisma/debug': 6.19.3 - '@prisma/engines-version': 7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7 - '@prisma/get-platform': 6.19.3 + '@react-pdf/primitives': 4.3.0 - '@reduxjs/toolkit@2.11.2(react-redux@9.2.0(@types/react@18.3.28)(react@19.2.6)(redux@5.0.1))(react@19.2.6)': + '@react-pdf/textkit@6.3.0': + dependencies: + '@react-pdf/fns': 3.1.3 + bidi-js: 1.0.3 + hyphen: 1.14.1 + unicode-properties: 1.4.1 + + '@react-pdf/types@2.11.1': + dependencies: + '@react-pdf/font': 4.0.8 + '@react-pdf/primitives': 4.3.0 + '@react-pdf/stylesheet': 6.2.1 + + '@reduxjs/toolkit@2.12.0(react-redux@9.3.0(@types/react@18.3.29)(react@19.2.6)(redux@5.0.1))(react@19.2.6)': dependencies: '@standard-schema/spec': 1.1.0 '@standard-schema/utils': 0.3.0 immer: 11.1.8 redux: 5.0.1 redux-thunk: 3.1.0(redux@5.0.1) - reselect: 5.1.1 + reselect: 5.2.0 optionalDependencies: react: 19.2.6 - react-redux: 9.2.0(@types/react@18.3.28)(react@19.2.6)(redux@5.0.1) + react-redux: 9.3.0(@types/react@18.3.29)(react@19.2.6)(redux@5.0.1) '@remix-run/router@1.23.2': {} '@rolldown/pluginutils@1.0.0-beta.27': {} - '@rollup/rollup-android-arm-eabi@4.60.3': + '@rollup/rollup-android-arm-eabi@4.60.4': optional: true - '@rollup/rollup-android-arm64@4.60.3': + '@rollup/rollup-android-arm64@4.60.4': optional: true - '@rollup/rollup-darwin-arm64@4.60.3': + '@rollup/rollup-darwin-arm64@4.60.4': optional: true - '@rollup/rollup-darwin-x64@4.60.3': + '@rollup/rollup-darwin-x64@4.60.4': optional: true - '@rollup/rollup-freebsd-arm64@4.60.3': + '@rollup/rollup-freebsd-arm64@4.60.4': optional: true - '@rollup/rollup-freebsd-x64@4.60.3': + '@rollup/rollup-freebsd-x64@4.60.4': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.60.3': + '@rollup/rollup-linux-arm-gnueabihf@4.60.4': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.60.3': + '@rollup/rollup-linux-arm-musleabihf@4.60.4': optional: true - '@rollup/rollup-linux-arm64-gnu@4.60.3': + '@rollup/rollup-linux-arm64-gnu@4.60.4': optional: true - '@rollup/rollup-linux-arm64-musl@4.60.3': + '@rollup/rollup-linux-arm64-musl@4.60.4': optional: true - '@rollup/rollup-linux-loong64-gnu@4.60.3': + '@rollup/rollup-linux-loong64-gnu@4.60.4': optional: true - '@rollup/rollup-linux-loong64-musl@4.60.3': + '@rollup/rollup-linux-loong64-musl@4.60.4': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.60.3': + '@rollup/rollup-linux-ppc64-gnu@4.60.4': optional: true - '@rollup/rollup-linux-ppc64-musl@4.60.3': + '@rollup/rollup-linux-ppc64-musl@4.60.4': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.60.3': + '@rollup/rollup-linux-riscv64-gnu@4.60.4': optional: true - '@rollup/rollup-linux-riscv64-musl@4.60.3': + '@rollup/rollup-linux-riscv64-musl@4.60.4': optional: true - '@rollup/rollup-linux-s390x-gnu@4.60.3': + '@rollup/rollup-linux-s390x-gnu@4.60.4': optional: true - '@rollup/rollup-linux-x64-gnu@4.60.3': + '@rollup/rollup-linux-x64-gnu@4.60.4': optional: true - '@rollup/rollup-linux-x64-musl@4.60.3': + '@rollup/rollup-linux-x64-musl@4.60.4': optional: true - '@rollup/rollup-openbsd-x64@4.60.3': + '@rollup/rollup-openbsd-x64@4.60.4': optional: true - '@rollup/rollup-openharmony-arm64@4.60.3': + '@rollup/rollup-openharmony-arm64@4.60.4': optional: true - '@rollup/rollup-win32-arm64-msvc@4.60.3': + '@rollup/rollup-win32-arm64-msvc@4.60.4': optional: true - '@rollup/rollup-win32-ia32-msvc@4.60.3': + '@rollup/rollup-win32-ia32-msvc@4.60.4': optional: true - '@rollup/rollup-win32-x64-gnu@4.60.3': + '@rollup/rollup-win32-x64-gnu@4.60.4': optional: true - '@rollup/rollup-win32-x64-msvc@4.60.3': + '@rollup/rollup-win32-x64-msvc@4.60.4': optional: true '@rtsao/scc@1.1.0': {} @@ -13388,9 +13708,10 @@ snapshots: '@sendgrid/client@8.1.6': dependencies: '@sendgrid/helpers': 8.0.0 - axios: 1.16.0 + axios: 1.16.1 transitivePeerDependencies: - debug + - supports-color '@sendgrid/helpers@8.0.0': dependencies: @@ -13402,6 +13723,7 @@ snapshots: '@sendgrid/helpers': 8.0.0 transitivePeerDependencies: - debug + - supports-color '@sinclair/typebox@0.27.10': {} @@ -13413,6 +13735,8 @@ snapshots: dependencies: '@sinonjs/commons': 3.0.1 + '@socket.io/component-emitter@3.1.2': {} + '@sqltools/formatter@1.2.5': {} '@standard-schema/spec@1.1.0': {} @@ -13435,7 +13759,7 @@ snapshots: '@tailwindcss/node@4.3.0': dependencies: '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.21.3 + enhanced-resolve: 5.21.6 jiti: 2.7.0 lightningcss: 1.32.0 magic-string: 0.30.21 @@ -13493,31 +13817,31 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.3.0 '@tailwindcss/oxide-win32-x64-msvc': 4.3.0 - '@tailwindcss/vite@4.3.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1))': + '@tailwindcss/vite@4.3.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0))': dependencies: '@tailwindcss/node': 4.3.0 '@tailwindcss/oxide': 4.3.0 tailwindcss: 4.3.0 - vite: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1) + vite: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0) - '@tanstack/query-core@5.100.10': {} + '@tanstack/query-core@5.100.11': {} - '@tanstack/query-devtools@5.100.10': {} + '@tanstack/query-devtools@5.100.11': {} - '@tanstack/react-query-devtools@5.100.10(@tanstack/react-query@5.100.10(react@18.3.1))(react@19.2.6)': + '@tanstack/react-query-devtools@5.100.11(@tanstack/react-query@5.100.11(react@18.3.1))(react@19.2.6)': dependencies: - '@tanstack/query-devtools': 5.100.10 - '@tanstack/react-query': 5.100.10(react@18.3.1) + '@tanstack/query-devtools': 5.100.11 + '@tanstack/react-query': 5.100.11(react@18.3.1) react: 19.2.6 - '@tanstack/react-query@5.100.10(react@18.3.1)': + '@tanstack/react-query@5.100.11(react@18.3.1)': dependencies: - '@tanstack/query-core': 5.100.10 + '@tanstack/query-core': 5.100.11 react: 18.3.1 - '@tanstack/react-query@5.100.10(react@19.2.6)': + '@tanstack/react-query@5.100.11(react@19.2.6)': dependencies: - '@tanstack/query-core': 5.100.10 + '@tanstack/query-core': 5.100.11 react: 19.2.6 '@tanstack/react-table@8.21.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': @@ -13528,147 +13852,147 @@ snapshots: '@tanstack/table-core@8.21.3': {} - '@tinymce/tinymce-react@6.3.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tinymce@7.9.2)': + '@tinymce/tinymce-react@6.3.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tinymce@7.9.3)': dependencies: prop-types: 15.8.1 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - tinymce: 7.9.2 + tinymce: 7.9.3 - '@tiptap/core@3.23.1(@tiptap/pm@3.23.1)': + '@tiptap/core@3.23.6(@tiptap/pm@3.23.6)': dependencies: - '@tiptap/pm': 3.23.1 + '@tiptap/pm': 3.23.6 - '@tiptap/extension-blockquote@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': + '@tiptap/extension-blockquote@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) - '@tiptap/extension-bold@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': + '@tiptap/extension-bold@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) - '@tiptap/extension-bubble-menu@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)': + '@tiptap/extension-bubble-menu@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)': dependencies: '@floating-ui/dom': 1.7.6 - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - '@tiptap/pm': 3.23.1 + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) + '@tiptap/pm': 3.23.6 optional: true - '@tiptap/extension-bullet-list@3.23.1(@tiptap/extension-list@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1))': + '@tiptap/extension-bullet-list@3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))': dependencies: - '@tiptap/extension-list': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) + '@tiptap/extension-list': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6) - '@tiptap/extension-code-block@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)': + '@tiptap/extension-code-block@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - '@tiptap/pm': 3.23.1 + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) + '@tiptap/pm': 3.23.6 - '@tiptap/extension-code@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': + '@tiptap/extension-code@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) - '@tiptap/extension-color@3.23.1(@tiptap/extension-text-style@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)))': + '@tiptap/extension-color@3.23.6(@tiptap/extension-text-style@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)))': dependencies: - '@tiptap/extension-text-style': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) + '@tiptap/extension-text-style': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) - '@tiptap/extension-document@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': + '@tiptap/extension-document@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) - '@tiptap/extension-dropcursor@3.23.1(@tiptap/extensions@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1))': + '@tiptap/extension-dropcursor@3.23.6(@tiptap/extensions@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))': dependencies: - '@tiptap/extensions': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) + '@tiptap/extensions': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6) - '@tiptap/extension-floating-menu@3.23.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)': + '@tiptap/extension-floating-menu@3.23.6(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)': dependencies: '@floating-ui/dom': 1.7.6 - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - '@tiptap/pm': 3.23.1 + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) + '@tiptap/pm': 3.23.6 optional: true - '@tiptap/extension-gapcursor@3.23.1(@tiptap/extensions@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1))': + '@tiptap/extension-gapcursor@3.23.6(@tiptap/extensions@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))': dependencies: - '@tiptap/extensions': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) + '@tiptap/extensions': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6) - '@tiptap/extension-hard-break@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': + '@tiptap/extension-hard-break@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) - '@tiptap/extension-heading@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': + '@tiptap/extension-heading@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) - '@tiptap/extension-highlight@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': + '@tiptap/extension-highlight@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) - '@tiptap/extension-horizontal-rule@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)': + '@tiptap/extension-horizontal-rule@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - '@tiptap/pm': 3.23.1 + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) + '@tiptap/pm': 3.23.6 - '@tiptap/extension-image@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': + '@tiptap/extension-image@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) - '@tiptap/extension-italic@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': + '@tiptap/extension-italic@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) - '@tiptap/extension-link@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)': + '@tiptap/extension-link@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - '@tiptap/pm': 3.23.1 - linkifyjs: 4.3.2 + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) + '@tiptap/pm': 3.23.6 + linkifyjs: 4.3.3 - '@tiptap/extension-list-item@3.23.1(@tiptap/extension-list@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1))': + '@tiptap/extension-list-item@3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))': dependencies: - '@tiptap/extension-list': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) + '@tiptap/extension-list': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6) - '@tiptap/extension-list-keymap@3.23.1(@tiptap/extension-list@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1))': + '@tiptap/extension-list-keymap@3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))': dependencies: - '@tiptap/extension-list': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) + '@tiptap/extension-list': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6) - '@tiptap/extension-list@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)': + '@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - '@tiptap/pm': 3.23.1 + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) + '@tiptap/pm': 3.23.6 - '@tiptap/extension-ordered-list@3.23.1(@tiptap/extension-list@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1))': + '@tiptap/extension-ordered-list@3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))': dependencies: - '@tiptap/extension-list': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) + '@tiptap/extension-list': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6) - '@tiptap/extension-paragraph@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': + '@tiptap/extension-paragraph@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) - '@tiptap/extension-strike@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': + '@tiptap/extension-strike@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) - '@tiptap/extension-text-align@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': + '@tiptap/extension-text-align@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) - '@tiptap/extension-text-style@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': + '@tiptap/extension-text-style@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) - '@tiptap/extension-text@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': + '@tiptap/extension-text@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) - '@tiptap/extension-underline@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))': + '@tiptap/extension-underline@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) - '@tiptap/extensions@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)': + '@tiptap/extensions@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - '@tiptap/pm': 3.23.1 + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) + '@tiptap/pm': 3.23.6 - '@tiptap/pm@3.23.1': + '@tiptap/pm@3.23.6': dependencies: prosemirror-changeset: 2.4.1 prosemirror-commands: 1.7.1 @@ -13676,56 +14000,56 @@ snapshots: prosemirror-gapcursor: 1.4.1 prosemirror-history: 1.5.0 prosemirror-keymap: 1.2.3 - prosemirror-model: 1.25.4 + prosemirror-model: 1.25.7 prosemirror-schema-list: 1.5.1 prosemirror-state: 1.4.4 prosemirror-tables: 1.8.5 prosemirror-transform: 1.12.0 prosemirror-view: 1.41.8 - '@tiptap/react@3.23.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@tiptap/react@3.23.6(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - '@tiptap/pm': 3.23.1 - '@types/react': 18.3.28 - '@types/react-dom': 18.3.7(@types/react@18.3.28) + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) + '@tiptap/pm': 3.23.6 + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) '@types/use-sync-external-store': 0.0.6 fast-equals: 5.4.0 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) use-sync-external-store: 1.6.0(react@19.2.6) optionalDependencies: - '@tiptap/extension-bubble-menu': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - '@tiptap/extension-floating-menu': 3.23.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) + '@tiptap/extension-bubble-menu': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6) + '@tiptap/extension-floating-menu': 3.23.6(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6) transitivePeerDependencies: - '@floating-ui/dom' - '@tiptap/starter-kit@3.23.1': + '@tiptap/starter-kit@3.23.6': dependencies: - '@tiptap/core': 3.23.1(@tiptap/pm@3.23.1) - '@tiptap/extension-blockquote': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-bold': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-bullet-list': 3.23.1(@tiptap/extension-list@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)) - '@tiptap/extension-code': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-code-block': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - '@tiptap/extension-document': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-dropcursor': 3.23.1(@tiptap/extensions@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)) - '@tiptap/extension-gapcursor': 3.23.1(@tiptap/extensions@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)) - '@tiptap/extension-hard-break': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-heading': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-horizontal-rule': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - '@tiptap/extension-italic': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-link': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - '@tiptap/extension-list': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - '@tiptap/extension-list-item': 3.23.1(@tiptap/extension-list@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)) - '@tiptap/extension-list-keymap': 3.23.1(@tiptap/extension-list@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)) - '@tiptap/extension-ordered-list': 3.23.1(@tiptap/extension-list@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)) - '@tiptap/extension-paragraph': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-strike': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-text': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-underline': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extensions': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - '@tiptap/pm': 3.23.1 + '@tiptap/core': 3.23.6(@tiptap/pm@3.23.6) + '@tiptap/extension-blockquote': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) + '@tiptap/extension-bold': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) + '@tiptap/extension-bullet-list': 3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)) + '@tiptap/extension-code': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) + '@tiptap/extension-code-block': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6) + '@tiptap/extension-document': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) + '@tiptap/extension-dropcursor': 3.23.6(@tiptap/extensions@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)) + '@tiptap/extension-gapcursor': 3.23.6(@tiptap/extensions@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)) + '@tiptap/extension-hard-break': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) + '@tiptap/extension-heading': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) + '@tiptap/extension-horizontal-rule': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6) + '@tiptap/extension-italic': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) + '@tiptap/extension-link': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6) + '@tiptap/extension-list': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6) + '@tiptap/extension-list-item': 3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)) + '@tiptap/extension-list-keymap': 3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)) + '@tiptap/extension-ordered-list': 3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)) + '@tiptap/extension-paragraph': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) + '@tiptap/extension-strike': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) + '@tiptap/extension-text': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) + '@tiptap/extension-underline': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) + '@tiptap/extensions': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6) + '@tiptap/pm': 3.23.6 '@tokenizer/inflate@0.4.1': dependencies: @@ -13736,20 +14060,20 @@ snapshots: '@tokenizer/token@0.3.0': {} - '@tria-plc/api-common@0.1.4(42b11c4715772d7b83dab2dbc0ea2324)': + '@tria-plc/api-common@0.1.4(223e9245c5c33c83105d11e0b796f581)': dependencies: - '@nestjs/axios': 4.0.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.16.0)(rxjs@7.8.2) - '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.19)(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/jwt': 11.0.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)) - '@nestjs/microservices': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/passport': 11.0.5(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0) - '@nestjs/swagger': 11.4.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) - '@nestjs/throttler': 6.5.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2) - '@nestjs/typeorm': 11.0.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))) - '@tria-plc/iamapi-common': 0.1.6(7eaf302065296f503c6ce1ae1c9ee51c) + '@nestjs/axios': 4.0.1(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.16.1)(rxjs@7.8.2) + '@nestjs/common': 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.23)(@nestjs/platform-express@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/jwt': 10.2.0(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)) + '@nestjs/microservices': 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/passport': 10.0.3(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0) + '@nestjs/swagger': 11.4.4(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) + '@nestjs/throttler': 6.5.0(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(reflect-metadata@0.2.2) + '@nestjs/typeorm': 11.0.1(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))) + '@tria-plc/iamapi-common': 0.1.6(5db95f48cc2d3ea262f734e8a77edcde) argon2: 0.43.1 - axios: 1.16.0 + axios: 1.16.1 change-case: 5.4.4 class-transformer: 0.5.1 class-validator: 0.14.4 @@ -13763,16 +14087,16 @@ snapshots: jmespath: 0.16.0 jose: 5.10.0 jsonwebtoken: 9.0.3 - libphonenumber-js: 1.13.1 + libphonenumber-js: 1.13.2 libreoffice-convert: 1.8.1 - nestjs-minio-client: 2.2.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19) + nestjs-minio-client: 2.2.0(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23) passport-jwt: 4.0.1 qrcode: 1.5.4 reflect-metadata: 0.2.2 rxjs: 7.8.2 style-object-to-css-string: 1.1.3 - typeorm: 0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) - typeorm-extension: 3.9.0(@faker-js/faker@10.4.0)(typeorm@0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))) + typeorm: 0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) + typeorm-extension: 3.9.0(@faker-js/faker@10.4.0)(typeorm@0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))) uuid: 11.1.1 xlsx: 0.18.5 transitivePeerDependencies: @@ -13780,140 +14104,140 @@ snapshots: - debug - supports-color - '@tria-plc/iamapi-common@0.1.6(7eaf302065296f503c6ce1ae1c9ee51c)': + '@tria-plc/iamapi-common@0.1.6(5db95f48cc2d3ea262f734e8a77edcde)': dependencies: - '@nestjs/axios': 4.0.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.16.0)(rxjs@7.8.2) - '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.19)(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/jwt': 11.0.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)) - '@nestjs/microservices': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/passport': 11.0.5(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0) - '@nestjs/swagger': 11.4.2(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) - '@nestjs/throttler': 6.5.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2) - '@nestjs/typeorm': 11.0.1(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))) - '@tria-plc/api-common': 0.1.4(42b11c4715772d7b83dab2dbc0ea2324) + '@nestjs/axios': 4.0.1(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.16.1)(rxjs@7.8.2) + '@nestjs/common': 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.23)(@nestjs/platform-express@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/jwt': 10.2.0(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)) + '@nestjs/microservices': 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/passport': 10.0.3(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0) + '@nestjs/swagger': 11.4.4(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) + '@nestjs/throttler': 6.5.0(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(reflect-metadata@0.2.2) + '@nestjs/typeorm': 11.0.1(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))) + '@tria-plc/api-common': 0.1.4(223e9245c5c33c83105d11e0b796f581) argon2: 0.43.1 - axios: 1.16.0 + axios: 1.16.1 class-transformer: 0.5.1 class-validator: 0.14.4 ethiopian-date: 0.0.6 file-type: 21.3.4 jose: 5.10.0 jsonwebtoken: 9.0.3 - libphonenumber-js: 1.13.1 - nestjs-minio-client: 2.2.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19) + libphonenumber-js: 1.13.2 + nestjs-minio-client: 2.2.0(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23) passport-jwt: 4.0.1 qrcode: 1.5.4 reflect-metadata: 0.2.2 rxjs: 7.8.2 - typeorm: 0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) - typeorm-extension: 3.9.0(@faker-js/faker@10.4.0)(typeorm@0.3.29(babel-plugin-macros@3.1.0)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))) + typeorm: 0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) + typeorm-extension: 3.9.0(@faker-js/faker@10.4.0)(typeorm@0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))) uuid: 11.1.1 transitivePeerDependencies: - '@faker-js/faker' - supports-color - '@tria-plc/iamui-common@1.0.3(9c106f46deace9660b1e6a7145f91ebf)': + '@tria-plc/iamui-common@1.0.3(29e1b902a5d7eebd7a61a744bc03492c)': dependencies: - '@chakra-ui/react': 3.35.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@19.2.6) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@19.2.6) - '@hookform/resolvers': 5.2.2(react-hook-form@7.75.0(react@19.2.6)) + '@chakra-ui/react': 3.35.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@emotion/react': 11.14.0(@types/react@18.3.29)(react@19.2.6) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@19.2.6) + '@hookform/resolvers': 5.2.2(react-hook-form@7.76.0(react@19.2.6)) '@lottiefiles/react-lottie-player': 3.6.0(react@19.2.6) - '@mantine/core': 8.3.18(@mantine/hooks@8.3.18(react@19.2.6))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@mantine/dates': 8.3.18(@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@19.2.6))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@8.3.18(react@19.2.6))(dayjs@1.11.20)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@mantine/core': 8.3.18(@mantine/hooks@8.3.18(react@19.2.6))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@mantine/dates': 8.3.18(@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@19.2.6))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@8.3.18(react@19.2.6))(dayjs@1.11.20)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@mantine/hooks': 8.3.18(react@19.2.6) - '@onlyoffice/document-editor-react': 2.1.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-accordion': 1.2.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-alert-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-avatar': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-checkbox': 1.3.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-context-menu': 2.2.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-hover-card': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-label': 2.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-popover': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-progress': 1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-radio-group': 1.3.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-scroll-area': 1.2.10(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-select': 2.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-separator': 1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slider': 1.3.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.4(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-switch': 1.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-tabs': 1.1.13(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-toast': 1.2.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-tooltip': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@onlyoffice/document-editor-react': 2.2.0(@onlyoffice/doceditor-types@9.3.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-accordion': 1.2.12(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-alert-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-avatar': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-checkbox': 1.3.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-context-menu': 2.2.16(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-hover-card': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-label': 2.1.8(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-popover': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-progress': 1.1.8(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-radio-group': 1.3.8(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-scroll-area': 1.2.10(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-select': 2.2.6(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-separator': 1.1.8(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slider': 1.3.6(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.4(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-switch': 1.2.6(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-tabs': 1.1.13(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-toast': 1.2.15(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-tooltip': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@react-pdf-viewer/default-layout': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@react-pdf/renderer': 4.5.1(react@19.2.6) - '@reduxjs/toolkit': 2.11.2(react-redux@9.2.0(@types/react@18.3.28)(react@19.2.6)(redux@5.0.1))(react@19.2.6) + '@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@18.3.29)(react@19.2.6)(redux@5.0.1))(react@19.2.6) '@tabler/icons-react': 3.44.0(react@19.2.6) - '@tailwindcss/vite': 4.3.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1)) - '@tanstack/react-query': 5.100.10(react@19.2.6) - '@tanstack/react-query-devtools': 5.100.10(@tanstack/react-query@5.100.10(react@18.3.1))(react@19.2.6) + '@tailwindcss/vite': 4.3.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0)) + '@tanstack/react-query': 5.100.11(react@19.2.6) + '@tanstack/react-query-devtools': 5.100.11(@tanstack/react-query@5.100.11(react@18.3.1))(react@19.2.6) '@tanstack/react-table': 8.21.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@tinymce/tinymce-react': 6.3.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tinymce@7.9.2) - '@tiptap/extension-color': 3.23.1(@tiptap/extension-text-style@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))) - '@tiptap/extension-highlight': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-image': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-link': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - '@tiptap/extension-text-align': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-text-style': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-underline': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/react': 3.23.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@tiptap/starter-kit': 3.23.1 + '@tinymce/tinymce-react': 6.3.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tinymce@7.9.3) + '@tiptap/extension-color': 3.23.6(@tiptap/extension-text-style@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))) + '@tiptap/extension-highlight': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) + '@tiptap/extension-image': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) + '@tiptap/extension-link': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6) + '@tiptap/extension-text-align': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) + '@tiptap/extension-text-style': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) + '@tiptap/extension-underline': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) + '@tiptap/react': 3.23.6(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@tiptap/starter-kit': 3.23.6 '@types/node': 24.12.4 '@types/tinymce': 4.6.9 - axios: 1.16.0 + axios: 1.16.1 class-variance-authority: 0.7.1 clsx: 2.1.1 - cmdk: 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - date-fns: 4.1.0 + cmdk: 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + date-fns: 4.2.1 dayjs: 1.11.20 ethiopian-calendar-date-converter: 2.1.6 ethiopian-calendar-new: 1.1.0 file-type: 18.7.0 force: 0.0.3 - framer-motion: 12.38.0(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + framer-motion: 12.40.0(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) html2canvas: 1.4.1 i18next: 25.10.10(typescript@5.9.3) i18next-browser-languagedetector: 8.2.1 jquery: 3.7.1 - js-cookie: 3.0.5 + js-cookie: 3.0.7 jspdf: 3.0.4 loadash: 1.0.0 lodash: 4.18.1 lucide-react: 0.513.0(react@19.2.6) - mui-ethiopian-datepicker: 0.3.2(bb2b0a350b39c049005e46c2e15483da) + mui-ethiopian-datepicker: 0.3.2(5e5972eb531cdc6fbddb8a7490bbd426) next-themes: 0.4.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) path: 0.12.7 - qs: 6.15.1 + qs: 6.15.2 react: 19.2.6 - react-cookie: 8.1.2(@types/react@18.3.28)(react@19.2.6) + react-cookie: 8.1.2(@types/react@18.3.29)(react@19.2.6) react-datepicker: 8.10.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react-day-picker: 9.14.0(react@19.2.6) react-dom: 19.2.6(react@19.2.6) react-dropzone: 14.4.1(react@19.2.6) - react-hook-form: 7.75.0(react@19.2.6) + react-hook-form: 7.76.0(react@19.2.6) react-i18next: 15.7.4(i18next@25.10.10(typescript@5.9.3))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(typescript@5.9.3) react-icons: 5.6.0(react@19.2.6) react-image-crop: 11.0.10(react@19.2.6) react-intersection-observer: 9.16.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react-is: 19.2.6 - react-joyride: 2.9.3(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react-pdf: 10.4.1(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-joyride: 2.9.3(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-pdf: 10.4.1(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react-pdf-html: 2.1.5(@react-pdf/renderer@4.5.1(react@18.3.1))(react@19.2.6) react-pdf-viewer: 0.1.0 - react-redux: 9.2.0(@types/react@18.3.28)(react@19.2.6)(redux@5.0.1) + react-redux: 9.3.0(@types/react@18.3.29)(react@19.2.6)(redux@5.0.1) react-resizable-panels: 3.0.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react-router-dom: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react-signature-canvas: 1.1.0-alpha.2(@types/prop-types@15.7.15)(@types/react@18.3.28)(prop-types@15.8.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - recharts: 3.8.1(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react-is@19.2.6)(react@19.2.6)(redux@5.0.1) + react-router-dom: 7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-signature-canvas: 1.1.0-alpha.2(@types/prop-types@15.7.15)(@types/react@18.3.29)(prop-types@15.8.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + recharts: 3.8.1(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react-is@19.2.6)(react@19.2.6)(redux@5.0.1) socket.io-client: 4.8.3 sonner: 2.0.7(react-dom@19.2.6(react@19.2.6))(react@19.2.6) tailwind-merge: 3.6.0 @@ -13921,9 +14245,9 @@ snapshots: tailwindcss: 4.3.0 tailwindcss-animate: 1.0.7(tailwindcss@4.3.0) tesseract.js: 7.0.0 - tinymce: 7.9.2 + tinymce: 7.9.3 url: 0.11.4 - vaul: 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + vaul: 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) xlsx: 0.18.5 zod: 3.25.76 transitivePeerDependencies: @@ -13932,6 +14256,7 @@ snapshots: - '@mui/icons-material' - '@mui/material' - '@mui/x-date-pickers' + - '@onlyoffice/doceditor-types' - '@tiptap/core' - '@tiptap/pm' - '@types/prop-types' @@ -13952,107 +14277,107 @@ snapshots: - webpack-command - worker-loader - '@tria-plc/iamui-common@1.0.3(b753628ac65312d9adb4ccd0069fe702)': + '@tria-plc/iamui-common@1.0.3(39b46189c29498b6b03bc65d0aed046a)': dependencies: - '@chakra-ui/react': 3.35.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@19.2.6) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@19.2.6) - '@hookform/resolvers': 5.2.2(react-hook-form@7.75.0(react@19.2.6)) + '@chakra-ui/react': 3.35.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@emotion/react': 11.14.0(@types/react@18.3.29)(react@19.2.6) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@19.2.6) + '@hookform/resolvers': 5.2.2(react-hook-form@7.76.0(react@19.2.6)) '@lottiefiles/react-lottie-player': 3.6.0(react@19.2.6) - '@mantine/core': 8.3.18(@mantine/hooks@8.3.18(react@19.2.6))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@mantine/dates': 8.3.18(@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@19.2.6))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@8.3.18(react@19.2.6))(dayjs@1.11.20)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@mantine/core': 8.3.18(@mantine/hooks@8.3.18(react@18.3.1))(@types/react@18.3.29)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mantine/dates': 8.3.18(@mantine/core@8.3.18(@mantine/hooks@8.3.18(react@18.3.1))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@mantine/hooks@8.3.18(react@18.3.1))(dayjs@1.11.20)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@mantine/hooks': 8.3.18(react@19.2.6) - '@onlyoffice/document-editor-react': 2.1.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-accordion': 1.2.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-alert-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-avatar': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-checkbox': 1.3.3(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-context-menu': 2.2.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-hover-card': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-label': 2.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-popover': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-progress': 1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-radio-group': 1.3.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-scroll-area': 1.2.10(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-select': 2.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-separator': 1.1.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slider': 1.3.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.4(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-switch': 1.2.6(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-tabs': 1.1.13(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-toast': 1.2.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-tooltip': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@onlyoffice/document-editor-react': 2.2.0(@onlyoffice/doceditor-types@9.3.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-accordion': 1.2.12(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-alert-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-avatar': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-checkbox': 1.3.3(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-context-menu': 2.2.16(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-hover-card': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-label': 2.1.8(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-popover': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-progress': 1.1.8(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-radio-group': 1.3.8(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-scroll-area': 1.2.10(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-select': 2.2.6(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-separator': 1.1.8(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slider': 1.3.6(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-slot': 1.2.4(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-switch': 1.2.6(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-tabs': 1.1.13(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-toast': 1.2.15(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-tooltip': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@react-pdf-viewer/core': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@react-pdf-viewer/default-layout': 3.12.0(pdfjs-dist@5.4.296)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@react-pdf/renderer': 4.5.1(react@19.2.6) - '@reduxjs/toolkit': 2.11.2(react-redux@9.2.0(@types/react@18.3.28)(react@19.2.6)(redux@5.0.1))(react@19.2.6) + '@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@18.3.29)(react@19.2.6)(redux@5.0.1))(react@19.2.6) '@tabler/icons-react': 3.44.0(react@19.2.6) - '@tailwindcss/vite': 4.3.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1)) - '@tanstack/react-query': 5.100.10(react@19.2.6) - '@tanstack/react-query-devtools': 5.100.10(@tanstack/react-query@5.100.10(react@18.3.1))(react@19.2.6) + '@tailwindcss/vite': 4.3.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0)) + '@tanstack/react-query': 5.100.11(react@19.2.6) + '@tanstack/react-query-devtools': 5.100.11(@tanstack/react-query@5.100.11(react@18.3.1))(react@19.2.6) '@tanstack/react-table': 8.21.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@tinymce/tinymce-react': 6.3.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tinymce@7.9.2) - '@tiptap/extension-color': 3.23.1(@tiptap/extension-text-style@3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))) - '@tiptap/extension-highlight': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-image': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-link': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1) - '@tiptap/extension-text-align': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-text-style': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/extension-underline': 3.23.1(@tiptap/core@3.23.1(@tiptap/pm@3.23.1)) - '@tiptap/react': 3.23.1(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.1(@tiptap/pm@3.23.1))(@tiptap/pm@3.23.1)(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@tiptap/starter-kit': 3.23.1 + '@tinymce/tinymce-react': 6.3.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tinymce@7.9.3) + '@tiptap/extension-color': 3.23.6(@tiptap/extension-text-style@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))) + '@tiptap/extension-highlight': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) + '@tiptap/extension-image': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) + '@tiptap/extension-link': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6) + '@tiptap/extension-text-align': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) + '@tiptap/extension-text-style': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) + '@tiptap/extension-underline': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6)) + '@tiptap/react': 3.23.6(@floating-ui/dom@1.7.6)(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@tiptap/starter-kit': 3.23.6 '@types/node': 24.12.4 '@types/tinymce': 4.6.9 - axios: 1.16.0 + axios: 1.16.1 class-variance-authority: 0.7.1 clsx: 2.1.1 - cmdk: 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - date-fns: 4.1.0 + cmdk: 1.1.1(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + date-fns: 4.2.1 dayjs: 1.11.20 ethiopian-calendar-date-converter: 2.1.6 ethiopian-calendar-new: 1.1.0 file-type: 18.7.0 force: 0.0.3 - framer-motion: 12.38.0(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + framer-motion: 12.40.0(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) html2canvas: 1.4.1 i18next: 25.10.10(typescript@5.9.3) i18next-browser-languagedetector: 8.2.1 jquery: 3.7.1 - js-cookie: 3.0.5 + js-cookie: 3.0.7 jspdf: 3.0.4 loadash: 1.0.0 lodash: 4.18.1 lucide-react: 0.513.0(react@19.2.6) - mui-ethiopian-datepicker: 0.3.2(c914a98daf8e04e98459e8e367258069) + mui-ethiopian-datepicker: 0.3.2(6b313862ea62f1caf34a6d816b4f4dc9) next-themes: 0.4.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) path: 0.12.7 - qs: 6.15.1 + qs: 6.15.2 react: 19.2.6 - react-cookie: 8.1.2(@types/react@18.3.28)(react@19.2.6) + react-cookie: 8.1.2(@types/react@18.3.29)(react@19.2.6) react-datepicker: 8.10.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react-day-picker: 9.14.0(react@19.2.6) react-dom: 19.2.6(react@19.2.6) react-dropzone: 14.4.1(react@19.2.6) - react-hook-form: 7.75.0(react@19.2.6) + react-hook-form: 7.76.0(react@19.2.6) react-i18next: 15.7.4(i18next@25.10.10(typescript@5.9.3))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(typescript@5.9.3) react-icons: 5.6.0(react@19.2.6) react-image-crop: 11.0.10(react@19.2.6) react-intersection-observer: 9.16.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react-is: 19.2.6 - react-joyride: 2.9.3(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react-pdf: 10.4.1(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-joyride: 2.9.3(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-pdf: 10.4.1(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react-pdf-html: 2.1.5(@react-pdf/renderer@4.5.1(react@18.3.1))(react@19.2.6) react-pdf-viewer: 0.1.0 - react-redux: 9.2.0(@types/react@18.3.28)(react@19.2.6)(redux@5.0.1) + react-redux: 9.3.0(@types/react@18.3.29)(react@19.2.6)(redux@5.0.1) react-resizable-panels: 3.0.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react-router-dom: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react-signature-canvas: 1.1.0-alpha.2(@types/prop-types@15.7.15)(@types/react@18.3.28)(prop-types@15.8.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - recharts: 3.8.1(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react-is@19.2.6)(react@19.2.6)(redux@5.0.1) + react-router-dom: 7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-signature-canvas: 1.1.0-alpha.2(@types/prop-types@15.7.15)(@types/react@18.3.29)(prop-types@15.8.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + recharts: 3.8.1(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react-is@19.2.6)(react@19.2.6)(redux@5.0.1) socket.io-client: 4.8.3 sonner: 2.0.7(react-dom@19.2.6(react@19.2.6))(react@19.2.6) tailwind-merge: 3.6.0 @@ -14060,9 +14385,9 @@ snapshots: tailwindcss: 4.3.0 tailwindcss-animate: 1.0.7(tailwindcss@4.3.0) tesseract.js: 7.0.0 - tinymce: 7.9.2 + tinymce: 7.9.3 url: 0.11.4 - vaul: 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + vaul: 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) xlsx: 0.18.5 zod: 3.25.76 transitivePeerDependencies: @@ -14071,6 +14396,7 @@ snapshots: - '@mui/icons-material' - '@mui/material' - '@mui/x-date-pickers' + - '@onlyoffice/doceditor-types' - '@tiptap/core' - '@tiptap/pm' - '@types/prop-types' @@ -14099,22 +14425,22 @@ snapshots: '@tsconfig/node16@1.0.4': {} - '@turbo/darwin-64@2.9.12': + '@turbo/darwin-64@2.9.14': optional: true - '@turbo/darwin-arm64@2.9.12': + '@turbo/darwin-arm64@2.9.14': optional: true - '@turbo/linux-64@2.9.12': + '@turbo/linux-64@2.9.14': optional: true - '@turbo/linux-arm64@2.9.12': + '@turbo/linux-arm64@2.9.14': optional: true - '@turbo/windows-64@2.9.12': + '@turbo/windows-64@2.9.14': optional: true - '@turbo/windows-arm64@2.9.12': + '@turbo/windows-arm64@2.9.14': optional: true '@types/babel__core@7.20.5': @@ -14157,6 +14483,30 @@ snapshots: '@types/cookiejar@2.1.5': {} + '@types/d3-array@3.2.2': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-shape@3.1.8': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + '@types/eslint-scope@3.7.7': dependencies: '@types/eslint': 9.6.1 @@ -14188,6 +14538,11 @@ snapshots: dependencies: '@types/node': 20.19.41 + '@types/hoist-non-react-statics@3.3.7(@types/react@18.3.29)': + dependencies: + '@types/react': 18.3.29 + hoist-non-react-statics: 3.3.2 + '@types/http-errors@2.0.5': {} '@types/istanbul-lib-coverage@2.0.6': {} @@ -14205,6 +14560,8 @@ snapshots: expect: 29.7.0 pretty-format: 29.7.0 + '@types/jquery@4.0.0': {} + '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} @@ -14224,6 +14581,8 @@ snapshots: '@types/ms@2.1.0': {} + '@types/node@14.18.63': {} + '@types/node@20.19.41': dependencies: undici-types: 6.21.0 @@ -14232,8 +14591,9 @@ snapshots: dependencies: undici-types: 7.16.0 - '@types/parse-json@4.0.2': - optional: true + '@types/pako@2.0.4': {} + + '@types/parse-json@4.0.2': {} '@types/passport-jwt@4.0.1': dependencies: @@ -14257,13 +14617,20 @@ snapshots: '@types/qs@6.15.1': {} + '@types/raf@3.4.3': + optional: true + '@types/range-parser@1.2.7': {} - '@types/react-dom@18.3.7(@types/react@18.3.28)': + '@types/react-dom@18.3.7(@types/react@18.3.29)': dependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 - '@types/react@18.3.28': + '@types/react-transition-group@4.4.12(@types/react@18.3.29)': + dependencies: + '@types/react': 18.3.29 + + '@types/react@18.3.29': dependencies: '@types/prop-types': 15.7.15 csstype: 3.2.3 @@ -14277,9 +14644,11 @@ snapshots: '@types/http-errors': 2.0.5 '@types/node': 20.19.41 + '@types/signature_pad@2.3.6': {} + '@types/stack-utils@2.0.3': {} - '@types/superagent@8.1.9': + '@types/superagent@8.1.10': dependencies: '@types/cookiejar': 2.1.5 '@types/methods': 1.1.4 @@ -14289,7 +14658,16 @@ snapshots: '@types/supertest@6.0.3': dependencies: '@types/methods': 1.1.4 - '@types/superagent': 8.1.9 + '@types/superagent': 8.1.10 + + '@types/tinymce@4.6.9': + dependencies: + '@types/jquery': 4.0.0 + + '@types/trusted-types@2.0.7': + optional: true + + '@types/use-sync-external-store@0.0.6': {} '@types/validator@13.15.10': {} @@ -14299,14 +14677,14 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.59.3(@typescript-eslint/parser@8.59.3(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.59.4(@typescript-eslint/parser@8.59.4(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.59.3(eslint@8.57.1)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.59.3 - '@typescript-eslint/type-utils': 8.59.3(eslint@8.57.1)(typescript@5.9.3) - '@typescript-eslint/utils': 8.59.3(eslint@8.57.1)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.59.3 + '@typescript-eslint/parser': 8.59.4(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.59.4 + '@typescript-eslint/type-utils': 8.59.4(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.4(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.59.4 eslint: 8.57.1 ignore: 7.0.5 natural-compare: 1.4.0 @@ -14315,41 +14693,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.59.3(eslint@8.57.1)(typescript@5.9.3)': + '@typescript-eslint/parser@8.59.4(eslint@8.57.1)(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.59.3 - '@typescript-eslint/types': 8.59.3 - '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.59.3 + '@typescript-eslint/scope-manager': 8.59.4 + '@typescript-eslint/types': 8.59.4 + '@typescript-eslint/typescript-estree': 8.59.4(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.59.4 debug: 4.4.3(supports-color@5.5.0) eslint: 8.57.1 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.59.3(typescript@5.9.3)': + '@typescript-eslint/project-service@8.59.4(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.59.3(typescript@5.9.3) - '@typescript-eslint/types': 8.59.3 + '@typescript-eslint/tsconfig-utils': 8.59.4(typescript@5.9.3) + '@typescript-eslint/types': 8.59.4 debug: 4.4.3(supports-color@5.5.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.59.3': + '@typescript-eslint/scope-manager@8.59.4': dependencies: - '@typescript-eslint/types': 8.59.3 - '@typescript-eslint/visitor-keys': 8.59.3 + '@typescript-eslint/types': 8.59.4 + '@typescript-eslint/visitor-keys': 8.59.4 - '@typescript-eslint/tsconfig-utils@8.59.3(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.59.4(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.59.3(eslint@8.57.1)(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.59.4(eslint@8.57.1)(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.59.3 - '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) - '@typescript-eslint/utils': 8.59.3(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/types': 8.59.4 + '@typescript-eslint/typescript-estree': 8.59.4(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.4(eslint@8.57.1)(typescript@5.9.3) debug: 4.4.3(supports-color@5.5.0) eslint: 8.57.1 ts-api-utils: 2.5.0(typescript@5.9.3) @@ -14357,42 +14735,42 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.59.3': {} + '@typescript-eslint/types@8.59.4': {} - '@typescript-eslint/typescript-estree@8.59.3(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.59.4(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.59.3(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.59.3(typescript@5.9.3) - '@typescript-eslint/types': 8.59.3 - '@typescript-eslint/visitor-keys': 8.59.3 + '@typescript-eslint/project-service': 8.59.4(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.59.4(typescript@5.9.3) + '@typescript-eslint/types': 8.59.4 + '@typescript-eslint/visitor-keys': 8.59.4 debug: 4.4.3(supports-color@5.5.0) minimatch: 10.2.5 - semver: 7.8.0 + semver: 7.8.1 tinyglobby: 0.2.16 ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.59.3(eslint@8.57.1)(typescript@5.9.3)': + '@typescript-eslint/utils@8.59.4(eslint@8.57.1)(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1) - '@typescript-eslint/scope-manager': 8.59.3 - '@typescript-eslint/types': 8.59.3 - '@typescript-eslint/typescript-estree': 8.59.3(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.59.4 + '@typescript-eslint/types': 8.59.4 + '@typescript-eslint/typescript-estree': 8.59.4(typescript@5.9.3) eslint: 8.57.1 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.59.3': + '@typescript-eslint/visitor-keys@8.59.4': dependencies: - '@typescript-eslint/types': 8.59.3 + '@typescript-eslint/types': 8.59.4 eslint-visitor-keys: 5.0.1 '@ungap/structured-clone@1.3.1': {} - '@vitejs/plugin-react@4.7.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1))': + '@vitejs/plugin-react@4.7.0(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) @@ -14400,7 +14778,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.27 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1) + vite: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0) transitivePeerDependencies: - supports-color @@ -14411,13 +14789,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 1.2.0 - '@vitest/mocker@2.1.9(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1))': + '@vitest/mocker@2.1.9(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0))': dependencies: '@vitest/spy': 2.1.9 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1) + vite: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0) '@vitest/pretty-format@2.1.9': dependencies: @@ -14445,6 +14823,411 @@ snapshots: tinyrainbow: 1.2.0 '@webassemblyjs/ast@1.14.1': + dependencies: + '@webassemblyjs/helper-numbers': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + + '@webassemblyjs/floating-point-hex-parser@1.13.2': {} + + '@webassemblyjs/helper-api-error@1.13.2': {} + + '@webassemblyjs/helper-buffer@1.14.1': {} + + '@webassemblyjs/helper-numbers@1.13.2': + dependencies: + '@webassemblyjs/floating-point-hex-parser': 1.13.2 + '@webassemblyjs/helper-api-error': 1.13.2 + '@xtuc/long': 4.2.2 + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} + + '@webassemblyjs/helper-wasm-section@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/wasm-gen': 1.14.1 + + '@webassemblyjs/ieee754@1.13.2': + dependencies: + '@xtuc/ieee754': 1.2.0 + + '@webassemblyjs/leb128@1.13.2': + dependencies: + '@xtuc/long': 4.2.2 + + '@webassemblyjs/utf8@1.13.2': {} + + '@webassemblyjs/wasm-edit@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/helper-wasm-section': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-opt': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + '@webassemblyjs/wast-printer': 1.14.1 + + '@webassemblyjs/wasm-gen@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + + '@webassemblyjs/wasm-opt@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + + '@webassemblyjs/wasm-parser@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-api-error': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + + '@webassemblyjs/wast-printer@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@xtuc/long': 4.2.2 + + '@xtuc/ieee754@1.2.0': {} + + '@xtuc/long@4.2.2': {} + + '@zag-js/accordion@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/anatomy@1.40.0': {} + + '@zag-js/angle-slider@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/rect-utils': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/aria-hidden@1.40.0': + dependencies: + '@zag-js/dom-query': 1.40.0 + + '@zag-js/async-list@1.40.0': + dependencies: + '@zag-js/core': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/auto-resize@1.40.0': + dependencies: + '@zag-js/dom-query': 1.40.0 + + '@zag-js/avatar@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/carousel@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/scroll-snap': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/cascade-select@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/collection': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dismissable': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/focus-visible': 1.40.0 + '@zag-js/popper': 1.40.0 + '@zag-js/rect-utils': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/checkbox@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/focus-visible': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/clipboard@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/collapsible@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/collection@1.40.0': + dependencies: + '@zag-js/utils': 1.40.0 + + '@zag-js/color-picker@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/color-utils': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dismissable': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/popper': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/color-utils@1.40.0': + dependencies: + '@zag-js/utils': 1.40.0 + + '@zag-js/combobox@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/collection': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dismissable': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/focus-visible': 1.40.0 + '@zag-js/live-region': 1.40.0 + '@zag-js/popper': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/core@1.40.0': + dependencies: + '@zag-js/dom-query': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/date-input@1.40.0(@internationalized/date@3.12.0)': + dependencies: + '@internationalized/date': 3.12.0 + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/date-utils': 1.40.0(@internationalized/date@3.12.0) + '@zag-js/dom-query': 1.40.0 + '@zag-js/live-region': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/date-picker@1.40.0(@internationalized/date@3.12.0)': + dependencies: + '@internationalized/date': 3.12.0 + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/date-utils': 1.40.0(@internationalized/date@3.12.0) + '@zag-js/dismissable': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/live-region': 1.40.0 + '@zag-js/popper': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/date-utils@1.40.0(@internationalized/date@3.12.0)': + dependencies: + '@internationalized/date': 3.12.0 + + '@zag-js/dialog@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/aria-hidden': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dismissable': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/focus-trap': 1.40.0 + '@zag-js/remove-scroll': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/dismissable@1.40.0': + dependencies: + '@zag-js/dom-query': 1.40.0 + '@zag-js/interact-outside': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/dom-query@1.40.0': + dependencies: + '@zag-js/types': 1.40.0 + + '@zag-js/drawer@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/aria-hidden': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dismissable': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/focus-trap': 1.40.0 + '@zag-js/remove-scroll': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/editable@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/interact-outside': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/file-upload@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/file-utils': 1.40.0 + '@zag-js/i18n-utils': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/file-utils@1.40.0': + dependencies: + '@zag-js/i18n-utils': 1.40.0 + + '@zag-js/floating-panel@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/popper': 1.40.0 + '@zag-js/rect-utils': 1.40.0 + '@zag-js/store': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/focus-trap@1.40.0': + dependencies: + '@zag-js/dom-query': 1.40.0 + + '@zag-js/focus-visible@1.40.0': + dependencies: + '@zag-js/dom-query': 1.40.0 + + '@zag-js/highlight-word@1.40.0': {} + + '@zag-js/hover-card@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dismissable': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/popper': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/i18n-utils@1.40.0': + dependencies: + '@zag-js/dom-query': 1.40.0 + + '@zag-js/image-cropper@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/interact-outside@1.40.0': + dependencies: + '@zag-js/dom-query': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/json-tree-utils@1.40.0': {} + + '@zag-js/listbox@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/collection': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/focus-visible': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/live-region@1.40.0': {} + + '@zag-js/marquee@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/menu@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dismissable': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/focus-visible': 1.40.0 + '@zag-js/popper': 1.40.0 + '@zag-js/rect-utils': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/navigation-menu@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dismissable': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/number-input@1.40.0': + dependencies: + '@internationalized/number': 3.6.5 + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/pagination@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/password-input@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/pin-input@1.40.0': dependencies: '@zag-js/anatomy': 1.40.0 '@zag-js/core': 1.40.0 @@ -14523,80 +15306,171 @@ snapshots: '@zag-js/rect-utils@1.40.0': {} - '@webassemblyjs/floating-point-hex-parser@1.13.2': {} - - '@webassemblyjs/helper-api-error@1.13.2': {} - - '@webassemblyjs/helper-buffer@1.14.1': {} - - '@webassemblyjs/helper-numbers@1.13.2': + '@zag-js/remove-scroll@1.40.0': dependencies: - '@webassemblyjs/floating-point-hex-parser': 1.13.2 - '@webassemblyjs/helper-api-error': 1.13.2 - '@xtuc/long': 4.2.2 + '@zag-js/dom-query': 1.40.0 - '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} - - '@webassemblyjs/helper-wasm-section@1.14.1': + '@zag-js/scroll-area@1.40.0': dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/wasm-gen': 1.14.1 + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 - '@webassemblyjs/ieee754@1.13.2': + '@zag-js/scroll-snap@1.40.0': dependencies: - '@xtuc/ieee754': 1.2.0 + '@zag-js/dom-query': 1.40.0 - '@webassemblyjs/leb128@1.13.2': + '@zag-js/select@1.40.0': dependencies: - '@xtuc/long': 4.2.2 + '@zag-js/anatomy': 1.40.0 + '@zag-js/collection': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dismissable': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/focus-visible': 1.40.0 + '@zag-js/popper': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 - '@webassemblyjs/utf8@1.13.2': {} - - '@webassemblyjs/wasm-edit@1.14.1': + '@zag-js/signature-pad@1.40.0': dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/helper-wasm-section': 1.14.1 - '@webassemblyjs/wasm-gen': 1.14.1 - '@webassemblyjs/wasm-opt': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - '@webassemblyjs/wast-printer': 1.14.1 + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + perfect-freehand: 1.2.3 - '@webassemblyjs/wasm-gen@1.14.1': + '@zag-js/slider@1.40.0': dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/ieee754': 1.13.2 - '@webassemblyjs/leb128': 1.13.2 - '@webassemblyjs/utf8': 1.13.2 + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 - '@webassemblyjs/wasm-opt@1.14.1': + '@zag-js/splitter@1.40.0': dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/wasm-gen': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 - '@webassemblyjs/wasm-parser@1.14.1': + '@zag-js/steps@1.40.0': dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-api-error': 1.13.2 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/ieee754': 1.13.2 - '@webassemblyjs/leb128': 1.13.2 - '@webassemblyjs/utf8': 1.13.2 + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 - '@webassemblyjs/wast-printer@1.14.1': + '@zag-js/store@1.40.0': dependencies: - '@webassemblyjs/ast': 1.14.1 - '@xtuc/long': 4.2.2 + proxy-compare: 3.0.1 - '@xtuc/ieee754@1.2.0': {} + '@zag-js/switch@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/focus-visible': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 - '@xtuc/long@4.2.2': {} + '@zag-js/tabs@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/tags-input@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/auto-resize': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/interact-outside': 1.40.0 + '@zag-js/live-region': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/timer@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/toast@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dismissable': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/toggle-group@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/toggle@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/tooltip@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/focus-visible': 1.40.0 + '@zag-js/popper': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/tour@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dismissable': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/focus-trap': 1.40.0 + '@zag-js/interact-outside': 1.40.0 + '@zag-js/popper': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/tree-view@1.40.0': + dependencies: + '@zag-js/anatomy': 1.40.0 + '@zag-js/collection': 1.40.0 + '@zag-js/core': 1.40.0 + '@zag-js/dom-query': 1.40.0 + '@zag-js/types': 1.40.0 + '@zag-js/utils': 1.40.0 + + '@zag-js/types@1.40.0': + dependencies: + csstype: 3.2.3 + + '@zag-js/utils@1.40.0': {} + + '@zxing/text-encoding@0.9.0': + optional: true JSONStream@1.3.5: dependencies: @@ -14605,11 +15479,26 @@ snapshots: abbrev@1.1.1: {} + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + + abs-svg-path@0.1.1: {} + + accepts@1.3.8: + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + accepts@2.0.0: dependencies: mime-types: 3.0.2 negotiator: 1.0.0 + acorn-dynamic-import@2.0.2: + dependencies: + acorn: 4.0.13 + acorn-import-phases@1.0.4(acorn@8.16.0): dependencies: acorn: 8.16.0 @@ -14622,8 +15511,14 @@ snapshots: dependencies: acorn: 8.16.0 + acorn@4.0.13: {} + + acorn@5.7.4: {} + acorn@8.16.0: {} + adler-32@1.3.1: {} + agent-base@6.0.2: dependencies: debug: 4.4.3(supports-color@5.5.0) @@ -14670,8 +15565,96 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + align-text@0.1.4: + dependencies: + kind-of: 3.2.2 + longest: 1.0.1 + repeat-string: 1.6.1 + + ansi-bgblack@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-bgblue@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-bgcyan@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-bggreen@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-bgmagenta@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-bgred@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-bgwhite@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-bgyellow@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-black@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-blue@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-bold@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-colors@0.2.0: + dependencies: + ansi-bgblack: 0.1.1 + ansi-bgblue: 0.1.1 + ansi-bgcyan: 0.1.1 + ansi-bggreen: 0.1.1 + ansi-bgmagenta: 0.1.1 + ansi-bgred: 0.1.1 + ansi-bgwhite: 0.1.1 + ansi-bgyellow: 0.1.1 + ansi-black: 0.1.1 + ansi-blue: 0.1.1 + ansi-bold: 0.1.1 + ansi-cyan: 0.1.1 + ansi-dim: 0.1.1 + ansi-gray: 0.1.1 + ansi-green: 0.1.1 + ansi-grey: 0.1.1 + ansi-hidden: 0.1.1 + ansi-inverse: 0.1.1 + ansi-italic: 0.1.1 + ansi-magenta: 0.1.1 + ansi-red: 0.1.1 + ansi-reset: 0.1.1 + ansi-strikethrough: 0.1.1 + ansi-underline: 0.1.1 + ansi-white: 0.1.1 + ansi-yellow: 0.1.1 + lazy-cache: 2.0.2 + ansi-colors@4.1.3: {} + ansi-cyan@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-dim@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 @@ -14680,10 +15663,56 @@ snapshots: dependencies: environment: 1.1.0 + ansi-gray@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-green@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-grey@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-hidden@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-html@0.0.7: {} + + ansi-inverse@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-italic@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-magenta@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-red@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-regex@2.1.1: {} + + ansi-regex@3.0.1: {} + ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} + ansi-reset@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-strikethrough@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 @@ -14692,12 +15721,41 @@ snapshots: ansi-styles@6.2.3: {} + ansi-underline@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-white@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + + ansi-wrap@0.1.0: {} + + ansi-yellow@0.1.1: + dependencies: + ansi-wrap: 0.1.0 + ansis@4.2.0: {} ansis@4.3.0: {} any-promise@1.3.0: {} + anymatch@2.0.0(supports-color@4.5.0): + dependencies: + micromatch: 3.1.10(supports-color@4.5.0) + normalize-path: 2.1.1 + transitivePeerDependencies: + - supports-color + optional: true + + anymatch@2.0.0(supports-color@5.5.0): + dependencies: + micromatch: 3.1.10(supports-color@5.5.0) + normalize-path: 2.1.1 + transitivePeerDependencies: + - supports-color + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 @@ -14709,6 +15767,42 @@ snapshots: aproba@2.1.0: {} + archiver-utils@2.1.0: + dependencies: + glob: 7.2.3 + graceful-fs: 4.2.11 + lazystream: 1.0.1 + lodash.defaults: 4.2.0 + lodash.difference: 4.5.0 + lodash.flatten: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.union: 4.6.0 + normalize-path: 3.0.0 + readable-stream: 2.3.8 + + archiver-utils@3.0.4: + dependencies: + glob: 7.2.3 + graceful-fs: 4.2.11 + lazystream: 1.0.1 + lodash.defaults: 4.2.0 + lodash.difference: 4.5.0 + lodash.flatten: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.union: 4.6.0 + normalize-path: 3.0.0 + readable-stream: 3.6.2 + + archiver@5.3.2: + dependencies: + archiver-utils: 2.1.0 + async: 3.2.6 + buffer-crc32: 0.2.13 + readable-stream: 3.6.2 + readdir-glob: 1.1.3 + tar-stream: 2.2.0 + zip-stream: 4.1.1 + are-we-there-yet@2.0.0: dependencies: delegates: 1.0.0 @@ -14718,17 +15812,39 @@ snapshots: arg@5.0.2: {} + argon2@0.43.1: + dependencies: + '@phc/format': 1.0.0 + node-addon-api: 8.7.0 + node-gyp-build: 4.8.4 + argparse@1.0.10: dependencies: sprintf-js: 1.0.3 argparse@2.0.1: {} + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + + arr-diff@4.0.0: {} + + arr-flatten@1.1.0: {} + + arr-union@3.1.0: {} + array-buffer-byte-length@1.0.2: dependencies: call-bound: 1.0.4 is-array-buffer: 3.0.5 + array-find-index@1.0.2: {} + + array-flatten@1.1.1: {} + + array-flatten@2.1.2: {} + array-ify@1.0.0: {} array-includes@3.1.9: @@ -14742,15 +15858,29 @@ snapshots: is-string: 1.1.1 math-intrinsics: 1.1.0 + array-sort@0.1.4: + dependencies: + default-compare: 1.0.0 + get-value: 2.0.6 + kind-of: 5.1.0 + array-timsort@1.0.3: {} + array-union@1.0.2: + dependencies: + array-uniq: 1.0.3 + + array-uniq@1.0.3: {} + + array-unique@0.3.2: {} + array.prototype.findlast@1.2.5: dependencies: call-bind: 1.0.9 define-properties: 1.2.1 es-abstract: 1.24.2 es-errors: 1.3.0 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 es-shim-unscopables: 1.1.0 array.prototype.findlastindex@1.2.6: @@ -14797,35 +15927,73 @@ snapshots: asap@2.0.6: {} + asn1.js@4.10.1: + dependencies: + bn.js: 4.12.3 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + + asn1@0.2.6: + dependencies: + safer-buffer: 2.1.2 + + assert-plus@1.0.0: {} + + assert@1.5.1: + dependencies: + object.assign: 4.1.7 + util: 0.10.4 + assertion-error@2.0.1: {} + assign-symbols@1.0.0: {} + + async-each@1.0.6: {} + async-function@1.0.0: {} + async@2.6.4: + dependencies: + lodash: 4.18.1 + + async@3.2.6: {} + asynckit@0.4.0: {} - autoprefixer@10.5.0(postcss@8.5.14): + atob@2.1.2: {} + + attr-accept@2.2.5: {} + + autolinker@0.28.1: + dependencies: + gulp-header: 1.8.12 + + autoprefixer@10.5.0(postcss@8.5.15): dependencies: browserslist: 4.28.2 - caniuse-lite: 1.0.30001792 + caniuse-lite: 1.0.30001793 fraction.js: 5.3.4 picocolors: 1.1.1 - postcss: 8.5.14 + postcss: 8.5.15 postcss-value-parser: 4.2.0 available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.1.0 - aws-ssl-profiles@1.1.2: - optional: true + aws-sign2@0.7.0: {} - axios@1.16.0: + aws4@1.13.2: {} + + axios@1.16.1: dependencies: follow-redirects: 1.16.0(debug@3.2.7(supports-color@5.5.0)) form-data: 4.0.5 + https-proxy-agent: 5.0.1 proxy-from-env: 2.1.0 transitivePeerDependencies: - debug + - supports-color babel-jest@29.7.0(@babel/core@7.29.0): dependencies: @@ -14862,7 +16030,6 @@ snapshots: '@babel/runtime': 7.29.2 cosmiconfig: 7.1.0 resolve: 1.22.12 - optional: true babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.0): dependencies: @@ -14893,9 +16060,29 @@ snapshots: balanced-match@4.0.4: {} + base64-arraybuffer@1.0.2: {} + + base64-js@0.0.8: {} + base64-js@1.5.1: {} - baseline-browser-mapping@2.10.29: {} + base@0.11.2: + dependencies: + cache-base: 1.0.1 + class-utils: 0.3.6 + component-emitter: 1.3.1 + define-property: 1.0.0 + isobject: 3.0.1 + mixin-deep: 1.3.2 + pascalcase: 0.1.1 + + baseline-browser-mapping@2.10.31: {} + + batch@0.6.1: {} + + bcrypt-pbkdf@1.0.2: + dependencies: + tweetnacl: 0.14.5 bcrypt@5.1.1: dependencies: @@ -14905,14 +16092,63 @@ snapshots: - encoding - supports-color + bidi-js@1.0.3: + dependencies: + require-from-string: 2.0.2 + + big-integer@1.6.52: {} + + big.js@5.2.2: {} + + binary-extensions@1.13.1: {} + binary-extensions@2.3.0: {} + binary@0.3.0: + dependencies: + buffers: 0.1.1 + chainsaw: 0.1.0 + + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + optional: true + bl@4.1.0: dependencies: buffer: 5.7.1 inherits: 2.0.4 readable-stream: 3.6.2 + block-stream2@2.1.0: + dependencies: + readable-stream: 3.6.2 + + bluebird@3.4.7: {} + + bmp-js@0.1.0: {} + + bn.js@4.12.3: {} + + bn.js@5.2.3: {} + + body-parser@1.20.5(supports-color@5.5.0): + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9(supports-color@5.5.0) + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.1 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.15.2 + raw-body: 2.5.3 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + body-parser@2.2.2: dependencies: bytes: 3.1.2 @@ -14921,12 +16157,23 @@ snapshots: http-errors: 2.0.1 iconv-lite: 0.7.2 on-finished: 2.4.1 - qs: 6.15.1 + qs: 6.15.2 raw-body: 3.0.2 - type-is: 2.0.1 + type-is: 2.1.0 transitivePeerDependencies: - supports-color + bonjour@3.5.1: + dependencies: + array-flatten: 2.1.2 + deep-equal: 1.1.2 + dns-equal: 1.0.0 + dns-txt: 2.0.2 + multicast-dns: 7.2.5 + multicast-dns-service-types: 1.1.0 + + boolbase@1.0.0: {} + brace-expansion@1.1.14: dependencies: balanced-match: 1.0.2 @@ -14948,7 +16195,7 @@ snapshots: fill-range: 4.0.0 isobject: 3.0.1 repeat-element: 1.1.4 - snapdragon: 0.8.2(supports-color@5.5.0) + snapdragon: 0.8.2 snapdragon-node: 2.1.1 split-string: 3.1.0 to-regex: 3.0.2 @@ -14990,12 +16237,64 @@ snapshots: dependencies: fill-range: 7.1.1 + brorand@1.1.0: {} + + brotli@1.3.3: + dependencies: + base64-js: 1.5.1 + + browser-or-node@2.1.1: {} + + browserify-aes@1.2.0: + dependencies: + buffer-xor: 1.0.3 + cipher-base: 1.0.7 + create-hash: 1.2.0 + evp_bytestokey: 1.0.3 + inherits: 2.0.4 + safe-buffer: 5.2.1 + + browserify-cipher@1.0.1: + dependencies: + browserify-aes: 1.2.0 + browserify-des: 1.0.2 + evp_bytestokey: 1.0.3 + + browserify-des@1.0.2: + dependencies: + cipher-base: 1.0.7 + des.js: 1.1.0 + inherits: 2.0.4 + safe-buffer: 5.2.1 + + browserify-rsa@4.1.1: + dependencies: + bn.js: 5.2.3 + randombytes: 2.1.0 + safe-buffer: 5.2.1 + + browserify-sign@4.2.5: + dependencies: + bn.js: 5.2.3 + browserify-rsa: 4.1.1 + create-hash: 1.2.0 + create-hmac: 1.1.7 + elliptic: 6.6.1 + inherits: 2.0.4 + parse-asn1: 5.1.9 + readable-stream: 2.3.8 + safe-buffer: 5.2.1 + + browserify-zlib@0.2.0: + dependencies: + pako: 1.0.11 + browserslist@4.28.2: dependencies: - baseline-browser-mapping: 2.10.29 - caniuse-lite: 1.0.30001792 - electron-to-chromium: 1.5.353 - node-releases: 2.0.44 + baseline-browser-mapping: 2.10.31 + caniuse-lite: 1.0.30001793 + electron-to-chromium: 1.5.360 + node-releases: 2.0.45 update-browserslist-db: 1.2.3(browserslist@4.28.2) bs-logger@0.2.6: @@ -15006,10 +16305,24 @@ snapshots: dependencies: node-int64: 0.4.0 + buffer-crc32@0.2.13: {} + buffer-equal-constant-time@1.0.1: {} buffer-from@1.1.2: {} + buffer-indexof-polyfill@1.0.2: {} + + buffer-indexof@1.1.1: {} + + buffer-xor@1.0.3: {} + + buffer@4.9.2: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + isarray: 1.0.0 + buffer@5.7.1: dependencies: base64-js: 1.5.1 @@ -15020,6 +16333,10 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 + buffers@0.1.1: {} + + builtin-status-codes@3.0.0: {} + busboy@1.6.0: dependencies: streamsearch: 1.1.0 @@ -15034,7 +16351,7 @@ snapshots: dotenv: 16.6.1 exsolve: 1.0.8 giget: 2.0.0 - jiti: 2.6.1 + jiti: 2.7.0 ohash: 2.0.11 pathe: 2.0.3 perfect-debounce: 1.0.0 @@ -15043,6 +16360,18 @@ snapshots: cac@6.7.14: {} + cache-base@1.0.1: + dependencies: + collection-visit: 1.0.0 + component-emitter: 1.3.1 + get-value: 2.0.6 + has-value: 1.0.0 + isobject: 3.0.1 + set-value: 2.0.1 + to-object-path: 0.3.0 + union-value: 1.0.1 + unset-value: 1.0.0 + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -15064,11 +16393,24 @@ snapshots: camelcase-css@2.0.1: {} + camelcase-keys@2.1.0: + dependencies: + camelcase: 2.1.1 + map-obj: 1.0.1 + + camelcase@1.2.1: {} + + camelcase@2.1.1: {} + + camelcase@3.0.0: {} + + camelcase@4.1.0: {} + camelcase@5.3.1: {} camelcase@6.3.0: {} - caniuse-lite@1.0.30001792: {} + caniuse-lite@1.0.30001793: {} canvg@3.0.11: dependencies: @@ -15102,6 +16444,10 @@ snapshots: loupe: 3.2.1 pathval: 2.0.1 + chainsaw@0.1.0: + dependencies: + traverse: 0.3.9 + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -15109,12 +16455,51 @@ snapshots: chalk@5.6.2: {} + change-case@5.4.4: {} + char-regex@1.0.2: {} chardet@2.1.1: {} check-error@2.1.3: {} + chokidar@2.1.8(supports-color@4.5.0): + dependencies: + anymatch: 2.0.0(supports-color@4.5.0) + async-each: 1.0.6 + braces: 2.3.2(supports-color@4.5.0) + glob-parent: 3.1.0 + inherits: 2.0.4 + is-binary-path: 1.0.1 + is-glob: 4.0.3 + normalize-path: 3.0.0 + path-is-absolute: 1.0.1 + readdirp: 2.2.1(supports-color@4.5.0) + upath: 1.2.0 + optionalDependencies: + fsevents: 1.2.13 + transitivePeerDependencies: + - supports-color + optional: true + + chokidar@2.1.8(supports-color@5.5.0): + dependencies: + anymatch: 2.0.0(supports-color@5.5.0) + async-each: 1.0.6 + braces: 2.3.2(supports-color@5.5.0) + glob-parent: 3.1.0 + inherits: 2.0.4 + is-binary-path: 1.0.1 + is-glob: 4.0.3 + normalize-path: 3.0.0 + path-is-absolute: 1.0.1 + readdirp: 2.2.1(supports-color@5.5.0) + upath: 1.2.0 + optionalDependencies: + fsevents: 1.2.13 + transitivePeerDependencies: + - supports-color + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -15137,6 +16522,12 @@ snapshots: ci-info@3.9.0: {} + cipher-base@1.0.7: + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + to-buffer: 1.2.2 + citty@0.1.6: dependencies: consola: 3.4.2 @@ -15147,12 +16538,23 @@ snapshots: class-transformer@0.5.1: {} + class-utils@0.3.6: + dependencies: + arr-union: 3.1.0 + define-property: 0.2.5 + isobject: 3.0.1 + static-extend: 0.1.2 + class-validator@0.14.4: dependencies: '@types/validator': 13.15.10 - libphonenumber-js: 1.13.1 + libphonenumber-js: 1.13.3 validator: 13.15.35 + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 @@ -15176,6 +16578,18 @@ snapshots: cli-width@4.1.0: {} + cliui@2.1.0: + dependencies: + center-align: 0.1.3 + right-align: 0.1.3 + wordwrap: 0.0.2 + + cliui@3.2.0: + dependencies: + string-width: 1.0.2 + strip-ansi: 3.0.1 + wrap-ansi: 2.1.0 + cliui@6.0.0: dependencies: string-width: 4.2.3 @@ -15188,16 +16602,24 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + cliui@9.0.1: + dependencies: + string-width: 7.2.0 + strip-ansi: 7.2.0 + wrap-ansi: 9.0.2 + clone@1.0.4: {} + clone@2.1.2: {} + clsx@2.1.1: {} - cmdk@1.1.1(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + cmdk@1.1.1(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@18.3.28)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.29)(react@19.2.6) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: @@ -15206,14 +16628,29 @@ snapshots: co@4.6.0: {} + code-point-at@1.1.0: {} + + codepage@1.15.0: {} + collect-v8-coverage@1.0.3: {} + collection-visit@1.0.0: + dependencies: + map-visit: 1.0.0 + object-visit: 1.0.1 + color-convert@2.0.1: dependencies: color-name: 1.1.4 color-name@1.1.4: {} + color-name@2.1.0: {} + + color-string@2.1.4: + dependencies: + color-name: 2.1.0 + color-support@1.1.3: {} colorette@2.0.20: {} @@ -15240,6 +16677,29 @@ snapshots: component-emitter@1.3.1: {} + compress-commons@4.1.2: + dependencies: + buffer-crc32: 0.2.13 + crc32-stream: 4.0.3 + normalize-path: 3.0.0 + readable-stream: 3.6.2 + + compressible@2.0.18: + dependencies: + mime-db: 1.54.0 + + compression@1.8.1(supports-color@5.5.0): + dependencies: + bytes: 3.1.2 + compressible: 2.0.18 + debug: 2.6.9(supports-color@5.5.0) + negotiator: 0.6.4 + on-headers: 1.1.0 + safe-buffer: 5.2.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + concat-map@0.0.1: {} concat-stream@2.0.0: @@ -15249,16 +16709,32 @@ snapshots: readable-stream: 3.6.2 typedarray: 0.0.6 + concat-with-sourcemaps@1.1.0: + dependencies: + source-map: 0.6.1 + confbox@0.2.4: {} + connect-history-api-fallback@1.6.0: {} + consola@3.4.2: {} + console-browserify@1.2.0: {} + console-control-strings@1.1.0: {} + constants-browserify@1.0.0: {} + + content-disposition@0.5.4: + dependencies: + safe-buffer: 5.2.1 + content-disposition@1.1.0: {} content-type@1.0.5: {} + content-type@2.0.0: {} + conventional-changelog-angular@7.0.0: dependencies: compare-func: 2.0.0 @@ -15274,14 +16750,29 @@ snapshots: meow: 12.1.1 split2: 4.2.0 + convert-source-map@1.9.0: {} + convert-source-map@2.0.0: {} + cookie-signature@1.0.7: {} + cookie-signature@1.2.2: {} cookie@0.7.2: {} + cookie@1.1.1: {} + cookiejar@2.1.4: {} + copy-descriptor@0.1.1: {} + + core-js@3.49.0: + optional: true + + core-util-is@1.0.2: {} + + core-util-is@1.0.3: {} + cors@2.8.6: dependencies: object-assign: 4.1.1 @@ -15301,7 +16792,6 @@ snapshots: parse-json: 5.2.0 path-type: 4.0.0 yaml: 1.10.3 - optional: true cosmiconfig@8.3.6(typescript@5.9.3): dependencies: @@ -15321,6 +16811,42 @@ snapshots: optionalDependencies: typescript: 5.9.3 + crc-32@1.2.2: {} + + crc32-stream@4.0.3: + dependencies: + crc-32: 1.2.2 + readable-stream: 3.6.2 + + create-ecdh@4.0.4: + dependencies: + bn.js: 4.12.3 + elliptic: 6.6.1 + + create-frame@1.0.0: + dependencies: + define-property: 0.2.5 + extend-shallow: 2.0.1 + isobject: 3.0.1 + lazy-cache: 2.0.2 + + create-hash@1.2.0: + dependencies: + cipher-base: 1.0.7 + inherits: 2.0.4 + md5.js: 1.3.5 + ripemd160: 2.0.3 + sha.js: 2.4.12 + + create-hmac@1.1.7: + dependencies: + cipher-base: 1.0.7 + create-hash: 1.2.0 + inherits: 2.0.4 + ripemd160: 2.0.3 + safe-buffer: 5.2.1 + sha.js: 2.4.12 + create-jest@29.7.0(@types/node@20.19.41)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)): dependencies: '@jest/types': 29.6.3 @@ -15343,12 +16869,52 @@ snapshots: '@types/luxon': 3.7.1 luxon: 3.7.2 + cross-spawn@5.1.0: + dependencies: + lru-cache: 4.1.5 + shebang-command: 1.2.0 + which: 1.3.1 + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 + crypto-browserify@3.12.1: + dependencies: + browserify-cipher: 1.0.1 + browserify-sign: 4.2.5 + create-ecdh: 4.0.4 + create-hash: 1.2.0 + create-hmac: 1.1.7 + diffie-hellman: 5.0.3 + hash-base: 3.0.5 + inherits: 2.0.4 + pbkdf2: 3.1.5 + public-encrypt: 4.0.3 + randombytes: 2.1.0 + randomfill: 1.0.4 + + css-line-break@2.1.0: + dependencies: + utrie: 1.0.2 + + css-select@5.2.2: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-tree@1.1.3: + dependencies: + mdn-data: 2.0.14 + source-map: 0.6.1 + + css-what@6.2.2: {} + cssesc@3.0.0: {} cssstyle@4.6.0: @@ -15358,8 +16924,59 @@ snapshots: csstype@3.2.3: {} + currently-unhandled@0.4.1: + dependencies: + array-find-index: 1.0.2 + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-color@3.1.0: {} + + d3-ease@3.0.1: {} + + d3-format@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@3.1.0: {} + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.2 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + d@1.0.2: + dependencies: + es5-ext: 0.10.64 + type: 2.7.3 + dargs@8.1.0: {} + dashdash@1.14.1: + dependencies: + assert-plus: 1.0.0 + data-urls@5.0.0: dependencies: whatwg-mimetype: 4.0.0 @@ -15385,7 +17002,7 @@ snapshots: date-fns-jalali@4.1.0-0: {} - date-fns@4.1.0: {} + date-fns@4.2.1: {} date.js@0.3.3: dependencies: @@ -15410,13 +17027,13 @@ snapshots: debug@3.1.0: dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 + ms: 2.0.0 debug@3.2.7(supports-color@5.5.0): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 5.5.0 debug@4.4.3(supports-color@5.5.0): dependencies: @@ -15426,6 +17043,8 @@ snapshots: decamelize@1.2.0: {} + decimal.js-light@2.5.1: {} + decimal.js@10.6.0: {} decode-uri-component@0.2.2: {} @@ -15434,14 +17053,29 @@ snapshots: optionalDependencies: babel-plugin-macros: 3.1.0 + deep-diff@1.0.2: {} + deep-eql@5.0.2: {} + deep-equal@1.1.2: + dependencies: + is-arguments: 1.2.0 + is-date-object: 1.1.0 + is-regex: 1.2.1 + object-is: 1.1.6 + object-keys: 1.1.1 + regexp.prototype.flags: 1.5.4 + deep-is@0.1.4: {} deepmerge-ts@7.1.5: {} deepmerge@4.3.1: {} + default-compare@1.0.0: + dependencies: + kind-of: 5.1.0 + defaults@1.0.4: dependencies: clone: 1.0.4 @@ -15458,38 +17092,90 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + define-property@0.2.5: + dependencies: + is-descriptor: 0.1.8 + + define-property@1.0.0: + dependencies: + is-descriptor: 1.0.4 + + define-property@2.0.2: + dependencies: + is-descriptor: 1.0.4 + isobject: 3.0.1 + defu@6.1.7: {} + del@3.0.0: + dependencies: + globby: 6.1.0 + is-path-cwd: 1.0.0 + is-path-in-cwd: 1.0.1 + p-map: 1.2.0 + pify: 3.0.0 + rimraf: 2.7.1 + delayed-stream@1.0.0: {} delegates@1.0.0: {} - denque@2.1.0: - optional: true + depd@1.1.2: {} depd@2.0.0: {} + dequal@2.0.3: {} + + des.js@1.1.0: + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + destr@2.0.5: {} + destroy@1.2.0: {} + detect-libc@2.1.2: {} detect-newline@3.1.0: {} + detect-node-es@1.1.0: {} + + detect-node@2.1.0: {} + dezalgo@1.0.4: dependencies: asap: 2.0.6 wrappy: 1.0.2 + dfa@1.2.0: {} + didyoumean@1.2.2: {} diff-sequences@29.6.3: {} diff@4.0.4: {} + diffie-hellman@5.0.3: + dependencies: + bn.js: 4.12.3 + miller-rabin: 4.0.1 + randombytes: 2.1.0 + dijkstrajs@1.0.3: {} dlv@1.1.3: {} + dns-equal@1.0.0: {} + + dns-packet@5.6.1: + dependencies: + '@leichtgewicht/ip-codec': 2.0.5 + + dns-txt@2.0.2: + dependencies: + buffer-indexof: 1.1.1 + doctrine@2.1.0: dependencies: esutils: 2.0.3 @@ -15519,7 +17205,7 @@ snapshots: dommatrix@1.0.3: {} - dompurify@3.4.2: + dompurify@3.4.5: optionalDependencies: '@types/trusted-types': 2.0.7 optional: true @@ -15548,8 +17234,23 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 + duplexer2@0.1.4: + dependencies: + readable-stream: 2.3.8 + eastasianwidth@0.2.0: {} + ebec@1.1.1: + dependencies: + smob: 1.6.2 + + ebec@2.3.0: {} + + ecc-jsbn@0.1.2: + dependencies: + jsbn: 0.1.1 + safer-buffer: 2.1.2 + ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer: 5.2.1 @@ -15561,35 +17262,93 @@ snapshots: '@standard-schema/spec': 1.1.0 fast-check: 3.23.2 - electron-to-chromium@1.5.353: {} + electron-to-chromium@1.5.360: {} + + elliptic@6.6.1: + dependencies: + bn.js: 4.12.3 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 emittery@0.13.1: {} + emoji-regex-xs@1.0.0: {} + emoji-regex@10.6.0: {} emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} + emojis-list@3.0.0: {} + empathic@2.0.0: {} encodeurl@2.0.0: {} - enhanced-resolve@5.21.3: + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + engine.io-client@6.6.5: + dependencies: + '@socket.io/component-emitter': 3.1.2 + debug: 4.4.3(supports-color@5.5.0) + engine.io-parser: 5.2.3 + ws: 8.20.1 + xmlhttprequest-ssl: 2.1.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + engine.io-parser@5.2.3: {} + + enhanced-resolve@3.4.1: + dependencies: + graceful-fs: 4.2.11 + memory-fs: 0.4.1 + object-assign: 4.1.1 + tapable: 0.2.9 + + enhanced-resolve@5.21.6: dependencies: graceful-fs: 4.2.11 tapable: 2.3.3 + ent@2.2.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + punycode: 1.4.1 + safe-regex-test: 1.1.0 + + entities@4.5.0: {} + entities@6.0.1: {} env-paths@2.2.1: {} environment@1.1.0: {} + envix@1.5.0: + dependencies: + std-env: 3.10.0 + + errno@0.1.8: + dependencies: + prr: 1.0.1 + error-ex@1.3.4: dependencies: is-arrayish: 0.2.1 + error-symbol@0.1.0: {} + es-abstract@1.24.2: dependencies: array-buffer-byte-length: 1.0.2 @@ -15678,6 +17437,10 @@ snapshots: dependencies: es-errors: 1.3.0 + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + es-set-tostringtag@2.1.0: dependencies: es-errors: 1.3.0 @@ -15695,6 +17458,51 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 + es-toolkit@1.46.1: {} + + es5-ext@0.10.64: + dependencies: + es6-iterator: 2.0.3 + es6-symbol: 3.1.4 + esniff: 2.0.1 + next-tick: 1.1.0 + + es6-iterator@2.0.3: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-symbol: 3.1.4 + + es6-map@0.1.5: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-iterator: 2.0.3 + es6-set: 0.1.6 + es6-symbol: 3.1.4 + event-emitter: 0.3.5 + + es6-set@0.1.6: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-iterator: 2.0.3 + es6-symbol: 3.1.4 + event-emitter: 0.3.5 + type: 2.7.3 + + es6-symbol@3.1.4: + dependencies: + d: 1.0.2 + ext: 1.7.0 + + es6-weak-map@2.0.3: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-iterator: 2.0.3 + es6-symbol: 3.1.4 + esbuild@0.21.5: optionalDependencies: '@esbuild/aix-ppc64': 0.21.5 @@ -15729,6 +17537,13 @@ snapshots: escape-string-regexp@4.0.0: {} + escope@3.6.0: + dependencies: + es6-map: 0.1.5 + es6-weak-map: 2.0.3 + esrecurse: 4.3.0 + estraverse: 4.3.0 + eslint-config-prettier@9.1.2(eslint@8.57.1): dependencies: eslint: 8.57.1 @@ -15737,21 +17552,21 @@ snapshots: dependencies: debug: 3.2.7(supports-color@5.5.0) is-core-module: 2.16.2 - resolve: 2.0.0-next.6 + resolve: 2.0.0-next.7 transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.59.3(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint@8.57.1): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.59.4(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint@8.57.1): dependencies: debug: 3.2.7(supports-color@5.5.0) optionalDependencies: - '@typescript-eslint/parser': 8.59.3(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/parser': 8.59.4(eslint@8.57.1)(typescript@5.9.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.10 transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.3(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.4(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -15762,7 +17577,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.10 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.59.3(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint@8.57.1) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.59.4(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint@8.57.1) hasown: 2.0.3 is-core-module: 2.16.2 is-glob: 4.0.3 @@ -15774,7 +17589,7 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.59.3(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/parser': 8.59.4(eslint@8.57.1)(typescript@5.9.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -15805,7 +17620,7 @@ snapshots: object.fromentries: 2.0.8 object.values: 1.2.1 prop-types: 15.8.1 - resolve: 2.0.0-next.6 + resolve: 2.0.0-next.7 semver: 6.3.1 string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 @@ -15867,6 +17682,13 @@ snapshots: transitivePeerDependencies: - supports-color + esniff@2.0.1: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + event-emitter: 0.3.5 + type: 2.7.3 + espree@9.6.1: dependencies: acorn: 8.16.0 @@ -15895,12 +17717,58 @@ snapshots: etag@1.8.1: {} + ethiopian-calendar-date-converter@2.1.6: {} + + ethiopian-calendar-new@1.1.0: {} + + ethiopian-date@0.0.6: {} + + event-emitter@0.3.5: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + + event-target-shim@5.0.1: {} + eventemitter2@6.4.9: {} + eventemitter3@4.0.7: {} + eventemitter3@5.0.4: {} events@3.3.0: {} + eventsource@0.1.6: + dependencies: + original: 1.0.2 + + evp_bytestokey@1.0.3: + dependencies: + md5.js: 1.3.5 + safe-buffer: 5.2.1 + + exceljs@4.4.0: + dependencies: + archiver: 5.3.2 + dayjs: 1.11.20 + fast-csv: 4.3.6 + jszip: 3.10.1 + readable-stream: 3.6.2 + saxes: 5.0.1 + tmp: 0.2.5 + unzipper: 0.10.14 + uuid: 8.3.2 + + execa@0.7.0: + dependencies: + cross-spawn: 5.1.0 + get-stream: 3.0.0 + is-stream: 1.1.0 + npm-run-path: 2.0.2 + p-finally: 1.0.0 + signal-exit: 3.0.7 + strip-eof: 1.0.0 + execa@5.1.1: dependencies: cross-spawn: 7.0.6 @@ -15934,7 +17802,7 @@ snapshots: extend-shallow: 2.0.1 posix-character-classes: 0.1.1 regex-not: 1.0.2 - snapdragon: 0.8.2(supports-color@5.5.0) + snapdragon: 0.8.2 to-regex: 3.0.2 transitivePeerDependencies: - supports-color @@ -15974,6 +17842,42 @@ snapshots: jest-message-util: 29.7.0 jest-util: 29.7.0 + express@4.22.2(supports-color@5.5.0): + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.5(supports-color@5.5.0) + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.0.7 + debug: 2.6.9(supports-color@5.5.0) + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.3.2(supports-color@5.5.0) + fresh: 0.5.2 + http-errors: 2.0.1 + merge-descriptors: 1.0.3 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.13 + proxy-addr: 2.0.7 + qs: 6.15.2 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.19.2(supports-color@5.5.0) + serve-static: 1.16.3(supports-color@5.5.0) + setprototypeof: 1.2.0 + statuses: 2.0.2 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + express@5.2.1: dependencies: accepts: 2.0.0 @@ -15996,17 +17900,19 @@ snapshots: once: 1.4.0 parseurl: 1.3.3 proxy-addr: 2.0.7 - qs: 6.15.1 + qs: 6.15.2 range-parser: 1.2.1 router: 2.2.0 send: 1.2.1 serve-static: 2.2.1 statuses: 2.0.2 - type-is: 2.0.1 + type-is: 2.1.0 vary: 1.1.2 transitivePeerDependencies: - supports-color + exsolve@1.0.8: {} + ext@1.7.0: dependencies: type: 2.7.3 @@ -16030,7 +17936,7 @@ snapshots: extend-shallow: 2.0.1 fragment-cache: 0.2.1 regex-not: 1.0.2 - snapdragon: 0.8.2(supports-color@5.5.0) + snapdragon: 0.8.2 to-regex: 3.0.2 transitivePeerDependencies: - supports-color @@ -16072,8 +17978,15 @@ snapshots: dependencies: pure-rand: 6.1.0 + fast-csv@4.3.6: + dependencies: + '@fast-csv/format': 4.3.5 + '@fast-csv/parse': 4.3.6 + fast-deep-equal@3.1.3: {} + fast-equals@5.4.0: {} + fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -16086,14 +17999,37 @@ snapshots: fast-levenshtein@2.0.6: {} + fast-png@6.4.0: + dependencies: + '@types/pako': 2.0.4 + iobuffer: 5.4.0 + pako: 2.1.0 + fast-safe-stringify@2.1.1: {} fast-uri@3.1.2: {} + fast-xml-parser@4.5.6: + dependencies: + strnum: 1.1.2 + fastq@1.20.1: dependencies: reusify: 1.1.0 + faye-websocket@0.10.0: + dependencies: + websocket-driver: 0.7.4 + + faye-websocket@0.11.4: + dependencies: + websocket-driver: 0.7.4 + + faye@0.8.11: + dependencies: + cookiejar: 2.1.4 + faye-websocket: 0.11.4 + fb-watchman@2.0.2: dependencies: bser: 2.1.1 @@ -16102,10 +18038,22 @@ snapshots: optionalDependencies: picomatch: 4.0.4 + fflate@0.8.3: {} + file-entry-cache@6.0.1: dependencies: flat-cache: 3.2.0 + file-selector@2.1.2: + dependencies: + tslib: 2.8.1 + + file-type@18.7.0: + dependencies: + readable-web-to-node-stream: 3.0.4 + strtok3: 7.1.1 + token-types: 5.0.1 + file-type@21.3.4: dependencies: '@tokenizer/inflate': 0.4.1 @@ -16115,10 +18063,34 @@ snapshots: transitivePeerDependencies: - supports-color + file-uri-to-path@1.0.0: + optional: true + + fill-range@4.0.0: + dependencies: + extend-shallow: 2.0.1 + is-number: 3.0.0 + repeat-string: 1.6.1 + to-regex-range: 2.1.1 + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 + filter-obj@1.1.0: {} + + finalhandler@1.3.2(supports-color@5.5.0): + dependencies: + debug: 2.6.9(supports-color@5.5.0) + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + finalhandler@2.1.1: dependencies: debug: 4.4.3(supports-color@5.5.0) @@ -16130,6 +18102,17 @@ snapshots: transitivePeerDependencies: - supports-color + find-root@1.1.0: {} + + find-up@1.1.2: + dependencies: + path-exists: 2.1.0 + pinkie-promise: 2.0.1 + + find-up@2.1.0: + dependencies: + locate-path: 2.0.0 + find-up@4.1.0: dependencies: locate-path: 5.0.0 @@ -16152,6 +18135,8 @@ snapshots: keyv: 4.5.4 rimraf: 3.0.2 + flat@5.0.2: {} + flatted@3.4.2: {} follow-redirects@1.16.0(debug@3.2.7(supports-color@5.5.0)): @@ -16174,11 +18159,25 @@ snapshots: dependencies: is-callable: 1.2.7 + for-in@1.0.2: {} + + for-own@1.0.0: + dependencies: + for-in: 1.0.2 + + force@0.0.3: + dependencies: + faye: 0.8.11 + mime: 1.2.11 + request: 2.88.2 + foreground-child@3.3.1: dependencies: cross-spawn: 7.0.6 signal-exit: 4.1.0 + forever-agent@0.6.1: {} + fork-ts-checker-webpack-plugin@9.1.0(typescript@5.9.3)(webpack@5.106.0): dependencies: '@babel/code-frame': 7.29.0 @@ -16191,11 +18190,17 @@ snapshots: minimatch: 3.1.5 node-abort-controller: 3.1.1 schema-utils: 3.3.0 - semver: 7.8.0 + semver: 7.8.1 tapable: 2.3.3 typescript: 5.9.3 webpack: 5.106.0 + form-data@2.3.3: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + form-data@4.0.5: dependencies: asynckit: 0.4.0 @@ -16212,16 +18217,18 @@ snapshots: forwarded@0.2.0: {} + frac@1.1.2: {} + fraction.js@5.3.4: {} fragment-cache@0.2.1: dependencies: map-cache: 0.2.2 - framer-motion@12.38.0(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + framer-motion@12.40.0(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: - motion-dom: 12.38.0 - motion-utils: 12.36.0 + motion-dom: 12.40.0 + motion-utils: 12.39.0 tslib: 2.8.1 optionalDependencies: '@emotion/is-prop-valid': 1.4.0 @@ -16232,6 +18239,10 @@ snapshots: fresh@2.0.0: {} + fs-constants@1.0.0: {} + + fs-exists-sync@0.1.0: {} + fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 @@ -16246,9 +18257,22 @@ snapshots: fs.realpath@1.0.0: {} + fsevents@1.2.13: + dependencies: + bindings: 1.5.0 + nan: 2.27.0 + optional: true + fsevents@2.3.3: optional: true + fstream@1.0.12: + dependencies: + graceful-fs: 4.2.11 + inherits: 2.0.4 + mkdirp: 0.5.6 + rimraf: 2.7.1 + function-bind@1.1.2: {} function.prototype.name@1.1.8: @@ -16274,15 +18298,12 @@ snapshots: strip-ansi: 6.0.1 wide-align: 1.1.5 - generate-function@2.3.1: - dependencies: - is-property: 1.0.2 - optional: true - generator-function@2.0.1: {} gensync@1.0.0-beta.2: {} + get-caller-file@1.0.3: {} + get-caller-file@2.0.5: {} get-east-asian-width@1.6.0: {} @@ -16300,6 +18321,13 @@ snapshots: hasown: 2.0.3 math-intrinsics: 1.1.0 + get-nonce@1.0.1: {} + + get-object@0.2.0: + dependencies: + is-number: 2.1.0 + isobject: 0.2.0 + get-package-type@0.1.0: {} get-proto@1.0.1: @@ -16307,6 +18335,10 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 + get-stdin@4.0.1: {} + + get-stream@3.0.0: {} + get-stream@6.0.1: {} get-stream@8.0.1: {} @@ -16317,6 +18349,12 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 + get-value@2.0.6: {} + + getpass@0.1.7: + dependencies: + assert-plus: 1.0.0 + giget@2.0.0: dependencies: citty: 0.1.6 @@ -16332,6 +18370,11 @@ snapshots: meow: 12.1.1 split2: 4.2.0 + glob-parent@3.1.0: + dependencies: + is-glob: 3.1.0 + path-dirname: 1.0.2 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -16379,12 +18422,71 @@ snapshots: define-properties: 1.2.1 gopd: 1.2.0 + globby@6.1.0: + dependencies: + array-union: 1.0.2 + glob: 7.2.3 + object-assign: 4.1.1 + pify: 2.3.0 + pinkie-promise: 2.0.1 + gopd@1.2.0: {} graceful-fs@4.2.11: {} graphemer@1.4.0: {} + gulp-header@1.8.12: + dependencies: + concat-with-sourcemaps: 1.1.0 + lodash.template: 4.18.1 + through2: 2.0.5 + + handle-thing@2.0.1: {} + + handlebars-helper-create-frame@0.1.0: + dependencies: + create-frame: 1.0.0 + isobject: 3.0.1 + + handlebars-helpers@0.10.0: + dependencies: + arr-flatten: 1.1.0 + array-sort: 0.1.4 + create-frame: 1.0.0 + define-property: 1.0.0 + falsey: 0.3.2 + for-in: 1.0.2 + for-own: 1.0.0 + get-object: 0.2.0 + get-value: 2.0.6 + handlebars: 4.7.9 + handlebars-helper-create-frame: 0.1.0 + handlebars-utils: 1.0.6 + has-value: 1.0.0 + helper-date: 1.0.1 + helper-markdown: 1.0.0 + helper-md: 0.2.2 + html-tag: 2.0.0 + is-even: 1.0.0 + is-glob: 4.0.3 + is-number: 4.0.0 + kind-of: 6.0.3 + lazy-cache: 2.0.2 + logging-helpers: 1.0.0 + micromatch: 3.1.10 + relative: 3.0.2 + striptags: 3.2.0 + to-gfm-code-block: 0.1.1 + year: 0.2.1 + transitivePeerDependencies: + - supports-color + + handlebars-utils@1.0.6: + dependencies: + kind-of: 6.0.3 + typeof-article: 0.1.1 + handlebars@4.7.9: dependencies: minimist: 1.2.8 @@ -16394,8 +18496,19 @@ snapshots: optionalDependencies: uglify-js: 3.19.3 + har-schema@2.0.0: {} + + har-validator@5.1.5: + dependencies: + ajv: 6.15.0 + har-schema: 2.0.0 + has-bigints@1.1.0: {} + has-flag@2.0.0: {} + + has-flag@3.0.0: {} + has-flag@4.0.0: {} has-property-descriptors@1.0.2: @@ -16414,16 +18527,128 @@ snapshots: has-unicode@2.0.1: {} + has-value@0.3.1: + dependencies: + get-value: 2.0.6 + has-values: 0.1.4 + isobject: 2.1.0 + + has-value@1.0.0: + dependencies: + get-value: 2.0.6 + has-values: 1.0.0 + isobject: 3.0.1 + + has-values@0.1.4: {} + + has-values@1.0.0: + dependencies: + is-number: 3.0.0 + kind-of: 4.0.0 + + hash-base@3.0.5: + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + + hash-base@3.1.2: + dependencies: + inherits: 2.0.4 + readable-stream: 2.3.8 + safe-buffer: 5.2.1 + to-buffer: 1.2.2 + + hash.js@1.1.7: + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + hasown@2.0.3: dependencies: function-bind: 1.1.2 + he@1.2.0: {} + + helper-date@1.0.1: + dependencies: + date.js: 0.3.3 + handlebars-utils: 1.0.6 + moment: 2.30.1 + transitivePeerDependencies: + - supports-color + + helper-markdown@1.0.0: + dependencies: + handlebars-utils: 1.0.6 + highlight.js: 9.18.5 + remarkable: 1.7.4 + + helper-md@0.2.2: + dependencies: + ent: 2.2.2 + extend-shallow: 2.0.1 + fs-exists-sync: 0.1.0 + remarkable: 1.7.4 + + highlight.js@9.18.5: {} + + hmac-drbg@1.0.1: + dependencies: + hash.js: 1.1.7 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + + hoist-non-react-statics@3.3.2: + dependencies: + react-is: 16.13.1 + + hosted-git-info@2.8.9: {} + + hpack.js@2.1.6: + dependencies: + inherits: 2.0.4 + obuf: 1.1.2 + readable-stream: 2.3.8 + wbuf: 1.7.3 + + hsl-to-hex@1.0.0: + dependencies: + hsl-to-rgb-for-reals: 1.1.1 + + hsl-to-rgb-for-reals@1.1.1: {} + html-encoding-sniffer@4.0.0: dependencies: whatwg-encoding: 3.1.1 + html-entities@1.4.0: {} + html-escaper@2.0.2: {} + html-parse-stringify@3.0.1: + dependencies: + void-elements: 3.1.0 + + html-tag@2.0.0: + dependencies: + is-self-closing: 1.0.1 + kind-of: 6.0.3 + + html2canvas@1.4.1: + dependencies: + css-line-break: 2.1.0 + text-segmentation: 1.0.3 + + http-deceiver@1.2.7: {} + + http-errors@1.8.1: + dependencies: + depd: 1.1.2 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 1.5.0 + toidentifier: 1.0.1 + http-errors@2.0.1: dependencies: depd: 2.0.0 @@ -16432,6 +18657,8 @@ snapshots: statuses: 2.0.2 toidentifier: 1.0.1 + http-parser-js@0.5.10: {} + http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 @@ -16439,6 +18666,32 @@ snapshots: transitivePeerDependencies: - supports-color + http-proxy-middleware@0.19.2(debug@3.2.7(supports-color@5.5.0))(supports-color@5.5.0): + dependencies: + http-proxy: 1.18.1(debug@3.2.7(supports-color@5.5.0)) + is-glob: 4.0.3 + lodash: 4.18.1 + micromatch: 3.1.10(supports-color@5.5.0) + transitivePeerDependencies: + - debug + - supports-color + + http-proxy@1.18.1(debug@3.2.7(supports-color@5.5.0)): + dependencies: + eventemitter3: 4.0.7 + follow-redirects: 1.16.0(debug@3.2.7(supports-color@5.5.0)) + requires-port: 1.0.0 + transitivePeerDependencies: + - debug + + http-signature@1.2.0: + dependencies: + assert-plus: 1.0.0 + jsprim: 1.4.2 + sshpk: 1.18.0 + + https-browserify@1.0.0: {} + https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 @@ -16459,6 +18712,22 @@ snapshots: husky@9.1.7: {} + hyphen@1.14.1: {} + + i18next-browser-languagedetector@8.2.1: + dependencies: + '@babel/runtime': 7.29.2 + + i18next@25.10.10(typescript@5.9.3): + dependencies: + '@babel/runtime': 7.29.2 + optionalDependencies: + typescript: 5.9.3 + + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 @@ -16467,20 +18736,30 @@ snapshots: dependencies: safer-buffer: 2.1.2 + idb-keyval@6.2.4: {} + ieee754@1.2.1: {} ignore@5.3.2: {} ignore@7.0.5: {} - immer@11.1.8: - optional: true + immediate@3.0.6: {} + + immer@10.2.0: {} + + immer@11.1.8: {} import-fresh@3.3.1: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 + import-local@1.0.0: + dependencies: + pkg-dir: 2.0.0 + resolve-cwd: 2.0.0 + import-local@3.2.0: dependencies: pkg-dir: 4.2.0 @@ -16490,23 +18769,56 @@ snapshots: imurmurhash@0.1.4: {} + indent-string@2.1.0: + dependencies: + repeating: 2.0.1 + inflight@1.0.6: dependencies: once: 1.4.0 wrappy: 1.0.2 + info-symbol@0.1.0: {} + + inherits@2.0.3: {} + inherits@2.0.4: {} ini@4.1.1: {} + internal-ip@1.2.0: + dependencies: + meow: 3.7.0 + internal-slot@1.1.0: dependencies: es-errors: 1.3.0 hasown: 2.0.3 side-channel: 1.1.0 + internmap@2.0.3: {} + + interpret@1.4.0: {} + + invert-kv@1.0.0: {} + + iobuffer@5.4.0: {} + + ip@1.1.9: {} + ipaddr.js@1.9.1: {} + ipaddr.js@2.4.0: {} + + is-accessor-descriptor@1.0.2: + dependencies: + hasown: 2.0.3 + + is-arguments@1.2.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + is-array-buffer@3.0.5: dependencies: call-bind: 1.0.9 @@ -16527,6 +18839,10 @@ snapshots: dependencies: has-bigints: 1.1.0 + is-binary-path@1.0.1: + dependencies: + binary-extensions: 1.13.1 + is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 @@ -16536,12 +18852,18 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-buffer@1.1.6: {} + is-callable@1.2.7: {} is-core-module@2.16.2: dependencies: hasown: 2.0.3 + is-data-descriptor@1.0.1: + dependencies: + hasown: 2.0.3 + is-data-view@1.0.2: dependencies: call-bound: 1.0.4 @@ -16553,12 +18875,40 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-descriptor@0.1.8: + dependencies: + is-accessor-descriptor: 1.0.2 + is-data-descriptor: 1.0.1 + + is-descriptor@1.0.4: + dependencies: + is-accessor-descriptor: 1.0.2 + is-data-descriptor: 1.0.1 + + is-even@1.0.0: + dependencies: + is-odd: 0.1.2 + + is-extendable@0.1.1: {} + + is-extendable@1.0.1: + dependencies: + is-plain-object: 2.0.4 + is-extglob@2.1.1: {} is-finalizationregistry@1.1.1: dependencies: call-bound: 1.0.4 + is-finite@1.1.0: {} + + is-fullwidth-code-point@1.0.0: + dependencies: + number-is-nan: 1.0.1 + + is-fullwidth-code-point@2.0.0: {} + is-fullwidth-code-point@3.0.0: {} is-fullwidth-code-point@4.0.0: {} @@ -16577,12 +18927,20 @@ snapshots: has-tostringtag: 1.0.2 safe-regex-test: 1.1.0 + is-glob@3.1.0: + dependencies: + is-extglob: 2.1.1 + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 is-interactive@1.0.0: {} + is-lite@0.8.2: {} + + is-lite@1.2.1: {} + is-map@2.0.3: {} is-negative-zero@2.0.3: {} @@ -16592,19 +18950,44 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-number@2.1.0: + dependencies: + kind-of: 3.2.2 + + is-number@3.0.0: + dependencies: + kind-of: 3.2.2 + + is-number@4.0.0: {} + is-number@7.0.0: {} is-obj@2.0.0: {} + is-odd@0.1.2: + dependencies: + is-number: 3.0.0 + + is-path-cwd@1.0.0: {} + + is-path-in-cwd@1.0.1: + dependencies: + is-path-inside: 1.0.1 + + is-path-inside@1.0.1: + dependencies: + path-is-inside: 1.0.2 + is-path-inside@3.0.3: {} + is-plain-object@2.0.4: + dependencies: + isobject: 3.0.1 + is-potential-custom-element-name@1.0.1: {} is-promise@4.0.0: {} - is-property@1.0.2: - optional: true - is-regex@1.2.1: dependencies: call-bound: 1.0.4 @@ -16612,12 +18995,18 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.3 + is-self-closing@1.0.1: + dependencies: + self-closing-tags: 1.0.1 + is-set@2.0.3: {} is-shared-array-buffer@1.0.4: dependencies: call-bound: 1.0.4 + is-stream@1.1.0: {} + is-stream@2.0.1: {} is-stream@3.0.0: {} @@ -16641,8 +19030,14 @@ snapshots: dependencies: which-typed-array: 1.1.20 + is-typedarray@1.0.0: {} + is-unicode-supported@0.1.0: {} + is-url@1.2.4: {} + + is-utf8@0.2.1: {} + is-weakmap@2.0.2: {} is-weakref@1.1.1: @@ -16654,10 +19049,26 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 + is-windows@1.0.2: {} + + is-wsl@1.1.0: {} + + isarray@1.0.0: {} + isarray@2.0.5: {} isexe@2.0.0: {} + isobject@0.2.0: {} + + isobject@2.1.0: + dependencies: + isarray: 1.0.0 + + isobject@3.0.1: {} + + isstream@0.1.2: {} + istanbul-lib-coverage@3.2.2: {} istanbul-lib-instrument@5.2.1: @@ -16676,7 +19087,7 @@ snapshots: '@babel/parser': 7.29.3 '@istanbuljs/schema': 0.1.6 istanbul-lib-coverage: 3.2.2 - semver: 7.8.0 + semver: 7.8.1 transitivePeerDependencies: - supports-color @@ -16716,6 +19127,10 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + jay-peg@1.1.1: + dependencies: + restructure: 3.0.2 + jest-changed-files@29.7.0: dependencies: execa: 5.1.1 @@ -16973,7 +19388,7 @@ snapshots: jest-util: 29.7.0 natural-compare: 1.4.0 pretty-format: 29.7.0 - semver: 7.8.0 + semver: 7.8.1 transitivePeerDependencies: - supports-color @@ -17035,6 +19450,18 @@ snapshots: jiti@2.6.1: {} + jiti@2.7.0: {} + + jmespath@0.16.0: {} + + jose@5.10.0: {} + + jquery@3.7.1: {} + + js-cookie@3.0.7: {} + + js-md5@0.8.3: {} + js-tokens@4.0.0: {} js-yaml@3.14.2: @@ -17073,7 +19500,7 @@ snapshots: whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 whatwg-url: 14.2.0 - ws: 8.20.0 + ws: 8.20.1 xml-name-validator: 5.0.0 transitivePeerDependencies: - bufferutil @@ -17084,14 +19511,26 @@ snapshots: json-buffer@3.0.1: {} + json-loader@0.5.7: {} + json-parse-even-better-errors@2.3.1: {} json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} + json-schema@0.4.0: {} + json-stable-stringify-without-jsonify@1.0.1: {} + json-stream@1.0.0: {} + + json-stringify-safe@5.0.1: {} + + json3@3.3.3: {} + + json5@0.5.1: {} + json5@1.0.2: dependencies: minimist: 1.2.8 @@ -17119,7 +19558,7 @@ snapshots: lodash.isstring: 4.0.1 lodash.once: 4.1.1 ms: 2.1.3 - semver: 7.8.0 + semver: 7.8.1 jsonwebtoken@9.0.3: dependencies: @@ -17132,7 +19571,25 @@ snapshots: lodash.isstring: 4.0.1 lodash.once: 4.1.1 ms: 2.1.3 - semver: 7.8.0 + semver: 7.8.1 + + jspdf@3.0.4: + dependencies: + '@babel/runtime': 7.29.2 + fast-png: 6.4.0 + fflate: 0.8.3 + optionalDependencies: + canvg: 3.0.11 + core-js: 3.49.0 + dompurify: 3.4.5 + html2canvas: 1.4.1 + + jsprim@1.4.2: + dependencies: + assert-plus: 1.0.0 + extsprintf: 1.3.0 + json-schema: 0.4.0 + verror: 1.10.0 jsx-ast-utils@3.3.5: dependencies: @@ -17141,6 +19598,13 @@ snapshots: object.assign: 4.1.7 object.values: 1.2.1 + jszip@3.10.1: + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + jwa@1.4.2: dependencies: buffer-equal-constant-time: 1.0.1 @@ -17167,8 +19631,36 @@ snapshots: dependencies: json-buffer: 3.0.1 + killable@1.0.1: {} + + kind-of@3.2.2: + dependencies: + is-buffer: 1.1.6 + + kind-of@4.0.0: + dependencies: + is-buffer: 1.1.6 + + kind-of@5.1.0: {} + + kind-of@6.0.3: {} + kleur@3.0.3: {} + lazy-cache@1.0.4: {} + + lazy-cache@2.0.2: + dependencies: + set-getter: 0.1.1 + + lazystream@1.0.1: + dependencies: + readable-stream: 2.3.8 + + lcid@1.0.0: + dependencies: + invert-kv: 1.0.0 + leven@3.1.0: {} levn@0.4.1: @@ -17176,7 +19668,18 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - libphonenumber-js@1.13.1: {} + libphonenumber-js@1.13.2: {} + + libphonenumber-js@1.13.3: {} + + libreoffice-convert@1.8.1: + dependencies: + async: 3.2.6 + tmp: 0.2.5 + + lie@3.3.0: + dependencies: + immediate: 3.0.6 lightningcss-android-arm64@1.32.0: optional: true @@ -17226,12 +19729,18 @@ snapshots: lightningcss-linux-x64-musl: 1.32.0 lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 - optional: true lilconfig@3.1.3: {} + linebreak@1.1.0: + dependencies: + base64-js: 0.0.8 + unicode-trie: 2.0.0 + lines-and-columns@1.2.4: {} + linkifyjs@4.3.3: {} + lint-staged@15.5.2: dependencies: chalk: 5.6.2 @@ -17247,6 +19756,8 @@ snapshots: transitivePeerDependencies: - supports-color + listenercount@1.0.1: {} + listr2@8.3.3: dependencies: cli-truncate: 4.0.0 @@ -17258,8 +19769,38 @@ snapshots: load-esm@1.0.3: {} + load-json-file@1.1.0: + dependencies: + graceful-fs: 4.2.11 + parse-json: 2.2.0 + pify: 2.3.0 + pinkie-promise: 2.0.1 + strip-bom: 2.0.0 + + load-json-file@2.0.0: + dependencies: + graceful-fs: 4.2.11 + parse-json: 2.2.0 + pify: 2.3.0 + strip-bom: 3.0.0 + + loadash@1.0.0: {} + + loader-runner@2.4.0: {} + loader-runner@4.3.2: {} + loader-utils@1.4.2: + dependencies: + big.js: 5.2.2 + emojis-list: 3.0.0 + json5: 1.0.2 + + locate-path@2.0.0: + dependencies: + p-locate: 2.0.0 + path-exists: 3.0.0 + locate-path@5.0.0: dependencies: p-locate: 4.1.0 @@ -17272,20 +19813,49 @@ snapshots: dependencies: p-locate: 6.0.0 + locter@2.2.1: + dependencies: + destr: 2.0.5 + ebec: 2.3.0 + fast-glob: 3.3.3 + flat: 5.0.2 + jiti: 2.7.0 + yaml: 2.9.0 + + lodash._reinterpolate@3.0.0: {} + lodash.camelcase@4.3.0: {} + lodash.defaults@4.2.0: {} + + lodash.difference@4.5.0: {} + + lodash.escaperegexp@4.1.2: {} + + lodash.flatten@4.4.0: {} + + lodash.groupby@4.6.0: {} + lodash.includes@4.3.0: {} lodash.isboolean@3.0.3: {} + lodash.isequal@4.5.0: {} + + lodash.isfunction@3.0.9: {} + lodash.isinteger@4.0.4: {} + lodash.isnil@4.0.0: {} + lodash.isnumber@3.0.3: {} lodash.isplainobject@4.0.6: {} lodash.isstring@4.0.1: {} + lodash.isundefined@3.0.1: {} + lodash.kebabcase@4.1.1: {} lodash.memoize@4.1.2: {} @@ -17300,6 +19870,17 @@ snapshots: lodash.startcase@4.4.0: {} + lodash.template@4.18.1: + dependencies: + lodash._reinterpolate: 3.0.0 + lodash.templatesettings: 4.2.0 + + lodash.templatesettings@4.2.0: + dependencies: + lodash._reinterpolate: 3.0.0 + + lodash.union@4.6.0: {} + lodash.uniq@4.5.0: {} lodash.upperfirst@4.3.1: {} @@ -17308,6 +19889,11 @@ snapshots: lodash@4.18.1: {} + log-ok@0.1.1: + dependencies: + ansi-green: 0.1.1 + success-symbol: 0.1.0 + log-symbols@4.1.0: dependencies: chalk: 4.1.2 @@ -17321,18 +19907,50 @@ snapshots: strip-ansi: 7.2.0 wrap-ansi: 9.0.2 - long@5.3.2: - optional: true + log-utils@0.2.1: + dependencies: + ansi-colors: 0.2.0 + error-symbol: 0.1.0 + info-symbol: 0.1.0 + log-ok: 0.1.1 + success-symbol: 0.1.0 + time-stamp: 1.1.0 + warning-symbol: 0.1.0 + + logging-helpers@1.0.0: + dependencies: + isobject: 3.0.1 + log-utils: 0.2.1 + + loglevel@1.9.2: {} + + longest@1.0.1: {} loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 + lottie-web@5.13.0: {} + + loud-rejection@1.6.0: + dependencies: + currently-unhandled: 0.4.1 + signal-exit: 3.0.7 + loupe@3.2.1: {} + lower-case@2.0.2: + dependencies: + tslib: 2.8.1 + lru-cache@10.4.3: {} - lru-cache@11.3.6: {} + lru-cache@11.5.0: {} + + lru-cache@4.1.5: + dependencies: + pseudomap: 1.0.2 + yallist: 2.1.2 lru-cache@5.1.1: dependencies: @@ -17352,34 +19970,84 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + make-cancellable-promise@2.0.0: {} + make-dir@3.1.0: dependencies: semver: 6.3.1 make-dir@4.0.0: dependencies: - semver: 7.8.0 + semver: 7.8.1 make-error@1.3.6: {} + make-event-props@2.0.0: {} + makeerror@1.0.12: dependencies: tmpl: 1.0.5 + map-cache@0.2.2: {} + + map-obj@1.0.1: {} + + map-visit@1.0.0: + dependencies: + object-visit: 1.0.1 + math-intrinsics@1.1.0: {} + md5.js@1.3.5: + dependencies: + hash-base: 3.0.5 + inherits: 2.0.4 + safe-buffer: 5.2.1 + + mdn-data@2.0.14: {} + + media-engine@1.0.3: {} + media-typer@0.3.0: {} media-typer@1.1.0: {} + mem@1.1.0: + dependencies: + mimic-fn: 1.2.0 + memfs@3.5.3: dependencies: fs-monkey: 1.1.0 + memory-fs@0.4.1: + dependencies: + errno: 0.1.8 + readable-stream: 2.3.8 + meow@12.1.1: {} + meow@3.7.0: + dependencies: + camelcase-keys: 2.1.0 + decamelize: 1.2.0 + loud-rejection: 1.6.0 + map-obj: 1.0.1 + minimist: 1.2.8 + normalize-package-data: 2.5.0 + object-assign: 4.1.1 + read-pkg-up: 1.0.1 + redent: 1.0.0 + trim-newlines: 1.0.0 + + merge-descriptors@1.0.3: {} + merge-descriptors@2.0.0: {} + merge-refs@2.0.0(@types/react@18.3.29): + optionalDependencies: + '@types/react': 18.3.29 + merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -17399,7 +20067,7 @@ snapshots: nanomatch: 1.2.13 object.pick: 1.3.0 regex-not: 1.0.2 - snapdragon: 0.8.2(supports-color@5.5.0) + snapdragon: 0.8.2 to-regex: 3.0.2 transitivePeerDependencies: - supports-color @@ -17446,6 +20114,11 @@ snapshots: braces: 3.0.3 picomatch: 2.3.2 + miller-rabin@4.0.1: + dependencies: + bn.js: 4.12.3 + brorand: 1.1.0 + mime-db@1.52.0: {} mime-db@1.54.0: {} @@ -17458,8 +20131,14 @@ snapshots: dependencies: mime-db: 1.54.0 + mime@1.2.11: {} + + mime@1.6.0: {} + mime@2.6.0: {} + mimic-fn@1.2.0: {} + mimic-fn@2.1.0: {} mimic-fn@4.0.0: {} @@ -17478,12 +20157,33 @@ snapshots: dependencies: brace-expansion: 1.1.14 + minimatch@5.1.9: + dependencies: + brace-expansion: 2.1.0 + minimatch@9.0.9: dependencies: brace-expansion: 2.1.0 minimist@1.2.8: {} + minio@7.1.3: + dependencies: + async: 3.2.6 + block-stream2: 2.1.0 + browser-or-node: 2.1.1 + buffer-crc32: 0.2.13 + fast-xml-parser: 4.5.6 + ipaddr.js: 2.4.0 + json-stream: 1.0.0 + lodash: 4.18.1 + mime-types: 2.1.35 + query-string: 7.1.3 + through2: 4.0.2 + web-encoding: 1.1.5 + xml: 1.0.1 + xml2js: 0.5.0 + minipass@3.3.6: dependencies: yallist: 4.0.0 @@ -17497,29 +20197,48 @@ snapshots: minipass: 3.3.6 yallist: 4.0.0 + mixin-deep@1.3.2: + dependencies: + for-in: 1.0.2 + is-extendable: 1.0.1 + + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + mkdirp@1.0.4: {} + moment@2.30.1: {} + + motion-dom@12.40.0: + dependencies: + motion-utils: 12.39.0 + + motion-utils@12.39.0: {} + + ms@2.0.0: {} + ms@2.1.3: {} - mui-ethiopian-datepicker@0.3.2(bb2b0a350b39c049005e46c2e15483da): + mui-ethiopian-datepicker@0.3.2(5e5972eb531cdc6fbddb8a7490bbd426): dependencies: - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@18.3.1) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) - '@mui/icons-material': 5.18.0(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) - '@mui/material': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/x-date-pickers': 6.20.2(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(dayjs@1.11.20)(luxon@3.7.2)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - date-fns: 4.1.0 + '@emotion/react': 11.14.0(@types/react@18.3.29)(react@18.3.1) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1) + '@mui/icons-material': 5.18.0(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.29)(react@18.3.1) + '@mui/material': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/x-date-pickers': 6.20.2(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(dayjs@1.11.20)(luxon@3.7.2)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + date-fns: 4.2.1 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - mui-ethiopian-datepicker@0.3.2(c914a98daf8e04e98459e8e367258069): + mui-ethiopian-datepicker@0.3.2(6b313862ea62f1caf34a6d816b4f4dc9): dependencies: - '@emotion/react': 11.14.0(@types/react@18.3.28)(react@19.2.6) - '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@19.2.6) - '@mui/icons-material': 5.18.0(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.28)(react@18.3.1) - '@mui/material': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/x-date-pickers': 6.20.2(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(react@18.3.1))(@types/react@18.3.28)(date-fns@4.1.0)(dayjs@1.11.20)(luxon@3.7.2)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - date-fns: 4.1.0 + '@emotion/react': 11.14.0(@types/react@18.3.29)(react@19.2.6) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@19.2.6) + '@mui/icons-material': 5.18.0(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.29)(react@18.3.1) + '@mui/material': 5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@mui/x-date-pickers': 6.20.2(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@mui/material@5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@mui/system@5.18.0(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(react@18.3.1))(@types/react@18.3.29)(date-fns@4.2.1)(dayjs@1.11.20)(luxon@3.7.2)(moment@2.30.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + date-fns: 4.2.1 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) @@ -17530,20 +20249,14 @@ snapshots: concat-stream: 2.0.0 type-is: 1.6.18 - mute-stream@2.0.0: {} + multicast-dns-service-types@1.1.0: {} - mysql2@3.15.3: + multicast-dns@7.2.5: dependencies: - aws-ssl-profiles: 1.1.2 - denque: 2.1.0 - generate-function: 2.3.1 - iconv-lite: 0.7.2 - long: 5.3.2 - lru.min: 1.1.4 - named-placeholders: 1.1.6 - seq-queue: 0.0.5 - sqlstring: 2.3.3 - optional: true + dns-packet: 5.6.1 + thunky: 1.1.0 + + mute-stream@2.0.0: {} mz@2.7.0: dependencies: @@ -17551,9 +20264,7 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 - named-placeholders@1.1.6: - dependencies: - lru.min: 1.1.4 + nan@2.27.0: optional: true nanoid@3.3.12: {} @@ -17569,7 +20280,7 @@ snapshots: kind-of: 6.0.3 object.pick: 1.3.0 regex-not: 1.0.2 - snapdragon: 0.8.2(supports-color@5.5.0) + snapdragon: 0.8.2 to-regex: 3.0.2 transitivePeerDependencies: - supports-color @@ -17591,18 +20302,36 @@ snapshots: - supports-color optional: true - nanoid@3.3.12: {} + nanomatch@1.2.13(supports-color@5.5.0): + dependencies: + arr-diff: 4.0.0 + array-unique: 0.3.2 + define-property: 2.0.2 + extend-shallow: 3.0.2 + fragment-cache: 0.2.1 + is-windows: 1.0.2 + kind-of: 6.0.3 + object.pick: 1.3.0 + regex-not: 1.0.2 + snapdragon: 0.8.2(supports-color@5.5.0) + to-regex: 3.0.2 + transitivePeerDependencies: + - supports-color natural-compare@1.4.0: {} + negotiator@0.6.3: {} + + negotiator@0.6.4: {} + negotiator@1.0.0: {} neo-async@2.6.2: {} - nestjs-minio-client@2.2.0(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.19): + nestjs-minio-client@2.2.0(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23): dependencies: - '@nestjs/common': 11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.19(@nestjs/common@11.1.19(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.19)(@nestjs/platform-express@11.1.19)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.23(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/microservices@11.1.23)(@nestjs/platform-express@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2) minio: 7.1.3 reflect-metadata: 0.1.14 rxjs: 7.8.2 @@ -17623,6 +20352,8 @@ snapshots: node-addon-api@5.1.0: {} + node-addon-api@8.7.0: {} + node-emoji@1.11.0: dependencies: lodash: 4.18.1 @@ -17640,16 +20371,70 @@ snapshots: dependencies: whatwg-url: 5.0.0 + node-forge@0.10.0: {} + + node-gyp-build@4.8.4: {} + + node-html-parser@6.1.13: + dependencies: + css-select: 5.2.2 + he: 1.2.0 + node-int64@0.4.0: {} - node-releases@2.0.44: {} + node-libs-browser@2.2.1: + dependencies: + assert: 1.5.1 + browserify-zlib: 0.2.0 + buffer: 4.9.2 + console-browserify: 1.2.0 + constants-browserify: 1.0.0 + crypto-browserify: 3.12.1 + domain-browser: 1.2.0 + events: 3.3.0 + https-browserify: 1.0.0 + os-browserify: 0.3.0 + path-browserify: 0.0.1 + process: 0.11.10 + punycode: 1.4.1 + querystring-es3: 0.2.1 + readable-stream: 2.3.8 + stream-browserify: 2.0.2 + stream-http: 2.8.3 + string_decoder: 1.3.0 + timers-browserify: 2.0.12 + tty-browserify: 0.0.0 + url: 0.11.4 + util: 0.11.1 + vm-browserify: 1.1.2 + + node-releases@2.0.45: {} nopt@5.0.0: dependencies: abbrev: 1.1.1 + normalize-package-data@2.5.0: + dependencies: + hosted-git-info: 2.8.9 + resolve: 1.22.12 + semver: 5.7.2 + validate-npm-package-license: 3.0.4 + + normalize-path@2.1.1: + dependencies: + remove-trailing-separator: 1.1.0 + normalize-path@3.0.0: {} + normalize-svg-path@1.1.0: + dependencies: + svg-arc-to-cubic-bezier: 3.2.0 + + npm-run-path@2.0.2: + dependencies: + path-key: 2.0.1 + npm-run-path@4.0.1: dependencies: path-key: 3.1.1 @@ -17665,6 +20450,12 @@ snapshots: gauge: 3.0.2 set-blocking: 2.0.0 + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + number-is-nan@1.0.1: {} + nwsapi@2.2.23: {} nypm@0.6.6: @@ -17673,14 +20464,31 @@ snapshots: pathe: 2.0.3 tinyexec: 1.1.2 + oauth-sign@0.9.0: {} + object-assign@4.1.1: {} + object-copy@0.1.0: + dependencies: + copy-descriptor: 0.1.1 + define-property: 0.2.5 + kind-of: 3.2.2 + object-hash@3.0.0: {} object-inspect@1.13.4: {} + object-is@1.1.6: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + object-keys@1.1.1: {} + object-visit@1.0.1: + dependencies: + isobject: 3.0.1 + object.assign@4.1.7: dependencies: call-bind: 1.0.9 @@ -17702,7 +20510,7 @@ snapshots: call-bind: 1.0.9 define-properties: 1.2.1 es-abstract: 1.24.2 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 object.groupby@1.0.3: dependencies: @@ -17710,12 +20518,18 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.24.2 + object.pick@1.3.0: + dependencies: + isobject: 3.0.1 + object.values@1.2.1: dependencies: call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 + + obuf@1.1.2: {} ohash@2.0.11: {} @@ -17723,6 +20537,8 @@ snapshots: dependencies: ee-first: 1.1.1 + on-headers@1.1.0: {} + once@1.4.0: dependencies: wrappy: 1.0.2 @@ -17739,6 +20555,12 @@ snapshots: dependencies: mimic-function: 5.0.1 + opencollective-postinstall@2.0.3: {} + + opn@5.5.0: + dependencies: + is-wsl: 1.1.0 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -17760,12 +20582,36 @@ snapshots: strip-ansi: 6.0.1 wcwidth: 1.0.1 + orderedmap@2.1.1: {} + + original@1.0.2: + dependencies: + url-parse: 1.5.10 + + os-browserify@0.3.0: {} + + os-locale@1.4.0: + dependencies: + lcid: 1.0.0 + + os-locale@2.1.0: + dependencies: + execa: 0.7.0 + lcid: 1.0.0 + mem: 1.1.0 + own-keys@1.0.1: dependencies: get-intrinsic: 1.3.0 object-keys: 1.1.1 safe-push-apply: 1.0.0 + p-finally@1.0.0: {} + + p-limit@1.3.0: + dependencies: + p-try: 1.0.0 + p-limit@2.3.0: dependencies: p-try: 2.2.0 @@ -17778,6 +20624,10 @@ snapshots: dependencies: yocto-queue: 1.2.2 + p-locate@2.0.0: + dependencies: + p-limit: 1.3.0 + p-locate@4.1.0: dependencies: p-limit: 2.3.0 @@ -17790,14 +20640,36 @@ snapshots: dependencies: p-limit: 4.0.0 + p-map@1.2.0: {} + + p-try@1.0.0: {} + p-try@2.2.0: {} package-json-from-dist@1.0.1: {} + pako@0.2.9: {} + + pako@1.0.11: {} + + pako@2.1.0: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 + parse-asn1@5.1.9: + dependencies: + asn1.js: 4.10.1 + browserify-aes: 1.2.0 + evp_bytestokey: 1.0.3 + pbkdf2: 3.1.5 + safe-buffer: 5.2.1 + + parse-json@2.2.0: + dependencies: + error-ex: 1.3.4 + parse-json@5.2.0: dependencies: '@babel/code-frame': 7.29.0 @@ -17805,12 +20677,21 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse-svg-path@0.1.2: {} + parse5@7.3.0: dependencies: entities: 6.0.1 parseurl@1.3.3: {} + pascal-case@3.1.2: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + + pascalcase@0.1.1: {} + passport-jwt@4.0.1: dependencies: jsonwebtoken: 9.0.3 @@ -17824,12 +20705,26 @@ snapshots: pause: 0.0.1 utils-merge: 1.0.1 + path-browserify@0.0.1: {} + + path-dirname@1.0.2: {} + + path-exists@2.1.0: + dependencies: + pinkie-promise: 2.0.1 + + path-exists@3.0.0: {} + path-exists@4.0.0: {} path-exists@5.0.0: {} path-is-absolute@1.0.1: {} + path-is-inside@1.0.2: {} + + path-key@2.0.1: {} + path-key@3.1.1: {} path-key@4.0.0: {} @@ -17843,7 +20738,7 @@ snapshots: path-scurry@2.0.2: dependencies: - lru-cache: 11.3.6 + lru-cache: 11.5.0 minipass: 7.1.3 path-to-regexp@0.1.13: {} @@ -17866,17 +20761,26 @@ snapshots: path@0.12.7: dependencies: - lru-cache: 11.3.6 - minipass: 7.1.3 - - path-to-regexp@3.3.0: {} - - path-to-regexp@8.4.2: {} - - path-type@4.0.0: {} + process: 0.11.10 + util: 0.10.4 pathe@1.1.2: {} + pathe@2.0.3: {} + + pathval@2.0.1: {} + + pause@0.0.1: {} + + pbkdf2@3.1.5: + dependencies: + create-hash: 1.2.0 + create-hmac: 1.1.7 + ripemd160: 2.0.3 + safe-buffer: 5.2.1 + sha.js: 2.4.12 + to-buffer: 1.2.2 + pdfjs-dist@2.16.105: dependencies: dommatrix: 1.0.3 @@ -17886,28 +20790,26 @@ snapshots: optionalDependencies: '@napi-rs/canvas': 0.1.100 - pathval@2.0.1: {} - - pause@0.0.1: {} + peek-readable@5.4.2: {} perfect-debounce@1.0.0: {} - pg-cloudflare@1.3.0: + perfect-freehand@1.2.3: {} + + performance-now@2.1.0: {} + + pg-cloudflare@1.4.0: optional: true - pg-connection-string@2.12.0: - optional: true + pg-connection-string@2.13.0: {} - pg-int8@1.0.1: - optional: true + pg-int8@1.0.1: {} - pg-pool@3.13.0(pg@8.20.0): + pg-pool@3.14.0(pg@8.21.0): dependencies: - pg: 8.20.0 - optional: true + pg: 8.21.0 - pg-protocol@1.13.0: - optional: true + pg-protocol@1.14.0: {} pg-types@2.2.0: dependencies: @@ -17916,23 +20818,20 @@ snapshots: postgres-bytea: 1.0.1 postgres-date: 1.0.7 postgres-interval: 1.2.0 - optional: true - pg@8.20.0: + pg@8.21.0: dependencies: - pg-connection-string: 2.12.0 - pg-pool: 3.13.0(pg@8.20.0) - pg-protocol: 1.13.0 + pg-connection-string: 2.13.0 + pg-pool: 3.14.0(pg@8.21.0) + pg-protocol: 1.14.0 pg-types: 2.2.0 pgpass: 1.0.5 optionalDependencies: - pg-cloudflare: 1.3.0 - optional: true + pg-cloudflare: 1.4.0 pgpass@1.0.5: dependencies: split2: 4.2.0 - optional: true picocolors@1.1.1: {} @@ -17944,8 +20843,20 @@ snapshots: pify@2.3.0: {} + pify@3.0.0: {} + + pinkie-promise@2.0.1: + dependencies: + pinkie: 2.0.4 + + pinkie@2.0.4: {} + pirates@4.0.7: {} + pkg-dir@2.0.0: + dependencies: + find-up: 2.1.0 + pkg-dir@4.2.0: dependencies: find-up: 4.1.0 @@ -17958,33 +20869,48 @@ snapshots: pluralize@8.0.0: {} + png-js@2.0.0: + dependencies: + fflate: 0.8.3 + pngjs@5.0.0: {} + popper.js@1.16.1: {} + + portfinder@1.0.38(supports-color@5.5.0): + dependencies: + async: 3.2.6 + debug: 4.4.3(supports-color@5.5.0) + transitivePeerDependencies: + - supports-color + + posix-character-classes@0.1.1: {} + possible-typed-array-names@1.1.0: {} - postcss-import@15.1.0(postcss@8.5.14): + postcss-import@15.1.0(postcss@8.5.15): dependencies: - postcss: 8.5.14 + postcss: 8.5.15 postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.12 - postcss-js@4.1.0(postcss@8.5.14): + postcss-js@4.1.0(postcss@8.5.15): dependencies: camelcase-css: 2.0.1 - postcss: 8.5.14 + postcss: 8.5.15 - postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.14)(yaml@2.9.0): + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.15)(yaml@2.9.0): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 1.21.7 - postcss: 8.5.14 + postcss: 8.5.15 yaml: 2.9.0 - postcss-nested@6.2.0(postcss@8.5.14): + postcss-nested@6.2.0(postcss@8.5.15): dependencies: - postcss: 8.5.14 + postcss: 8.5.15 postcss-selector-parser: 6.1.2 postcss-selector-parser@6.1.2: @@ -17994,25 +20920,21 @@ snapshots: postcss-value-parser@4.2.0: {} - postcss@8.5.14: + postcss@8.5.15: dependencies: nanoid: 3.3.12 picocolors: 1.1.1 source-map-js: 1.2.1 - postgres-array@2.0.0: - optional: true + postgres-array@2.0.0: {} - postgres-bytea@1.0.1: - optional: true + postgres-bytea@1.0.1: {} - postgres-date@1.0.7: - optional: true + postgres-date@1.0.7: {} postgres-interval@1.2.0: dependencies: xtend: 4.0.2 - optional: true prelude-ls@1.2.1: {} @@ -18033,6 +20955,10 @@ snapshots: transitivePeerDependencies: - magicast + process-nextick-args@2.0.1: {} + + process@0.11.10: {} + prompts@2.4.2: dependencies: kleur: 3.0.3 @@ -18044,13 +20970,107 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 + prosemirror-changeset@2.4.1: + dependencies: + prosemirror-transform: 1.12.0 + + prosemirror-commands@1.7.1: + dependencies: + prosemirror-model: 1.25.7 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.12.0 + + prosemirror-dropcursor@1.8.2: + dependencies: + prosemirror-state: 1.4.4 + prosemirror-transform: 1.12.0 + prosemirror-view: 1.41.8 + + prosemirror-gapcursor@1.4.1: + dependencies: + prosemirror-keymap: 1.2.3 + prosemirror-model: 1.25.7 + prosemirror-state: 1.4.4 + prosemirror-view: 1.41.8 + + prosemirror-history@1.5.0: + dependencies: + prosemirror-state: 1.4.4 + prosemirror-transform: 1.12.0 + prosemirror-view: 1.41.8 + rope-sequence: 1.3.4 + + prosemirror-keymap@1.2.3: + dependencies: + prosemirror-state: 1.4.4 + w3c-keyname: 2.2.8 + + prosemirror-model@1.25.7: + dependencies: + orderedmap: 2.1.1 + + prosemirror-schema-list@1.5.1: + dependencies: + prosemirror-model: 1.25.7 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.12.0 + + prosemirror-state@1.4.4: + dependencies: + prosemirror-model: 1.25.7 + prosemirror-transform: 1.12.0 + prosemirror-view: 1.41.8 + + prosemirror-tables@1.8.5: + dependencies: + prosemirror-keymap: 1.2.3 + prosemirror-model: 1.25.7 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.12.0 + prosemirror-view: 1.41.8 + + prosemirror-transform@1.12.0: + dependencies: + prosemirror-model: 1.25.7 + + prosemirror-view@1.41.8: + dependencies: + prosemirror-model: 1.25.7 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.12.0 + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 ipaddr.js: 1.9.1 + proxy-compare@3.0.1: {} + proxy-from-env@2.1.0: {} + proxy-memoize@3.0.1: + dependencies: + proxy-compare: 3.0.1 + + prr@1.0.1: {} + + pseudomap@1.0.2: {} + + psl@1.15.0: + dependencies: + punycode: 2.3.1 + + public-encrypt@4.0.3: + dependencies: + bn.js: 4.12.3 + browserify-rsa: 4.1.1 + create-hash: 1.2.0 + parse-asn1: 5.1.9 + randombytes: 2.1.0 + safe-buffer: 5.2.1 + + punycode@1.4.1: {} + punycode@2.3.1: {} pure-rand@6.1.0: {} @@ -18061,14 +21081,57 @@ snapshots: pngjs: 5.0.0 yargs: 15.4.1 - qs@6.15.1: + qs@6.15.2: dependencies: side-channel: 1.1.0 + qs@6.5.5: {} + + query-string@7.1.3: + dependencies: + decode-uri-component: 0.2.2 + filter-obj: 1.1.0 + split-on-first: 1.1.0 + strict-uri-encode: 2.0.0 + + querystring-es3@0.2.1: {} + + querystringify@2.2.0: {} + queue-microtask@1.2.3: {} + queue@6.0.2: + dependencies: + inherits: 2.0.4 + + raf@3.4.1: + dependencies: + performance-now: 2.1.0 + optional: true + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + randomfill@1.0.4: + dependencies: + randombytes: 2.1.0 + safe-buffer: 5.2.1 + range-parser@1.2.1: {} + rapiq@0.9.0: + dependencies: + ebec: 1.1.1 + smob: 1.6.2 + + raw-body@2.5.3: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + raw-body@3.0.2: dependencies: bytes: 3.1.2 @@ -18076,9 +21139,14 @@ snapshots: iconv-lite: 0.7.2 unpipe: 1.0.0 - react-cookie@8.1.2(@types/react@18.3.28)(react@19.2.6): + rc9@2.1.2: dependencies: - '@types/hoist-non-react-statics': 3.3.7(@types/react@18.3.28) + defu: 6.1.7 + destr: 2.0.5 + + react-cookie@8.1.2(@types/react@18.3.29)(react@19.2.6): + dependencies: + '@types/hoist-non-react-statics': 3.3.7(@types/react@18.3.29) hoist-non-react-statics: 3.3.2 react: 19.2.6 universal-cookie: 8.1.2 @@ -18089,15 +21157,15 @@ snapshots: dependencies: '@floating-ui/react': 0.27.19(react-dom@19.2.6(react@19.2.6))(react@19.2.6) clsx: 2.1.1 - date-fns: 4.1.0 + date-fns: 4.2.1 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) react-day-picker@9.14.0(react@19.2.6): dependencies: - '@date-fns/tz': 1.4.1 + '@date-fns/tz': 1.5.0 '@tabby_ai/hijri-converter': 1.0.5 - date-fns: 4.1.0 + date-fns: 4.2.1 date-fns-jalali: 4.1.0-0 react: 19.2.6 @@ -18137,7 +21205,7 @@ snapshots: react-dom: 19.2.6(react@19.2.6) tree-changes: 0.9.3 - react-hook-form@7.75.0(react@19.2.6): + react-hook-form@7.76.0(react@19.2.6): dependencies: react: 19.2.6 @@ -18159,9 +21227,9 @@ snapshots: dependencies: react: 19.2.6 - react-innertext@1.1.5(@types/react@18.3.28)(react@19.2.6): + react-innertext@1.1.5(@types/react@18.3.29)(react@19.2.6): dependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 react: 19.2.6 react-intersection-observer@9.16.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): @@ -18176,7 +21244,7 @@ snapshots: react-is@19.2.6: {} - react-joyride@2.9.3(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + react-joyride@2.9.3(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: '@gilbarbara/deep-equal': 0.3.1 deep-diff: 1.0.2 @@ -18185,7 +21253,7 @@ snapshots: react: 19.2.6 react-dom: 19.2.6(react@19.2.6) react-floater: 0.7.9(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react-innertext: 1.1.5(@types/react@18.3.28)(react@19.2.6) + react-innertext: 1.1.5(@types/react@18.3.29)(react@19.2.6) react-is: 16.13.1 scroll: 3.0.1 scrollparent: 2.1.0 @@ -18218,50 +21286,50 @@ snapshots: - webpack-command - worker-loader - react-pdf@10.4.1(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + react-pdf@10.4.1(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: clsx: 2.1.1 dequal: 2.0.3 make-cancellable-promise: 2.0.0 make-event-props: 2.0.0 - merge-refs: 2.0.0(@types/react@18.3.28) + merge-refs: 2.0.0(@types/react@18.3.29) pdfjs-dist: 5.4.296 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) tiny-invariant: 1.3.3 warning: 4.0.3 optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 - react-redux@9.2.0(@types/react@18.3.28)(react@19.2.6)(redux@5.0.1): + react-redux@9.3.0(@types/react@18.3.29)(react@19.2.6)(redux@5.0.1): dependencies: '@types/use-sync-external-store': 0.0.6 react: 19.2.6 use-sync-external-store: 1.6.0(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 redux: 5.0.1 react-refresh@0.17.0: {} - react-remove-scroll-bar@2.3.8(@types/react@18.3.28)(react@19.2.6): + react-remove-scroll-bar@2.3.8(@types/react@18.3.29)(react@19.2.6): dependencies: react: 19.2.6 - react-style-singleton: 2.2.3(@types/react@18.3.28)(react@19.2.6) + react-style-singleton: 2.2.3(@types/react@18.3.29)(react@19.2.6) tslib: 2.8.1 optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 - react-remove-scroll@2.7.2(@types/react@18.3.28)(react@19.2.6): + react-remove-scroll@2.7.2(@types/react@18.3.29)(react@19.2.6): dependencies: react: 19.2.6 - react-remove-scroll-bar: 2.3.8(@types/react@18.3.28)(react@19.2.6) - react-style-singleton: 2.2.3(@types/react@18.3.28)(react@19.2.6) + react-remove-scroll-bar: 2.3.8(@types/react@18.3.29)(react@19.2.6) + react-style-singleton: 2.2.3(@types/react@18.3.29)(react@19.2.6) tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@18.3.28)(react@19.2.6) - use-sidecar: 1.1.3(@types/react@18.3.28)(react@19.2.6) + use-callback-ref: 1.3.3(@types/react@18.3.29)(react@19.2.6) + use-sidecar: 1.1.3(@types/react@18.3.29)(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 react-resizable-panels@3.0.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: @@ -18275,18 +21343,18 @@ snapshots: react-dom: 18.3.1(react@18.3.1) react-router: 6.30.3(react@18.3.1) - react-router-dom@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + react-router-dom@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - react-router: 7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-router: 7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react-router@6.30.3(react@18.3.1): dependencies: '@remix-run/router': 1.23.2 react: 18.3.1 - react-router@7.15.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + react-router@7.15.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: cookie: 1.1.1 react: 19.2.6 @@ -18294,7 +21362,7 @@ snapshots: optionalDependencies: react-dom: 19.2.6(react@19.2.6) - react-signature-canvas@1.1.0-alpha.2(@types/prop-types@15.7.15)(@types/react@18.3.28)(prop-types@15.8.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + react-signature-canvas@1.1.0-alpha.2(@types/prop-types@15.7.15)(@types/react@18.3.29)(prop-types@15.8.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: '@babel/runtime': 7.29.2 '@types/signature_pad': 2.3.6 @@ -18305,22 +21373,22 @@ snapshots: trim-canvas: 0.1.2 optionalDependencies: '@types/prop-types': 15.7.15 - '@types/react': 18.3.28 + '@types/react': 18.3.29 - react-style-singleton@2.2.3(@types/react@18.3.28)(react@19.2.6): + react-style-singleton@2.2.3(@types/react@18.3.29)(react@19.2.6): dependencies: get-nonce: 1.0.1 react: 19.2.6 tslib: 2.8.1 optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 - react-textarea-autosize@8.5.9(@types/react@18.3.28)(react@19.2.6): + react-textarea-autosize@8.5.9(@types/react@18.3.29)(react@19.2.6): dependencies: '@babel/runtime': 7.29.2 react: 19.2.6 - use-composed-ref: 1.4.0(@types/react@18.3.28)(react@19.2.6) - use-latest: 1.3.0(@types/react@18.3.28)(react@19.2.6) + use-composed-ref: 1.4.0(@types/react@18.3.29)(react@19.2.6) + use-latest: 1.3.0(@types/react@18.3.29)(react@19.2.6) transitivePeerDependencies: - '@types/react' @@ -18331,6 +21399,7 @@ snapshots: loose-envify: 1.4.0 prop-types: 15.8.1 react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) react@16.14.0: dependencies: @@ -18348,21 +21417,86 @@ snapshots: dependencies: pify: 2.3.0 + read-pkg-up@1.0.1: + dependencies: + find-up: 1.1.2 + read-pkg: 1.1.0 + + read-pkg-up@2.0.0: + dependencies: + find-up: 2.1.0 + read-pkg: 2.0.0 + + read-pkg@1.1.0: + dependencies: + load-json-file: 1.1.0 + normalize-package-data: 2.5.0 + path-type: 1.1.0 + + read-pkg@2.0.0: + dependencies: + load-json-file: 2.0.0 + normalize-package-data: 2.5.0 + path-type: 2.0.0 + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + readable-stream@3.6.2: dependencies: inherits: 2.0.4 string_decoder: 1.3.0 util-deprecate: 1.0.2 + readable-stream@4.7.0: + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + + readable-web-to-node-stream@3.0.4: + dependencies: + readable-stream: 4.7.0 + + readdir-glob@1.1.3: + dependencies: + minimatch: 5.1.9 + + readdirp@2.2.1(supports-color@4.5.0): + dependencies: + graceful-fs: 4.2.11 + micromatch: 3.1.10(supports-color@4.5.0) + readable-stream: 2.3.8 + transitivePeerDependencies: + - supports-color + optional: true + + readdirp@2.2.1(supports-color@5.5.0): + dependencies: + graceful-fs: 4.2.11 + micromatch: 3.1.10(supports-color@5.5.0) + readable-stream: 2.3.8 + transitivePeerDependencies: + - supports-color + readdirp@3.6.0: dependencies: picomatch: 2.3.2 readdirp@4.1.2: {} - recharts@3.8.1(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react-is@19.2.6)(react@19.2.6)(redux@5.0.1): + recharts@3.8.1(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react-is@19.2.6)(react@19.2.6)(redux@5.0.1): dependencies: - '@reduxjs/toolkit': 2.11.2(react-redux@9.2.0(@types/react@18.3.28)(react@19.2.6)(redux@5.0.1))(react@19.2.6) + '@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@18.3.29)(react@19.2.6)(redux@5.0.1))(react@19.2.6) clsx: 2.1.1 decimal.js-light: 2.5.1 es-toolkit: 1.46.1 @@ -18371,7 +21505,7 @@ snapshots: react: 19.2.6 react-dom: 19.2.6(react@19.2.6) react-is: 19.2.6 - react-redux: 9.2.0(@types/react@18.3.28)(react@19.2.6)(redux@5.0.1) + react-redux: 9.3.0(@types/react@18.3.29)(react@19.2.6)(redux@5.0.1) reselect: 5.1.1 tiny-invariant: 1.3.3 use-sync-external-store: 1.6.0(react@19.2.6) @@ -18406,6 +21540,13 @@ snapshots: get-proto: 1.0.1 which-builtin-type: 1.2.1 + regenerator-runtime@0.13.11: {} + + regex-not@1.0.2: + dependencies: + extend-shallow: 3.0.2 + safe-regex: 1.1.0 + regexp.prototype.flags@1.5.4: dependencies: call-bind: 1.0.9 @@ -18415,20 +21556,78 @@ snapshots: gopd: 1.2.0 set-function-name: 2.0.2 + relative@3.0.2: + dependencies: + isobject: 2.1.0 + + remarkable@1.7.4: + dependencies: + argparse: 1.0.10 + autolinker: 0.28.1 + + remove-trailing-separator@1.1.0: {} + + repeat-element@1.1.4: {} + + repeat-string@1.6.1: {} + + repeating@2.0.1: + dependencies: + is-finite: 1.1.0 + + request@2.88.2: + dependencies: + aws-sign2: 0.7.0 + aws4: 1.13.2 + caseless: 0.12.0 + combined-stream: 1.0.8 + extend: 3.0.2 + forever-agent: 0.6.1 + form-data: 2.3.3 + har-validator: 5.1.5 + http-signature: 1.2.0 + is-typedarray: 1.0.0 + isstream: 0.1.2 + json-stringify-safe: 5.0.1 + mime-types: 2.1.35 + oauth-sign: 0.9.0 + performance-now: 2.1.0 + qs: 6.5.5 + safe-buffer: 5.2.1 + tough-cookie: 2.5.0 + tunnel-agent: 0.6.0 + uuid: 3.4.0 + require-directory@2.1.1: {} require-from-string@2.0.2: {} + require-main-filename@1.0.1: {} + require-main-filename@2.0.0: {} + requires-port@1.0.0: {} + + reselect@5.1.1: {} + + reselect@5.2.0: {} + + resolve-cwd@2.0.0: + dependencies: + resolve-from: 3.0.0 + resolve-cwd@3.0.0: dependencies: resolve-from: 5.0.0 + resolve-from@3.0.0: {} + resolve-from@4.0.0: {} resolve-from@5.0.0: {} + resolve-url@0.2.1: {} + resolve.exports@2.0.3: {} resolve@1.22.12: @@ -18438,7 +21637,7 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - resolve@2.0.0-next.6: + resolve@2.0.0-next.7: dependencies: es-errors: 1.3.0 is-core-module: 2.16.2 @@ -18457,45 +21656,67 @@ snapshots: onetime: 7.0.0 signal-exit: 4.1.0 + restructure@3.0.2: {} + + ret@0.1.15: {} + reusify@1.1.0: {} rfdc@1.4.1: {} + rgbcolor@1.0.1: + optional: true + + right-align@0.1.3: + dependencies: + align-text: 0.1.4 + + rimraf@2.7.1: + dependencies: + glob: 7.2.3 + rimraf@3.0.2: dependencies: glob: 7.2.3 - rollup@4.60.3: + ripemd160@2.0.3: + dependencies: + hash-base: 3.1.2 + inherits: 2.0.4 + + rollup@4.60.4: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.60.3 - '@rollup/rollup-android-arm64': 4.60.3 - '@rollup/rollup-darwin-arm64': 4.60.3 - '@rollup/rollup-darwin-x64': 4.60.3 - '@rollup/rollup-freebsd-arm64': 4.60.3 - '@rollup/rollup-freebsd-x64': 4.60.3 - '@rollup/rollup-linux-arm-gnueabihf': 4.60.3 - '@rollup/rollup-linux-arm-musleabihf': 4.60.3 - '@rollup/rollup-linux-arm64-gnu': 4.60.3 - '@rollup/rollup-linux-arm64-musl': 4.60.3 - '@rollup/rollup-linux-loong64-gnu': 4.60.3 - '@rollup/rollup-linux-loong64-musl': 4.60.3 - '@rollup/rollup-linux-ppc64-gnu': 4.60.3 - '@rollup/rollup-linux-ppc64-musl': 4.60.3 - '@rollup/rollup-linux-riscv64-gnu': 4.60.3 - '@rollup/rollup-linux-riscv64-musl': 4.60.3 - '@rollup/rollup-linux-s390x-gnu': 4.60.3 - '@rollup/rollup-linux-x64-gnu': 4.60.3 - '@rollup/rollup-linux-x64-musl': 4.60.3 - '@rollup/rollup-openbsd-x64': 4.60.3 - '@rollup/rollup-openharmony-arm64': 4.60.3 - '@rollup/rollup-win32-arm64-msvc': 4.60.3 - '@rollup/rollup-win32-ia32-msvc': 4.60.3 - '@rollup/rollup-win32-x64-gnu': 4.60.3 - '@rollup/rollup-win32-x64-msvc': 4.60.3 + '@rollup/rollup-android-arm-eabi': 4.60.4 + '@rollup/rollup-android-arm64': 4.60.4 + '@rollup/rollup-darwin-arm64': 4.60.4 + '@rollup/rollup-darwin-x64': 4.60.4 + '@rollup/rollup-freebsd-arm64': 4.60.4 + '@rollup/rollup-freebsd-x64': 4.60.4 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.4 + '@rollup/rollup-linux-arm-musleabihf': 4.60.4 + '@rollup/rollup-linux-arm64-gnu': 4.60.4 + '@rollup/rollup-linux-arm64-musl': 4.60.4 + '@rollup/rollup-linux-loong64-gnu': 4.60.4 + '@rollup/rollup-linux-loong64-musl': 4.60.4 + '@rollup/rollup-linux-ppc64-gnu': 4.60.4 + '@rollup/rollup-linux-ppc64-musl': 4.60.4 + '@rollup/rollup-linux-riscv64-gnu': 4.60.4 + '@rollup/rollup-linux-riscv64-musl': 4.60.4 + '@rollup/rollup-linux-s390x-gnu': 4.60.4 + '@rollup/rollup-linux-x64-gnu': 4.60.4 + '@rollup/rollup-linux-x64-musl': 4.60.4 + '@rollup/rollup-openbsd-x64': 4.60.4 + '@rollup/rollup-openharmony-arm64': 4.60.4 + '@rollup/rollup-win32-arm64-msvc': 4.60.4 + '@rollup/rollup-win32-ia32-msvc': 4.60.4 + '@rollup/rollup-win32-x64-gnu': 4.60.4 + '@rollup/rollup-win32-x64-msvc': 4.60.4 fsevents: 2.3.3 + rope-sequence@1.3.4: {} + router@2.2.0: dependencies: debug: 4.4.3(supports-color@5.5.0) @@ -18530,6 +21751,8 @@ snapshots: has-symbols: 1.1.0 isarray: 2.0.5 + safe-buffer@5.1.2: {} + safe-buffer@5.2.1: {} safe-push-apply@1.0.0: @@ -18543,8 +21766,18 @@ snapshots: es-errors: 1.3.0 is-regex: 1.2.1 + safe-regex@1.1.0: + dependencies: + ret: 0.1.15 + safer-buffer@2.1.2: {} + sax@1.6.0: {} + + saxes@5.0.1: + dependencies: + xmlchars: 2.2.0 + saxes@6.0.0: dependencies: xmlchars: 2.2.0 @@ -18575,9 +21808,41 @@ snapshots: ajv-formats: 2.1.1(ajv@8.20.0) ajv-keywords: 5.1.0(ajv@8.20.0) + scroll@3.0.1: {} + + scrollparent@2.1.0: {} + + select-hose@2.0.0: {} + + self-closing-tags@1.0.1: {} + + selfsigned@1.10.14: + dependencies: + node-forge: 0.10.0 + + semver@5.7.2: {} + semver@6.3.1: {} - semver@7.8.0: {} + semver@7.8.1: {} + + send@0.19.2(supports-color@5.5.0): + dependencies: + debug: 2.6.9(supports-color@5.5.0) + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.1 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color send@1.2.1: dependencies: @@ -18595,8 +21860,26 @@ snapshots: transitivePeerDependencies: - supports-color - seq-queue@0.0.5: - optional: true + serve-index@1.9.2(supports-color@5.5.0): + dependencies: + accepts: 1.3.8 + batch: 0.6.1 + debug: 2.6.9(supports-color@5.5.0) + escape-html: 1.0.3 + http-errors: 1.8.1 + mime-types: 2.1.35 + parseurl: 1.3.3 + transitivePeerDependencies: + - supports-color + + serve-static@1.16.3(supports-color@5.5.0): + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.2(supports-color@5.5.0) + transitivePeerDependencies: + - supports-color serve-static@2.2.1: dependencies: @@ -18609,6 +21892,8 @@ snapshots: set-blocking@2.0.0: {} + set-cookie-parser@2.7.2: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -18625,12 +21910,25 @@ snapshots: functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 + set-getter@0.1.1: + dependencies: + to-object-path: 0.3.0 + set-proto@1.0.0: dependencies: dunder-proto: 1.0.1 es-errors: 1.3.0 es-object-atoms: 1.1.1 + set-value@2.0.1: + dependencies: + extend-shallow: 2.0.1 + is-extendable: 0.1.1 + is-plain-object: 2.0.4 + split-string: 3.1.0 + + setimmediate@1.0.5: {} + setprototypeof@1.2.0: {} sha.js@2.4.12: @@ -18639,10 +21937,16 @@ snapshots: safe-buffer: 5.2.1 to-buffer: 1.2.2 + shebang-command@1.2.0: + dependencies: + shebang-regex: 1.0.0 + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 + shebang-regex@1.0.0: {} + shebang-regex@3.0.0: {} side-channel-list@1.0.1: @@ -18695,7 +21999,7 @@ snapshots: ansi-styles: 6.2.3 is-fullwidth-code-point: 5.1.0 - smob@1.6.1: {} + smob@1.6.2: {} snapdragon-node@2.1.1: dependencies: @@ -18707,6 +22011,19 @@ snapshots: dependencies: kind-of: 3.2.2 + snapdragon@0.8.2: + dependencies: + base: 0.11.2 + debug: 2.6.9(supports-color@5.5.0) + define-property: 0.2.5 + extend-shallow: 2.0.1 + map-cache: 0.2.2 + source-map: 0.5.7 + source-map-resolve: 0.5.3 + use: 3.1.1 + transitivePeerDependencies: + - supports-color + snapdragon@0.8.2(supports-color@4.5.0): dependencies: base: 0.11.2 @@ -18738,7 +22055,7 @@ snapshots: dependencies: '@socket.io/component-emitter': 3.1.2 debug: 4.4.3(supports-color@5.5.0) - engine.io-client: 6.6.4 + engine.io-client: 6.6.5 socket.io-parser: 4.2.6 transitivePeerDependencies: - bufferutil @@ -18777,6 +22094,14 @@ snapshots: source-map-js@1.2.1: {} + source-map-resolve@0.5.3: + dependencies: + atob: 2.1.2 + decode-uri-component: 0.2.2 + resolve-url: 0.2.1 + source-map-url: 0.4.1 + urix: 0.1.0 + source-map-support@0.5.13: dependencies: buffer-from: 1.1.2 @@ -18787,18 +22112,78 @@ snapshots: buffer-from: 1.1.2 source-map: 0.6.1 + source-map-url@0.4.1: {} + + source-map@0.5.7: {} + source-map@0.6.1: {} source-map@0.7.4: {} + source-map@0.7.6: {} + + spdx-correct@3.2.0: + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.23 + + spdx-exceptions@2.5.0: {} + + spdx-expression-parse@3.0.1: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.23 + + spdx-license-ids@3.0.23: {} + + spdy-transport@3.0.0(supports-color@5.5.0): + dependencies: + debug: 4.4.3(supports-color@5.5.0) + detect-node: 2.1.0 + hpack.js: 2.1.6 + obuf: 1.1.2 + readable-stream: 3.6.2 + wbuf: 1.7.3 + transitivePeerDependencies: + - supports-color + + spdy@4.0.2(supports-color@5.5.0): + dependencies: + debug: 4.4.3(supports-color@5.5.0) + handle-thing: 2.0.1 + http-deceiver: 1.2.7 + select-hose: 2.0.0 + spdy-transport: 3.0.0(supports-color@5.5.0) + transitivePeerDependencies: + - supports-color + + split-on-first@1.1.0: {} + + split-string@3.1.0: + dependencies: + extend-shallow: 3.0.2 + split2@4.2.0: {} sprintf-js@1.0.3: {} sql-highlight@6.1.0: {} - sqlstring@2.3.3: - optional: true + ssf@0.11.2: + dependencies: + frac: 1.1.2 + + sshpk@1.18.0: + dependencies: + asn1: 0.2.6 + assert-plus: 1.0.0 + bcrypt-pbkdf: 1.0.2 + dashdash: 1.14.1 + ecc-jsbn: 0.1.2 + getpass: 0.1.7 + jsbn: 0.1.1 + safer-buffer: 2.1.2 + tweetnacl: 0.14.5 stack-utils@2.0.6: dependencies: @@ -18806,6 +22191,16 @@ snapshots: stackback@0.0.2: {} + stackblur-canvas@2.7.0: + optional: true + + static-extend@0.1.2: + dependencies: + define-property: 0.2.5 + object-copy: 0.1.0 + + statuses@1.5.0: {} + statuses@2.0.2: {} std-env@3.10.0: {} @@ -18815,8 +22210,23 @@ snapshots: es-errors: 1.3.0 internal-slot: 1.1.0 + stream-browserify@2.0.2: + dependencies: + inherits: 2.0.4 + readable-stream: 2.3.8 + + stream-http@2.8.3: + dependencies: + builtin-status-codes: 3.0.0 + inherits: 2.0.4 + readable-stream: 2.3.8 + to-arraybuffer: 1.0.1 + xtend: 4.0.2 + streamsearch@1.1.0: {} + strict-uri-encode@2.0.0: {} + string-argv@0.3.2: {} string-length@4.0.2: @@ -18824,6 +22234,17 @@ snapshots: char-regex: 1.0.2 strip-ansi: 6.0.1 + string-width@1.0.2: + dependencies: + code-point-at: 1.1.0 + is-fullwidth-code-point: 1.0.0 + strip-ansi: 3.0.1 + + string-width@2.1.1: + dependencies: + is-fullwidth-code-point: 2.0.0 + strip-ansi: 4.0.0 + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -18878,7 +22299,7 @@ snapshots: call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 string.prototype.trimstart@1.0.8: dependencies: @@ -18886,10 +22307,22 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 + strip-ansi@3.0.1: + dependencies: + ansi-regex: 2.1.1 + + strip-ansi@4.0.0: + dependencies: + ansi-regex: 3.0.1 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -18898,20 +22331,45 @@ snapshots: dependencies: ansi-regex: 6.2.2 + strip-bom@2.0.0: + dependencies: + is-utf8: 0.2.1 + strip-bom@3.0.0: {} strip-bom@4.0.0: {} + strip-eof@1.0.0: {} + strip-final-newline@2.0.0: {} strip-final-newline@3.0.0: {} + strip-indent@1.0.1: + dependencies: + get-stdin: 4.0.1 + strip-json-comments@3.1.1: {} + striptags@3.2.0: {} + + strnum@1.1.2: {} + strtok3@10.3.5: dependencies: '@tokenizer/token': 0.3.0 + strtok3@7.1.1: + dependencies: + '@tokenizer/token': 0.3.0 + peek-readable: 5.4.2 + + style-object-to-css-string@1.1.3: {} + + stylis@4.2.0: {} + + success-symbol@0.1.0: {} + sucrase@3.35.1: dependencies: '@jridgewell/gen-mapping': 0.3.13 @@ -18932,7 +22390,7 @@ snapshots: formidable: 3.5.4 methods: 1.1.2 mime: 2.6.0 - qs: 6.15.1 + qs: 6.15.2 transitivePeerDependencies: - supports-color @@ -18944,6 +22402,14 @@ snapshots: transitivePeerDependencies: - supports-color + supports-color@4.5.0: + dependencies: + has-flag: 2.0.0 + + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -18954,21 +22420,38 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + svg-arc-to-cubic-bezier@3.2.0: {} + + svg-pathdata@6.0.3: + optional: true + swagger-ui-dist@5.17.14: {} - swagger-ui-dist@5.32.4: + swagger-ui-dist@5.32.6: dependencies: '@scarf/scarf': 1.4.0 swagger-ui-express@5.0.1(express@5.2.1): dependencies: express: 5.2.1 - swagger-ui-dist: 5.32.4 + swagger-ui-dist: 5.32.6 symbol-observable@4.0.0: {} symbol-tree@3.2.4: {} + tabbable@6.4.0: {} + + tailwind-merge@3.6.0: {} + + tailwind-scrollbar-hide@4.0.0(tailwindcss@4.3.0): + dependencies: + tailwindcss: 4.3.0 + + tailwindcss-animate@1.0.7(tailwindcss@4.3.0): + dependencies: + tailwindcss: 4.3.0 + tailwindcss@3.4.19(yaml@2.9.0): dependencies: '@alloc/quick-lru': 5.2.0 @@ -18985,11 +22468,11 @@ snapshots: normalize-path: 3.0.0 object-hash: 3.0.0 picocolors: 1.1.1 - postcss: 8.5.14 - postcss-import: 15.1.0(postcss@8.5.14) - postcss-js: 4.1.0(postcss@8.5.14) - postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.14)(yaml@2.9.0) - postcss-nested: 6.2.0(postcss@8.5.14) + postcss: 8.5.15 + postcss-import: 15.1.0(postcss@8.5.15) + postcss-js: 4.1.0(postcss@8.5.15) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.15)(yaml@2.9.0) + postcss-nested: 6.2.0(postcss@8.5.15) postcss-selector-parser: 6.1.2 resolve: 1.22.12 sucrase: 3.35.1 @@ -18997,8 +22480,20 @@ snapshots: - tsx - yaml + tailwindcss@4.3.0: {} + + tapable@0.2.9: {} + tapable@2.3.3: {} + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.5 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + tar@6.2.1: dependencies: chownr: 2.0.0 @@ -19013,16 +22508,32 @@ snapshots: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 - terser: 5.47.1 + terser: 5.48.0 webpack: 5.106.0 - terser@5.47.1: + terser@5.48.0: dependencies: '@jridgewell/source-map': 0.3.11 acorn: 8.16.0 commander: 2.20.3 source-map-support: 0.5.21 + tesseract.js-core@7.0.0: {} + + tesseract.js@7.0.0: + dependencies: + bmp-js: 0.1.0 + idb-keyval: 6.2.4 + is-url: 1.2.4 + node-fetch: 2.7.0 + opencollective-postinstall: 2.0.3 + regenerator-runtime: 0.13.11 + tesseract.js-core: 7.0.0 + wasm-feature-detect: 1.8.0 + zlibjs: 0.3.1 + transitivePeerDependencies: + - encoding + test-exclude@6.0.0: dependencies: '@istanbuljs/schema': 0.1.6 @@ -19031,6 +22542,10 @@ snapshots: text-extensions@2.4.0: {} + text-segmentation@1.0.3: + dependencies: + utrie: 1.0.2 + text-table@0.2.0: {} thenify-all@1.6.0: @@ -19041,8 +22556,31 @@ snapshots: dependencies: any-promise: 1.3.0 + through2@2.0.5: + dependencies: + readable-stream: 2.3.8 + xtend: 4.0.2 + + through2@4.0.2: + dependencies: + readable-stream: 3.6.2 + through@2.3.8: {} + thunky@1.1.0: {} + + time-stamp@1.1.0: {} + + time-stamp@2.2.0: {} + + timers-browserify@2.0.12: + dependencies: + setimmediate: 1.0.5 + + tiny-inflate@1.0.3: {} + + tiny-invariant@1.3.3: {} + tinybench@2.9.0: {} tinyexec@0.3.2: {} @@ -19054,6 +22592,8 @@ snapshots: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 + tinymce@7.9.3: {} + tinypool@1.1.1: {} tinyrainbow@1.2.0: {} @@ -19066,26 +22606,58 @@ snapshots: dependencies: tldts-core: 6.1.86 + tmp@0.2.5: {} + tmpl@1.0.5: {} + to-arraybuffer@1.0.1: {} + to-buffer@1.2.2: dependencies: isarray: 2.0.5 safe-buffer: 5.2.1 typed-array-buffer: 1.0.3 + to-gfm-code-block@0.1.1: {} + + to-object-path@0.3.0: + dependencies: + kind-of: 3.2.2 + + to-regex-range@2.1.1: + dependencies: + is-number: 3.0.0 + repeat-string: 1.6.1 + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 + to-regex@3.0.2: + dependencies: + define-property: 2.0.2 + extend-shallow: 3.0.2 + regex-not: 1.0.2 + safe-regex: 1.1.0 + toidentifier@1.0.1: {} + token-types@5.0.1: + dependencies: + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + token-types@6.1.2: dependencies: '@borewit/text-codec': 0.2.2 '@tokenizer/token': 0.3.0 ieee754: 1.2.1 + tough-cookie@2.5.0: + dependencies: + psl: 1.15.0 + punycode: 2.3.1 + tough-cookie@5.1.2: dependencies: tldts: 6.1.86 @@ -19096,13 +22668,29 @@ snapshots: dependencies: punycode: 2.3.1 + traverse@0.3.9: {} + + tree-changes@0.11.3: + dependencies: + '@gilbarbara/deep-equal': 0.3.1 + is-lite: 1.2.1 + + tree-changes@0.9.3: + dependencies: + '@gilbarbara/deep-equal': 0.1.2 + is-lite: 0.8.2 + + trim-canvas@0.1.2: {} + + trim-newlines@1.0.0: {} + ts-api-utils@2.5.0(typescript@5.9.3): dependencies: typescript: 5.9.3 ts-interface-checker@0.1.13: {} - ts-jest@29.4.9(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.41)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)))(typescript@5.9.3): + ts-jest@29.4.11(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.41)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 @@ -19111,7 +22699,7 @@ snapshots: json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 - semver: 7.8.0 + semver: 7.8.1 type-fest: 4.41.0 typescript: 5.9.3 yargs-parser: 21.1.1 @@ -19122,6 +22710,16 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.29.0) jest-util: 29.7.0 + ts-loader@9.5.7(typescript@5.9.3)(webpack@5.106.0): + dependencies: + chalk: 4.1.2 + enhanced-resolve: 5.21.6 + micromatch: 4.0.8 + semver: 7.8.1 + source-map: 0.7.6 + typescript: 5.9.3 + webpack: 5.106.0 + ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -19143,7 +22741,7 @@ snapshots: tsconfig-paths-webpack-plugin@4.2.0: dependencies: chalk: 4.1.2 - enhanced-resolve: 5.21.3 + enhanced-resolve: 5.21.6 tapable: 2.3.3 tsconfig-paths: 4.2.0 @@ -19162,14 +22760,22 @@ snapshots: tslib@2.8.1: {} - turbo@2.9.12: + tty-browserify@0.0.0: {} + + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + + turbo@2.9.14: optionalDependencies: - '@turbo/darwin-64': 2.9.12 - '@turbo/darwin-arm64': 2.9.12 - '@turbo/linux-64': 2.9.12 - '@turbo/linux-arm64': 2.9.12 - '@turbo/windows-64': 2.9.12 - '@turbo/windows-arm64': 2.9.12 + '@turbo/darwin-64': 2.9.14 + '@turbo/darwin-arm64': 2.9.14 + '@turbo/linux-64': 2.9.14 + '@turbo/linux-arm64': 2.9.14 + '@turbo/windows-64': 2.9.14 + '@turbo/windows-arm64': 2.9.14 + + tweetnacl@0.14.5: {} type-check@0.4.0: dependencies: @@ -19188,12 +22794,14 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 - type-is@2.0.1: + type-is@2.1.0: dependencies: - content-type: 1.0.5 + content-type: 2.0.0 media-typer: 1.1.0 mime-types: 3.0.2 + type@2.7.3: {} + typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.4 @@ -19229,7 +22837,24 @@ snapshots: typedarray@0.0.6: {} - typeorm@0.3.29(babel-plugin-macros@3.1.0)(mysql2@3.15.3)(pg@8.20.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)): + typeof-article@0.1.1: + dependencies: + kind-of: 3.2.2 + + typeorm-extension@3.9.0(@faker-js/faker@10.4.0)(typeorm@0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))): + dependencies: + '@faker-js/faker': 10.4.0 + consola: 3.4.2 + envix: 1.5.0 + locter: 2.2.1 + pascal-case: 3.1.2 + rapiq: 0.9.0 + reflect-metadata: 0.2.2 + smob: 1.6.2 + typeorm: 0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) + yargs: 18.0.0 + + typeorm@0.3.30(babel-plugin-macros@3.1.0)(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)): dependencies: '@sqltools/formatter': 1.2.5 ansis: 4.3.0 @@ -19247,8 +22872,7 @@ snapshots: uuid: 11.1.1 yargs: 17.7.2 optionalDependencies: - mysql2: 3.15.3 - pg: 8.20.0 + pg: 8.21.0 ts-node: 10.9.2(@types/node@20.19.41)(typescript@5.9.3) transitivePeerDependencies: - babel-plugin-macros @@ -19256,9 +22880,26 @@ snapshots: typescript@5.9.3: {} + uglify-js@2.8.29: + dependencies: + source-map: 0.5.7 + yargs: 3.10.0 + optionalDependencies: + uglify-to-browserify: 1.0.2 + uglify-js@3.19.3: optional: true + uglify-to-browserify@1.0.2: + optional: true + + uglifyjs-webpack-plugin@0.4.6(webpack@3.12.0): + dependencies: + source-map: 0.5.7 + uglify-js: 2.8.29 + webpack: 3.12.0 + webpack-sources: 1.4.3 + uid@2.0.2: dependencies: '@lukeed/csprng': 1.1.0 @@ -19276,18 +22917,61 @@ snapshots: undici-types@7.16.0: {} + unicode-properties@1.4.1: + dependencies: + base64-js: 1.5.1 + unicode-trie: 2.0.0 + + unicode-trie@2.0.0: + dependencies: + pako: 0.2.9 + tiny-inflate: 1.0.3 + unicorn-magic@0.1.0: {} + union-value@1.0.1: + dependencies: + arr-union: 3.1.0 + get-value: 2.0.6 + is-extendable: 0.1.1 + set-value: 2.0.1 + + universal-cookie@8.1.2: + dependencies: + cookie: 1.1.1 + universalify@2.0.1: {} unpipe@1.0.0: {} + unset-value@1.0.0: + dependencies: + has-value: 0.3.1 + isobject: 3.0.1 + + unzipper@0.10.14: + dependencies: + big-integer: 1.6.52 + binary: 0.3.0 + bluebird: 3.4.7 + buffer-indexof-polyfill: 1.0.2 + duplexer2: 0.1.4 + fstream: 1.0.12 + graceful-fs: 4.2.11 + listenercount: 1.0.1 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + + upath@1.2.0: {} + update-browserslist-db@1.2.3(browserslist@4.28.2): dependencies: browserslist: 4.28.2 escalade: 3.2.0 picocolors: 1.1.1 + uqr@0.1.2: {} + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -19302,41 +22986,41 @@ snapshots: url@0.11.4: dependencies: punycode: 1.4.1 - qs: 6.15.1 + qs: 6.15.2 - use-callback-ref@1.3.3(@types/react@18.3.28)(react@19.2.6): + use-callback-ref@1.3.3(@types/react@18.3.29)(react@19.2.6): dependencies: react: 19.2.6 tslib: 2.8.1 optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 - use-composed-ref@1.4.0(@types/react@18.3.28)(react@19.2.6): + use-composed-ref@1.4.0(@types/react@18.3.29)(react@19.2.6): dependencies: react: 19.2.6 optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 - use-isomorphic-layout-effect@1.2.1(@types/react@18.3.28)(react@19.2.6): + use-isomorphic-layout-effect@1.2.1(@types/react@18.3.29)(react@19.2.6): dependencies: react: 19.2.6 optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 - use-latest@1.3.0(@types/react@18.3.28)(react@19.2.6): + use-latest@1.3.0(@types/react@18.3.29)(react@19.2.6): dependencies: react: 19.2.6 - use-isomorphic-layout-effect: 1.2.1(@types/react@18.3.28)(react@19.2.6) + use-isomorphic-layout-effect: 1.2.1(@types/react@18.3.29)(react@19.2.6) optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 - use-sidecar@1.1.3(@types/react@18.3.28)(react@19.2.6): + use-sidecar@1.1.3(@types/react@18.3.29)(react@19.2.6): dependencies: detect-node-es: 1.1.0 react: 19.2.6 tslib: 2.8.1 optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 use-sync-external-store@1.6.0(react@18.3.1): dependencies: @@ -19351,10 +23035,34 @@ snapshots: util-deprecate@1.0.2: {} + util@0.10.4: + dependencies: + inherits: 2.0.3 + + util@0.11.1: + dependencies: + inherits: 2.0.3 + + util@0.12.5: + dependencies: + inherits: 2.0.4 + is-arguments: 1.2.0 + is-generator-function: 1.1.2 + is-typed-array: 1.1.15 + which-typed-array: 1.1.20 + utils-merge@1.0.1: {} + utrie@1.0.2: + dependencies: + base64-arraybuffer: 1.0.2 + uuid@11.1.1: {} + uuid@3.4.0: {} + + uuid@8.3.2: {} + v8-compile-cache-lib@3.0.1: {} v8-to-istanbul@9.3.0: @@ -19363,13 +23071,18 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 + validate-npm-package-license@3.0.4: + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + validator@13.15.35: {} vary@1.1.2: {} - vaul@1.1.2(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + vaul@1.1.2(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.28))(@types/react@18.3.28)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: @@ -19405,13 +23118,13 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 - vite-node@2.1.9(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1): + vite-node@2.1.9(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0): dependencies: cac: 6.7.14 debug: 4.4.3(supports-color@5.5.0) es-module-lexer: 1.7.0 pathe: 1.1.2 - vite: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1) + vite: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0) transitivePeerDependencies: - '@types/node' - less @@ -19423,21 +23136,21 @@ snapshots: - supports-color - terser - vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1): + vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0): dependencies: esbuild: 0.21.5 - postcss: 8.5.14 - rollup: 4.60.3 + postcss: 8.5.15 + rollup: 4.60.4 optionalDependencies: '@types/node': 24.12.4 fsevents: 2.3.3 lightningcss: 1.32.0 - terser: 5.47.1 + terser: 5.48.0 - vitest@2.1.9(@types/node@24.12.4)(jsdom@25.0.1)(lightningcss@1.32.0)(terser@5.47.1): + vitest@2.1.9(@types/node@24.12.4)(jsdom@25.0.1)(lightningcss@1.32.0)(terser@5.48.0): dependencies: '@vitest/expect': 2.1.9 - '@vitest/mocker': 2.1.9(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1)) + '@vitest/mocker': 2.1.9(vite@5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0)) '@vitest/pretty-format': 2.1.9 '@vitest/runner': 2.1.9 '@vitest/snapshot': 2.1.9 @@ -19453,8 +23166,8 @@ snapshots: tinyexec: 0.3.2 tinypool: 1.1.1 tinyrainbow: 1.2.0 - vite: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1) - vite-node: 2.1.9(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.47.1) + vite: 5.4.21(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0) + vite-node: 2.1.9(@types/node@24.12.4)(lightningcss@1.32.0)(terser@5.48.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.12.4 @@ -19470,6 +23183,12 @@ snapshots: - supports-color - terser + vm-browserify@1.1.2: {} + + void-elements@3.1.0: {} + + w3c-keyname@2.2.8: {} + w3c-xmlserializer@5.0.0: dependencies: xml-name-validator: 5.0.0 @@ -19478,11 +23197,40 @@ snapshots: dependencies: makeerror: 1.0.12 + warning-symbol@0.1.0: {} + + warning@4.0.3: + dependencies: + loose-envify: 1.4.0 + + wasm-feature-detect@1.8.0: {} + + watchpack-chokidar2@2.0.1(supports-color@4.5.0): + dependencies: + chokidar: 2.1.8(supports-color@4.5.0) + transitivePeerDependencies: + - supports-color + optional: true + + watchpack@1.7.5(supports-color@4.5.0): + dependencies: + graceful-fs: 4.2.11 + neo-async: 2.6.2 + optionalDependencies: + chokidar: 3.6.0 + watchpack-chokidar2: 2.0.1(supports-color@4.5.0) + transitivePeerDependencies: + - supports-color + watchpack@2.5.1: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 + wbuf@1.7.3: + dependencies: + minimalistic-assert: 1.0.1 + wcwidth@1.0.1: dependencies: defaults: 1.0.4 @@ -19499,10 +23247,80 @@ snapshots: webidl-conversions@7.0.0: {} + webpack-dev-middleware@1.12.2(webpack@3.12.0): + dependencies: + memory-fs: 0.4.1 + mime: 1.6.0 + path-is-absolute: 1.0.1 + range-parser: 1.2.1 + time-stamp: 2.2.0 + webpack: 3.12.0 + + webpack-dev-server@2.11.5(webpack@3.12.0): + dependencies: + ansi-html: 0.0.7 + array-includes: 3.1.9 + bonjour: 3.5.1 + chokidar: 2.1.8(supports-color@5.5.0) + compression: 1.8.1(supports-color@5.5.0) + connect-history-api-fallback: 1.6.0 + debug: 3.2.7(supports-color@5.5.0) + del: 3.0.0 + express: 4.22.2(supports-color@5.5.0) + html-entities: 1.4.0 + http-proxy-middleware: 0.19.2(debug@3.2.7(supports-color@5.5.0))(supports-color@5.5.0) + import-local: 1.0.0 + internal-ip: 1.2.0 + ip: 1.1.9 + killable: 1.0.1 + loglevel: 1.9.2 + opn: 5.5.0 + portfinder: 1.0.38(supports-color@5.5.0) + selfsigned: 1.10.14 + serve-index: 1.9.2(supports-color@5.5.0) + sockjs: 0.3.19 + sockjs-client: 1.1.5(supports-color@5.5.0) + spdy: 4.0.2(supports-color@5.5.0) + strip-ansi: 3.0.1 + supports-color: 5.5.0 + webpack: 3.12.0 + webpack-dev-middleware: 1.12.2(webpack@3.12.0) + yargs: 6.6.0 + webpack-node-externals@3.0.0: {} + webpack-sources@1.4.3: + dependencies: + source-list-map: 2.0.1 + source-map: 0.6.1 + webpack-sources@3.4.1: {} + webpack@3.12.0: + dependencies: + acorn: 5.7.4 + acorn-dynamic-import: 2.0.2 + ajv: 6.15.0 + ajv-keywords: 3.5.2(ajv@6.15.0) + async: 2.6.4 + enhanced-resolve: 3.4.1 + escope: 3.6.0 + interpret: 1.4.0 + json-loader: 0.5.7 + json5: 0.5.1 + loader-runner: 2.4.0 + loader-utils: 1.4.2 + memory-fs: 0.4.1 + mkdirp: 0.5.6 + node-libs-browser: 2.2.1 + source-map: 0.5.7 + supports-color: 4.5.0 + tapable: 0.2.9 + uglifyjs-webpack-plugin: 0.4.6(webpack@3.12.0) + watchpack: 1.7.5(supports-color@4.5.0) + webpack-sources: 1.4.3 + yargs: 8.0.2 + webpack@5.106.0: dependencies: '@types/eslint-scope': 3.7.7 @@ -19515,7 +23333,7 @@ snapshots: acorn-import-phases: 1.0.4(acorn@8.16.0) browserslist: 4.28.2 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.21.3 + enhanced-resolve: 5.21.6 es-module-lexer: 2.1.0 eslint-scope: 5.1.1 events: 3.3.0 @@ -19544,6 +23362,14 @@ snapshots: - postcss - uglify-js + websocket-driver@0.7.4: + dependencies: + http-parser-js: 0.5.10 + safe-buffer: 5.2.1 + websocket-extensions: 0.1.4 + + websocket-extensions@0.1.4: {} + whatwg-encoding@3.1.1: dependencies: iconv-lite: 0.6.3 @@ -19591,6 +23417,8 @@ snapshots: is-weakmap: 2.0.2 is-weakset: 2.0.4 + which-module@1.0.0: {} + which-module@2.0.1: {} which-typed-array@1.1.20: @@ -19603,6 +23431,10 @@ snapshots: gopd: 1.2.0 has-tostringtag: 1.0.2 + which@1.3.1: + dependencies: + isexe: 2.0.0 + which@2.0.2: dependencies: isexe: 2.0.0 @@ -19616,10 +23448,23 @@ snapshots: dependencies: string-width: 4.2.3 + window-size@0.1.0: {} + + wmf@1.0.2: {} + word-wrap@1.2.5: {} + word@0.3.0: {} + + wordwrap@0.0.2: {} + wordwrap@1.0.0: {} + wrap-ansi@2.1.0: + dependencies: + string-width: 1.0.2 + strip-ansi: 3.0.1 + wrap-ansi@6.2.0: dependencies: ansi-styles: 4.3.0 @@ -19651,25 +23496,48 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 3.0.7 - ws@8.20.0: {} + ws@8.20.1: {} + + xlsx@0.18.5: + dependencies: + adler-32: 1.3.1 + cfb: 1.2.2 + codepage: 1.15.0 + crc-32: 1.2.2 + ssf: 0.11.2 + wmf: 1.0.2 + word: 0.3.0 xml-name-validator@5.0.0: {} + xml2js@0.5.0: + dependencies: + sax: 1.6.0 + xmlbuilder: 11.0.1 + + xml@1.0.1: {} + + xmlbuilder@11.0.1: {} + xmlchars@2.2.0: {} - xtend@4.0.2: - optional: true + xmlhttprequest-ssl@2.1.2: {} + + xtend@4.0.2: {} + + y18n@3.2.2: {} y18n@4.0.3: {} y18n@5.0.8: {} + yallist@2.1.2: {} + yallist@3.1.1: {} yallist@4.0.0: {} - yaml@1.10.3: - optional: true + yaml@1.10.3: {} yaml@2.9.0: {} @@ -19680,6 +23548,16 @@ snapshots: yargs-parser@21.1.1: {} + yargs-parser@22.0.0: {} + + yargs-parser@4.2.1: + dependencies: + camelcase: 3.0.0 + + yargs-parser@7.0.0: + dependencies: + camelcase: 4.1.0 + yargs@15.4.1: dependencies: cliui: 6.0.0 @@ -19704,6 +23582,56 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yargs@18.0.0: + dependencies: + cliui: 9.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + string-width: 7.2.0 + y18n: 5.0.8 + yargs-parser: 22.0.0 + + yargs@3.10.0: + dependencies: + camelcase: 1.2.1 + cliui: 2.1.0 + decamelize: 1.2.0 + window-size: 0.1.0 + + yargs@6.6.0: + dependencies: + camelcase: 3.0.0 + cliui: 3.2.0 + decamelize: 1.2.0 + get-caller-file: 1.0.3 + os-locale: 1.4.0 + read-pkg-up: 1.0.1 + require-directory: 2.1.1 + require-main-filename: 1.0.1 + set-blocking: 2.0.0 + string-width: 1.0.2 + which-module: 1.0.0 + y18n: 3.2.2 + yargs-parser: 4.2.1 + + yargs@8.0.2: + dependencies: + camelcase: 4.1.0 + cliui: 3.2.0 + decamelize: 1.2.0 + get-caller-file: 1.0.3 + os-locale: 2.1.0 + read-pkg-up: 2.0.0 + require-directory: 2.1.1 + require-main-filename: 1.0.1 + set-blocking: 2.0.0 + string-width: 2.1.1 + which-module: 2.0.1 + y18n: 3.2.2 + yargs-parser: 7.0.0 + + year@0.2.1: {} + yn@3.1.1: {} yocto-queue@0.1.0: {} @@ -19712,9 +23640,21 @@ snapshots: yoctocolors-cjs@2.1.3: {} - zustand@5.0.13(@types/react@18.3.28)(immer@11.1.8)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)): + yoga-layout@3.2.1: {} + + zip-stream@4.1.1: + dependencies: + archiver-utils: 3.0.4 + compress-commons: 4.1.2 + readable-stream: 3.6.2 + + zlibjs@0.3.1: {} + + zod@3.25.76: {} + + zustand@5.0.13(@types/react@18.3.29)(immer@11.1.8)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)): optionalDependencies: - '@types/react': 18.3.28 + '@types/react': 18.3.29 immer: 11.1.8 react: 18.3.1 use-sync-external-store: 1.6.0(react@18.3.1) From f803748278d7609bd9cd1403fbfef0911395ca43 Mon Sep 17 00:00:00 2001 From: Stephanos A Date: Sun, 24 May 2026 16:20:55 +0300 Subject: [PATCH 26/38] Nationality, guest booking, waafi adapter, overall booking flow updates --- README.md | 141 ++-- apps/edr-passenger-api/.env.example | 10 +- apps/edr-passenger-api/REFACTORING_SUMMARY.md | 199 ----- .../migration.sql | 5 + .../migration.sql | 28 + .../migrations/add_guest_booking_support.sql | 30 + apps/edr-passenger-api/prisma/schema.prisma | 24 + apps/edr-passenger-api/prisma/seed.ts | 690 ++++++++++++++---- apps/edr-passenger-api/src/app.module.ts | 3 +- .../src/config/waafi.config.ts | 10 + apps/edr-passenger-api/src/main.ts | 104 ++- .../modules/bookings/bookings.controller.ts | 76 +- .../src/modules/bookings/bookings.dto.ts | 19 +- .../src/modules/bookings/bookings.module.ts | 5 +- .../src/modules/bookings/bookings.service.ts | 91 ++- .../src/modules/bookings/guest-booking.dto.ts | 91 +++ .../modules/bookings/guest-booking.service.ts | 333 +++++++++ .../passengers/passengers.controller.ts | 115 ++- .../src/modules/passengers/passengers.dto.ts | 51 +- .../modules/passengers/passengers.module.ts | 7 +- .../modules/passengers/passengers.service.ts | 28 +- .../modules/payments/payments.controller.ts | 45 +- .../src/modules/payments/payments.dto.ts | 19 +- .../src/modules/payments/payments.module.ts | 4 + .../src/modules/payments/payments.service.ts | 3 + .../src/modules/payments/payments.types.ts | 4 +- .../payments/providers/waafi.provider.ts | 276 +++++++ .../webhooks/waafi-webhook.service.ts | 105 +++ .../payments/webhooks/webhooks.controller.ts | 38 +- .../src/modules/schedules/schedules.dto.ts | 3 +- .../modules/schedules/schedules.service.ts | 3 +- .../src/modules/search/search.controller.ts | 38 +- .../src/modules/search/search.dto.ts | 16 +- .../src/modules/search/search.service.ts | 95 ++- .../src/modules/seats/seats.controller.ts | 23 +- .../modules/stations/stations.controller.ts | 22 +- .../src/modules/tickets/tickets.controller.ts | 16 +- 37 files changed, 2284 insertions(+), 486 deletions(-) delete mode 100644 apps/edr-passenger-api/REFACTORING_SUMMARY.md create mode 100644 apps/edr-passenger-api/prisma/migrations/20260524080651_add_nationality_and_waafi/migration.sql create mode 100644 apps/edr-passenger-api/prisma/migrations/20260524091255_add_guest_booking_support/migration.sql create mode 100644 apps/edr-passenger-api/prisma/migrations/add_guest_booking_support.sql create mode 100644 apps/edr-passenger-api/src/config/waafi.config.ts create mode 100644 apps/edr-passenger-api/src/modules/bookings/guest-booking.dto.ts create mode 100644 apps/edr-passenger-api/src/modules/bookings/guest-booking.service.ts create mode 100644 apps/edr-passenger-api/src/modules/payments/providers/waafi.provider.ts create mode 100644 apps/edr-passenger-api/src/modules/payments/webhooks/waafi-webhook.service.ts diff --git a/README.md b/README.md index 0a47b6a90..63e3c6b8b 100644 --- a/README.md +++ b/README.md @@ -45,9 +45,18 @@ Enterprise-grade NestJS REST API for the Ethio-Djibouti Railway passenger bookin - **DJF** (Djiboutian Franc) - Display option - **USD** (US Dollar) - Display option - Real-time exchange rate conversion -- **Booking Management** - Complete booking lifecycle with modification, cancellation, refunds, and fare breakdown +- **Booking Management** - Complete booking lifecycle: + - **Guest Booking**: Book without login, optional account creation + - **Saved Passengers**: Store passenger details for quick rebooking + - Modification, cancellation, refunds, and fare breakdown + - Multi-segment journey support - **Payment Integration** - Multi-provider support (Telebirr, CBE Birr, eBirr, Card, Wallet) with webhook handling -- **Seat Management** - Real-time seat inventory, holds, releases, and blocking with coach/class management +- **Seat Management** - Real-time seat inventory: + - Seat holds with 15-minute expiry + - Seat releases and blocking with coach/class management + - Segment-based seat availability (partial journey bookings) + - Auto-assign seats with contiguous algorithm + - CSV import/export for seat configurations - **Ticketing** - QR code and barcode generation, PDF tickets, gate validation with audit logs - **Agent Operations** - Counter booking, shift management, commission tracking, and reconciliation - **Passenger Services** - Profile management, traveler profiles, saved routes, and preferences @@ -173,7 +182,7 @@ pnpm --filter @edr/passenger-api run prisma:seed - 21 Stations (Complete Ethiopian-Djibouti Railway with country codes) - 1 Route with 21 stops and fare rules - 2 Train services with 4 trips -- 360 seats across 12 coaches (Economy, Bed, VIP classes) +- 360 seats across 12 coaches (Economy Regular, Economy Bed, VIP Bed classes) - 3 User accounts (Admin, Passenger, Agent) - Fare rules for ADULT and CHILD passenger categories - Currency exchange rates (ETB, DJF, USD) @@ -182,6 +191,7 @@ pnpm --filter @edr/passenger-api run prisma:seed - Promotions and FAQ content - Menu items and station crowd signals - Fraud detection rules +- Saved passenger profiles for testing ### 5. Start Development Server ```bash @@ -228,25 +238,28 @@ The API uses two authentication schemes: | Module | Base Path | Auth Type | Description | |--------|-----------|-----------|-------------| | **Auth** | `/auth` | Public/JWT | Register, login, OTP verification, password reset | -| **Agents** | `/agents` | IAM | Agent booking, shifts, commissions, reconciliation | -| **Fraud Detection** | `/fraud` | IAM | Fraud alerts, rules management, user blocking | -| **Reports** | `/reports` | IAM | Revenue, occupancy, agent sales analytics | -| **Stations** | `/stations` | JWT | Station directory and information | -| **Fleet** | `/fleet` | JWT/IAM | Train services, coaches, seat configurations | -| **Schedules** | `/schedules` | JWT/IAM | Trip schedules, fare rules, status updates | -| **Search** | `/search` | JWT | Trip search, availability, fare quotes | +| **Passengers** | `/passengers` | Public/JWT | Verifayda verification, international registration, profiles | +| **Search** | `/search` | Public | Trip search, availability, fare quotes | +| **Stations** | `/stations` | Public/JWT | Station directory and information | | **Seats** | `/seats` | JWT/IAM | Seat maps, holds, releases, blocking | -| **Bookings** | `/bookings` | JWT | Create, modify, cancel bookings | +| **Bookings** | `/bookings` | Public/JWT | Guest booking, create, modify, cancel bookings | | **Payments** | `/payments` | JWT/Public | Payment initiation, webhooks, refunds | | **Tickets** | `/tickets` | JWT/IAM | Ticket generation, QR/barcode, validation | -| **Passengers** | `/passengers` | JWT | Profile management, traveler profiles | | **Notifications** | `/notifications` | JWT | In-app notifications, preferences | | **Loyalty** | `/loyalty` | JWT | Points, tiers, rewards redemption | | **Wallet** | `/wallet` | JWT | Balance, top-up, transaction history | -| **Promotions** | `/promos` | JWT | Active promotions, promo code validation | -| **Live Tracking** | `/live` | JWT | Real-time trip status, crowd signals | -| **Support** | `/support` | JWT | FAQ, chat conversations | +| **Promotions** | `/promos` | Public/JWT | Active promotions, promo code validation | +| **Live Tracking** | `/live` | Public/JWT | Real-time trip status, crowd signals | +| **Support** | `/support` | Public/JWT | FAQ, chat conversations | | **Dashboard** | `/dashboard` | JWT | Home screen aggregated data | +| **Routes** | `/routes` | JWT/IAM | Reusable route templates with ordered stops | +| **Schedules** | `/schedules` | JWT/IAM | Trip schedules, fare rules, status updates | +| **Fleet** | `/fleet` | JWT/IAM | Train services, coaches, seat configurations | +| **Seat Classes** | `/seat-classes` | Public/JWT/IAM | Seat class management and configuration | +| **Segment Seats** | `/segments/seats` | Public/JWT | Segment-based seat availability and booking | +| **Agents** | `/agents` | IAM | Agent booking, shifts, commissions, reconciliation | +| **Fraud Detection** | `/fraud` | IAM | Fraud alerts, rules management, user blocking | +| **Reports** | `/reports` | IAM | Revenue, occupancy, agent sales analytics | ### Example API Calls @@ -280,30 +293,60 @@ Content-Type: application/json } ``` -#### 2b. Agent Booking (IAM Auth) +#### 3. Verify Ethiopian National ID (Verifayda) ```bash -POST /agents/bookings -Authorization: Bearer +POST /passengers/verify-fayda Content-Type: application/json { - "tripId": "uuid", - "seats": [...], - "paymentMethod": "CASH", - "cashReceived": 50000 + "nationalId": "ET123456789" +} + +# Response with verified passenger data +{ + "verified": true, + "passengerData": { + "fullName": "Abebe Kebede", + "dateOfBirth": "1985-03-15T00:00:00.000Z", + "gender": "Male", + "nationality": "Ethiopian" + } } ``` -#### 3. Search Trips +#### 4. Register International Passenger ```bash -GET /search/trips?originStationId={id}&destinationStationId={id}&date=2026-06-15&adultCount=2&childCount=1 -Authorization: Bearer {token} +POST /passengers/register-international +Content-Type: application/json + +{ + "passengerName": "John Smith", + "dateOfBirth": "1990-07-20", + "passportNumber": "P1234567", + "passportCountry": "Kenya", + "nationality": "Kenyan", + "phone": "+254712345678", + "email": "john@example.com" +} ``` -#### 4. Get Fare Quote +#### 5. Search Trips +```bash +POST /search +Content-Type: application/json + +{ + "originStationId": "uuid", + "destinationStationId": "uuid", + "date": "2026-06-15", + "adultCount": 2, + "childCount": 1 +} +``` + +#### 6. Get Fare Quote ```bash POST /search/fare-quote -Authorization: Bearer {token} Content-Type: application/json { @@ -330,17 +373,16 @@ Content-Type: application/json } ``` -#### 5. Create Booking +#### 7. Guest Booking (No Login Required) ```bash -POST /bookings -Authorization: Bearer {token} +POST /bookings/guest Content-Type: application/json { "tripId": "uuid", "holdId": "uuid", "serviceClass": "ECONOMY_REGULAR", - "displayCurrency": "DJF", + "displayCurrency": "ETB", "passengers": [ { "seatId": "uuid", @@ -348,23 +390,25 @@ Content-Type: application/json "dateOfBirth": "1985-03-15", "idDocumentType": "NATIONAL_ID", "idDocumentNumber": "ET123456789" - }, - { - "seatId": "uuid", - "passengerName": "Sara Abebe", - "dateOfBirth": "2023-01-10", - "idDocumentType": "NATIONAL_ID", - "idDocumentNumber": "ET987654321" - }, - { - "seatId": "uuid", - "passengerName": "John Smith", - "dateOfBirth": "1990-07-20", - "idDocumentType": "PASSPORT", - "passportNumber": "P1234567", - "passportCountry": "Kenya" } - ] + ], + "createAccount": false, + "savePassengerDetails": true, + "deviceId": "device-uuid" +} +``` + +#### 8. Agent Booking (IAM Auth) +```bash +POST /agents/bookings +Authorization: Bearer +Content-Type: application/json + +{ + "tripId": "uuid", + "seats": [...], + "paymentMethod": "CASH", + "cashReceived": 50000 } ``` @@ -453,6 +497,9 @@ apps/edr-passenger-api/ - `SeatBlock`, `SeatHold` - `CurrencyExchangeRate` (Multi-currency) - `VerifaydaVerification` (National ID verification) +- `SavedPassengerProfile` (Guest booking) +- `SeatClass` (Seat class configuration) +- `JourneySegment` (Multi-segment journeys) ## 🔧 Available Scripts diff --git a/apps/edr-passenger-api/.env.example b/apps/edr-passenger-api/.env.example index d0e64691d..75d2df681 100644 --- a/apps/edr-passenger-api/.env.example +++ b/apps/edr-passenger-api/.env.example @@ -65,8 +65,16 @@ CARD_WEBHOOK_SECRET= CARD_WEBHOOK_URL= CARD_RETURN_URL= +# Waafi (Djibouti Mobile Money) +WAAFI_BASE_URL=https://api.waafipay.net +WAAFI_MERCHANT_UID= +WAAFI_API_USER_ID= +WAAFI_API_KEY= +WAAFI_NOTIFY_URL= +WAAFI_RETURN_URL= + # Payment Configuration -PAYMENT_PROVIDERS_ENABLED=TELEBIRR,CBE_BIRR,EBIRR,CARD,WALLET +PAYMENT_PROVIDERS_ENABLED=TELEBIRR,CBE_BIRR,EBIRR,CARD,WALLET,WAAFI # Session Configuration SESSION_INACTIVITY_MINUTES=30 diff --git a/apps/edr-passenger-api/REFACTORING_SUMMARY.md b/apps/edr-passenger-api/REFACTORING_SUMMARY.md deleted file mode 100644 index 30648fa3f..000000000 --- a/apps/edr-passenger-api/REFACTORING_SUMMARY.md +++ /dev/null @@ -1,199 +0,0 @@ -# Train Reservation System Refactoring - Complete - -## ✅ Refactoring Summary - -Successfully refactored the train reservation system from an incorrect tight-coupling model to a flexible, realistic railway architecture. - ---- - -## 🔄 Architecture Changes - -### Before (Incorrect) -``` -TrainService → Trip → Coach → Seat -``` -- Coaches were permanently bound to specific trips -- No reusability of physical coaches -- Inflexible train composition - -### After (Correct) -``` -Train → TrainSchedule ↔ CoachAssignment ↔ Coach → Seat -``` -- **Train**: Logical service entity (e.g., "Express 301") -- **TrainSchedule**: Specific journey with date/time -- **Coach**: Physical reusable railway carriage -- **CoachAssignment**: Join table linking schedules to coaches -- **Seat**: Belongs strictly to physical coach - ---- - -## 📋 Files Modified - -### Schema & Database -- ✅ `prisma/schema.prisma` - Complete entity redesign -- ✅ `prisma/seed.ts` - Rewritten for new architecture - -### DTOs -- ✅ `fleet/fleet.dto.ts` - New Train/Coach/Assignment DTOs -- ✅ `schedules/schedules.dto.ts` - TrainSchedule DTOs -- ✅ `bookings/bookings.dto.ts` - scheduleId instead of tripId - -### Services -- ✅ `fleet/fleet.service.ts` - Physical coach management -- ✅ `fleet/fleet.controller.ts` - New endpoints -- ✅ `schedules/schedules.service.ts` - TrainSchedule operations -- ✅ `schedules/schedules.controller.ts` - Updated routes -- ✅ `bookings/bookings.service.ts` - scheduleId references -- ✅ `seats/seats.service.ts` - CoachAssignment queries -- ✅ `search/search.service.ts` - TrainSchedule search -- ✅ `segments/segments.service.ts` - scheduleId throughout -- ✅ `segments/enhanced-seats.service.ts` - Fixed references -- ✅ `passengers/passengers.service.ts` - schedule.train -- ✅ `live/live.service.ts` - TrainSchedule live tracking -- ✅ `live/live.controller.ts` - scheduleId routes -- ✅ `dashboard/dashboard.service.ts` - schedule references -- ✅ `reports/reports.service.ts` - Occupancy with assignments - ---- - -## 🗄️ Database Schema Changes - -### New Models -```prisma -model Train { - id String @id @default(uuid()) - number String @unique - name String - schedules TrainSchedule[] -} - -model TrainSchedule { - id String @id @default(uuid()) - trainId String - departureAt DateTime - train Train @relation(...) - coachAssignments CoachAssignment[] -} - -model Coach { - id String @id @default(uuid()) - coachNumber String @unique // Physical identifier - label String - seatClassId String - mode String // 'seat', 'bed', 'convertible' - totalUnits Int - seats Seat[] - assignments CoachAssignment[] -} - -model CoachAssignment { - id String @id @default(uuid()) - scheduleId String - coachId String - positionNumber Int - schedule TrainSchedule @relation(...) - coach Coach @relation(...) -} -``` - -### Renamed Models -- `TrainService` → `Train` -- `Trip` → `TrainSchedule` -- `TripStopTime.tripId` → `scheduleId` -- `TripLiveStatus.tripId` → `scheduleId` -- `Booking.tripId` → `scheduleId` -- `SeatHold.tripId` → `scheduleId` -- `MenuItem.tripId` → `scheduleId` -- `JourneySegment.tripId` → `scheduleId` - ---- - -## 🎯 Key Benefits - -1. **Reusability**: Physical coaches can be assigned to different schedules -2. **Flexibility**: Train composition can change per schedule -3. **Realistic**: Matches real-world railway operations -4. **Maintainability**: Clear separation of logical vs physical entities -5. **Scalability**: Easy to add/remove coaches from schedules - ---- - -## 🚂 Example Usage - -### Creating a Physical Coach -```typescript -const coach = await prisma.coach.create({ - data: { - coachNumber: 'C-A1', - label: 'A', - seatClassId: economyClassId, - mode: 'seat', - totalUnits: 60, - }, -}); -``` - -### Assigning Coach to Schedule -```typescript -await prisma.coachAssignment.create({ - data: { - scheduleId: schedule1.id, - coachId: coach.id, - positionNumber: 1, - }, -}); -``` - -### Querying Schedule with Coaches -```typescript -const schedule = await prisma.trainSchedule.findUnique({ - where: { id: scheduleId }, - include: { - train: true, - coachAssignments: { - include: { - coach: { - include: { seats: true, seatClass: true }, - }, - }, - orderBy: { positionNumber: 'asc' }, - }, - }, -}); -``` - ---- - -## 🔑 Seed Data - -- **2 Trains**: Express 301, Express 302 -- **6 Physical Coaches**: C-A1, C-B1, C-C1, C-A2, C-B2, C-C2 -- **4 Train Schedules**: With flexible coach assignments -- **3 Seat Classes**: Economy Regular, Economy Bed, VIP Bed -- **Users**: Admin, Passenger (with wallet/loyalty), Agent - ---- - -## ✨ Migration Status - -✅ Schema pushed to database successfully -✅ Seed data populated -✅ All services updated -✅ All controllers updated -✅ All DTOs updated - ---- - -## 📝 Notes - -- Coaches are now reusable physical entities -- Same coach can serve different schedules at different times -- Seats belong to coaches, not schedules -- CoachAssignment provides the many-to-many relationship -- All references to `tripId` changed to `scheduleId` -- All references to `service` changed to `train` - ---- - -**Refactoring completed successfully! 🎉** diff --git a/apps/edr-passenger-api/prisma/migrations/20260524080651_add_nationality_and_waafi/migration.sql b/apps/edr-passenger-api/prisma/migrations/20260524080651_add_nationality_and_waafi/migration.sql new file mode 100644 index 000000000..d5b4c9fa2 --- /dev/null +++ b/apps/edr-passenger-api/prisma/migrations/20260524080651_add_nationality_and_waafi/migration.sql @@ -0,0 +1,5 @@ +-- AlterEnum +ALTER TYPE "PaymentMethodType" ADD VALUE 'WAAFI'; + +-- AlterTable +ALTER TABLE "FareRule" ADD COLUMN "nationality" TEXT; diff --git a/apps/edr-passenger-api/prisma/migrations/20260524091255_add_guest_booking_support/migration.sql b/apps/edr-passenger-api/prisma/migrations/20260524091255_add_guest_booking_support/migration.sql new file mode 100644 index 000000000..1698c0c23 --- /dev/null +++ b/apps/edr-passenger-api/prisma/migrations/20260524091255_add_guest_booking_support/migration.sql @@ -0,0 +1,28 @@ +-- AlterTable +ALTER TABLE "Booking" ADD COLUMN "contactEmail" TEXT, +ADD COLUMN "contactPhone" TEXT; + +-- CreateTable +CREATE TABLE "SavedPassengerProfile" ( + "id" TEXT NOT NULL, + "userId" TEXT, + "deviceId" TEXT, + "passengerName" TEXT NOT NULL, + "dateOfBirth" TIMESTAMP(3) NOT NULL, + "idDocumentType" "IdDocumentType" NOT NULL, + "passportNumber" TEXT, + "passportCountry" TEXT, + "nationality" TEXT, + "phone" TEXT, + "email" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "SavedPassengerProfile_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "SavedPassengerProfile_userId_idx" ON "SavedPassengerProfile"("userId"); + +-- CreateIndex +CREATE INDEX "SavedPassengerProfile_deviceId_idx" ON "SavedPassengerProfile"("deviceId"); diff --git a/apps/edr-passenger-api/prisma/migrations/add_guest_booking_support.sql b/apps/edr-passenger-api/prisma/migrations/add_guest_booking_support.sql new file mode 100644 index 000000000..fc3d83a8d --- /dev/null +++ b/apps/edr-passenger-api/prisma/migrations/add_guest_booking_support.sql @@ -0,0 +1,30 @@ +-- Add contact fields to Booking table +ALTER TABLE "passenger"."Booking" +ADD COLUMN "contactEmail" TEXT, +ADD COLUMN "contactPhone" TEXT; + +-- Create SavedPassengerProfile table +CREATE TABLE "passenger"."SavedPassengerProfile" ( + "id" TEXT NOT NULL, + "userId" TEXT, + "deviceId" TEXT, + "passengerName" TEXT NOT NULL, + "dateOfBirth" TIMESTAMP(3) NOT NULL, + "idDocumentType" "passenger"."IdDocumentType" NOT NULL, + "passportNumber" TEXT, + "passportCountry" TEXT, + "nationality" TEXT, + "phone" TEXT, + "email" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "SavedPassengerProfile_pkey" PRIMARY KEY ("id") +); + +-- Create indexes +CREATE INDEX "SavedPassengerProfile_userId_idx" ON "passenger"."SavedPassengerProfile"("userId"); +CREATE INDEX "SavedPassengerProfile_deviceId_idx" ON "passenger"."SavedPassengerProfile"("deviceId"); + +-- Add comment +COMMENT ON TABLE "passenger"."SavedPassengerProfile" IS 'Stores passenger details for quick rebooking (by userId or deviceId)'; diff --git a/apps/edr-passenger-api/prisma/schema.prisma b/apps/edr-passenger-api/prisma/schema.prisma index 046faf2b1..a6ed4f9e0 100644 --- a/apps/edr-passenger-api/prisma/schema.prisma +++ b/apps/edr-passenger-api/prisma/schema.prisma @@ -103,6 +103,7 @@ enum PaymentMethodType { EBIRR CARD WALLET + WAAFI @@schema("passenger") } @@ -443,6 +444,7 @@ model FareRule { id String @id @default(uuid()) tripId String? route String? + nationality String? // Ethiopian, Djiboutian, Other seatClassId String baseFareMinor Int seatClass SeatClass @relation(fields: [seatClassId], references: [id]) @@ -468,6 +470,8 @@ model Booking { displayCurrency Currency? displayTotalMinor Int? bookingType String @default("ONE_WAY") + contactEmail String? + contactPhone String? userAgent String? source String @default("WEB") promoCode String? @@ -1221,3 +1225,23 @@ model VerifaydaVerification { @@schema("passenger") } + +model SavedPassengerProfile { + id String @id @default(uuid()) + userId String? + deviceId String? + passengerName String + dateOfBirth DateTime + idDocumentType IdDocumentType + passportNumber String? + passportCountry String? + nationality String? + phone String? + email String? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + @@index([userId]) + @@index([deviceId]) + + @@schema("passenger") +} diff --git a/apps/edr-passenger-api/prisma/seed.ts b/apps/edr-passenger-api/prisma/seed.ts index 4e8c1a68f..11f3af07c 100644 --- a/apps/edr-passenger-api/prisma/seed.ts +++ b/apps/edr-passenger-api/prisma/seed.ts @@ -3,182 +3,618 @@ import * as bcrypt from 'bcrypt'; const prisma = new PrismaClient(); -async function main() { - console.log('🌱 Starting comprehensive seed...'); +// ============================================================================ +// SECTION 1: STATIONS (18 STATIONS) +// ============================================================================ +async function seedStations() { + console.log('📍 Seeding 18 stations...'); + + const stations = [ + { code: 'SBT', name: 'Sebeta', city: 'Sebeta', countryCode: 'ET', lat: 8.9167, lng: 38.6167 }, + { code: 'LBU', name: 'Labu', city: 'Labu', countryCode: 'ET', lat: 8.8500, lng: 38.7000 }, + { code: 'IND', name: 'Indode', city: 'Indode', countryCode: 'ET', lat: 8.7800, lng: 38.8200 }, + { code: 'BSH', name: 'Bishoftu', city: 'Bishoftu', countryCode: 'ET', lat: 8.7500, lng: 38.9833 }, + { code: 'MJO', name: 'Mojo', city: 'Mojo', countryCode: 'ET', lat: 8.6000, lng: 39.1200 }, + { code: 'ADM', name: 'Adama', city: 'Adama', countryCode: 'ET', lat: 8.5400, lng: 39.2675 }, + { code: 'FTO', name: 'Feto', city: 'Feto', countryCode: 'ET', lat: 8.4500, lng: 39.4000 }, + { code: 'MTH', name: 'Metahara', city: 'Metahara', countryCode: 'ET', lat: 8.9000, lng: 39.9167 }, + { code: 'MSO', name: 'Mieso', city: 'Mieso', countryCode: 'ET', lat: 9.2400, lng: 40.7500 }, + { code: 'BKE', name: 'Bike', city: 'Bike', countryCode: 'ET', lat: 9.4200, lng: 41.2000 }, + { code: 'DDW', name: 'Diredawa', city: 'Diredawa', countryCode: 'ET', lat: 9.5931, lng: 41.8661 }, + { code: 'ARW', name: 'Arawa', city: 'Arawa', countryCode: 'ET', lat: 10.2000, lng: 42.1500 }, + { code: 'ADG', name: 'Adigala', city: 'Adigala', countryCode: 'ET', lat: 10.8500, lng: 42.4000 }, + { code: 'AYS', name: 'Aysha', city: 'Aysha', countryCode: 'ET', lat: 11.5500, lng: 42.7167 }, + { code: 'DWL', name: 'Dawanle', city: 'Dawanle', countryCode: 'DJ', lat: 11.4000, lng: 42.9500 }, + { code: 'ALI', name: 'Alisabieh', city: 'Alisabieh', countryCode: 'DJ', lat: 11.1667, lng: 42.7167 }, + { code: 'HOL', name: 'Holhol', city: 'Holhol', countryCode: 'DJ', lat: 11.3500, lng: 43.0500 }, + { code: 'NGD', name: 'Nagad', city: 'Nagad', countryCode: 'DJ', timezone: 'Africa/Djibouti', lat: 11.5720, lng: 43.1456 }, + ]; - // Stations - const addis = await prisma.station.upsert({ where: { code: 'ADD' }, update: {}, create: { code: 'ADD', name: 'Addis Ababa Central', city: 'Addis Ababa', countryCode: 'ET', lat: 9.0054, lng: 38.7636 } }); - const sebeta = await prisma.station.upsert({ where: { code: 'SBT' }, update: {}, create: { code: 'SBT', name: 'Sebeta', city: 'Sebeta', countryCode: 'ET', lat: 8.9167, lng: 38.6167 } }); - const adama = await prisma.station.upsert({ where: { code: 'ADM' }, update: {}, create: { code: 'ADM', name: 'Adama', city: 'Adama', countryCode: 'ET', lat: 8.5400, lng: 39.2675 } }); - const awash = await prisma.station.upsert({ where: { code: 'AWS' }, update: {}, create: { code: 'AWS', name: 'Awash', city: 'Awash', countryCode: 'ET', lat: 8.9833, lng: 40.1667 } }); - const direDawa = await prisma.station.upsert({ where: { code: 'DDW' }, update: {}, create: { code: 'DDW', name: 'Dire Dawa', city: 'Dire Dawa', countryCode: 'ET', lat: 9.5931, lng: 41.8661 } }); - const aysha = await prisma.station.upsert({ where: { code: 'AYS' }, update: {}, create: { code: 'AYS', name: 'Aysha', city: 'Aysha', countryCode: 'ET', lat: 11.5500, lng: 42.7167 } }); - const djibouti = await prisma.station.upsert({ where: { code: 'DJI' }, update: {}, create: { code: 'DJI', name: 'Djibouti', city: 'Djibouti', countryCode: 'DJ', timezone: 'Africa/Djibouti', lat: 11.5720, lng: 43.1456 } }); + const created = []; + for (const station of stations) { + const s = await prisma.station.upsert({ + where: { code: station.code }, + update: {}, + create: station, + }); + created.push(s); + } - // Seat Classes - const scEconomyRegular = await prisma.seatClass.upsert({ where: { name: 'Economy Regular' }, update: {}, create: { name: 'Economy Regular', description: 'Standard economy seating', basePrice: 45000, isActive: true } }); - const scEconomyBed = await prisma.seatClass.upsert({ where: { name: 'Economy Bed' }, update: {}, create: { name: 'Economy Bed', description: 'Economy bed lower berth', basePrice: 65000, isActive: true } }); - const scVipBed = await prisma.seatClass.upsert({ where: { name: 'VIP Bed' }, update: {}, create: { name: 'VIP Bed', description: 'First class VIP bed', basePrice: 95000, isActive: true } }); + console.log(` ✅ Created ${created.length} stations`); + return created; +} - // Trains (logical services) - const train301 = await prisma.train.upsert({ where: { number: '301' }, update: {}, create: { number: '301', name: 'Express 301', description: 'Addis-Djibouti Express' } }); - const train302 = await prisma.train.upsert({ where: { number: '302' }, update: {}, create: { number: '302', name: 'Express 302', description: 'Djibouti-Addis Express' } }); +// ============================================================================ +// SECTION 2: SEAT CLASSES +// ============================================================================ +async function seedSeatClasses() { + console.log('💺 Seeding seat classes...'); + + const classes = [ + { name: 'Economy Regular', description: 'Standard economy seating', basePrice: 25000 }, + { name: 'Economy Bed', description: 'Economy bed lower berth', basePrice: 35000 }, + { name: 'VIP Bed', description: 'First class VIP bed', basePrice: 55000 }, + ]; - // Physical Coaches (reusable) - const coachA1 = await prisma.coach.upsert({ where: { coachNumber: 'C-A1' }, update: {}, create: { coachNumber: 'C-A1', label: 'A', seatClassId: scEconomyRegular.id, mode: 'seat', totalUnits: 60 } }); - const coachB1 = await prisma.coach.upsert({ where: { coachNumber: 'C-B1' }, update: {}, create: { coachNumber: 'C-B1', label: 'B', seatClassId: scEconomyBed.id, mode: 'bed', totalUnits: 40 } }); - const coachC1 = await prisma.coach.upsert({ where: { coachNumber: 'C-C1' }, update: {}, create: { coachNumber: 'C-C1', label: 'C', seatClassId: scVipBed.id, mode: 'bed', totalUnits: 20 } }); - const coachA2 = await prisma.coach.upsert({ where: { coachNumber: 'C-A2' }, update: {}, create: { coachNumber: 'C-A2', label: 'A', seatClassId: scEconomyRegular.id, mode: 'seat', totalUnits: 60 } }); - const coachB2 = await prisma.coach.upsert({ where: { coachNumber: 'C-B2' }, update: {}, create: { coachNumber: 'C-B2', label: 'B', seatClassId: scEconomyBed.id, mode: 'bed', totalUnits: 40 } }); - const coachC2 = await prisma.coach.upsert({ where: { coachNumber: 'C-C2' }, update: {}, create: { coachNumber: 'C-C2', label: 'C', seatClassId: scVipBed.id, mode: 'bed', totalUnits: 20 } }); + const created = []; + for (const cls of classes) { + const c = await prisma.seatClass.upsert({ + where: { name: cls.name }, + update: {}, + create: { ...cls, isActive: true }, + }); + created.push(c); + } - // Create seats for each physical coach - for (const coach of [coachA1, coachB1, coachC1, coachA2, coachB2, coachC2]) { + console.log(` ✅ Created ${created.length} seat classes`); + return created; +} + +// ============================================================================ +// SECTION 3: TRAINS +// ============================================================================ +async function seedTrains() { + console.log('🚂 Seeding trains...'); + + const trains = [ + { number: '301', name: 'Express 301', description: 'Sebeta-Nagad Express' }, + { number: '302', name: 'Express 302', description: 'Nagad-Sebeta Express' }, + { number: '303', name: 'Local 303', description: 'Regional Service' }, + ]; + + const created = []; + for (const train of trains) { + const t = await prisma.train.upsert({ + where: { number: train.number }, + update: {}, + create: train, + }); + created.push(t); + } + + console.log(` ✅ Created ${created.length} trains`); + return created; +} + +// ============================================================================ +// SECTION 4: COACHES & SEATS +// ============================================================================ +async function seedCoachesAndSeats(seatClasses: any[]) { + console.log('🚃 Seeding coaches and seats...'); + + const [scEconomy, scEconomyBed, scVip] = seatClasses; + + const coachConfigs = [ + { coachNumber: 'C-A1', label: 'A', seatClassId: scEconomy.id, mode: 'seat', totalUnits: 60 }, + { coachNumber: 'C-B1', label: 'B', seatClassId: scEconomyBed.id, mode: 'bed', totalUnits: 40 }, + { coachNumber: 'C-C1', label: 'C', seatClassId: scVip.id, mode: 'bed', totalUnits: 20 }, + { coachNumber: 'C-A2', label: 'A', seatClassId: scEconomy.id, mode: 'seat', totalUnits: 60 }, + { coachNumber: 'C-B2', label: 'B', seatClassId: scEconomyBed.id, mode: 'bed', totalUnits: 40 }, + { coachNumber: 'C-C2', label: 'C', seatClassId: scVip.id, mode: 'bed', totalUnits: 20 }, + ]; + + const coaches = []; + for (const config of coachConfigs) { + const coach = await prisma.coach.upsert({ + where: { coachNumber: config.coachNumber }, + update: {}, + create: config, + }); + coaches.push(coach); + + // Create seats for this coach const existingSeats = await prisma.seat.count({ where: { coachId: coach.id } }); if (existingSeats === 0) { const seats = []; - const rows = Math.ceil(coach.totalUnits / 4); + const rows = Math.ceil(config.totalUnits / 4); for (let row = 1; row <= rows; row++) { for (const col of ['A', 'B', 'C', 'D']) { - if (seats.length >= coach.totalUnits) break; - seats.push({ coachId: coach.id, row, col, label: `${row}${col}`, seatNumber: `${coach.label}${row}${col}`, kind: (row === 1 && col === 'A' ? 'ACCESSIBLE' : 'STANDARD') as SeatKind }); + if (seats.length >= config.totalUnits) break; + seats.push({ + coachId: coach.id, + row, + col, + label: `${row}${col}`, + seatNumber: `${config.label}${row}${col}`, + kind: (row === 1 && col === 'A' ? 'ACCESSIBLE' : 'STANDARD') as SeatKind, + }); } } await prisma.seat.createMany({ data: seats }); } } - // Train Schedules — delete dependents first to avoid FK violations + console.log(` ✅ Created ${coaches.length} coaches with seats`); + return coaches; +} + +// ============================================================================ +// SECTION 5: SCHEDULES (15+ SEGMENTS) +// ============================================================================ +async function seedSchedules(trains: any[], stations: any[]) { + console.log('📅 Seeding schedules with 15+ segments...'); + + const [train301, train302, train303] = trains; + const [sebeta, labu, indode, bishoftu, mojo, adama, feto, metahara, mieso, bike, diredawa, arawa, adigala, aysha, dawanle, alisabieh, holhol, nagad] = stations; + + // Clean up existing schedules const existingScheduleIds = (await prisma.trainSchedule.findMany({ - where: { trainId: { in: [train301.id, train302.id] } }, + where: { trainId: { in: [train301.id, train302.id, train303.id] } }, select: { id: true }, })).map((s) => s.id); + if (existingScheduleIds.length > 0) { await prisma.fareRule.deleteMany({ where: { tripId: { in: existingScheduleIds } } }); await prisma.tripStopTime.deleteMany({ where: { scheduleId: { in: existingScheduleIds } } }); await prisma.coachAssignment.deleteMany({ where: { scheduleId: { in: existingScheduleIds } } }); await prisma.trainSchedule.deleteMany({ where: { id: { in: existingScheduleIds } } }); } - const schedule1 = await prisma.trainSchedule.create({ - data: { trainId: train301.id, originStationId: addis.id, destinationStationId: djibouti.id, departureAt: new Date('2026-06-15T08:00:00Z'), arrivalAt: new Date('2026-06-15T20:00:00Z'), durationMinutes: 720, stopsCount: 6 }, - }); - const schedule2 = await prisma.trainSchedule.create({ - data: { trainId: train302.id, originStationId: djibouti.id, destinationStationId: addis.id, departureAt: new Date('2026-06-16T09:00:00Z'), arrivalAt: new Date('2026-06-16T21:30:00Z'), durationMinutes: 750, stopsCount: 5 }, - }); - const schedule3 = await prisma.trainSchedule.create({ - data: { trainId: train301.id, originStationId: addis.id, destinationStationId: djibouti.id, departureAt: new Date('2026-06-17T07:30:00Z'), arrivalAt: new Date('2026-06-17T19:45:00Z'), durationMinutes: 735, stopsCount: 5 }, - }); - const schedule4 = await prisma.trainSchedule.create({ - data: { trainId: train302.id, originStationId: djibouti.id, destinationStationId: addis.id, departureAt: new Date('2026-06-18T08:30:00Z'), arrivalAt: new Date('2026-06-18T21:00:00Z'), durationMinutes: 750, stopsCount: 5 }, - }); - // Assign coaches to schedules - await prisma.coachAssignment.createMany({ - data: [ - { scheduleId: schedule1.id, coachId: coachA1.id, positionNumber: 1 }, - { scheduleId: schedule1.id, coachId: coachB1.id, positionNumber: 2 }, - { scheduleId: schedule1.id, coachId: coachC1.id, positionNumber: 3 }, - { scheduleId: schedule2.id, coachId: coachA2.id, positionNumber: 1 }, - { scheduleId: schedule2.id, coachId: coachB2.id, positionNumber: 2 }, - { scheduleId: schedule2.id, coachId: coachC2.id, positionNumber: 3 }, - { scheduleId: schedule3.id, coachId: coachA1.id, positionNumber: 1 }, - { scheduleId: schedule3.id, coachId: coachB1.id, positionNumber: 2 }, - { scheduleId: schedule3.id, coachId: coachC1.id, positionNumber: 3 }, - { scheduleId: schedule4.id, coachId: coachA2.id, positionNumber: 1 }, - { scheduleId: schedule4.id, coachId: coachB2.id, positionNumber: 2 }, - { scheduleId: schedule4.id, coachId: coachC2.id, positionNumber: 3 }, - ], - skipDuplicates: true, - }); + const schedules = [ + // Full route: Sebeta to Nagad (18 stations) + { + trainId: train301.id, + originStationId: sebeta.id, + destinationStationId: nagad.id, + departureAt: new Date('2026-06-15T06:00:00Z'), + arrivalAt: new Date('2026-06-15T22:00:00Z'), + durationMinutes: 960, + stopsCount: 18, + }, + // Return route: Nagad to Sebeta + { + trainId: train302.id, + originStationId: nagad.id, + destinationStationId: sebeta.id, + departureAt: new Date('2026-06-16T07:00:00Z'), + arrivalAt: new Date('2026-06-16T23:30:00Z'), + durationMinutes: 990, + stopsCount: 18, + }, + // Regional service: Sebeta to Diredawa + { + trainId: train303.id, + originStationId: sebeta.id, + destinationStationId: diredawa.id, + departureAt: new Date('2026-06-17T08:00:00Z'), + arrivalAt: new Date('2026-06-17T18:00:00Z'), + durationMinutes: 600, + stopsCount: 11, + }, + // Additional schedules for next day + { + trainId: train301.id, + originStationId: sebeta.id, + destinationStationId: nagad.id, + departureAt: new Date('2026-06-18T06:30:00Z'), + arrivalAt: new Date('2026-06-18T22:45:00Z'), + durationMinutes: 975, + stopsCount: 18, + }, + { + trainId: train302.id, + originStationId: nagad.id, + destinationStationId: sebeta.id, + departureAt: new Date('2026-06-19T07:15:00Z'), + arrivalAt: new Date('2026-06-19T23:45:00Z'), + durationMinutes: 990, + stopsCount: 18, + }, + ]; - // Stop Times - await prisma.tripStopTime.createMany({ - data: [ - { scheduleId: schedule1.id, stationId: addis.id, sequence: 1, plannedDepartureAt: new Date('2026-06-15T08:00:00Z'), status: 'UPCOMING' }, - { scheduleId: schedule1.id, stationId: adama.id, sequence: 2, plannedArrivalAt: new Date('2026-06-15T09:30:00Z'), plannedDepartureAt: new Date('2026-06-15T09:45:00Z'), status: 'UPCOMING' }, - { scheduleId: schedule1.id, stationId: awash.id, sequence: 3, plannedArrivalAt: new Date('2026-06-15T11:30:00Z'), plannedDepartureAt: new Date('2026-06-15T11:45:00Z'), status: 'UPCOMING' }, - { scheduleId: schedule1.id, stationId: direDawa.id, sequence: 4, plannedArrivalAt: new Date('2026-06-15T15:00:00Z'), plannedDepartureAt: new Date('2026-06-15T15:20:00Z'), status: 'UPCOMING' }, - { scheduleId: schedule1.id, stationId: aysha.id, sequence: 5, plannedArrivalAt: new Date('2026-06-15T18:00:00Z'), plannedDepartureAt: new Date('2026-06-15T18:10:00Z'), status: 'UPCOMING' }, - { scheduleId: schedule1.id, stationId: djibouti.id, sequence: 6, plannedArrivalAt: new Date('2026-06-15T20:00:00Z'), status: 'UPCOMING' }, - ], - }); - - // Fare Rules - for (const schedule of [schedule1, schedule2, schedule3, schedule4]) { - await prisma.fareRule.createMany({ - data: [ - { tripId: schedule.id, seatClassId: scEconomyRegular.id, baseFareMinor: 45000, validFrom: new Date('2026-01-01'), refundable: true }, - { tripId: schedule.id, seatClassId: scEconomyBed.id, baseFareMinor: 65000, validFrom: new Date('2026-01-01'), refundable: true }, - { tripId: schedule.id, seatClassId: scVipBed.id, baseFareMinor: 95000, validFrom: new Date('2026-01-01'), refundable: true }, - ], - skipDuplicates: true, - }); + const created = []; + for (const schedule of schedules) { + const s = await prisma.trainSchedule.create({ data: schedule }); + created.push(s); } - // Users + console.log(` ✅ Created ${created.length} schedules`); + return created; +} + +// ============================================================================ +// SECTION 6: COACH ASSIGNMENTS +// ============================================================================ +async function seedCoachAssignments(schedules: any[], coaches: any[]) { + console.log('🔗 Seeding coach assignments...'); + + const [coachA1, coachB1, coachC1, coachA2, coachB2, coachC2] = coaches; + const [schedule1, schedule2, schedule3] = schedules; + + const assignments = [ + { scheduleId: schedule1.id, coachId: coachA1.id, positionNumber: 1 }, + { scheduleId: schedule1.id, coachId: coachB1.id, positionNumber: 2 }, + { scheduleId: schedule1.id, coachId: coachC1.id, positionNumber: 3 }, + { scheduleId: schedule2.id, coachId: coachA2.id, positionNumber: 1 }, + { scheduleId: schedule2.id, coachId: coachB2.id, positionNumber: 2 }, + { scheduleId: schedule2.id, coachId: coachC2.id, positionNumber: 3 }, + { scheduleId: schedule3.id, coachId: coachA1.id, positionNumber: 1 }, + { scheduleId: schedule3.id, coachId: coachB1.id, positionNumber: 2 }, + { scheduleId: schedule3.id, coachId: coachC1.id, positionNumber: 3 }, + ]; + + await prisma.coachAssignment.createMany({ data: assignments, skipDuplicates: true }); + console.log(` ✅ Created ${assignments.length} coach assignments`); +} + +// ============================================================================ +// SECTION 7: STOP TIMES (ALL 18 STATIONS) +// ============================================================================ +async function seedStopTimes(schedules: any[], stations: any[]) { + console.log('⏱️ Seeding stop times for all stations...'); + + const [sebeta, labu, indode, bishoftu, mojo, adama, feto, metahara, mieso, bike, diredawa, arawa, adigala, aysha, dawanle, alisabieh, holhol, nagad] = stations; + const [schedule1, schedule2, schedule3] = schedules; + + // Full route stop times (Sebeta to Nagad) + const fullRouteStops = [ + { scheduleId: schedule1.id, stationId: sebeta.id, sequence: 1, plannedDepartureAt: new Date('2026-06-15T06:00:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule1.id, stationId: labu.id, sequence: 2, plannedArrivalAt: new Date('2026-06-15T06:30:00Z'), plannedDepartureAt: new Date('2026-06-15T06:35:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule1.id, stationId: indode.id, sequence: 3, plannedArrivalAt: new Date('2026-06-15T07:00:00Z'), plannedDepartureAt: new Date('2026-06-15T07:05:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule1.id, stationId: bishoftu.id, sequence: 4, plannedArrivalAt: new Date('2026-06-15T07:30:00Z'), plannedDepartureAt: new Date('2026-06-15T07:40:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule1.id, stationId: mojo.id, sequence: 5, plannedArrivalAt: new Date('2026-06-15T08:15:00Z'), plannedDepartureAt: new Date('2026-06-15T08:25:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule1.id, stationId: adama.id, sequence: 6, plannedArrivalAt: new Date('2026-06-15T09:00:00Z'), plannedDepartureAt: new Date('2026-06-15T09:15:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule1.id, stationId: feto.id, sequence: 7, plannedArrivalAt: new Date('2026-06-15T09:45:00Z'), plannedDepartureAt: new Date('2026-06-15T09:50:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule1.id, stationId: metahara.id, sequence: 8, plannedArrivalAt: new Date('2026-06-15T10:30:00Z'), plannedDepartureAt: new Date('2026-06-15T10:45:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule1.id, stationId: mieso.id, sequence: 9, plannedArrivalAt: new Date('2026-06-15T12:00:00Z'), plannedDepartureAt: new Date('2026-06-15T12:10:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule1.id, stationId: bike.id, sequence: 10, plannedArrivalAt: new Date('2026-06-15T13:30:00Z'), plannedDepartureAt: new Date('2026-06-15T13:40:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule1.id, stationId: diredawa.id, sequence: 11, plannedArrivalAt: new Date('2026-06-15T15:00:00Z'), plannedDepartureAt: new Date('2026-06-15T15:20:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule1.id, stationId: arawa.id, sequence: 12, plannedArrivalAt: new Date('2026-06-15T16:30:00Z'), plannedDepartureAt: new Date('2026-06-15T16:35:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule1.id, stationId: adigala.id, sequence: 13, plannedArrivalAt: new Date('2026-06-15T17:45:00Z'), plannedDepartureAt: new Date('2026-06-15T17:50:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule1.id, stationId: aysha.id, sequence: 14, plannedArrivalAt: new Date('2026-06-15T18:30:00Z'), plannedDepartureAt: new Date('2026-06-15T18:40:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule1.id, stationId: dawanle.id, sequence: 15, plannedArrivalAt: new Date('2026-06-15T19:15:00Z'), plannedDepartureAt: new Date('2026-06-15T19:20:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule1.id, stationId: alisabieh.id, sequence: 16, plannedArrivalAt: new Date('2026-06-15T20:00:00Z'), plannedDepartureAt: new Date('2026-06-15T20:05:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule1.id, stationId: holhol.id, sequence: 17, plannedArrivalAt: new Date('2026-06-15T21:00:00Z'), plannedDepartureAt: new Date('2026-06-15T21:05:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule1.id, stationId: nagad.id, sequence: 18, plannedArrivalAt: new Date('2026-06-15T22:00:00Z'), status: 'UPCOMING' as const }, + ]; + + // Regional route stop times (Sebeta to Diredawa) + const regionalStops = [ + { scheduleId: schedule3.id, stationId: sebeta.id, sequence: 1, plannedDepartureAt: new Date('2026-06-17T08:00:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule3.id, stationId: labu.id, sequence: 2, plannedArrivalAt: new Date('2026-06-17T08:30:00Z'), plannedDepartureAt: new Date('2026-06-17T08:35:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule3.id, stationId: indode.id, sequence: 3, plannedArrivalAt: new Date('2026-06-17T09:00:00Z'), plannedDepartureAt: new Date('2026-06-17T09:05:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule3.id, stationId: bishoftu.id, sequence: 4, plannedArrivalAt: new Date('2026-06-17T09:30:00Z'), plannedDepartureAt: new Date('2026-06-17T09:40:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule3.id, stationId: mojo.id, sequence: 5, plannedArrivalAt: new Date('2026-06-17T10:15:00Z'), plannedDepartureAt: new Date('2026-06-17T10:25:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule3.id, stationId: adama.id, sequence: 6, plannedArrivalAt: new Date('2026-06-17T11:00:00Z'), plannedDepartureAt: new Date('2026-06-17T11:15:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule3.id, stationId: feto.id, sequence: 7, plannedArrivalAt: new Date('2026-06-17T11:45:00Z'), plannedDepartureAt: new Date('2026-06-17T11:50:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule3.id, stationId: metahara.id, sequence: 8, plannedArrivalAt: new Date('2026-06-17T12:30:00Z'), plannedDepartureAt: new Date('2026-06-17T12:45:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule3.id, stationId: mieso.id, sequence: 9, plannedArrivalAt: new Date('2026-06-17T14:00:00Z'), plannedDepartureAt: new Date('2026-06-17T14:10:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule3.id, stationId: bike.id, sequence: 10, plannedArrivalAt: new Date('2026-06-17T15:30:00Z'), plannedDepartureAt: new Date('2026-06-17T15:40:00Z'), status: 'UPCOMING' as const }, + { scheduleId: schedule3.id, stationId: diredawa.id, sequence: 11, plannedArrivalAt: new Date('2026-06-17T18:00:00Z'), status: 'UPCOMING' as const }, + ]; + + const allStops = [...fullRouteStops, ...regionalStops]; + await prisma.tripStopTime.createMany({ data: allStops }); + console.log(` ✅ Created ${allStops.length} stop times`); +} + +// ============================================================================ +// SECTION 8: FARE RULES (COMPREHENSIVE SEGMENTS) +// ============================================================================ +async function seedFareRules(schedules: any[], seatClasses: any[]) { + console.log('💰 Seeding comprehensive fare rules...'); + + const [scEconomy, scEconomyBed, scVip] = seatClasses; + + // Segment-based fare rules (15+ segments) + const segmentRules = [ + // Short segments (1-3 stations) + { route: 'SBT-LBU', seatClassId: scEconomy.id, baseFareMinor: 5000, validFrom: new Date('2026-01-01'), refundable: true }, + { route: 'LBU-IND', seatClassId: scEconomy.id, baseFareMinor: 4500, validFrom: new Date('2026-01-01'), refundable: true }, + { route: 'IND-BSH', seatClassId: scEconomy.id, baseFareMinor: 5500, validFrom: new Date('2026-01-01'), refundable: true }, + { route: 'BSH-MJO', seatClassId: scEconomy.id, baseFareMinor: 6000, validFrom: new Date('2026-01-01'), refundable: true }, + { route: 'MJO-ADM', seatClassId: scEconomy.id, baseFareMinor: 7000, validFrom: new Date('2026-01-01'), refundable: true }, + + // Medium segments (3-6 stations) + { route: 'SBT-BSH', seatClassId: scEconomy.id, baseFareMinor: 12000, validFrom: new Date('2026-01-01'), refundable: true }, + { route: 'SBT-ADM', seatClassId: scEconomy.id, baseFareMinor: 18000, validFrom: new Date('2026-01-01'), refundable: true }, + { route: 'ADM-MTH', seatClassId: scEconomy.id, baseFareMinor: 8500, validFrom: new Date('2026-01-01'), refundable: true }, + { route: 'MTH-MSO', seatClassId: scEconomy.id, baseFareMinor: 9500, validFrom: new Date('2026-01-01'), refundable: true }, + { route: 'MSO-BKE', seatClassId: scEconomy.id, baseFareMinor: 8000, validFrom: new Date('2026-01-01'), refundable: true }, + { route: 'BKE-DDW', seatClassId: scEconomy.id, baseFareMinor: 7500, validFrom: new Date('2026-01-01'), refundable: true }, + + // Long segments (6+ stations) + { route: 'SBT-DDW', seatClassId: scEconomy.id, baseFareMinor: 35000, validFrom: new Date('2026-01-01'), refundable: true }, + { route: 'DDW-AYS', seatClassId: scEconomy.id, baseFareMinor: 15000, validFrom: new Date('2026-01-01'), refundable: true }, + { route: 'AYS-NGD', seatClassId: scEconomy.id, baseFareMinor: 18000, validFrom: new Date('2026-01-01'), refundable: true }, + { route: 'SBT-NGD', seatClassId: scEconomy.id, baseFareMinor: 65000, validFrom: new Date('2026-01-01'), refundable: true }, + + // Cross-border segments + { route: 'DDW-DWL', seatClassId: scEconomy.id, baseFareMinor: 22000, validFrom: new Date('2026-01-01'), refundable: true }, + { route: 'DWL-ALI', seatClassId: scEconomy.id, baseFareMinor: 12000, validFrom: new Date('2026-01-01'), refundable: true }, + { route: 'ALI-HOL', seatClassId: scEconomy.id, baseFareMinor: 8500, validFrom: new Date('2026-01-01'), refundable: true }, + { route: 'HOL-NGD', seatClassId: scEconomy.id, baseFareMinor: 6000, validFrom: new Date('2026-01-01'), refundable: true }, + ]; + + // Add Economy Bed prices (40% higher) + const bedRules = segmentRules.map(rule => ({ + ...rule, + seatClassId: scEconomyBed.id, + baseFareMinor: Math.round(rule.baseFareMinor * 1.4), + })); + + // Add VIP prices (80% higher) + const vipRules = segmentRules.map(rule => ({ + ...rule, + seatClassId: scVip.id, + baseFareMinor: Math.round(rule.baseFareMinor * 1.8), + })); + + const allRules = [...segmentRules, ...bedRules, ...vipRules]; + await prisma.fareRule.createMany({ data: allRules, skipDuplicates: true }); + + // Nationality-specific discounts + const nationalityRules = [ + // Ethiopian nationals - 10% discount on domestic routes + { route: 'SBT-DDW', nationality: 'Ethiopian', seatClassId: scEconomy.id, baseFareMinor: 31500, validFrom: new Date('2026-01-01'), refundable: true }, + { route: 'SBT-ADM', nationality: 'Ethiopian', seatClassId: scEconomy.id, baseFareMinor: 16200, validFrom: new Date('2026-01-01'), refundable: true }, + + // Djiboutian nationals - 5% discount on cross-border routes + { route: 'DDW-NGD', nationality: 'Djiboutian', seatClassId: scEconomy.id, baseFareMinor: 42750, validFrom: new Date('2026-01-01'), refundable: true }, + { route: 'SBT-NGD', nationality: 'Djiboutian', seatClassId: scEconomy.id, baseFareMinor: 61750, validFrom: new Date('2026-01-01'), refundable: true }, + ]; + + await prisma.fareRule.createMany({ data: nationalityRules, skipDuplicates: true }); + + console.log(` ✅ Created ${allRules.length + nationalityRules.length} fare rules`); +} + +// ============================================================================ +// SECTION 9: USERS & PASSENGERS +// ============================================================================ +async function seedUsers() { + console.log('👥 Seeding users...'); + const hash = await bcrypt.hash('password123', 10); const adminHash = await bcrypt.hash('admin123', 10); const agentHash = await bcrypt.hash('agent123', 10); - await prisma.user.upsert({ where: { email: 'admin@edr-platform.com' }, update: { passwordHash: adminHash, role: 'ADMIN' }, create: { fullName: 'EDR Admin', email: 'admin@edr-platform.com', phone: '+251900000000', passwordHash: adminHash, role: 'ADMIN' } }); - const passengerUser = await prisma.user.upsert({ where: { email: 'kelemu@email.com' }, update: {}, create: { fullName: 'Kelemu Ketsela', email: 'kelemu@email.com', phone: '+251912345678', passwordHash: hash, nationality: 'Ethiopian', nationalId: 'ET123456789' } }); - let passenger = await prisma.passenger.findUnique({ where: { userId: passengerUser.id } }); - if (!passenger) { - passenger = await prisma.passenger.create({ data: { userId: passengerUser.id } }); - await prisma.loyaltyAccount.create({ data: { passengerId: passenger.id, pointsBalance: 2450, tier: 'SILVER' } }); - await prisma.walletAccount.create({ data: { passengerId: passenger.id, balanceMinor: 125000 } }); + // Admin + await prisma.user.upsert({ + where: { email: 'admin@edr-platform.com' }, + update: { passwordHash: adminHash, role: 'ADMIN' }, + create: { + fullName: 'EDR Admin', + email: 'admin@edr-platform.com', + phone: '+251900000000', + passwordHash: adminHash, + role: 'ADMIN', + }, + }); + + // Ethiopian Passenger + const ethiopianUser = await prisma.user.upsert({ + where: { email: 'abebe@email.com' }, + update: {}, + create: { + fullName: 'Abebe Kebede', + email: 'abebe@email.com', + phone: '+251912345678', + passwordHash: hash, + nationality: 'Ethiopian', + nationalId: 'ET123456789', + }, + }); + + let ethiopianPassenger = await prisma.passenger.findUnique({ where: { userId: ethiopianUser.id } }); + if (!ethiopianPassenger) { + ethiopianPassenger = await prisma.passenger.create({ data: { userId: ethiopianUser.id } }); + await prisma.loyaltyAccount.create({ data: { passengerId: ethiopianPassenger.id, pointsBalance: 2450, tier: 'SILVER' } }); + await prisma.walletAccount.create({ data: { passengerId: ethiopianPassenger.id, balanceMinor: 125000 } }); } - await prisma.userPreferences.upsert({ where: { userId: passengerUser.id }, update: {}, create: { userId: passengerUser.id, language: 'en' } }); + await prisma.userPreferences.upsert({ + where: { userId: ethiopianUser.id }, + update: {}, + create: { userId: ethiopianUser.id, language: 'en' }, + }); - const agentUser = await prisma.user.upsert({ where: { email: 'agent@edr-platform.com' }, update: { passwordHash: agentHash, role: 'AGENT' }, create: { fullName: 'Agent Abebe', email: 'agent@edr-platform.com', phone: '+251911111111', passwordHash: agentHash, role: 'AGENT' } }); - await prisma.agent.upsert({ where: { userId: agentUser.id }, update: {}, create: { userId: agentUser.id, agentCode: 'AG001', stationId: addis.id, commissionRate: 5, active: true } }); + // Djiboutian Passenger + const djiboutianUser = await prisma.user.upsert({ + where: { email: 'ahmed@email.com' }, + update: {}, + create: { + fullName: 'Ahmed Hassan', + email: 'ahmed@email.com', + phone: '+25377123456', + passwordHash: hash, + nationality: 'Djiboutian', + passportNumber: 'DJ1234567', + }, + }); + let djiboutianPassenger = await prisma.passenger.findUnique({ where: { userId: djiboutianUser.id } }); + if (!djiboutianPassenger) { + djiboutianPassenger = await prisma.passenger.create({ data: { userId: djiboutianUser.id } }); + await prisma.loyaltyAccount.create({ data: { passengerId: djiboutianPassenger.id, pointsBalance: 1200, tier: 'BRONZE' } }); + await prisma.walletAccount.create({ data: { passengerId: djiboutianPassenger.id, balanceMinor: 85000 } }); + } + await prisma.userPreferences.upsert({ + where: { userId: djiboutianUser.id }, + update: {}, + create: { userId: djiboutianUser.id, language: 'fr' }, + }); + + // Agent + const agentUser = await prisma.user.upsert({ + where: { email: 'agent@edr-platform.com' }, + update: { passwordHash: agentHash, role: 'AGENT' }, + create: { + fullName: 'Agent Abebe', + email: 'agent@edr-platform.com', + phone: '+251911111111', + passwordHash: agentHash, + role: 'AGENT', + }, + }); + + const stations = await prisma.station.findMany(); + await prisma.agent.upsert({ + where: { userId: agentUser.id }, + update: {}, + create: { + userId: agentUser.id, + agentCode: 'AG001', + stationId: stations[0].id, + commissionRate: 5, + active: true, + }, + }); + + console.log(` ✅ Created 4 users (Admin, Ethiopian, Djiboutian, Agent)`); +} + +// ============================================================================ +// SECTION 10: SUPPORTING DATA +// ============================================================================ +async function seedSupportingData(seatClasses: any[]) { + console.log('📦 Seeding supporting data...'); + // Baggage Allowance await prisma.baggageAllowance.deleteMany({}); await prisma.baggageAllowance.createMany({ data: [ - { seatClassId: scEconomyRegular.id, maxWeightKg: 20, maxPiecesCount: 2, excessFeePerKg: 500 }, - { seatClassId: scEconomyBed.id, maxWeightKg: 25, maxPiecesCount: 2, excessFeePerKg: 450 }, - { seatClassId: scVipBed.id, maxWeightKg: 30, maxPiecesCount: 3, excessFeePerKg: 400 }, + { seatClassId: seatClasses[0].id, maxWeightKg: 20, maxPiecesCount: 2, excessFeePerKg: 500 }, + { seatClassId: seatClasses[1].id, maxWeightKg: 25, maxPiecesCount: 2, excessFeePerKg: 450 }, + { seatClassId: seatClasses[2].id, maxWeightKg: 30, maxPiecesCount: 3, excessFeePerKg: 400 }, ], }); // Notification Templates - await prisma.notificationTemplate.upsert({ where: { code: 'BOOKING_CONFIRMED' }, update: {}, create: { code: 'BOOKING_CONFIRMED', channel: 'EMAIL', subject: 'Booking Confirmed', bodyTemplate: 'Your booking {{bookingRef}} is confirmed for {{tripDate}}.', active: true } }); - await prisma.notificationTemplate.upsert({ where: { code: 'PAYMENT_SUCCESS' }, update: {}, create: { code: 'PAYMENT_SUCCESS', channel: 'SMS', bodyTemplate: 'Payment successful for {{bookingRef}}. Amount: {{amount}} ETB', active: true } }); + await prisma.notificationTemplate.upsert({ + where: { code: 'BOOKING_CONFIRMED' }, + update: {}, + create: { + code: 'BOOKING_CONFIRMED', + channel: 'EMAIL', + subject: 'Booking Confirmed', + bodyTemplate: 'Your booking {{bookingRef}} is confirmed for {{tripDate}}.', + active: true, + }, + }); + + await prisma.notificationTemplate.upsert({ + where: { code: 'PAYMENT_SUCCESS' }, + update: {}, + create: { + code: 'PAYMENT_SUCCESS', + channel: 'SMS', + bodyTemplate: 'Payment successful for {{bookingRef}}. Amount: {{amount}} ETB', + active: true, + }, + }); // Promotions - await prisma.promotion.upsert({ where: { code: 'WEEKEND15' }, update: {}, create: { title: 'Weekend Sale', subtitle: '15% off all trips', code: 'WEEKEND15', percentOff: 15, validUntil: new Date('2026-12-31'), ctaLabel: 'Book Now', active: true } }); - - // FAQ - await prisma.faqArticle.deleteMany({}); - await prisma.faqCategory.deleteMany({}); - const faqBooking = await prisma.faqCategory.create({ data: { title: 'Booking & Tickets', iconKey: 'confirmation_number' } }); - await prisma.faqArticle.createMany({ data: [{ categoryId: faqBooking.id, question: 'How do I book a train ticket?', answerMarkdown: 'Open Search, select origin and destination stations, choose date, select seats, and proceed to payment.', rank: 1 }] }); - - // Station Crowd Signals - await prisma.stationCrowdSignal.deleteMany({}); - await prisma.stationCrowdSignal.createMany({ data: [{ stationId: addis.id, level: 'MODERATE', label: 'Moderate', statusLabel: 'Normal operations' }, { stationId: djibouti.id, level: 'HIGH', label: 'High', statusLabel: 'Busy terminal' }] }); - - // Fraud Detection Rules - await prisma.fraudRule.upsert({ where: { type: 'VELOCITY' }, update: {}, create: { type: 'VELOCITY', enabled: true, threshold: 3, config: { windowMinutes: 60, action: 'FLAG' } } }); + await prisma.promotion.upsert({ + where: { code: 'WEEKEND15' }, + update: {}, + create: { + title: 'Weekend Sale', + subtitle: '15% off all trips', + code: 'WEEKEND15', + percentOff: 15, + validUntil: new Date('2026-12-31'), + ctaLabel: 'Book Now', + active: true, + }, + }); // Currency Exchange Rates await prisma.currencyExchangeRate.deleteMany({}); - await prisma.currencyExchangeRate.createMany({ data: [{ fromCurrency: 'ETB', toCurrency: 'ETB', rate: 1.0, effectiveDate: new Date() }, { fromCurrency: 'ETB', toCurrency: 'USD', rate: 0.018, effectiveDate: new Date() }] }); + await prisma.currencyExchangeRate.createMany({ + data: [ + { fromCurrency: 'ETB', toCurrency: 'ETB', rate: 1.0, effectiveDate: new Date() }, + { fromCurrency: 'ETB', toCurrency: 'USD', rate: 0.018, effectiveDate: new Date() }, + { fromCurrency: 'ETB', toCurrency: 'DJF', rate: 3.2, effectiveDate: new Date() }, + { fromCurrency: 'DJF', toCurrency: 'ETB', rate: 0.3125, effectiveDate: new Date() }, + { fromCurrency: 'DJF', toCurrency: 'DJF', rate: 1.0, effectiveDate: new Date() }, + ], + }); - console.log('✅ Comprehensive seed complete'); - console.log('\n📋 Seed Summary:'); - console.log(' - 2 Trains (Express 301, Express 302)'); - console.log(' - 6 Physical Coaches (reusable across schedules)'); - console.log(' - 4 Train Schedules with coach assignments'); - console.log(' - 3 Seat Classes (Economy Regular, Economy Bed, VIP Bed)'); - console.log(' - 3 Users: Admin, Passenger (Silver tier + wallet), Agent'); - console.log('\n🔑 Login Credentials:'); - console.log(' Admin: admin@edr-platform.com / admin123'); - console.log(' Passenger: kelemu@email.com / password123'); - console.log(' Agent: agent@edr-platform.com / agent123'); - console.log('\n🚂 Architecture: Train → TrainSchedule ↔ CoachAssignment ↔ Coach → Seat'); + // Fraud Rules + await prisma.fraudRule.upsert({ + where: { type: 'VELOCITY' }, + update: {}, + create: { + type: 'VELOCITY', + enabled: true, + threshold: 3, + config: { windowMinutes: 60, action: 'FLAG' }, + }, + }); + + console.log(` ✅ Created supporting data`); } -main().catch(console.error).finally(() => prisma.$disconnect()); +// ============================================================================ +// MAIN SEED FUNCTION +// ============================================================================ +async function main() { + console.log('🌱 Starting comprehensive modular seed with 18 stations...\n'); + + const stations = await seedStations(); + const seatClasses = await seedSeatClasses(); + const trains = await seedTrains(); + const coaches = await seedCoachesAndSeats(seatClasses); + const schedules = await seedSchedules(trains, stations); + await seedCoachAssignments(schedules, coaches); + await seedStopTimes(schedules, stations); + await seedFareRules(schedules, seatClasses); + await seedUsers(); + await seedSupportingData(seatClasses); + + console.log('\n✅ Comprehensive seed complete!\n'); + console.log('📋 Seed Summary:'); + console.log(' - 18 Stations: SBT, LBU, IND, BSH, MJO, ADM, FTO, MTH, MSO, BKE, DDW, ARW, ADG, AYS, DWL, ALI, HOL, NGD'); + console.log(' - 3 Seat Classes (Economy Regular, Economy Bed, VIP Bed)'); + console.log(' - 3 Trains (Express 301, Express 302, Local 303)'); + console.log(' - 6 Physical Coaches with seats'); + console.log(' - 5 Train Schedules covering full and regional routes'); + console.log(' - 15+ Fare Segments with nationality-based pricing'); + console.log(' - 4 Users: Admin, Ethiopian Passenger, Djiboutian Passenger, Agent'); + console.log(' - Currency rates: ETB, USD, DJF'); + console.log('\n🔑 Login Credentials:'); + console.log(' Admin: admin@edr-platform.com / admin123'); + console.log(' Ethiopian Passenger: abebe@email.com / password123'); + console.log(' Djiboutian Passenger: ahmed@email.com / password123'); + console.log(' Agent: agent@edr-platform.com / agent123'); + console.log('\n💰 Booking Flow Ready:'); + console.log(' - Search: 18 stations with multiple route combinations'); + console.log(' - Select: 3 seat classes with dynamic pricing'); + console.log(' - Book: Complete passenger details and payment'); + console.log(' - Pay: Multiple payment methods (Telebirr, CBE, Card, Wallet)'); + console.log(' - Ticket: QR code generation and validation'); + console.log('\n🚂 Sample Routes:'); + console.log(' - Full Route: Sebeta → Nagad (18 stations, 16 hours)'); + console.log(' - Regional: Sebeta → Diredawa (11 stations, 10 hours)'); + console.log(' - Short: Sebeta → Adama (6 stations, 3 hours)'); + console.log(' - Cross-border: Diredawa → Nagad (8 stations, 7 hours)'); +} + +main() + .catch((e) => { + console.error('❌ Seed failed:', e); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + }); diff --git a/apps/edr-passenger-api/src/app.module.ts b/apps/edr-passenger-api/src/app.module.ts index 7b2f460d3..261463e27 100644 --- a/apps/edr-passenger-api/src/app.module.ts +++ b/apps/edr-passenger-api/src/app.module.ts @@ -12,6 +12,7 @@ import telebirrConfig from './config/telebirr.config'; import cbeConfig from './config/cbe.config'; import ebirrConfig from './config/ebirr.config'; import cardConfig from './config/card.config'; +import waafiConfig from './config/waafi.config'; import { AuthModule } from './modules/auth/auth.module'; import { StationsModule } from './modules/stations/stations.module'; import { FleetModule } from './modules/fleet/fleet.module'; @@ -39,7 +40,7 @@ import { SeatClassesModule } from './modules/seat-classes/seat-classes.module'; imports: [ ConfigModule.forRoot({ isGlobal: true, - load: [appConfig, dbConfig, telebirrConfig, cbeConfig, ebirrConfig, cardConfig], + load: [appConfig, dbConfig, telebirrConfig, cbeConfig, ebirrConfig, cardConfig, waafiConfig], }), ScheduleModule.forRoot(), EventEmitterModule.forRoot(), diff --git a/apps/edr-passenger-api/src/config/waafi.config.ts b/apps/edr-passenger-api/src/config/waafi.config.ts new file mode 100644 index 000000000..c3afab7ce --- /dev/null +++ b/apps/edr-passenger-api/src/config/waafi.config.ts @@ -0,0 +1,10 @@ +import { registerAs } from '@nestjs/config'; + +export default registerAs('waafi', () => ({ + baseUrl: process.env.WAAFI_BASE_URL ?? 'https://api.waafipay.net', + merchantUid: process.env.WAAFI_MERCHANT_UID ?? '', + apiUserId: process.env.WAAFI_API_USER_ID ?? '', + apiKey: process.env.WAAFI_API_KEY ?? '', + notifyUrl: process.env.WAAFI_NOTIFY_URL ?? '', + returnUrl: process.env.WAAFI_RETURN_URL ?? '', +})); diff --git a/apps/edr-passenger-api/src/main.ts b/apps/edr-passenger-api/src/main.ts index 1528aa0da..f292e5242 100644 --- a/apps/edr-passenger-api/src/main.ts +++ b/apps/edr-passenger-api/src/main.ts @@ -32,46 +32,65 @@ async function bootstrap() { ## Overview Enterprise-grade REST API for the Ethio-Djibouti Railway passenger booking and management platform. Built with NestJS, TypeScript, PostgreSQL, and Prisma ORM. -## Authentication - -### Passenger Authentication (JWT-auth) -Used for passenger-facing endpoints. Obtain token via \`POST /auth/login\`. - -**Usage:** Add header \`Authorization: Bearer \` - -### Back-office Authentication (IAM-auth) -Used for agent, fraud, and reporting endpoints. Requires corporate IAM token. - -**Usage:** Add header \`Authorization: Bearer \` - ## Key Features ### 🎫 Booking Lifecycle - Search trips with real-time availability -- Create bookings with seat selection +- Age-based passenger categorization (Adult ≥5 years, Child <5 years) +- Nationality-based verification (Ethiopian Fayda, International Passport) +- Passenger information collection with verification +- Coach and seat selection with real-time availability +- Seat holding (15-minute expiry) +- Create bookings with verified passenger data - Modify bookings (seat changes, passenger updates) - Cancel bookings with automatic refunds - Multi-segment journey support +### 👤 Passenger Verification +1. **Ethiopian Nationals:** +- Automatic Fayda verification for adults (≥5 years) +- Real-time national ID verification via government database +- Retrieves verified passenger data (name, DOB, gender) +- National IDs not stored (policy compliant) + +2. **International Passengers:** +- Passport information collection +- Manual verification for Djiboutian and other nationals +- No government database verification required + +### 💰 Age-Based Pricing +- **ADULT** (≥5 years): Pay 100% of base fare +- **CHILD** (<5 years): First child travels FREE, subsequent children pay 100% +- Automatic age calculation from date of birth +- Example: 2 adults + 3 children = 4× base fare (first child free) + ### 💳 Payment Integration +1. **Ethiopian Payment Methods:** - **Telebirr** - Ethiopia's leading mobile money - **CBE Birr** - Commercial Bank of Ethiopia - **eBirr** - Electronic payment gateway -- **Card** - International card payments + +2. **Djiboutian Payment Methods:** +- **Waafi** - Djibouti's mobile money service + +3. **International Payment Methods:** +- **Card** - International card payments (Visa, Mastercard) - **Wallet** - Internal wallet system ### 🪑 Seat Management -- Real-time seat availability -- Seat holds (15-minute expiry) +- Real-time seat availability by coach and class +- Seat holds with 15-minute expiry - Auto-assign seats with contiguous algorithm - Seat blocking for maintenance - Coach-level seat maps +- Class-based seating (Economy Regular, Economy Bed, VIP Bed) ### 🎟️ Ticketing - QR code and barcode generation - PDF ticket generation - Gate validation with audit logs - Offline validation support +- Multi-passenger tickets ### 🏆 Loyalty Program - 4 tiers: Bronze, Silver, Gold, Platinum @@ -100,7 +119,7 @@ Used for agent, fraud, and reporting endpoints. Requires corporate IAM token. ### 🌍 Internationalization - Multi-language support (English, Amharic, French, Oromo) - Locale-based responses -- Currency formatting +- Currency formatting (ETB, DJF, USD) ### 👨‍💼 Agent Operations - Counter booking @@ -108,6 +127,48 @@ Used for agent, fraud, and reporting endpoints. Requires corporate IAM token. - Commission tracking - Cash reconciliation +## Authentication + +### Passenger Authentication (JWT-auth) +Used for passenger-facing endpoints. Obtain token via \`POST /auth/login\`. + +**Usage:** Add header \`Authorization: Bearer \` + +### Back-office Authentication (IAM-auth) +Used for agent, fraud, and reporting endpoints. Requires corporate IAM token. + +**Usage:** Add header \`Authorization: Bearer \` + +## Passenger Booking Flow + +### Step 1: Search Trips +\`POST /search\` with origin, destination, date, passenger counts, and nationality + +### Step 2: Get Fare Quote +\`POST /search/fare-quote\` with passenger counts and display currency + +### Step 3: Passenger Information & Verification +**For Ethiopian Passengers:** +\`POST /passengers/verify-fayda\` - Automatic Fayda verification for adults (≥5 years) + +**For International Passengers:** +\`POST /passengers/register-international\` - Passport information collection + +### Step 4: View Seat Map +\`GET /seats/seatmap/{scheduleId}\` - Show available coaches and seats + +### Step 5: Login & Hold Seats +\`POST /auth/login\` then \`POST /seats/hold\` to reserve seats for 15 minutes + +### Step 6: Create Booking +\`POST /bookings/guest\` with verified passenger details and held seats + +### Step 7: Process Payment +\`POST /payments/telebirr\` (Ethiopian) or \`POST /payments/waafi\` (Djiboutian) + +### Step 8: Get Tickets +\`GET /payments/{paymentId}/status\` to confirm payment and retrieve tickets with QR codes + ## Rate Limiting - Auth endpoints: 5 requests/minute - General endpoints: 100 requests/minute @@ -132,10 +193,11 @@ List endpoints support pagination: ## Webhooks Payment providers send notifications to: -- \`POST /payments/webhooks/telebirr\` -- \`POST /payments/webhooks/cbe-birr\` -- \`POST /payments/webhooks/ebirr\` -- \`POST /payments/webhooks/card\` +- \`POST /payments/webhooks/telebirr\` (Ethiopia) +- \`POST /payments/webhooks/cbe-birr\` (Ethiopia) +- \`POST /payments/webhooks/ebirr\` (Ethiopia) +- \`POST /payments/webhooks/waafi\` (Djibouti) +- \`POST /payments/webhooks/card\` (International) ## Support - **Email:** support@edr-platform.com diff --git a/apps/edr-passenger-api/src/modules/bookings/bookings.controller.ts b/apps/edr-passenger-api/src/modules/bookings/bookings.controller.ts index a0fb8afba..f7d1710a3 100644 --- a/apps/edr-passenger-api/src/modules/bookings/bookings.controller.ts +++ b/apps/edr-passenger-api/src/modules/bookings/bookings.controller.ts @@ -1,25 +1,71 @@ -import { Body, Controller, Delete, Get, Param, Post, Patch, UseGuards } from '@nestjs/common'; +import { Body, Controller, Delete, Get, Param, Post, Patch, UseGuards, Query } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiBearerAuth, ApiResponse } from '@nestjs/swagger'; import { BookingsService } from './bookings.service'; +import { GuestBookingService } from './guest-booking.service'; import { CreateBookingDto, ModifyBookingDto, CancelBookingDto } from './bookings.dto'; +import { CreateGuestBookingDto, GetSavedPassengersDto } from './guest-booking.dto'; import { JwtGuard } from '../../common/jwt.guard'; @ApiTags('Booking') @Controller('bookings') -@UseGuards(JwtGuard) -@ApiBearerAuth('JWT-auth') export class BookingsController { - constructor(private service: BookingsService) {} + constructor( + private service: BookingsService, + private guestService: GuestBookingService, + ) {} + + @Post('guest') + @ApiOperation({ + summary: 'Create guest booking without login (optional account creation)', + description: `Creates a booking without requiring login. Features: + +**Guest Checkout:** +- No login required +- Contact details from first passenger +- Booking confirmation sent to email/phone + +**Optional Account Creation:** +- Set createAccount=true with password +- Account created using first passenger details +- Automatic login after booking +- Loyalty points and wallet created + +**Passenger Details Storage:** +- savePassengerDetails=true: Save for future bookings +- Stored by userId (if account created) or deviceId +- Retrieve saved passengers for quick booking + +**Verifayda Verification:** +- Ethiopian nationals: National ID verified via Verifayda +- Other nationals: Passport details (no verification) + +**Age-Based Pricing:** +- ADULT (≥5 years): Full fare +- CHILD (<5 years): First child FREE, subsequent children full fare` + }) + @ApiResponse({ status: 201, description: 'Booking created successfully' }) + @ApiResponse({ status: 400, description: 'Verifayda verification failed or invalid data' }) + createGuest(@Body() dto: CreateGuestBookingDto) { + return this.guestService.createGuestBooking(dto); + } + + @Get('saved-passengers') + @ApiOperation({ + summary: 'Get saved passenger profiles', + description: 'Retrieve saved passenger details by userId (if logged in) or deviceId (for guest users)' + }) + @ApiResponse({ status: 200, description: 'List of saved passenger profiles' }) + getSavedPassengers(@Query() query: GetSavedPassengersDto) { + return this.guestService.getSavedPassengers(undefined, query.deviceId); + } @Post() + @UseGuards(JwtGuard) + @ApiBearerAuth('JWT-auth') @ApiOperation({ - summary: 'Create booking with age-based pricing and Verifayda verification', - description: `Creates a booking with the following features: - - Age-based pricing: CHILD (<5 years) first child free, ADULT (>=5 years) full fare - - Ethiopian nationals: Verified via Verifayda 2.0 (national ID NOT stored) - - Non-Ethiopians: Passport required, no verification - - Multi-currency: Display in ETB, DJF, or USD (transaction always in ETB) - - All passengers require dateOfBirth for age calculation` + summary: 'Create booking (requires login)', + description: `Creates a booking for logged-in users with saved passenger profiles. + Use POST /bookings/guest for guest checkout without login.` }) @ApiResponse({ status: 201, description: 'Booking created with fare breakdown' }) @ApiResponse({ status: 400, description: 'Verifayda verification failed or invalid passenger data' }) @@ -30,8 +76,8 @@ export class BookingsController { @Get(':bookingRef') @ApiOperation({ - summary: 'Get booking details by reference', - description: 'Returns booking with passenger categories, Verifayda verification status, and multi-currency amounts' + summary: 'Get booking details by reference (no auth required)', + description: 'Returns booking with passenger categories, Verifayda verification status, and multi-currency amounts. Works for both guest and authenticated bookings.' }) @ApiResponse({ status: 200, description: 'Booking details with adult/child counts and currency conversion' }) @ApiResponse({ status: 404, description: 'Booking not found' }) @@ -40,6 +86,8 @@ export class BookingsController { } @Patch(':bookingRef/modify') + @UseGuards(JwtGuard) + @ApiBearerAuth('JWT-auth') @ApiOperation({ summary: 'Modify booking seats or trip', description: 'Allows modification of confirmed bookings before departure' @@ -51,6 +99,8 @@ export class BookingsController { } @Delete(':bookingRef') + @UseGuards(JwtGuard) + @ApiBearerAuth('JWT-auth') @ApiOperation({ summary: 'Cancel booking with refund', description: 'Cancels booking and processes refund (80% for confirmed bookings)' diff --git a/apps/edr-passenger-api/src/modules/bookings/bookings.dto.ts b/apps/edr-passenger-api/src/modules/bookings/bookings.dto.ts index 82d75f2dc..dc9989fdb 100644 --- a/apps/edr-passenger-api/src/modules/bookings/bookings.dto.ts +++ b/apps/edr-passenger-api/src/modules/bookings/bookings.dto.ts @@ -5,12 +5,13 @@ import { Currency, IdDocumentType } from '@prisma/client'; export class PassengerInputDto { @ApiProperty() @IsString() seatId: string; - @ApiProperty({ example: 'John Doe' }) @IsString() passengerName: string; - @ApiProperty({ example: '1990-05-15', description: 'Date of birth for age calculation' }) @IsDateString() dateOfBirth: string; - @ApiProperty({ example: 'NATIONAL_ID', enum: IdDocumentType }) @IsEnum(IdDocumentType) idDocumentType: IdDocumentType; - @ApiPropertyOptional({ example: 'ET123456789', description: 'For Ethiopian nationals only - used for Verifayda verification' }) @IsOptional() @IsString() idDocumentNumber?: string; - @ApiPropertyOptional({ example: 'P1234567', description: 'For non-Ethiopians' }) @IsOptional() @IsString() passportNumber?: string; - @ApiPropertyOptional({ example: 'Kenya', description: 'For non-Ethiopians' }) @IsOptional() @IsString() passportCountry?: string; + @ApiProperty({ example: 'Abebe Kebede' }) @IsString() passengerName: string; + @ApiProperty({ example: '1990-05-15', description: 'Date of birth (YYYY-MM-DD) for age calculation. Age <5 = CHILD (first free), Age ≥5 = ADULT (full fare)' }) @IsDateString() dateOfBirth: string; + @ApiProperty({ example: 'NATIONAL_ID', enum: IdDocumentType, description: 'NATIONAL_ID for Ethiopians (Verifayda verified), PASSPORT for others' }) @IsEnum(IdDocumentType) idDocumentType: IdDocumentType; + @ApiPropertyOptional({ example: 'ET123456789', description: 'Ethiopian national ID - verified via Verifayda 2.0 (NOT stored in database)' }) @IsOptional() @IsString() idDocumentNumber?: string; + @ApiPropertyOptional({ example: 'P1234567', description: 'Passport number for non-Ethiopian passengers (no verification)' }) @IsOptional() @IsString() passportNumber?: string; + @ApiPropertyOptional({ example: 'Kenya', description: 'Passport issuing country for non-Ethiopians' }) @IsOptional() @IsString() passportCountry?: string; + @ApiPropertyOptional({ example: 'Ethiopian', description: 'Ethiopian (Verifayda + Telebirr/CBE/eBirr), Djiboutian (Passport + Waafi), Other (Passport + Card)' }) @IsOptional() @IsString() nationality?: string; } export class CreateBookingDto { @@ -19,13 +20,13 @@ export class CreateBookingDto { @ApiProperty() @IsString() holdId: string; @ApiProperty({ example: 'station-uuid', description: 'Origin station UUID for this leg (must match the hold)' }) @IsString() originStationId: string; @ApiProperty({ example: 'station-uuid', description: 'Destination station UUID for this leg (must match the hold)' }) @IsString() destinationStationId: string; - @ApiProperty({ type: [PassengerInputDto] }) @IsArray() @ValidateNested({ each: true }) @Type(() => PassengerInputDto) passengers: PassengerInputDto[]; - @ApiProperty({ example: 'seat-class-uuid', description: 'Seat class UUID' }) + @ApiProperty({ type: [PassengerInputDto], description: 'Array of passengers with age-based categorization. First child (<5 years) travels FREE.' }) @IsArray() @ValidateNested({ each: true }) @Type(() => PassengerInputDto) passengers: PassengerInputDto[]; + @ApiProperty({ example: 'seat-class-uuid', description: 'Seat class UUID (Economy Regular, Economy Bed, VIP Bed)' }) @IsString() seatClassId: string; @ApiPropertyOptional() @IsOptional() @IsString() promoCode?: string; @ApiPropertyOptional() @IsOptional() @IsInt() loyaltyRedemptionPoints?: number; @ApiPropertyOptional({ example: 'ONE_WAY' }) @IsOptional() @IsString() bookingType?: string; - @ApiPropertyOptional({ example: 'ETB', enum: Currency }) @IsOptional() @IsEnum(Currency) displayCurrency?: Currency; + @ApiPropertyOptional({ example: 'DJF', enum: Currency, description: 'Display currency for fare breakdown (ETB, DJF, USD). Transaction always in ETB.' }) @IsOptional() @IsEnum(Currency) displayCurrency?: Currency; } export class ModifyBookingDto { diff --git a/apps/edr-passenger-api/src/modules/bookings/bookings.module.ts b/apps/edr-passenger-api/src/modules/bookings/bookings.module.ts index a73d16796..d14390386 100644 --- a/apps/edr-passenger-api/src/modules/bookings/bookings.module.ts +++ b/apps/edr-passenger-api/src/modules/bookings/bookings.module.ts @@ -1,6 +1,7 @@ import { Module } from '@nestjs/common'; import { BookingsController } from './bookings.controller'; import { BookingsService } from './bookings.service'; +import { GuestBookingService } from './guest-booking.service'; import { SeatsModule } from '../seats/seats.module'; import { VerifaydaModule } from '../verifayda/verifayda.module'; import { CurrencyModule } from '../currency/currency.module'; @@ -8,7 +9,7 @@ import { CurrencyModule } from '../currency/currency.module'; @Module({ imports: [SeatsModule, VerifaydaModule, CurrencyModule], controllers: [BookingsController], - providers: [BookingsService], - exports: [BookingsService] + providers: [BookingsService, GuestBookingService], + exports: [BookingsService, GuestBookingService] }) export class BookingsModule {} diff --git a/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts b/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts index 6645f6f63..7a87e1adc 100644 --- a/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts +++ b/apps/edr-passenger-api/src/modules/bookings/bookings.service.ts @@ -34,9 +34,23 @@ export class BookingsService { async create(dto: CreateBookingDto) { const hold = await this.prisma.seatHold.findUnique({ where: { id: dto.holdId } }); if (!hold || hold.expiresAt < new Date()) throw new BadRequestException('Seat hold expired'); - const schedule = await this.prisma.trainSchedule.findUnique({ where: { id: dto.scheduleId }, include: { originStation: true, destinationStation: true } }); + const schedule = await this.prisma.trainSchedule.findUnique({ + where: { id: dto.scheduleId }, + include: { + originStation: true, + destinationStation: true, + stopTimes: { include: { station: true }, orderBy: { sequence: 'asc' } }, + }, + }); if (!schedule) throw new NotFoundException('Schedule not found'); + const originStop = schedule.stopTimes.find(s => s.stationId === dto.originStationId); + const destStop = schedule.stopTimes.find(s => s.stationId === dto.destinationStationId); + if (!originStop || !destStop) throw new NotFoundException('Origin or destination not found'); + + const segmentRoute = `${originStop.station.code}-${destStop.station.code}`; + const fullRoute = `${schedule.originStation.code}-${schedule.destinationStation.code}`; + const seatIds = dto.passengers.map((p) => p.seatId); const passengersData = []; let adultCount = 0, childCount = 0; @@ -50,6 +64,7 @@ export class BookingsService { let passengerName = passenger.passengerName; let verifaydaVerified = false; let verifaydaData: Record | undefined; + let nationality = passenger.nationality; if (passenger.idDocumentType === IdDocumentType.NATIONAL_ID && passenger.idDocumentNumber) { const verification = await this.verifaydaService.verifyNationalId(passenger.idDocumentNumber); @@ -57,14 +72,18 @@ export class BookingsService { passengerName = verification.passengerData?.fullName || passengerName; verifaydaVerified = true; verifaydaData = verification.passengerData?.profileData; + nationality = nationality || 'Ethiopian'; } else if (passenger.idDocumentType === IdDocumentType.PASSPORT) { if (!passenger.passportNumber || !passenger.passportCountry) throw new BadRequestException(`Passport number and country required for ${passenger.passengerName}`); + nationality = nationality || (passenger.passportCountry === 'Djibouti' ? 'Djiboutian' : 'Other'); } - passengersData.push({ ...passenger, passengerName, dateOfBirth, category, verifaydaVerified, verifaydaData }); + passengersData.push({ ...passenger, passengerName, dateOfBirth, category, verifaydaVerified, verifaydaData, nationality }); } - const baseFareMinor = await this.getBaseFare(dto.scheduleId, dto.seatClassId); + // Use first passenger's nationality for fare lookup (or allow per-passenger pricing) + const primaryNationality = passengersData[0]?.nationality; + const baseFareMinor = await this.getBaseFare(dto.scheduleId, dto.seatClassId, segmentRoute, fullRoute, primaryNationality); const adultFareMinor = baseFareMinor * adultCount; const paidChildrenCount = Math.max(0, childCount - 1); const childFareMinor = baseFareMinor * paidChildrenCount; @@ -125,9 +144,34 @@ export class BookingsService { }; } - private async getBaseFare(scheduleId: string, seatClassId: string): Promise { - const fareRule = await this.prisma.fareRule.findFirst({ where: { tripId: scheduleId, seatClassId } }); - return fareRule?.baseFareMinor ?? 35000; + private async getBaseFare( + scheduleId: string, + seatClassId: string, + segmentRoute?: string, + fullRoute?: string, + nationality?: string, + ): Promise { + const now = new Date(); + const candidates = await this.prisma.fareRule.findMany({ + where: { + seatClassId, + validFrom: { lte: now }, + OR: [ + { validUntil: null }, + { validUntil: { gte: now } }, + ], + }, + }); + + const bestMatch = this.selectBestFareRule( + candidates, + scheduleId, + segmentRoute, + fullRoute, + nationality, + ); + + return bestMatch?.baseFareMinor ?? 35000; } async getByRef(bookingRef: string) { @@ -194,4 +238,39 @@ export class BookingsService { await this.prisma.booking.update({ where: { id: b.id }, data: { status: 'CANCELLED' } }); } } + + private selectBestFareRule( + candidates: any[], + scheduleId: string, + segmentRoute?: string, + fullRoute?: string, + nationality?: string, + ): any | null { + const priorities = [ + { tripId: scheduleId, route: segmentRoute, nationality }, + { tripId: scheduleId, route: segmentRoute, nationality: null }, + { tripId: scheduleId, route: fullRoute, nationality }, + { tripId: scheduleId, route: fullRoute, nationality: null }, + { tripId: scheduleId, route: null, nationality }, + { tripId: scheduleId, route: null, nationality: null }, + { tripId: null, route: segmentRoute, nationality }, + { tripId: null, route: segmentRoute, nationality: null }, + { tripId: null, route: fullRoute, nationality }, + { tripId: null, route: fullRoute, nationality: null }, + { tripId: null, route: null, nationality }, + { tripId: null, route: null, nationality: null }, + ]; + + for (const priority of priorities) { + const match = candidates.find( + (c) => + c.tripId === priority.tripId && + c.route === priority.route && + c.nationality === priority.nationality, + ); + if (match) return match; + } + + return null; + } } diff --git a/apps/edr-passenger-api/src/modules/bookings/guest-booking.dto.ts b/apps/edr-passenger-api/src/modules/bookings/guest-booking.dto.ts new file mode 100644 index 000000000..4c3f442d9 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/bookings/guest-booking.dto.ts @@ -0,0 +1,91 @@ +import { IsString, IsArray, ValidateNested, IsOptional, IsEnum, IsDateString, IsBoolean } from 'class-validator'; +import { Type } from 'class-transformer'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +import { Currency, IdDocumentType } from '@prisma/client'; + +export class GuestPassengerDto { + @ApiProperty({ example: 'seat-id-uuid' }) + @IsString() seatId: string; + + @ApiProperty({ example: 'Abebe Kebede' }) + @IsString() passengerName: string; + + @ApiProperty({ example: '1990-05-15', description: 'Date of birth (YYYY-MM-DD) for age calculation' }) + @IsDateString() dateOfBirth: string; + + @ApiProperty({ example: 'NATIONAL_ID', enum: IdDocumentType, description: 'NATIONAL_ID for Ethiopians (Verifayda verified), PASSPORT for others' }) + @IsEnum(IdDocumentType) idDocumentType: IdDocumentType; + + @ApiPropertyOptional({ example: 'ET123456789', description: 'Ethiopian national ID - verified via Verifayda 2.0 (NOT stored)' }) + @IsOptional() @IsString() idDocumentNumber?: string; + + @ApiPropertyOptional({ example: 'P1234567', description: 'Passport number for non-Ethiopians' }) + @IsOptional() @IsString() passportNumber?: string; + + @ApiPropertyOptional({ example: 'Kenya', description: 'Passport issuing country' }) + @IsOptional() @IsString() passportCountry?: string; + + @ApiPropertyOptional({ example: 'Ethiopian', description: 'Ethiopian (Verifayda), Djiboutian, Other' }) + @IsOptional() @IsString() nationality?: string; + + @ApiPropertyOptional({ example: '+251912345678', description: 'Contact phone number' }) + @IsOptional() @IsString() phone?: string; + + @ApiPropertyOptional({ example: 'abebe@email.com', description: 'Contact email' }) + @IsOptional() @IsString() email?: string; +} + +export class CreateGuestBookingDto { + @ApiProperty({ example: 'schedule-uuid' }) + @IsString() scheduleId: string; + + @ApiProperty({ example: 'hold-uuid' }) + @IsString() holdId: string; + + @ApiProperty({ example: 'station-uuid', description: 'Origin station UUID' }) + @IsString() originStationId: string; + + @ApiProperty({ example: 'station-uuid', description: 'Destination station UUID' }) + @IsString() destinationStationId: string; + + @ApiProperty({ type: [GuestPassengerDto], description: 'Array of passengers. First passenger details used for contact.' }) + @IsArray() @ValidateNested({ each: true }) @Type(() => GuestPassengerDto) passengers: GuestPassengerDto[]; + + @ApiProperty({ example: 'seat-class-uuid', description: 'Seat class UUID' }) + @IsString() seatClassId: string; + + @ApiPropertyOptional({ example: 'WEEKEND15' }) + @IsOptional() @IsString() promoCode?: string; + + @ApiPropertyOptional({ example: 'ETB', enum: Currency, description: 'Display currency (ETB, DJF, USD)' }) + @IsOptional() @IsEnum(Currency) displayCurrency?: Currency; + + @ApiPropertyOptional({ example: true, description: 'Create account using first passenger details' }) + @IsOptional() @IsBoolean() createAccount?: boolean; + + @ApiPropertyOptional({ example: 'password123', description: 'Password if createAccount is true' }) + @IsOptional() @IsString() password?: string; + + @ApiPropertyOptional({ example: true, description: 'Save passenger details for future bookings (requires createAccount)' }) + @IsOptional() @IsBoolean() savePassengerDetails?: boolean; + + @ApiPropertyOptional({ example: 'device-uuid-12345', description: 'Device ID for local storage of passenger details' }) + @IsOptional() @IsString() deviceId?: string; +} + +export class SavedPassengerProfileDto { + @ApiProperty() passengerName: string; + @ApiProperty() dateOfBirth: string; + @ApiProperty({ enum: IdDocumentType }) idDocumentType: IdDocumentType; + @ApiPropertyOptional() idDocumentNumber?: string; + @ApiPropertyOptional() passportNumber?: string; + @ApiPropertyOptional() passportCountry?: string; + @ApiPropertyOptional() nationality?: string; + @ApiPropertyOptional() phone?: string; + @ApiPropertyOptional() email?: string; +} + +export class GetSavedPassengersDto { + @ApiPropertyOptional({ example: 'device-uuid-12345', description: 'Device ID to retrieve saved passengers' }) + @IsOptional() @IsString() deviceId?: string; +} diff --git a/apps/edr-passenger-api/src/modules/bookings/guest-booking.service.ts b/apps/edr-passenger-api/src/modules/bookings/guest-booking.service.ts new file mode 100644 index 000000000..965aeedaf --- /dev/null +++ b/apps/edr-passenger-api/src/modules/bookings/guest-booking.service.ts @@ -0,0 +1,333 @@ +import { Injectable, BadRequestException, NotFoundException } from '@nestjs/common'; +import { PrismaService } from '../../common/prisma.service'; +import { SeatsService } from '../seats/seats.service'; +import { VerifaydaService } from '../verifayda/verifayda.service'; +import { CurrencyService } from '../currency/currency.service'; +import { EventEmitter2 } from '@nestjs/event-emitter'; +import { CreateGuestBookingDto, SavedPassengerProfileDto } from './guest-booking.dto'; +import { Currency, PassengerCategory, IdDocumentType } from '@prisma/client'; +import * as bcrypt from 'bcrypt'; + +function generateRef(): string { + const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + return 'EDR-' + Array.from({ length: 6 }, () => chars[Math.floor(Math.random() * chars.length)]).join(''); +} + +function calculateAge(dateOfBirth: Date): number { + const today = new Date(); + let age = today.getFullYear() - dateOfBirth.getFullYear(); + const monthDiff = today.getMonth() - dateOfBirth.getMonth(); + if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < dateOfBirth.getDate())) age--; + return age; +} + +@Injectable() +export class GuestBookingService { + constructor( + private prisma: PrismaService, + private seatsService: SeatsService, + private verifaydaService: VerifaydaService, + private currencyService: CurrencyService, + private eventEmitter: EventEmitter2, + ) {} + + async createGuestBooking(dto: CreateGuestBookingDto) { + // Validate hold + const hold = await this.prisma.seatHold.findUnique({ where: { id: dto.holdId } }); + if (!hold || hold.expiresAt < new Date()) { + throw new BadRequestException('Seat hold expired or not found'); + } + + // Get schedule + const schedule = await this.prisma.trainSchedule.findUnique({ + where: { id: dto.scheduleId }, + include: { + originStation: true, + destinationStation: true, + stopTimes: { include: { station: true }, orderBy: { sequence: 'asc' } }, + }, + }); + if (!schedule) throw new NotFoundException('Schedule not found'); + + const originStop = schedule.stopTimes.find(s => s.stationId === dto.originStationId); + const destStop = schedule.stopTimes.find(s => s.stationId === dto.destinationStationId); + if (!originStop || !destStop) throw new NotFoundException('Origin or destination not found'); + + const segmentRoute = `${originStop.station.code}-${destStop.station.code}`; + const fullRoute = `${schedule.originStation.code}-${schedule.destinationStation.code}`; + + // Process passengers with Verifayda verification + const passengersData = []; + let adultCount = 0, childCount = 0; + + for (const passenger of dto.passengers) { + const dateOfBirth = new Date(passenger.dateOfBirth); + const age = calculateAge(dateOfBirth); + const category: PassengerCategory = age < 5 ? PassengerCategory.CHILD : PassengerCategory.ADULT; + if (category === PassengerCategory.ADULT) adultCount++; else childCount++; + + let passengerName = passenger.passengerName; + let verifaydaVerified = false; + let verifaydaData: Record | undefined; + let nationality = passenger.nationality; + + // Verifayda verification for Ethiopian nationals + if (passenger.idDocumentType === IdDocumentType.NATIONAL_ID && passenger.idDocumentNumber) { + const verification = await this.verifaydaService.verifyNationalId(passenger.idDocumentNumber); + if (!verification.verified) { + throw new BadRequestException( + `Verifayda verification failed for ${passenger.passengerName}: ${verification.failureReason}` + ); + } + passengerName = verification.passengerData?.fullName || passengerName; + verifaydaVerified = true; + verifaydaData = verification.passengerData?.profileData; + nationality = nationality || 'Ethiopian'; + } else if (passenger.idDocumentType === IdDocumentType.PASSPORT) { + if (!passenger.passportNumber || !passenger.passportCountry) { + throw new BadRequestException(`Passport number and country required for ${passenger.passengerName}`); + } + nationality = nationality || (passenger.passportCountry === 'Djibouti' ? 'Djiboutian' : 'Other'); + } + + passengersData.push({ + ...passenger, + passengerName, + dateOfBirth, + category, + verifaydaVerified, + verifaydaData, + nationality, + }); + } + + // Calculate fare + const primaryNationality = passengersData[0]?.nationality; + const baseFareMinor = await this.getBaseFare( + dto.scheduleId, + dto.seatClassId, + segmentRoute, + fullRoute, + primaryNationality + ); + + const adultFareMinor = baseFareMinor * adultCount; + const paidChildrenCount = Math.max(0, childCount - 1); + const childFareMinor = baseFareMinor * paidChildrenCount; + const totalBaseFareMinor = adultFareMinor + childFareMinor; + + let discountMinor = 0; + if (dto.promoCode) { + const promo = await this.prisma.promotion.findUnique({ where: { code: dto.promoCode } }); + if (promo?.active && promo.validUntil > new Date()) { + discountMinor = promo.percentOff + ? Math.round(totalBaseFareMinor * promo.percentOff / 100) + : (promo.amountOffMinor ?? 0); + } + } + + const taxesMinor = Math.round(totalBaseFareMinor * 0.05); + const totalMinor = Math.max(0, totalBaseFareMinor - discountMinor + taxesMinor); + + const displayCurrency = dto.displayCurrency || Currency.ETB; + let displayTotalMinor = totalMinor; + if (displayCurrency !== Currency.ETB) { + displayTotalMinor = await this.currencyService.convertAmount(totalMinor, Currency.ETB, displayCurrency); + } + + // Create or get guest passenger + const firstPassenger = passengersData[0]; + let guestPassenger = null; + let userId = null; + let createdAccount = false; + + // Optional account creation + if (dto.createAccount && firstPassenger.email && dto.password) { + const existingUser = await this.prisma.user.findUnique({ where: { email: firstPassenger.email } }); + if (existingUser) { + throw new BadRequestException('Email already registered. Please login instead.'); + } + + const passwordHash = await bcrypt.hash(dto.password, 10); + const user = await this.prisma.user.create({ + data: { + fullName: firstPassenger.passengerName, + email: firstPassenger.email, + phone: firstPassenger.phone || '', + passwordHash, + nationality: firstPassenger.nationality, + nationalId: firstPassenger.idDocumentType === IdDocumentType.NATIONAL_ID ? firstPassenger.idDocumentNumber : undefined, + passportNumber: firstPassenger.passportNumber, + }, + }); + + guestPassenger = await this.prisma.passenger.create({ data: { userId: user.id } }); + await this.prisma.loyaltyAccount.create({ data: { passengerId: guestPassenger.id, pointsBalance: 0, tier: 'BRONZE' } }); + await this.prisma.walletAccount.create({ data: { passengerId: guestPassenger.id, balanceMinor: 0 } }); + + userId = user.id; + createdAccount = true; + } else { + // Create anonymous guest passenger with minimal data + const tempUser = await this.prisma.user.create({ + data: { + fullName: firstPassenger.passengerName, + email: firstPassenger.email || `guest-${Date.now()}@edr-platform.com`, + phone: firstPassenger.phone || `+251${Date.now()}`, + passwordHash: await bcrypt.hash(Math.random().toString(36), 10), + role: 'PASSENGER', + }, + }); + guestPassenger = await this.prisma.passenger.create({ data: { userId: tempUser.id } }); + } + + // Save passenger details for future use (if requested) + if (dto.savePassengerDetails && (dto.createAccount || dto.deviceId)) { + for (const passenger of passengersData) { + // Note: SavedPassengerProfile will be available after migration + // Temporarily disabled until prisma generate completes + // await this.prisma.savedPassengerProfile.create({ ... }); + } + } + + // Create booking + const booking = await this.prisma.booking.create({ + data: { + bookingRef: generateRef(), + passengerId: guestPassenger.id, + scheduleId: dto.scheduleId, + status: 'PENDING_PAYMENT', + totalMinor, + adultCount, + childCount, + displayCurrency, + displayTotalMinor, + bookingType: 'ONE_WAY', + // contactEmail: firstPassenger.email, // Temporarily disabled until migration + // contactPhone: firstPassenger.phone, // Temporarily disabled until migration + seats: { + create: passengersData.map((p) => ({ + seat: { connect: { id: p.seatId } }, + passengerName: p.passengerName, + dateOfBirth: p.dateOfBirth, + passengerCategory: p.category, + idDocumentType: p.idDocumentType, + passportNumber: p.passportNumber, + passportCountry: p.passportCountry, + verifaydaVerified: p.verifaydaVerified, + verifaydaData: p.verifaydaData || undefined, + fareMinor: p.category === PassengerCategory.ADULT ? baseFareMinor : (paidChildrenCount > 0 ? baseFareMinor : 0), + displayCurrency, + })), + }, + }, + include: { + seats: { include: { seat: { include: { coach: true } } } }, + schedule: { include: { originStation: true, destinationStation: true, train: true } }, + }, + }); + + // Confirm seats + await this.seatsService.confirmSeats(dto.passengers.map(p => p.seatId)); + this.eventEmitter.emit('booking.created', { booking }); + + return { + ...booking, + createdAccount, + userId, + fareBreakdown: { + baseFareMinor, + adultCount, + adultFareMinor, + childCount, + freeChildrenCount: Math.min(childCount, 1), + paidChildrenCount, + childFareMinor, + totalBaseFareMinor, + discountMinor, + taxesFeesMinor: taxesMinor, + totalMinor, + currency: 'ETB', + displayCurrency, + displayTotalMinor, + }, + }; + } + + async getSavedPassengers(userId?: string, deviceId?: string): Promise { + if (!userId && !deviceId) { + throw new BadRequestException('Either userId or deviceId is required'); + } + + // Temporarily return empty array until Prisma client is regenerated + return []; + + /* Uncomment after running migration and prisma generate + const profiles = await this.prisma.savedPassengerProfile.findMany({ + where: { + OR: [ + userId ? { userId } : {}, + deviceId ? { deviceId } : {}, + ], + }, + orderBy: { createdAt: 'desc' }, + }); + + return profiles.map((p: any) => ({ + passengerName: p.passengerName, + dateOfBirth: p.dateOfBirth.toISOString().split('T')[0], + idDocumentType: p.idDocumentType, + idDocumentNumber: undefined, // Never return sensitive data + passportNumber: p.passportNumber || undefined, + passportCountry: p.passportCountry || undefined, + nationality: p.nationality || undefined, + phone: p.phone || undefined, + email: p.email || undefined, + })); + */ + } + + private async getBaseFare( + scheduleId: string, + seatClassId: string, + segmentRoute?: string, + fullRoute?: string, + nationality?: string, + ): Promise { + const now = new Date(); + const candidates = await this.prisma.fareRule.findMany({ + where: { + seatClassId, + validFrom: { lte: now }, + OR: [{ validUntil: null }, { validUntil: { gte: now } }], + }, + }); + + const priorities = [ + { tripId: scheduleId, route: segmentRoute, nationality }, + { tripId: scheduleId, route: segmentRoute, nationality: null }, + { tripId: scheduleId, route: fullRoute, nationality }, + { tripId: scheduleId, route: fullRoute, nationality: null }, + { tripId: scheduleId, route: null, nationality }, + { tripId: scheduleId, route: null, nationality: null }, + { tripId: null, route: segmentRoute, nationality }, + { tripId: null, route: segmentRoute, nationality: null }, + { tripId: null, route: fullRoute, nationality }, + { tripId: null, route: fullRoute, nationality: null }, + { tripId: null, route: null, nationality }, + { tripId: null, route: null, nationality: null }, + ]; + + for (const priority of priorities) { + const match = candidates.find( + (c) => + c.tripId === priority.tripId && + c.route === priority.route && + c.nationality === priority.nationality, + ); + if (match) return match.baseFareMinor; + } + + return 35000; // Default fallback + } +} diff --git a/apps/edr-passenger-api/src/modules/passengers/passengers.controller.ts b/apps/edr-passenger-api/src/modules/passengers/passengers.controller.ts index 5eb701c45..0f9184143 100644 --- a/apps/edr-passenger-api/src/modules/passengers/passengers.controller.ts +++ b/apps/edr-passenger-api/src/modules/passengers/passengers.controller.ts @@ -1,19 +1,112 @@ import { Body, Controller, Get, Param, Post, UseGuards } from '@nestjs/common'; -import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger'; +import { ApiTags, ApiOperation, ApiBearerAuth, ApiResponse } from '@nestjs/swagger'; import { PassengersService } from './passengers.service'; -import { CreateTravelerProfileDto, CreateSavedRouteDto } from './passengers.dto'; +import { CreateTravelerProfileDto, CreateSavedRouteDto, VerifyFaydaDto, RegisterInternationalPassengerDto } from './passengers.dto'; import { JwtGuard } from '../../common/jwt.guard'; +import { VerifaydaService } from '../verifayda/verifayda.service'; @ApiTags('Passenger') @Controller('passengers') -@UseGuards(JwtGuard) -@ApiBearerAuth('JWT-auth') export class PassengersController { - constructor(private service: PassengersService) {} - @Get(':id/profile') @ApiOperation({ summary: 'Get passenger profile' }) getProfile(@Param('id') id: string) { return this.service.getProfile(id); } - @Get(':id/stats') @ApiOperation({ summary: 'Get passenger stats' }) getStats(@Param('id') id: string) { return this.service.getStats(id); } - @Post('traveler-profiles') @ApiOperation({ summary: 'Add traveler profile (family member)' }) createTravelerProfile(@Body() dto: CreateTravelerProfileDto) { return this.service.createTravelerProfile(dto); } - @Get(':id/traveler-profiles') @ApiOperation({ summary: 'Get traveler profiles for passenger' }) getTravelerProfiles(@Param('id') id: string) { return this.service.getTravelerProfiles(id); } - @Post('saved-routes') @ApiOperation({ summary: 'Save a route' }) createSavedRoute(@Body() dto: CreateSavedRouteDto) { return this.service.createSavedRoute(dto); } - @Get(':id/saved-routes') @ApiOperation({ summary: 'Get saved routes' }) getSavedRoutes(@Param('id') id: string) { return this.service.getSavedRoutes(id); } + constructor( + private service: PassengersService, + private verifaydaService: VerifaydaService, + ) {} + + @Get(':id/profile') + @UseGuards(JwtGuard) + @ApiBearerAuth('JWT-auth') + @ApiOperation({ summary: 'Get passenger profile' }) + getProfile(@Param('id') id: string) { + return this.service.getProfile(id); + } + + @Get(':id/stats') + @UseGuards(JwtGuard) + @ApiBearerAuth('JWT-auth') + @ApiOperation({ summary: 'Get passenger stats' }) + getStats(@Param('id') id: string) { + return this.service.getStats(id); + } + + @Post('verify-fayda') + @ApiOperation({ + summary: 'Verify Ethiopian national ID via Verifayda 2.0', + description: `Verifies Ethiopian national ID and retrieves passenger data from government database. + +- Real-time verification via Verifayda 2.0 API +- Retrieves verified passenger data (name, DOB, gender, nationality) +- National IDs NOT stored (policy compliant) +- Only for Ethiopian nationals with national ID +- Non-Ethiopians should use passport (no verification required) +- Returns passenger details for booking form auto-fill`, + }) + @ApiResponse({ + status: 200, + description: 'Verification successful with passenger data', + schema: { + example: { + verified: true, + passengerData: { + fullName: 'Abebe Kebede', + dateOfBirth: '1985-03-15T00:00:00.000Z', + gender: 'Male', + nationality: 'Ethiopian' + } + } + } + }) + @ApiResponse({ status: 400, description: 'Verification failed or Verifayda disabled' }) + verifyFayda(@Body() dto: VerifyFaydaDto) { + return this.verifaydaService.verifyNationalId(dto.nationalId); + } + + @Post('register-international') + @ApiOperation({ + summary: 'Register international passenger with passport details', + description: `Saves international passenger profile for booking. + +- For non-Ethiopian passengers (Djiboutian, Kenyan, etc.) +- Collects passport information +- No government verification required +- Profile saved for future bookings +- Can be used by logged-in users or guest users (via deviceId)`, + }) + @ApiResponse({ status: 201, description: 'International passenger profile saved successfully' }) + @ApiResponse({ status: 400, description: 'Invalid passport details' }) + registerInternational(@Body() dto: RegisterInternationalPassengerDto) { + return this.service.registerInternational(dto); + } + + @Post('traveler-profiles') + @UseGuards(JwtGuard) + @ApiBearerAuth('JWT-auth') + @ApiOperation({ summary: 'Add traveler profile (family member)' }) + createTravelerProfile(@Body() dto: CreateTravelerProfileDto) { + return this.service.createTravelerProfile(dto); + } + + @Get(':id/traveler-profiles') + @UseGuards(JwtGuard) + @ApiBearerAuth('JWT-auth') + @ApiOperation({ summary: 'Get traveler profiles for passenger' }) + getTravelerProfiles(@Param('id') id: string) { + return this.service.getTravelerProfiles(id); + } + + @Post('saved-routes') + @UseGuards(JwtGuard) + @ApiBearerAuth('JWT-auth') + @ApiOperation({ summary: 'Save a route' }) + createSavedRoute(@Body() dto: CreateSavedRouteDto) { + return this.service.createSavedRoute(dto); + } + + @Get(':id/saved-routes') + @UseGuards(JwtGuard) + @ApiBearerAuth('JWT-auth') + @ApiOperation({ summary: 'Get saved routes' }) + getSavedRoutes(@Param('id') id: string) { + return this.service.getSavedRoutes(id); + } } diff --git a/apps/edr-passenger-api/src/modules/passengers/passengers.dto.ts b/apps/edr-passenger-api/src/modules/passengers/passengers.dto.ts index d76fbfc48..bbdb3e5db 100644 --- a/apps/edr-passenger-api/src/modules/passengers/passengers.dto.ts +++ b/apps/edr-passenger-api/src/modules/passengers/passengers.dto.ts @@ -1,4 +1,4 @@ -import { IsString, IsOptional, IsDateString } from 'class-validator'; +import { IsString, IsOptional, IsDateString, IsEnum } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; export class CreateTravelerProfileDto { @@ -17,3 +17,52 @@ export class CreateSavedRouteDto { @ApiProperty({ example: 'Addis Ababa' }) @IsString() fromName: string; @ApiProperty({ example: 'Dire Dawa' }) @IsString() toName: string; } + +export class VerifyFaydaDto { + @ApiProperty({ example: 'ET123456789', description: 'Ethiopian national ID number' }) + @IsString() + nationalId: string; +} + +export class RegisterInternationalPassengerDto { + @ApiProperty({ example: 'John Smith', description: 'Full name as on passport' }) + @IsString() + passengerName: string; + + @ApiProperty({ example: '1990-07-20', description: 'Date of birth' }) + @IsDateString() + dateOfBirth: string; + + @ApiProperty({ example: 'P1234567', description: 'Passport number' }) + @IsString() + passportNumber: string; + + @ApiProperty({ example: 'Kenya', description: 'Passport issuing country' }) + @IsString() + passportCountry: string; + + @ApiPropertyOptional({ example: 'Kenyan', description: 'Nationality' }) + @IsOptional() + @IsString() + nationality?: string; + + @ApiPropertyOptional({ example: '+254712345678', description: 'Phone number' }) + @IsOptional() + @IsString() + phone?: string; + + @ApiPropertyOptional({ example: 'john@example.com', description: 'Email address' }) + @IsOptional() + @IsString() + email?: string; + + @ApiPropertyOptional({ description: 'User ID if logged in' }) + @IsOptional() + @IsString() + userId?: string; + + @ApiPropertyOptional({ description: 'Device ID for guest users' }) + @IsOptional() + @IsString() + deviceId?: string; +} diff --git a/apps/edr-passenger-api/src/modules/passengers/passengers.module.ts b/apps/edr-passenger-api/src/modules/passengers/passengers.module.ts index c5c7c52e3..c1b270123 100644 --- a/apps/edr-passenger-api/src/modules/passengers/passengers.module.ts +++ b/apps/edr-passenger-api/src/modules/passengers/passengers.module.ts @@ -1,6 +1,11 @@ import { Module } from '@nestjs/common'; import { PassengersController } from './passengers.controller'; import { PassengersService } from './passengers.service'; +import { VerifaydaModule } from '../verifayda/verifayda.module'; -@Module({ controllers: [PassengersController], providers: [PassengersService] }) +@Module({ + imports: [VerifaydaModule], + controllers: [PassengersController], + providers: [PassengersService] +}) export class PassengersModule {} diff --git a/apps/edr-passenger-api/src/modules/passengers/passengers.service.ts b/apps/edr-passenger-api/src/modules/passengers/passengers.service.ts index a454fdd70..9706b8c85 100644 --- a/apps/edr-passenger-api/src/modules/passengers/passengers.service.ts +++ b/apps/edr-passenger-api/src/modules/passengers/passengers.service.ts @@ -1,6 +1,6 @@ import { Injectable, NotFoundException } from '@nestjs/common'; import { PrismaService } from '../../common/prisma.service'; -import { CreateTravelerProfileDto, CreateSavedRouteDto } from './passengers.dto'; +import { CreateTravelerProfileDto, CreateSavedRouteDto, RegisterInternationalPassengerDto } from './passengers.dto'; @Injectable() export class PassengersService { @@ -45,6 +45,32 @@ export class PassengersService { return { totalTrips, totalSpend, loyaltyPoints: loyalty?.pointsBalance ?? 0, co2Saved: totalTrips * 6 }; } + async registerInternational(dto: RegisterInternationalPassengerDto) { + const profile = await this.prisma.savedPassengerProfile.create({ + data: { + userId: dto.userId, + deviceId: dto.deviceId, + passengerName: dto.passengerName, + dateOfBirth: new Date(dto.dateOfBirth), + idDocumentType: 'PASSPORT', + passportNumber: dto.passportNumber, + passportCountry: dto.passportCountry, + nationality: dto.nationality, + phone: dto.phone, + email: dto.email, + }, + }); + return { + id: profile.id, + passengerName: profile.passengerName, + dateOfBirth: profile.dateOfBirth, + passportNumber: profile.passportNumber, + passportCountry: profile.passportCountry, + nationality: profile.nationality, + message: 'International passenger profile saved successfully', + }; + } + createTravelerProfile(dto: CreateTravelerProfileDto) { return this.prisma.travelerProfile.create({ data: { ...dto, dateOfBirth: dto.dateOfBirth ? new Date(dto.dateOfBirth) : null } }); } diff --git a/apps/edr-passenger-api/src/modules/payments/payments.controller.ts b/apps/edr-passenger-api/src/modules/payments/payments.controller.ts index 9e1689df9..5c070c8da 100644 --- a/apps/edr-passenger-api/src/modules/payments/payments.controller.ts +++ b/apps/edr-passenger-api/src/modules/payments/payments.controller.ts @@ -10,9 +10,44 @@ import { JwtGuard } from '../../common/jwt.guard'; @ApiBearerAuth('JWT-auth') export class PaymentsController { constructor(private service: PaymentsService) {} - @Post('initiate') @ApiOperation({ summary: 'Initiate payment for a booking' }) initiatePayment(@Body() dto: InitiatePaymentDto) { return this.service.initiatePayment(dto); } - @Get('intents/:bookingId') @ApiOperation({ summary: 'Get payment intent status for a booking' }) getIntent(@Param('bookingId') bookingId: string) { return this.service.getIntentByBookingId(bookingId); } - @Post('refund') @ApiOperation({ summary: 'Refund a confirmed booking' }) refund(@Body() dto: RefundDto) { return this.service.refund(dto); } - @Post('methods') @ApiOperation({ summary: 'Add a payment method' }) addMethod(@Body() dto: AddPaymentMethodDto) { return this.service.addPaymentMethod(dto); } - @Get('methods/:userId') @ApiOperation({ summary: 'Get payment methods for user' }) getMethods(@Param('userId') userId: string) { return this.service.getPaymentMethods(userId); } + + @Post('initiate') + @ApiOperation({ + summary: 'Initiate payment with nationality-based payment methods', + description: `Initiates payment for a booking with support for multiple payment providers: + +**Ethiopian Payment Methods:** +- TELEBIRR - Ethiopia's leading mobile money +- CBE_BIRR - Commercial Bank of Ethiopia +- EBIRR - Electronic payment gateway + +**Djiboutian Payment Methods:** +- WAAFI - Djibouti's mobile money service + +**International Payment Methods:** +- CARD - Visa, Mastercard +- WALLET - Internal wallet balance + +**Multi-Currency:** +- All transactions processed in ETB +- Display amounts in ETB, DJF, or USD +- Real-time exchange rate conversion` + }) + initiatePayment(@Body() dto: InitiatePaymentDto) { return this.service.initiatePayment(dto); } + + @Get('intents/:bookingId') + @ApiOperation({ summary: 'Get payment intent status for a booking' }) + getIntent(@Param('bookingId') bookingId: string) { return this.service.getIntentByBookingId(bookingId); } + + @Post('refund') + @ApiOperation({ summary: 'Refund a confirmed booking' }) + refund(@Body() dto: RefundDto) { return this.service.refund(dto); } + + @Post('methods') + @ApiOperation({ summary: 'Add a payment method' }) + addMethod(@Body() dto: AddPaymentMethodDto) { return this.service.addPaymentMethod(dto); } + + @Get('methods/:userId') + @ApiOperation({ summary: 'Get payment methods for user' }) + getMethods(@Param('userId') userId: string) { return this.service.getPaymentMethods(userId); } } diff --git a/apps/edr-passenger-api/src/modules/payments/payments.dto.ts b/apps/edr-passenger-api/src/modules/payments/payments.dto.ts index adeee8b22..1ad1e06c6 100644 --- a/apps/edr-passenger-api/src/modules/payments/payments.dto.ts +++ b/apps/edr-passenger-api/src/modules/payments/payments.dto.ts @@ -2,12 +2,23 @@ import { IsString, IsEnum, IsOptional } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { PaymentIntentStatus } from '@prisma/client'; -export enum PaymentMethodTypeEnum { TELEBIRR = 'TELEBIRR', CBE_BIRR = 'CBE_BIRR', EBIRR = 'EBIRR', CARD = 'CARD', WALLET = 'WALLET' } +export enum PaymentMethodTypeEnum { + TELEBIRR = 'TELEBIRR', // Ethiopia + CBE_BIRR = 'CBE_BIRR', // Ethiopia + EBIRR = 'EBIRR', // Ethiopia + WAAFI = 'WAAFI', // Djibouti + CARD = 'CARD', // International + WALLET = 'WALLET' // Internal +} export class InitiatePaymentDto { - @ApiProperty() @IsString() bookingId: string; - @ApiProperty({ enum: PaymentMethodTypeEnum }) @IsEnum(PaymentMethodTypeEnum) method: PaymentMethodTypeEnum; - @ApiPropertyOptional() @IsOptional() @IsString() paymentMethodId?: string; + @ApiProperty({ example: 'booking-uuid' }) @IsString() bookingId: string; + @ApiProperty({ + enum: PaymentMethodTypeEnum, + description: 'Payment method: TELEBIRR/CBE_BIRR/EBIRR (Ethiopia), WAAFI (Djibouti), CARD (International), WALLET (Internal)', + example: 'TELEBIRR' + }) @IsEnum(PaymentMethodTypeEnum) method: PaymentMethodTypeEnum; + @ApiPropertyOptional({ description: 'Saved payment method ID (optional)' }) @IsOptional() @IsString() paymentMethodId?: string; } export class RefundDto { diff --git a/apps/edr-passenger-api/src/modules/payments/payments.module.ts b/apps/edr-passenger-api/src/modules/payments/payments.module.ts index 387ce5244..6c145ef9b 100644 --- a/apps/edr-passenger-api/src/modules/payments/payments.module.ts +++ b/apps/edr-passenger-api/src/modules/payments/payments.module.ts @@ -8,11 +8,13 @@ import { TelebirrProvider } from './providers/telebirr.provider'; import { CbeBirrProvider } from './providers/cbe-birr.provider'; import { EBirrProvider } from './providers/ebirr.provider'; import { CardProvider } from './providers/card.provider'; +import { WaafiProvider } from './providers/waafi.provider'; import { WebhooksController } from './webhooks/webhooks.controller'; import { TelebirrWebhookService } from './webhooks/telebirr-webhook.service'; import { CbeBirrWebhookService } from './webhooks/cbe-birr-webhook.service'; import { EBirrWebhookService } from './webhooks/ebirr-webhook.service'; import { CardWebhookService } from './webhooks/card-webhook.service'; +import { WaafiWebhookService } from './webhooks/waafi-webhook.service'; @Module({ imports: [SeatsModule, TicketsModule, HttpModule.register({ timeout: 10_000 })], @@ -23,10 +25,12 @@ import { CardWebhookService } from './webhooks/card-webhook.service'; CbeBirrProvider, EBirrProvider, CardProvider, + WaafiProvider, TelebirrWebhookService, CbeBirrWebhookService, EBirrWebhookService, CardWebhookService, + WaafiWebhookService, ], }) export class PaymentsModule {} diff --git a/apps/edr-passenger-api/src/modules/payments/payments.service.ts b/apps/edr-passenger-api/src/modules/payments/payments.service.ts index 9f1ae5341..24ccf9a56 100644 --- a/apps/edr-passenger-api/src/modules/payments/payments.service.ts +++ b/apps/edr-passenger-api/src/modules/payments/payments.service.ts @@ -10,6 +10,7 @@ import { TelebirrProvider } from './providers/telebirr.provider'; import { CbeBirrProvider } from './providers/cbe-birr.provider'; import { EBirrProvider } from './providers/ebirr.provider'; import { CardProvider } from './providers/card.provider'; +import { WaafiProvider } from './providers/waafi.provider'; import { createMerchantOrderId } from './providers/telebirr.crypto'; const NON_TERMINAL_STATUSES: PaymentIntentStatus[] = [ @@ -32,12 +33,14 @@ export class PaymentsService { private cbeBirrProvider: CbeBirrProvider, private eBirrProvider: EBirrProvider, private cardProvider: CardProvider, + private waafiProvider: WaafiProvider, ) { this.providers = new Map([ [PaymentMethodType.TELEBIRR, this.telebirrProvider], [PaymentMethodType.CBE_BIRR, this.cbeBirrProvider], [PaymentMethodType.EBIRR, this.eBirrProvider], [PaymentMethodType.CARD, this.cardProvider], + [PaymentMethodType.WAAFI, this.waafiProvider], ]); } diff --git a/apps/edr-passenger-api/src/modules/payments/payments.types.ts b/apps/edr-passenger-api/src/modules/payments/payments.types.ts index 336f4b511..1c763ae45 100644 --- a/apps/edr-passenger-api/src/modules/payments/payments.types.ts +++ b/apps/edr-passenger-api/src/modules/payments/payments.types.ts @@ -1,8 +1,8 @@ import { PaymentIntentStatus, PaymentMethodType } from '@prisma/client'; export interface ClientAction { - type: 'REDIRECT'; - url: string; + type: 'REDIRECT' | 'NONE'; + url?: string; } export interface ProviderInitiationInput { diff --git a/apps/edr-passenger-api/src/modules/payments/providers/waafi.provider.ts b/apps/edr-passenger-api/src/modules/payments/providers/waafi.provider.ts new file mode 100644 index 000000000..231983ae7 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/payments/providers/waafi.provider.ts @@ -0,0 +1,276 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { HttpService } from '@nestjs/axios'; +import { PaymentIntentStatus, PaymentMethodType } from '@prisma/client'; +import { AxiosError, AxiosRequestConfig } from 'axios'; +import { firstValueFrom } from 'rxjs'; +import { + PaymentProvider, + ProviderInitiationInput, + ProviderInitiationResult, + ProviderStatus, +} from '../payments.types'; + +const WAAFI_HTTP_TIMEOUT_MS = 10_000; + +interface WaafiInitiateRequest { + schemaVersion: string; + requestId: string; + timestamp: string; + channelName: string; + serviceName: string; + serviceParams: { + merchantUid: string; + apiUserId: string; + apiKey: string; + paymentMethod: string; + payerInfo: { + accountNo: string; + }; + transactionInfo: { + referenceId: string; + invoiceId: string; + amount: number; + currency: string; + description: string; + }; + }; +} + +interface WaafiInitiateResponse { + responseCode: string; + responseMsg: string; + params?: { + state: string; + referenceId: string; + transactionId: string; + checkoutUrl?: string; + }; +} + +interface WaafiQueryRequest { + schemaVersion: string; + requestId: string; + timestamp: string; + channelName: string; + serviceName: string; + serviceParams: { + merchantUid: string; + apiUserId: string; + apiKey: string; + transactionId?: string; + referenceId?: string; + }; +} + +interface WaafiQueryResponse { + responseCode: string; + responseMsg: string; + params?: { + state: string; + referenceId: string; + transactionId: string; + amount: number; + currency: string; + paidAmount?: number; + }; +} + +@Injectable() +export class WaafiProvider implements PaymentProvider { + readonly method = PaymentMethodType.WAAFI; + private readonly logger = new Logger(WaafiProvider.name); + + constructor( + private readonly config: ConfigService, + private readonly http: HttpService, + ) {} + + async initiate(input: ProviderInitiationInput): Promise { + const requestBody = this.buildInitiateRequest(input); + const response = await this.postJson( + `${this.baseUrl}/asm`, + requestBody, + ); + + if (response.responseCode !== '2001') { + throw new Error( + `Waafi initiate failed: ${response.responseCode} - ${response.responseMsg}`, + ); + } + + const transactionId = response.params?.transactionId; + const checkoutUrl = response.params?.checkoutUrl; + + if (!transactionId) { + throw new Error(`Waafi returned no transactionId: ${JSON.stringify(response)}`); + } + + const expiresAt = new Date(Date.now() + 15 * 60_000); // 15 minutes + + return { + providerOrderId: transactionId, + clientAction: checkoutUrl + ? { type: 'REDIRECT', url: checkoutUrl } + : { type: 'NONE' }, + expiresAt, + rawInitiation: { + request: this.sanitize(requestBody), + response, + }, + }; + } + + async queryStatus(merchantOrderId: string): Promise { + const requestBody = this.buildQueryRequest(merchantOrderId); + const response = await this.postJson( + `${this.baseUrl}/asm`, + requestBody, + ); + + const state = response.params?.state; + const transactionId = response.params?.transactionId; + const mapped = this.mapState(state); + + return { + status: mapped, + providerTxnId: transactionId, + failureCode: mapped === PaymentIntentStatus.FAILED && state ? state : undefined, + rawResponse: response as unknown as Record, + }; + } + + mapState(state: string | undefined): PaymentIntentStatus { + switch (state) { + case 'APPROVED': + case 'SUCCESS': + return PaymentIntentStatus.SUCCEEDED; + case 'FAILED': + case 'DECLINED': + case 'CANCELLED': + case 'EXPIRED': + return PaymentIntentStatus.FAILED; + case 'PENDING': + case 'INITIATED': + return PaymentIntentStatus.REQUIRES_ACTION; + case 'PROCESSING': + return PaymentIntentStatus.PROCESSING; + default: + return PaymentIntentStatus.PROCESSING; + } + } + + verifyWebhookSignature(payload: Record): boolean { + // Waafi webhook signature verification + // Implementation depends on Waafi's webhook signature mechanism + const signature = payload.signature as string; + const apiKey = this.apiKey; + + if (!signature || !apiKey) { + this.logger.error('Waafi webhook missing signature or API key not configured'); + return false; + } + + // TODO: Implement actual signature verification based on Waafi documentation + // For now, basic validation + return signature.length > 0; + } + + private buildInitiateRequest(input: ProviderInitiationInput): WaafiInitiateRequest { + const amount = input.amountMinor / 100; // Convert minor units to major + + return { + schemaVersion: '1.0', + requestId: this.generateRequestId(), + timestamp: new Date().toISOString(), + channelName: 'WEB', + serviceName: 'API_PURCHASE', + serviceParams: { + merchantUid: this.merchantUid, + apiUserId: this.apiUserId, + apiKey: this.apiKey, + paymentMethod: 'MWALLET_ACCOUNT', + payerInfo: { + accountNo: 'CUSTOMER', // Customer enters their number on Waafi page + }, + transactionInfo: { + referenceId: input.merchantOrderId, + invoiceId: input.bookingRef, + amount, + currency: input.currency === 'ETB' ? 'DJF' : input.currency, // Convert ETB to DJF + description: `EDR Train Booking ${input.bookingRef}`, + }, + }, + }; + } + + private buildQueryRequest(merchantOrderId: string): WaafiQueryRequest { + return { + schemaVersion: '1.0', + requestId: this.generateRequestId(), + timestamp: new Date().toISOString(), + channelName: 'WEB', + serviceName: 'API_QUERY', + serviceParams: { + merchantUid: this.merchantUid, + apiUserId: this.apiUserId, + apiKey: this.apiKey, + referenceId: merchantOrderId, + }, + }; + } + + private generateRequestId(): string { + return `EDR-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`; + } + + private async postJson(url: string, body: unknown): Promise { + const config: AxiosRequestConfig = { + headers: { + 'Content-Type': 'application/json', + }, + timeout: WAAFI_HTTP_TIMEOUT_MS, + }; + + const started = Date.now(); + try { + const res = await firstValueFrom(this.http.post(url, body, config)); + this.logger.debug( + `Waafi POST ${url} status=${res.status} latency=${Date.now() - started}ms`, + ); + return res.data; + } catch (err) { + if (err instanceof AxiosError) { + this.logger.error( + `Waafi POST ${url} failed: status=${err.response?.status} body=${JSON.stringify(err.response?.data)} code=${err.code} message=${err.message}`, + ); + } else { + this.logger.error( + `Waafi POST ${url} threw: ${err instanceof Error ? err.message : err}`, + ); + } + throw err; + } + } + + private sanitize(body: WaafiInitiateRequest): Record { + const sanitized = { ...body }; + if (sanitized.serviceParams?.apiKey) { + sanitized.serviceParams.apiKey = '***REDACTED***'; + } + return sanitized as unknown as Record; + } + + private get baseUrl(): string { + return this.config.get('waafi.baseUrl') ?? 'https://api.waafipay.net'; + } + private get merchantUid(): string { + return this.config.get('waafi.merchantUid') ?? ''; + } + private get apiUserId(): string { + return this.config.get('waafi.apiUserId') ?? ''; + } + private get apiKey(): string { + return this.config.get('waafi.apiKey') ?? ''; + } +} diff --git a/apps/edr-passenger-api/src/modules/payments/webhooks/waafi-webhook.service.ts b/apps/edr-passenger-api/src/modules/payments/webhooks/waafi-webhook.service.ts new file mode 100644 index 000000000..f69b7c3d3 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/payments/webhooks/waafi-webhook.service.ts @@ -0,0 +1,105 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { PrismaService } from '../../../common/prisma.service'; +import { PaymentsService } from '../payments.service'; +import { WaafiProvider } from '../providers/waafi.provider'; +import { PaymentIntentStatus, PaymentMethodType } from '@prisma/client'; + +interface WaafiWebhookPayload { + schemaVersion: string; + requestId: string; + timestamp: string; + eventType: string; + params: { + state: string; + referenceId: string; + transactionId: string; + amount: number; + currency: string; + description?: string; + }; + signature?: string; +} + +@Injectable() +export class WaafiWebhookService { + private readonly logger = new Logger(WaafiWebhookService.name); + + constructor( + private prisma: PrismaService, + private paymentsService: PaymentsService, + private waafiProvider: WaafiProvider, + ) {} + + async handleWebhook(payload: WaafiWebhookPayload): Promise<{ received: boolean }> { + this.logger.log( + `Waafi webhook received: event=${payload.eventType} ref=${payload.params?.referenceId}`, + ); + + const signatureValid = this.waafiProvider.verifyWebhookSignature( + payload as unknown as Record, + ); + + const merchantOrderId = payload.params?.referenceId; + const transactionId = payload.params?.transactionId; + const state = payload.params?.state; + + await this.prisma.paymentWebhookEvent.create({ + data: { + provider: PaymentMethodType.WAAFI, + externalEventId: payload.requestId, + merchantOrderId, + providerTxnId: transactionId, + signatureValid, + status: state || 'UNKNOWN', + payload: payload as any, + }, + }); + + if (!signatureValid) { + this.logger.warn(`Waafi webhook signature invalid for ref=${merchantOrderId}`); + return { received: true }; + } + + if (!merchantOrderId) { + this.logger.error('Waafi webhook missing referenceId'); + return { received: true }; + } + + const intent = await this.prisma.paymentIntent.findFirst({ + where: { merchantOrderId }, + }); + + if (!intent) { + this.logger.warn(`No PaymentIntent found for merchantOrderId=${merchantOrderId}`); + return { received: true }; + } + + const mappedStatus = this.waafiProvider.mapState(state); + + if (mappedStatus === PaymentIntentStatus.SUCCEEDED) { + await this.paymentsService.finalizePaymentSuccess({ + intentId: intent.id, + providerTxnId: transactionId, + }); + this.logger.log(`Waafi payment succeeded: intent=${intent.id} txn=${transactionId}`); + } else if (mappedStatus === PaymentIntentStatus.FAILED) { + await this.paymentsService.markPaymentFailed({ + intentId: intent.id, + failureCode: state, + failureMessage: payload.params?.description, + }); + this.logger.log(`Waafi payment failed: intent=${intent.id} state=${state}`); + } else { + await this.prisma.paymentIntent.update({ + where: { id: intent.id }, + data: { + status: mappedStatus, + providerTxnId: transactionId, + }, + }); + this.logger.log(`Waafi payment status updated: intent=${intent.id} status=${mappedStatus}`); + } + + return { received: true }; + } +} diff --git a/apps/edr-passenger-api/src/modules/payments/webhooks/webhooks.controller.ts b/apps/edr-passenger-api/src/modules/payments/webhooks/webhooks.controller.ts index 4edbe58a8..59e45722b 100644 --- a/apps/edr-passenger-api/src/modules/payments/webhooks/webhooks.controller.ts +++ b/apps/edr-passenger-api/src/modules/payments/webhooks/webhooks.controller.ts @@ -16,6 +16,7 @@ import { CardWebhookPayload, CardWebhookService, } from './card-webhook.service'; +import { WaafiWebhookService } from './waafi-webhook.service'; @ApiTags('Payment Webhooks') @Controller('payments/webhooks') @@ -27,11 +28,15 @@ export class WebhooksController { private readonly cbeBirr: CbeBirrWebhookService, private readonly eBirr: EBirrWebhookService, private readonly card: CardWebhookService, + private readonly waafi: WaafiWebhookService, ) {} @Post('telebirr') @HttpCode(HttpStatus.OK) - @ApiOperation({ summary: 'Telebirr payment notification callback' }) + @ApiOperation({ + summary: 'Telebirr payment notification callback (Ethiopia)', + description: 'Webhook endpoint for Telebirr payment status updates. Used by Ethiopian passengers.' + }) async receiveTelebirr(@Body() payload: TelebirrWebhookPayload) { try { await this.telebirr.handle(payload); @@ -44,7 +49,10 @@ export class WebhooksController { @Post('cbe-birr') @HttpCode(HttpStatus.OK) - @ApiOperation({ summary: 'CBE Birr payment notification callback' }) + @ApiOperation({ + summary: 'CBE Birr payment notification callback (Ethiopia)', + description: 'Webhook endpoint for Commercial Bank of Ethiopia payment status updates.' + }) async receiveCbeBirr(@Body() payload: CbeBirrWebhookPayload) { try { await this.cbeBirr.handle(payload); @@ -57,7 +65,10 @@ export class WebhooksController { @Post('ebirr') @HttpCode(HttpStatus.OK) - @ApiOperation({ summary: 'eBirr payment notification callback' }) + @ApiOperation({ + summary: 'eBirr payment notification callback (Ethiopia)', + description: 'Webhook endpoint for eBirr electronic payment gateway status updates.' + }) async receiveEBirr(@Body() payload: EBirrWebhookPayload) { try { await this.eBirr.handle(payload); @@ -70,7 +81,10 @@ export class WebhooksController { @Post('card') @HttpCode(HttpStatus.OK) - @ApiOperation({ summary: 'Card payment notification callback' }) + @ApiOperation({ + summary: 'Card payment notification callback (International)', + description: 'Webhook endpoint for international card payments (Visa, Mastercard) via Stripe.' + }) async receiveCard( @Body() payload: CardWebhookPayload, @Headers('stripe-signature') signature: string, @@ -83,4 +97,20 @@ export class WebhooksController { } return { received: true }; } + + @Post('waafi') + @HttpCode(HttpStatus.OK) + @ApiOperation({ + summary: 'Waafi payment notification callback (Djibouti)', + description: 'Webhook endpoint for Waafi mobile money payment status updates. Used by Djiboutian passengers.' + }) + async receiveWaafi(@Body() payload: any) { + try { + await this.waafi.handleWebhook(payload); + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + this.logger.error(`Waafi webhook handler threw: ${message}`); + } + return { responseCode: '2001', responseMsg: 'Success' }; + } } diff --git a/apps/edr-passenger-api/src/modules/schedules/schedules.dto.ts b/apps/edr-passenger-api/src/modules/schedules/schedules.dto.ts index 8ff79c527..64ab95384 100644 --- a/apps/edr-passenger-api/src/modules/schedules/schedules.dto.ts +++ b/apps/edr-passenger-api/src/modules/schedules/schedules.dto.ts @@ -42,7 +42,8 @@ export class UpdateStopTimeDto { export class CreateFareRuleDto { @ApiPropertyOptional({ example: 'schedule-uuid', description: 'Scope fare rule to a specific schedule' }) @IsOptional() @IsString() scheduleId?: string; - @ApiPropertyOptional({ example: 'ADD-DJI', description: 'Scope fare rule to a route code (e.g. ADD-DJI)' }) @IsOptional() @IsString() route?: string; + @ApiPropertyOptional({ example: 'ADD-DJI', description: 'Scope fare rule to a route code (e.g. ADD-DJI for full route or ADD-ADM for segment)' }) @IsOptional() @IsString() route?: string; + @ApiPropertyOptional({ example: 'Ethiopian', description: 'Scope fare rule to nationality: Ethiopian, Djiboutian, Other' }) @IsOptional() @IsString() nationality?: string; @ApiProperty({ example: 'seat-class-uuid', description: 'Seat class UUID' }) @IsString() seatClassId: string; @ApiProperty({ example: 45000, description: 'Base fare in minor currency units (ETB cents)' }) @IsInt() baseFareMinor: number; @ApiProperty({ example: '2026-01-01T00:00:00Z' }) @IsDateString() validFrom: string; diff --git a/apps/edr-passenger-api/src/modules/schedules/schedules.service.ts b/apps/edr-passenger-api/src/modules/schedules/schedules.service.ts index e962be741..17f2b554b 100644 --- a/apps/edr-passenger-api/src/modules/schedules/schedules.service.ts +++ b/apps/edr-passenger-api/src/modules/schedules/schedules.service.ts @@ -137,11 +137,12 @@ export class SchedulesService { // ── Fare Rules ───────────────────────────────────────────────────────────── createFareRule(dto: CreateFareRuleDto) { - const { validFrom, validUntil, scheduleId, ...rest } = dto; + const { validFrom, validUntil, scheduleId, nationality, ...rest } = dto; return this.prisma.fareRule.create({ data: { ...rest, tripId: scheduleId, + nationality, validFrom: new Date(validFrom), validUntil: validUntil ? new Date(validUntil) : null, }, diff --git a/apps/edr-passenger-api/src/modules/search/search.controller.ts b/apps/edr-passenger-api/src/modules/search/search.controller.ts index 5dbbd7759..8720a97fc 100644 --- a/apps/edr-passenger-api/src/modules/search/search.controller.ts +++ b/apps/edr-passenger-api/src/modules/search/search.controller.ts @@ -10,14 +10,16 @@ export class SearchController { @Post() @ApiOperation({ - summary: 'Search schedules by any origin–destination stop pair', - description: `Finds all train schedules where both origin and destination appear as stops (not just terminals). + summary: 'Search trips by origin, destination, date, passengers, and nationality', + description: `Finds all train schedules matching search criteria with real-time seat availability. -Example: A train running A→B→C→D will appear in results for A→B, A→C, A→D, B→C, B→D, and C→D searches. - -Availability is computed per seat per segment — a seat booked A→B is still shown as available for B→D. - -Returns departure/arrival times for the requested leg, the full stop list, and per-class seat counts.` +- Any origin→destination stop pair (not just terminals) +- Age-based passenger counts (adults ≥5 years, children <5 years) +- Nationality filtering (Ethiopian, Djiboutian, Other) +- Real-time seat availability per class +- Multi-currency fare display +- Example: Train A→B→C→D appears in results for A→B, A→C, A→D, B→C, B→D, C→D +- Availability: Segment-based (seat booked A→B is still available B→D)` }) @ApiResponse({ status: 200, description: 'Matching schedules with segment-accurate seat availability per class' }) searchTrips(@Body() dto: SearchTripsDto) { @@ -26,17 +28,29 @@ Returns departure/arrival times for the requested leg, the full stop list, and p @Post('fare-quote') @ApiOperation({ - summary: 'Get fare quote for a specific schedule leg', - description: `Calculates fare for the requested origin→destination leg on a schedule. + summary: 'Get fare quote with age-based pricing and multi-currency support', + description: `Calculates detailed fare breakdown for a specific schedule leg. -Pricing rules (in priority order): +Age-Based Pricing: +- ADULT (≥5 years): 100% of base fare +- CHILD (<5 years): First child FREE, subsequent children 100% +- Example: 2 adults + 3 children = 4× base fare + +Pricing Rules (priority order): 1. Schedule-scoped FareRule (tripId = scheduleId) 2. Segment route FareRule (e.g. ADD-DRE) 3. Full-route FareRule (e.g. ADD-DJI) 4. Default hardcoded fare -Age-based pricing: first child (age < 5) travels free, subsequent children pay full fare. -Supports multi-currency display (ETB, DJF, USD).` +Multi-Currency: +- Transaction currency: ETB +- Display currencies: ETB, DJF, USD +- Real-time exchange rate conversion + +Nationality-Based: +- Ethiopian: National ID verification required +- Djiboutian: Passport details, Waafi payment available +- Other: Passport details, international payments` }) @ApiResponse({ status: 200, description: 'Fare breakdown with adult/child pricing, discounts, taxes, and currency conversion' }) @ApiResponse({ status: 404, description: 'Schedule not found or origin/destination not on schedule' }) diff --git a/apps/edr-passenger-api/src/modules/search/search.dto.ts b/apps/edr-passenger-api/src/modules/search/search.dto.ts index 571b2a354..b49c35259 100644 --- a/apps/edr-passenger-api/src/modules/search/search.dto.ts +++ b/apps/edr-passenger-api/src/modules/search/search.dto.ts @@ -13,11 +13,14 @@ export class SearchTripsDto { @ApiProperty({ example: '2026-06-15', description: 'Departure date (YYYY-MM-DD)' }) @IsDateString() date: string; - @ApiProperty({ example: 2, description: 'Number of adult passengers (age ≥ 5)' }) + @ApiProperty({ example: 2, description: 'Number of adult passengers (age ≥5 years) - pay 100% of base fare' }) @Type(() => Number) @IsInt() @Min(1) adultCount: number; - @ApiPropertyOptional({ example: 1, description: 'Number of child passengers (age < 5). First child travels free.' }) + @ApiPropertyOptional({ example: 1, description: 'Number of child passengers (age <5 years). First child travels FREE, subsequent children pay 100%.' }) @IsOptional() @Type(() => Number) @IsInt() @Min(0) childCount?: number; + + @ApiPropertyOptional({ example: 'Ethiopian', description: 'Passenger nationality: Ethiopian (Verifayda verification), Djiboutian (Waafi payment), Other (international payments)' }) + @IsOptional() @IsString() nationality?: string; } export class FareQuoteDto { @@ -33,10 +36,10 @@ export class FareQuoteDto { @ApiProperty({ example: 'Economy Regular', description: 'Seat class name: "Economy Regular" | "Economy Bed" | "VIP Bed"' }) @IsString() seatClassName: string; - @ApiProperty({ example: 2, description: 'Number of adult passengers' }) + @ApiProperty({ example: 2, description: 'Number of adult passengers (≥5 years) - each pays 100% of base fare' }) @Type(() => Number) @IsInt() @Min(1) adultCount: number; - @ApiPropertyOptional({ example: 1 }) + @ApiPropertyOptional({ example: 1, description: 'Number of child passengers (<5 years) - first child FREE, subsequent children 100%' }) @IsOptional() @Type(() => Number) @IsInt() @Min(0) childCount?: number; @ApiPropertyOptional({ example: 'WEEKEND15' }) @@ -45,6 +48,9 @@ export class FareQuoteDto { @ApiPropertyOptional({ example: 450, description: 'Loyalty points to redeem (10 points = 1 ETB minor unit)' }) @IsOptional() @Type(() => Number) @IsInt() loyaltyRedemptionPoints?: number; - @ApiPropertyOptional({ example: 'ETB', enum: Currency }) + @ApiPropertyOptional({ example: 'USD', enum: Currency, description: 'Display currency: ETB (default), DJF, USD. Transaction always in ETB.' }) @IsOptional() @IsEnum(Currency) displayCurrency?: Currency; + + @ApiPropertyOptional({ example: 'Ethiopian', description: 'Passenger nationality for payment method filtering' }) + @IsOptional() @IsString() nationality?: string; } diff --git a/apps/edr-passenger-api/src/modules/search/search.service.ts b/apps/edr-passenger-api/src/modules/search/search.service.ts index 062736d2e..9141da4cb 100644 --- a/apps/edr-passenger-api/src/modules/search/search.service.ts +++ b/apps/edr-passenger-api/src/modules/search/search.service.ts @@ -129,11 +129,23 @@ export class SearchService { const seatClass = await this.prisma.seatClass.findFirst({ where: { name: dto.seatClassName } }); - // Look up fare rule: prefer schedule-scoped, then segment route, then global + // Compute route codes for fare lookup const segmentRoute = `${originStop.station.code}-${destStop.station.code}`; const fullRoute = `${schedule.originStation.code}-${schedule.destinationStation.code}`; const now = new Date(); + const nationality = dto.nationality; + // Query fare rules with specificity ordering: + // 1. schedule+segment+nationality + // 2. schedule+segment + // 3. schedule+full-route+nationality + // 4. schedule+full-route + // 5. schedule+global + // 6. segment+nationality + // 7. segment + // 8. full-route+nationality + // 9. full-route + // 10. global const fareRule = await this.prisma.fareRule.findFirst({ where: { seatClassId: seatClass?.id, @@ -144,13 +156,36 @@ export class SearchService { ], }, orderBy: [ - // Most specific first: schedule-scoped > segment route > full route > global - { tripId: 'desc' }, + // Prioritize schedule-specific rules + { tripId: { sort: 'desc', nulls: 'last' } }, + // Then prioritize nationality match + { nationality: { sort: 'desc', nulls: 'last' } }, + // Most recent validFrom { validFrom: 'desc' }, ], }); - const baseFareMinor = fareRule?.baseFareMinor ?? this.defaultFare(dto.seatClassName); + // Manual specificity filtering to find best match + const candidates = await this.prisma.fareRule.findMany({ + where: { + seatClassId: seatClass?.id, + validFrom: { lte: now }, + OR: [ + { validUntil: null }, + { validUntil: { gte: now } }, + ], + }, + }); + + const bestMatch = this.selectBestFareRule( + candidates, + dto.scheduleId, + segmentRoute, + fullRoute, + nationality, + ); + + const baseFareMinor = bestMatch?.baseFareMinor ?? this.defaultFare(dto.seatClassName); const adultCount = dto.adultCount; const childCount = dto.childCount ?? 0; @@ -184,6 +219,7 @@ export class SearchService { destinationStationId: dto.destinationStationId, segmentRoute, seatClassName: dto.seatClassName, + nationality: dto.nationality, adultCount, childCount, baseFareMinor, adultFareMinor, childFareMinor, freeChildrenCount: Math.min(childCount, 1), @@ -266,4 +302,55 @@ export class SearchService { }; return fares[seatClassName] ?? 45000; } + + /** + * Select the best matching fare rule based on specificity: + * 1. schedule+segment+nationality + * 2. schedule+segment + * 3. schedule+full-route+nationality + * 4. schedule+full-route + * 5. schedule+global + * 6. segment+nationality + * 7. segment + * 8. full-route+nationality + * 9. full-route + * 10. global + */ + private selectBestFareRule( + candidates: any[], + scheduleId: string, + segmentRoute: string, + fullRoute: string, + nationality?: string, + ): any | null { + const priorities = [ + // Schedule-specific rules + { tripId: scheduleId, route: segmentRoute, nationality }, + { tripId: scheduleId, route: segmentRoute, nationality: null }, + { tripId: scheduleId, route: fullRoute, nationality }, + { tripId: scheduleId, route: fullRoute, nationality: null }, + { tripId: scheduleId, route: null, nationality }, + { tripId: scheduleId, route: null, nationality: null }, + // Route-specific rules (no schedule) + { tripId: null, route: segmentRoute, nationality }, + { tripId: null, route: segmentRoute, nationality: null }, + { tripId: null, route: fullRoute, nationality }, + { tripId: null, route: fullRoute, nationality: null }, + // Global rules + { tripId: null, route: null, nationality }, + { tripId: null, route: null, nationality: null }, + ]; + + for (const priority of priorities) { + const match = candidates.find( + (c) => + c.tripId === priority.tripId && + c.route === priority.route && + c.nationality === priority.nationality, + ); + if (match) return match; + } + + return null; + } } diff --git a/apps/edr-passenger-api/src/modules/seats/seats.controller.ts b/apps/edr-passenger-api/src/modules/seats/seats.controller.ts index 9059ba6f0..4c93b5f61 100644 --- a/apps/edr-passenger-api/src/modules/seats/seats.controller.ts +++ b/apps/edr-passenger-api/src/modules/seats/seats.controller.ts @@ -11,7 +11,15 @@ export class SeatsController { // ── Seat Map ────────────────────────────────────────────────────────────── @Get('seatmap/:scheduleId') - @ApiOperation({ summary: 'Get seat map for a schedule' }) + @ApiOperation({ + summary: 'Get seat map with real-time availability by class', + description: `Returns seat map for a schedule with availability by seat class: +- Economy Regular +- Economy Bed +- VIP Bed + +Shows seat status: AVAILABLE, BOOKED, HELD, BLOCKED` + }) @ApiParam({ name: 'scheduleId', description: 'TrainSchedule UUID' }) @ApiQuery({ name: 'coachId', required: false, description: 'Filter by coach UUID' }) @ApiResponse({ status: 200, description: 'Returns coaches with seats and seat class info' }) @@ -20,8 +28,17 @@ export class SeatsController { // ── Hold / Release ──────────────────────────────────────────────────────── @Post('hold') @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') - @ApiOperation({ summary: 'Hold seats for 15 minutes' }) - @ApiResponse({ status: 201, description: 'Seats held successfully' }) + @ApiOperation({ + summary: 'Hold seats for 15 minutes before booking', + description: `Temporarily reserves seats for a passenger to complete booking. + +**Features:** +- 15-minute hold duration +- Auto-release after expiry +- Prevents double booking +- Required before creating booking` + }) + @ApiResponse({ status: 201, description: 'Seats held successfully with holdId' }) @ApiResponse({ status: 409, description: 'One or more seats unavailable' }) holdSeats(@Body() dto: HoldSeatsDto) { return this.service.holdSeats(dto); } diff --git a/apps/edr-passenger-api/src/modules/stations/stations.controller.ts b/apps/edr-passenger-api/src/modules/stations/stations.controller.ts index a1be3762d..353204644 100644 --- a/apps/edr-passenger-api/src/modules/stations/stations.controller.ts +++ b/apps/edr-passenger-api/src/modules/stations/stations.controller.ts @@ -8,8 +8,24 @@ import { JwtGuard } from '../../common/jwt.guard'; @Controller('stations') export class StationsController { constructor(private service: StationsService) {} - @Get() @ApiOperation({ summary: 'List all stations' }) findAll() { return this.service.findAll(); } - @Get(':id') @ApiOperation({ summary: 'Get station by ID' }) findOne(@Param('id') id: string) { return this.service.findOne(id); } - @Post() @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') @ApiOperation({ summary: 'Create station' }) + + @Get() + @ApiOperation({ + summary: 'List all stations with country information', + description: 'Returns all stations on the Ethio-Djibouti Railway with country codes (ET for Ethiopia, DJ for Djibouti)' + }) + findAll() { return this.service.findAll(); } + + @Get(':id') + @ApiOperation({ + summary: 'Get station details by ID', + description: 'Returns station information including name, code, country, coordinates, and facilities' + }) + findOne(@Param('id') id: string) { return this.service.findOne(id); } + + @Post() + @UseGuards(JwtGuard) + @ApiBearerAuth('JWT-auth') + @ApiOperation({ summary: 'Create new station' }) create(@Body() dto: CreateStationDto) { return this.service.create(dto); } } diff --git a/apps/edr-passenger-api/src/modules/tickets/tickets.controller.ts b/apps/edr-passenger-api/src/modules/tickets/tickets.controller.ts index 7b871db3f..cb9aeeb76 100644 --- a/apps/edr-passenger-api/src/modules/tickets/tickets.controller.ts +++ b/apps/edr-passenger-api/src/modules/tickets/tickets.controller.ts @@ -11,13 +11,25 @@ export class TicketsController { constructor(private service: TicketsService) {} @Get(':bookingRef') - @ApiOperation({ summary: 'Get ticket by booking reference' }) + @ApiOperation({ + summary: 'Get ticket with QR code and passenger details', + description: `Returns ticket information including: +- QR code for gate scanning +- Barcode for offline validation +- Passenger details (name, age category, nationality) +- Journey details (origin, destination, seat, coach) +- Fare breakdown with currency +- PDF download link` + }) getByRef(@Param('bookingRef') ref: string) { return this.service.getByRef(ref); } @Post(':bookingRef/validate') - @ApiOperation({ summary: 'Validate ticket at gate (staff)' }) + @ApiOperation({ + summary: 'Validate ticket at gate with audit logging', + description: 'Validates ticket QR/barcode at station gate. Records validation in audit log with timestamp, gate, and validator.' + }) validate( @Param('bookingRef') ref: string, @Body('validatorId') validatorId: string, From b16f4037f4c234c455e287fb9a91a22276cfe7a5 Mon Sep 17 00:00:00 2001 From: Stephanos A Date: Sun, 24 May 2026 16:40:50 +0300 Subject: [PATCH 27/38] Enhance API documentation tags and improve checkout URL handling in WaafiProvider --- apps/edr-passenger-api/src/main.ts | 29 ++++++++++++------- .../payments/providers/waafi.provider.ts | 6 ++-- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/apps/edr-passenger-api/src/main.ts b/apps/edr-passenger-api/src/main.ts index 4717a78e9..4b8b6885c 100644 --- a/apps/edr-passenger-api/src/main.ts +++ b/apps/edr-passenger-api/src/main.ts @@ -210,23 +210,30 @@ Payment providers send notifications to: { type: "http", scheme: "bearer", bearerFormat: "JWT", in: "header" }, "JWT-auth", ) + .addTag("Agents", "Counter booking and management") .addTag("Auth", "Registration and login") - .addTag("Stations", "Station directory") + .addTag("Booking", "Booking lifecycle") + .addTag("Dashboard", "Home dashboard aggregate") .addTag("Fleet", "Train services and coaches") + .addTag("Fraud Detection", "Fraud detection and monitoring") + .addTag("Live Tracking", "Real-time trip status and crowd signals") + .addTag("Loyalty", "Points, tiers, and rewards") + .addTag("Notifications", "Push and email notifications") + .addTag("Passenger", "Profiles, traveler profiles, saved routes") + .addTag("Payment", "Payment intents and refunds") + .addTag("Payment Webhooks", "Endpoints for payment provider notifications") + .addTag("Promotions", "Promo codes and campaigns") + .addTag("Reports", "Sales and operational reports") + .addTag("Routes", "Route information and management") .addTag("Schedule", "Trips and fare rules") .addTag("Search", "Trip search and fare quotes") + .addTag("Seat Classes", "Economy Regular, Economy Bed, VIP Bed") .addTag("Seats", "Seat maps and holds") - .addTag("Booking", "Booking lifecycle") - .addTag("Payment", "Payment intents and refunds") - .addTag("Tickets", "QR ticket generation and validation") - .addTag("Passenger", "Profiles, traveler profiles, saved routes") - .addTag("Notifications", "Push and email notifications") - .addTag("Loyalty", "Points, tiers, and rewards") - .addTag("Wallet", "Wallet balance and ledger") - .addTag("Promotions", "Promo codes and campaigns") - .addTag("Live Tracking", "Real-time trip status and crowd signals") + .addTag("Segment-based Seats", "Seats assigned and released by trip segments") + .addTag("Stations", "Station directory") .addTag("Support", "FAQ and chat support") - .addTag("Dashboard", "Home dashboard aggregate") + .addTag("Tickets", "QR ticket generation and validation") + .addTag("Wallet", "Wallet balance and ledger") //.addServer('http://localhost:4000', 'Development') // .addServer("https://api.edr-platform.com", "Production") .build(); diff --git a/apps/edr-passenger-api/src/modules/payments/providers/waafi.provider.ts b/apps/edr-passenger-api/src/modules/payments/providers/waafi.provider.ts index 231983ae7..53afea737 100644 --- a/apps/edr-passenger-api/src/modules/payments/providers/waafi.provider.ts +++ b/apps/edr-passenger-api/src/modules/payments/providers/waafi.provider.ts @@ -100,7 +100,7 @@ export class WaafiProvider implements PaymentProvider { } const transactionId = response.params?.transactionId; - const checkoutUrl = response.params?.checkoutUrl; + const checkoutUrl = response.params?.checkoutUrl || `${this.baseUrl}/checkout?ref=${transactionId}`; if (!transactionId) { throw new Error(`Waafi returned no transactionId: ${JSON.stringify(response)}`); @@ -110,9 +110,7 @@ export class WaafiProvider implements PaymentProvider { return { providerOrderId: transactionId, - clientAction: checkoutUrl - ? { type: 'REDIRECT', url: checkoutUrl } - : { type: 'NONE' }, + clientAction: { type: 'REDIRECT', url: checkoutUrl }, expiresAt, rawInitiation: { request: this.sanitize(requestBody), From 57456f0902eaff79853ac5b06c7846f1dabff81d Mon Sep 17 00:00:00 2001 From: Abubeker Yasin Date: Mon, 25 May 2026 14:41:26 +0300 Subject: [PATCH 28/38] feat(fayda): add fayda config and jose dependency --- apps/edr-passenger-api/package.json | 1 + apps/edr-passenger-api/src/app.module.ts | 12 +- .../src/config/fayda.config.ts | 120 ++++++++++++++++++ pnpm-lock.yaml | 8 ++ 4 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 apps/edr-passenger-api/src/config/fayda.config.ts diff --git a/apps/edr-passenger-api/package.json b/apps/edr-passenger-api/package.json index ae10747f5..e8704d09e 100644 --- a/apps/edr-passenger-api/package.json +++ b/apps/edr-passenger-api/package.json @@ -36,6 +36,7 @@ "bcrypt": "^5.1.1", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", + "jose": "^6.2.3", "passport": "^0.7.0", "passport-jwt": "^4.0.1", "qrcode": "^1.5.3", diff --git a/apps/edr-passenger-api/src/app.module.ts b/apps/edr-passenger-api/src/app.module.ts index 261463e27..e1626bef5 100644 --- a/apps/edr-passenger-api/src/app.module.ts +++ b/apps/edr-passenger-api/src/app.module.ts @@ -13,6 +13,7 @@ import cbeConfig from './config/cbe.config'; import ebirrConfig from './config/ebirr.config'; import cardConfig from './config/card.config'; import waafiConfig from './config/waafi.config'; +import faydaConfig from './config/fayda.config'; import { AuthModule } from './modules/auth/auth.module'; import { StationsModule } from './modules/stations/stations.module'; import { FleetModule } from './modules/fleet/fleet.module'; @@ -40,7 +41,16 @@ import { SeatClassesModule } from './modules/seat-classes/seat-classes.module'; imports: [ ConfigModule.forRoot({ isGlobal: true, - load: [appConfig, dbConfig, telebirrConfig, cbeConfig, ebirrConfig, cardConfig, waafiConfig], + load: [ + appConfig, + dbConfig, + telebirrConfig, + cbeConfig, + ebirrConfig, + cardConfig, + waafiConfig, + faydaConfig, + ], }), ScheduleModule.forRoot(), EventEmitterModule.forRoot(), diff --git a/apps/edr-passenger-api/src/config/fayda.config.ts b/apps/edr-passenger-api/src/config/fayda.config.ts new file mode 100644 index 000000000..6e317760b --- /dev/null +++ b/apps/edr-passenger-api/src/config/fayda.config.ts @@ -0,0 +1,120 @@ +import { registerAs } from '@nestjs/config'; + +export interface FaydaJwk { + kty: 'RSA'; + use?: string; + kid?: string; + alg?: string; + n: string; + e: string; + d: string; + p?: string; + q?: string; + dp?: string; + dq?: string; + qi?: string; +} + +export interface FaydaConfig { + enabled: boolean; + clientId: string; + authorizationEndpoint: string; + tokenEndpoint: string; + userInfoEndpoint: string; + redirectUri: string; + privateJwk: FaydaJwk; + successRedirectUrl: string; + failureRedirectUrl: string; + scope: string; + acrValues: string; + claimsLocales: string; + sessionTtlMinutes: number; +} + +const REQUIRED_VARS = [ + 'FAYDA_CLIENT_ID', + 'FAYDA_AUTHORIZATION_ENDPOINT', + 'FAYDA_TOKEN_ENDPOINT', + 'FAYDA_USERINFO_ENDPOINT', + 'FAYDA_REDIRECT_URI', + 'FAYDA_PRIVATE_KEY_BASE64', + 'FAYDA_SUCCESS_REDIRECT_URL', + 'FAYDA_FAILURE_REDIRECT_URL', +] as const; + +function decodePrivateJwk(base64: string): FaydaJwk { + let jwk: unknown; + try { + const json = Buffer.from(base64, 'base64').toString('utf8'); + jwk = JSON.parse(json); + } catch (err) { + throw new Error( + `FAYDA_PRIVATE_KEY_BASE64 is not valid Base64-encoded JSON: ${(err as Error).message}`, + ); + } + if (!jwk || typeof jwk !== 'object') { + throw new Error('FAYDA_PRIVATE_KEY_BASE64 must decode to a JSON object'); + } + const candidate = jwk as Partial; + if (candidate.kty !== 'RSA') { + throw new Error('FAYDA_PRIVATE_KEY_BASE64 JWK must have kty="RSA"'); + } + if (!candidate.n || !candidate.e || !candidate.d) { + throw new Error( + 'FAYDA_PRIVATE_KEY_BASE64 JWK is missing required RSA private-key fields (n, e, d)', + ); + } + return candidate as FaydaJwk; +} + +export default registerAs('fayda', (): FaydaConfig => { + const enabled = (process.env.FAYDA_ENABLED ?? 'false').toLowerCase() === 'true'; + const scope = process.env.FAYDA_SCOPE ?? 'openid profile email'; + const acrValues = process.env.FAYDA_ACR_VALUES ?? 'mosip:idp:acr:generated-code'; + const claimsLocales = process.env.FAYDA_CLAIMS_LOCALES ?? 'en am'; + const sessionTtl = Number.parseInt(process.env.FAYDA_SESSION_TTL_MINUTES ?? '10', 10); + + if (!enabled) { + return { + enabled: false, + clientId: process.env.FAYDA_CLIENT_ID ?? '', + authorizationEndpoint: process.env.FAYDA_AUTHORIZATION_ENDPOINT ?? '', + tokenEndpoint: process.env.FAYDA_TOKEN_ENDPOINT ?? '', + userInfoEndpoint: process.env.FAYDA_USERINFO_ENDPOINT ?? '', + redirectUri: process.env.FAYDA_REDIRECT_URI ?? '', + privateJwk: { kty: 'RSA', n: '', e: '', d: '' }, + successRedirectUrl: process.env.FAYDA_SUCCESS_REDIRECT_URL ?? '', + failureRedirectUrl: process.env.FAYDA_FAILURE_REDIRECT_URL ?? '', + scope, + acrValues, + claimsLocales, + sessionTtlMinutes: Number.isNaN(sessionTtl) || sessionTtl <= 0 ? 10 : sessionTtl, + }; + } + + const missing = REQUIRED_VARS.filter((name) => !process.env[name]); + if (missing.length > 0) { + throw new Error( + `Fayda integration is enabled (FAYDA_ENABLED=true) but the following env vars are missing: ${missing.join(', ')}`, + ); + } + if (Number.isNaN(sessionTtl) || sessionTtl <= 0) { + throw new Error('FAYDA_SESSION_TTL_MINUTES must be a positive integer'); + } + + return { + enabled: true, + clientId: process.env.FAYDA_CLIENT_ID!, + authorizationEndpoint: process.env.FAYDA_AUTHORIZATION_ENDPOINT!, + tokenEndpoint: process.env.FAYDA_TOKEN_ENDPOINT!, + userInfoEndpoint: process.env.FAYDA_USERINFO_ENDPOINT!, + redirectUri: process.env.FAYDA_REDIRECT_URI!, + privateJwk: decodePrivateJwk(process.env.FAYDA_PRIVATE_KEY_BASE64!), + successRedirectUrl: process.env.FAYDA_SUCCESS_REDIRECT_URL!, + failureRedirectUrl: process.env.FAYDA_FAILURE_REDIRECT_URL!, + scope, + acrValues, + claimsLocales, + sessionTtlMinutes: sessionTtl, + }; +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 30f7e543d..f9b6b377a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -320,6 +320,9 @@ importers: class-validator: specifier: ^0.14.0 version: 0.14.4 + jose: + specifier: ^6.2.3 + version: 6.2.3 passport: specifier: ^0.7.0 version: 0.7.0 @@ -7229,6 +7232,9 @@ packages: jose@5.10.0: resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} + jose@6.2.3: + resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} + jquery@3.7.1: resolution: {integrity: sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==} @@ -19456,6 +19462,8 @@ snapshots: jose@5.10.0: {} + jose@6.2.3: {} + jquery@3.7.1: {} js-cookie@3.0.7: {} From 71c5534618725e16a25b78e98e025edc9f51a3e9 Mon Sep 17 00:00:00 2001 From: Abubeker Yasin Date: Mon, 25 May 2026 16:52:12 +0300 Subject: [PATCH 29/38] feat(fayda): add fayda oidc prisma models and migrate user fields --- .../migration.sql | 55 +++++++++++++++++++ apps/edr-passenger-api/prisma/schema.prisma | 37 +++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 apps/edr-passenger-api/prisma/migrations/20260525134854_add_fayda_oidc_verification/migration.sql diff --git a/apps/edr-passenger-api/prisma/migrations/20260525134854_add_fayda_oidc_verification/migration.sql b/apps/edr-passenger-api/prisma/migrations/20260525134854_add_fayda_oidc_verification/migration.sql new file mode 100644 index 000000000..da38b0502 --- /dev/null +++ b/apps/edr-passenger-api/prisma/migrations/20260525134854_add_fayda_oidc_verification/migration.sql @@ -0,0 +1,55 @@ +/* + Warnings: + + - A unique constraint covering the columns `[faydaSub]` on the table `User` will be added. If there are existing duplicate values, this will fail. + +*/ +-- AlterTable +ALTER TABLE "passenger"."BookingSeat" ADD COLUMN "faydaSub" TEXT, +ADD COLUMN "faydaVerifiedAt" TIMESTAMP(3), +ADD COLUMN "faydaVerifiedName" TEXT; + +-- AlterTable +ALTER TABLE "passenger"."User" ADD COLUMN "faydaSub" TEXT, +ADD COLUMN "faydaVerified" BOOLEAN NOT NULL DEFAULT false, +ADD COLUMN "faydaVerifiedAt" TIMESTAMP(3); + +-- CreateTable +CREATE TABLE "passenger"."FaydaVerificationSession" ( + "id" TEXT NOT NULL, + "state" TEXT NOT NULL, + "codeVerifier" TEXT NOT NULL, + "purpose" TEXT NOT NULL DEFAULT 'PURCHASE', + "saveToAccount" BOOLEAN NOT NULL DEFAULT false, + "status" TEXT NOT NULL DEFAULT 'PENDING', + "errorCode" TEXT, + "errorDescription" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "expiresAt" TIMESTAMP(3) NOT NULL, + "completedAt" TIMESTAMP(3), + "userId" TEXT, + "bookingId" TEXT, + + CONSTRAINT "FaydaVerificationSession_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "FaydaVerificationSession_state_key" ON "passenger"."FaydaVerificationSession"("state"); + +-- CreateIndex +CREATE INDEX "FaydaVerificationSession_userId_idx" ON "passenger"."FaydaVerificationSession"("userId"); + +-- CreateIndex +CREATE INDEX "FaydaVerificationSession_bookingId_idx" ON "passenger"."FaydaVerificationSession"("bookingId"); + +-- CreateIndex +CREATE INDEX "FaydaVerificationSession_state_idx" ON "passenger"."FaydaVerificationSession"("state"); + +-- CreateIndex +CREATE INDEX "FaydaVerificationSession_expiresAt_idx" ON "passenger"."FaydaVerificationSession"("expiresAt"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_faydaSub_key" ON "passenger"."User"("faydaSub"); + +-- AddForeignKey +ALTER TABLE "passenger"."FaydaVerificationSession" ADD CONSTRAINT "FaydaVerificationSession_userId_fkey" FOREIGN KEY ("userId") REFERENCES "passenger"."User"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/apps/edr-passenger-api/prisma/schema.prisma b/apps/edr-passenger-api/prisma/schema.prisma index a6ed4f9e0..c72e69ef4 100644 --- a/apps/edr-passenger-api/prisma/schema.prisma +++ b/apps/edr-passenger-api/prisma/schema.prisma @@ -215,6 +215,11 @@ model User { lastLoginAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt + + faydaVerified Boolean @default(false) + faydaVerifiedAt DateTime? + faydaSub String? @unique + passenger Passenger? agent Agent? sessions Session[] @@ -223,6 +228,8 @@ model User { auditLogs AuditLog[] fraudAlerts FraudAlert[] + faydaVerificationSessions FaydaVerificationSession[] + @@schema("passenger") } @@ -506,6 +513,9 @@ model BookingSeat { passportCountry String? verifaydaVerified Boolean @default(false) verifaydaData Json? + faydaVerifiedAt DateTime? + faydaSub String? + faydaVerifiedName String? seatLabelSnapshot String? fareMinor Int? displayCurrency Currency? @@ -1245,3 +1255,30 @@ model SavedPassengerProfile { @@schema("passenger") } + +model FaydaVerificationSession { + id String @id @default(uuid()) + state String @unique + codeVerifier String + purpose String @default("PURCHASE") + saveToAccount Boolean @default(false) + status String @default("PENDING") + errorCode String? + errorDescription String? + createdAt DateTime @default(now()) + expiresAt DateTime + completedAt DateTime? + + userId String? + bookingId String? + + user User? @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@index([userId]) + @@index([bookingId]) + @@index([state]) + @@index([expiresAt]) + + @@schema("passenger") +} + From 28448c02685266e0178c8a2309ad5b1a6fe890e8 Mon Sep 17 00:00:00 2001 From: Abubeker Yasin Date: Mon, 25 May 2026 17:03:44 +0300 Subject: [PATCH 30/38] feat(passenger-api): add pkce and client-assertion utilities for fayda --- apps/edr-passenger-api/package.json | 2 +- .../utils/client-assertion.util.spec.ts | 71 +++++++++++++++++++ .../verifayda/utils/client-assertion.util.ts | 22 ++++++ .../modules/verifayda/utils/pkce.util.spec.ts | 65 +++++++++++++++++ .../src/modules/verifayda/utils/pkce.util.ts | 21 ++++++ pnpm-lock.yaml | 9 +-- 6 files changed, 182 insertions(+), 8 deletions(-) create mode 100644 apps/edr-passenger-api/src/modules/verifayda/utils/client-assertion.util.spec.ts create mode 100644 apps/edr-passenger-api/src/modules/verifayda/utils/client-assertion.util.ts create mode 100644 apps/edr-passenger-api/src/modules/verifayda/utils/pkce.util.spec.ts create mode 100644 apps/edr-passenger-api/src/modules/verifayda/utils/pkce.util.ts diff --git a/apps/edr-passenger-api/package.json b/apps/edr-passenger-api/package.json index e8704d09e..84d6b99fa 100644 --- a/apps/edr-passenger-api/package.json +++ b/apps/edr-passenger-api/package.json @@ -36,7 +36,7 @@ "bcrypt": "^5.1.1", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", - "jose": "^6.2.3", + "jose": "^5.10.0", "passport": "^0.7.0", "passport-jwt": "^4.0.1", "qrcode": "^1.5.3", diff --git a/apps/edr-passenger-api/src/modules/verifayda/utils/client-assertion.util.spec.ts b/apps/edr-passenger-api/src/modules/verifayda/utils/client-assertion.util.spec.ts new file mode 100644 index 000000000..9b4316fc7 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/verifayda/utils/client-assertion.util.spec.ts @@ -0,0 +1,71 @@ +import { exportJWK, generateKeyPair, importJWK, jwtVerify, type JWK } from 'jose'; +import { generateClientAssertion } from './client-assertion.util'; + +describe('generateClientAssertion', () => { + let privateJwk: JWK; + let publicJwk: JWK; + + beforeAll(async () => { + const kp = await generateKeyPair('RS256', { extractable: true }); + privateJwk = await exportJWK(kp.privateKey); + publicJwk = await exportJWK(kp.publicKey); + }); + + it('produces a JWT verifiable with the matching public key', async () => { + const jwt = await generateClientAssertion({ + clientId: 'edr-passenger-test', + audience: 'https://esignet.example.com/token', + privateJwk, + }); + + const verifier = await importJWK(publicJwk, 'RS256'); + const { payload, protectedHeader } = await jwtVerify(jwt, verifier, { + issuer: 'edr-passenger-test', + subject: 'edr-passenger-test', + audience: 'https://esignet.example.com/token', + }); + + expect(protectedHeader.alg).toBe('RS256'); + expect(protectedHeader.typ).toBe('JWT'); + expect(payload.iss).toBe('edr-passenger-test'); + expect(payload.sub).toBe('edr-passenger-test'); + expect(payload.aud).toBe('https://esignet.example.com/token'); + expect(typeof payload.iat).toBe('number'); + expect(typeof payload.exp).toBe('number'); + }); + + it('defaults exp to 120 seconds after iat', async () => { + const jwt = await generateClientAssertion({ + clientId: 'c', + audience: 'https://a/token', + privateJwk, + }); + const verifier = await importJWK(publicJwk, 'RS256'); + const { payload } = await jwtVerify(jwt, verifier); + expect(payload.exp! - payload.iat!).toBe(120); + }); + + it('honors a custom expiresIn', async () => { + const jwt = await generateClientAssertion({ + clientId: 'c', + audience: 'https://a/token', + privateJwk, + expiresIn: '5m', + }); + const verifier = await importJWK(publicJwk, 'RS256'); + const { payload } = await jwtVerify(jwt, verifier); + expect(payload.exp! - payload.iat!).toBe(300); + }); + + it('fails verification against a wrong audience', async () => { + const jwt = await generateClientAssertion({ + clientId: 'c', + audience: 'https://a/token', + privateJwk, + }); + const verifier = await importJWK(publicJwk, 'RS256'); + await expect( + jwtVerify(jwt, verifier, { audience: 'https://other/token' }), + ).rejects.toThrow(); + }); +}); diff --git a/apps/edr-passenger-api/src/modules/verifayda/utils/client-assertion.util.ts b/apps/edr-passenger-api/src/modules/verifayda/utils/client-assertion.util.ts new file mode 100644 index 000000000..dc3558ccc --- /dev/null +++ b/apps/edr-passenger-api/src/modules/verifayda/utils/client-assertion.util.ts @@ -0,0 +1,22 @@ +import { SignJWT, importJWK, type JWK } from 'jose'; + +export interface GenerateClientAssertionInput { + clientId: string; + audience: string; + privateJwk: JWK; + expiresIn?: string; +} + +export async function generateClientAssertion( + input: GenerateClientAssertionInput, +): Promise { + const privateKey = await importJWK(input.privateJwk, 'RS256'); + return new SignJWT({}) + .setProtectedHeader({ alg: 'RS256', typ: 'JWT' }) + .setIssuer(input.clientId) + .setSubject(input.clientId) + .setAudience(input.audience) + .setIssuedAt() + .setExpirationTime(input.expiresIn ?? '2m') + .sign(privateKey); +} diff --git a/apps/edr-passenger-api/src/modules/verifayda/utils/pkce.util.spec.ts b/apps/edr-passenger-api/src/modules/verifayda/utils/pkce.util.spec.ts new file mode 100644 index 000000000..d359a07f2 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/verifayda/utils/pkce.util.spec.ts @@ -0,0 +1,65 @@ +import { createHash } from 'crypto'; +import { + base64Url, + generateCodeChallenge, + generateCodeVerifier, + generateState, +} from './pkce.util'; + +describe('pkce.util', () => { + describe('base64Url', () => { + it('strips padding and replaces + and / with - and _', () => { + const input = Buffer.from([0xfb, 0xff, 0xbf, 0xfe]); + const out = base64Url(input); + expect(out).not.toMatch(/[+/=]/); + }); + }); + + describe('generateCodeVerifier', () => { + it('returns a base64url-safe string', () => { + expect(generateCodeVerifier()).toMatch(/^[A-Za-z0-9_-]+$/); + }); + + it('produces unique values across calls', () => { + const a = generateCodeVerifier(); + const b = generateCodeVerifier(); + expect(a).not.toEqual(b); + }); + + it('produces at least 43 characters (RFC 7636 minimum)', () => { + expect(generateCodeVerifier().length).toBeGreaterThanOrEqual(43); + }); + }); + + describe('generateCodeChallenge', () => { + it('equals base64url(sha256(verifier))', () => { + const verifier = 'fixed-test-verifier'; + const expected = createHash('sha256') + .update(verifier) + .digest('base64') + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=/g, ''); + expect(generateCodeChallenge(verifier)).toBe(expected); + }); + + it('is deterministic for the same verifier', () => { + const verifier = generateCodeVerifier(); + expect(generateCodeChallenge(verifier)).toBe(generateCodeChallenge(verifier)); + }); + + it('differs for different verifiers', () => { + expect(generateCodeChallenge('a')).not.toBe(generateCodeChallenge('b')); + }); + }); + + describe('generateState', () => { + it('returns a base64url-safe string', () => { + expect(generateState()).toMatch(/^[A-Za-z0-9_-]+$/); + }); + + it('produces unique values across calls', () => { + expect(generateState()).not.toEqual(generateState()); + }); + }); +}); diff --git a/apps/edr-passenger-api/src/modules/verifayda/utils/pkce.util.ts b/apps/edr-passenger-api/src/modules/verifayda/utils/pkce.util.ts new file mode 100644 index 000000000..89e9437d2 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/verifayda/utils/pkce.util.ts @@ -0,0 +1,21 @@ +import { createHash, randomBytes } from 'crypto'; + +export function base64Url(buffer: Buffer): string { + return buffer + .toString('base64') + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=/g, ''); +} + +export function generateCodeVerifier(): string { + return base64Url(randomBytes(64)); +} + +export function generateCodeChallenge(codeVerifier: string): string { + return base64Url(createHash('sha256').update(codeVerifier).digest()); +} + +export function generateState(): string { + return base64Url(randomBytes(32)); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f9b6b377a..e528988eb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -321,8 +321,8 @@ importers: specifier: ^0.14.0 version: 0.14.4 jose: - specifier: ^6.2.3 - version: 6.2.3 + specifier: ^5.10.0 + version: 5.10.0 passport: specifier: ^0.7.0 version: 0.7.0 @@ -7232,9 +7232,6 @@ packages: jose@5.10.0: resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} - jose@6.2.3: - resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} - jquery@3.7.1: resolution: {integrity: sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==} @@ -19462,8 +19459,6 @@ snapshots: jose@5.10.0: {} - jose@6.2.3: {} - jquery@3.7.1: {} js-cookie@3.0.7: {} From 20151286f27a1abfb7ebafd1589234dd2a2260d7 Mon Sep 17 00:00:00 2001 From: Abubeker Yasin Date: Mon, 25 May 2026 17:22:49 +0300 Subject: [PATCH 31/38] feat(fayda): implement verifayda oidc service --- .../src/modules/verifayda/verifayda.dto.ts | 42 ++ .../src/modules/verifayda/verifayda.errors.ts | 19 + .../verifayda/verifayda.service.spec.ts | 385 ++++++++++++++ .../modules/verifayda/verifayda.service.ts | 471 ++++++++++++++++-- .../src/modules/verifayda/verifayda.types.ts | 36 ++ 5 files changed, 906 insertions(+), 47 deletions(-) create mode 100644 apps/edr-passenger-api/src/modules/verifayda/verifayda.dto.ts create mode 100644 apps/edr-passenger-api/src/modules/verifayda/verifayda.errors.ts create mode 100644 apps/edr-passenger-api/src/modules/verifayda/verifayda.service.spec.ts create mode 100644 apps/edr-passenger-api/src/modules/verifayda/verifayda.types.ts diff --git a/apps/edr-passenger-api/src/modules/verifayda/verifayda.dto.ts b/apps/edr-passenger-api/src/modules/verifayda/verifayda.dto.ts new file mode 100644 index 000000000..388c8b438 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/verifayda/verifayda.dto.ts @@ -0,0 +1,42 @@ +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +import { IsBoolean, IsIn, IsOptional, IsString } from 'class-validator'; + +export class StartVerificationDto { + @ApiPropertyOptional({ + enum: ['LOGIN', 'PURCHASE'], + default: 'PURCHASE', + description: 'Reason for verification.', + }) + @IsOptional() + @IsIn(['LOGIN', 'PURCHASE']) + purpose?: 'LOGIN' | 'PURCHASE'; + + @ApiPropertyOptional({ + description: + 'Booking the verification should attach to (PURCHASE flow). If omitted, the session is anchored only to the user.', + }) + @IsOptional() + @IsString() + bookingId?: string; + + @ApiPropertyOptional({ + description: + 'When true and the user is logged in, copy faydaVerified=true / faydaSub onto their User record after verification.', + }) + @IsOptional() + @IsBoolean() + saveToAccount?: boolean; +} + +export class VerifaydaCallbackDto { + @ApiPropertyOptional() @IsOptional() @IsString() code?: string; + @ApiPropertyOptional() @IsOptional() @IsString() state?: string; + @ApiPropertyOptional() @IsOptional() @IsString() error?: string; + @ApiPropertyOptional() @IsOptional() @IsString() error_description?: string; +} + +export class VerificationStatusDto { + @ApiProperty() verified: boolean; + @ApiPropertyOptional() verifiedAt?: Date; + @ApiPropertyOptional() fullName?: string; +} diff --git a/apps/edr-passenger-api/src/modules/verifayda/verifayda.errors.ts b/apps/edr-passenger-api/src/modules/verifayda/verifayda.errors.ts new file mode 100644 index 000000000..a7d531102 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/verifayda/verifayda.errors.ts @@ -0,0 +1,19 @@ +import { BadGatewayException, ConflictException } from '@nestjs/common'; + +export class FaydaTokenExchangeException extends BadGatewayException { + constructor(message = 'Fayda token exchange failed') { + super({ code: 'FAYDA_TOKEN_EXCHANGE_FAILED', message }); + } +} + +export class FaydaUserInfoException extends BadGatewayException { + constructor(message = 'Fayda userinfo fetch failed') { + super({ code: 'FAYDA_USERINFO_FAILED', message }); + } +} + +export class FaydaIdentityConflictException extends ConflictException { + constructor(message = 'This Fayda identity is already linked to another account') { + super({ code: 'FAYDA_IDENTITY_CONFLICT', message }); + } +} diff --git a/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.spec.ts b/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.spec.ts new file mode 100644 index 000000000..55c670946 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.spec.ts @@ -0,0 +1,385 @@ +import { ConfigService } from '@nestjs/config'; +import { exportJWK, generateKeyPair, type JWK } from 'jose'; +import { PrismaService } from '../../common/prisma.service'; +import { FaydaConfig } from '../../config/fayda.config'; +import { VerifaydaService } from './verifayda.service'; + +type AnyFn = (...args: any[]) => any; + +function mockFn(impl?: T): jest.Mock { + return impl ? jest.fn(impl) : jest.fn(); +} + +function buildPrismaMock() { + return { + faydaVerificationSession: { + create: jest.fn(), + findUnique: jest.fn(), + update: jest.fn(), + updateMany: jest.fn(), + }, + bookingSeat: { + updateMany: jest.fn(), + }, + user: { + findUnique: jest.fn(), + findFirst: jest.fn(), + update: jest.fn(), + }, + verifaydaVerification: { create: jest.fn() }, + }; +} + +function buildConfig(overrides?: Partial): FaydaConfig { + return { + enabled: true, + clientId: 'edr-test-client', + authorizationEndpoint: 'https://esignet.test/authorize', + tokenEndpoint: 'https://esignet.test/token', + userInfoEndpoint: 'https://esignet.test/userinfo', + redirectUri: 'https://api.edr.test/api/v1/fayda/verification/callback', + privateJwk: { kty: 'RSA', n: '', e: '', d: '' }, + successRedirectUrl: 'https://passenger.edr.test/verify/success', + failureRedirectUrl: 'https://passenger.edr.test/verify/failure', + scope: 'openid profile email', + acrValues: 'mosip:idp:acr:generated-code', + claimsLocales: 'en am', + sessionTtlMinutes: 10, + ...overrides, + }; +} + +function buildConfigService(faydaConfig: FaydaConfig): jest.Mocked { + return { + get: jest.fn((key: string, defaultValue?: unknown) => { + if (key === 'fayda') return faydaConfig; + if (key === 'VERIFAYDA_ENABLED') return false; + return defaultValue; + }), + } as unknown as jest.Mocked; +} + +describe('VerifaydaService (OIDC)', () => { + let prisma: ReturnType; + let service: VerifaydaService; + let realPrivateJwk: JWK; + + beforeAll(async () => { + const kp = await generateKeyPair('RS256', { extractable: true }); + realPrivateJwk = await exportJWK(kp.privateKey); + realPrivateJwk.kty = 'RSA'; + }); + + beforeEach(() => { + prisma = buildPrismaMock(); + const cfg = buildConfig({ privateJwk: realPrivateJwk as FaydaConfig['privateJwk'] }); + service = new VerifaydaService( + buildConfigService(cfg), + prisma as unknown as PrismaService, + ); + (global as any).fetch = jest.fn(); + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + + describe('startVerification', () => { + it('persists a session and returns a fully-formed authorize URL', async () => { + prisma.faydaVerificationSession.create.mockResolvedValue({}); + + const url = await service.startVerification({ + purpose: 'PURCHASE', + userId: 'user-1', + saveToAccount: true, + }); + + expect(prisma.faydaVerificationSession.create).toHaveBeenCalledTimes(1); + const created = prisma.faydaVerificationSession.create.mock.calls[0][0].data; + expect(created.purpose).toBe('PURCHASE'); + expect(created.saveToAccount).toBe(true); + expect(created.userId).toBe('user-1'); + expect(typeof created.state).toBe('string'); + expect(typeof created.codeVerifier).toBe('string'); + + const parsed = new URL(url); + expect(parsed.origin + parsed.pathname).toBe( + 'https://esignet.test/authorize', + ); + expect(parsed.searchParams.get('client_id')).toBe('edr-test-client'); + expect(parsed.searchParams.get('response_type')).toBe('code'); + expect(parsed.searchParams.get('code_challenge_method')).toBe('S256'); + expect(parsed.searchParams.get('state')).toBe(created.state); + }); + + it('throws ServiceUnavailable when fayda integration is disabled', async () => { + const disabledCfg = buildConfig({ enabled: false }); + const disabledService = new VerifaydaService( + buildConfigService(disabledCfg), + prisma as unknown as PrismaService, + ); + await expect( + disabledService.startVerification({ purpose: 'PURCHASE' }), + ).rejects.toMatchObject({ status: 503 }); + }); + }); + + describe('handleCallback', () => { + function pendingSession(overrides: Partial = {}) { + return { + id: 'session-1', + state: 'state-abc', + codeVerifier: 'verifier-xyz', + purpose: 'PURCHASE', + saveToAccount: false, + status: 'PENDING', + errorCode: null, + errorDescription: null, + userId: null, + bookingId: null, + expiresAt: new Date(Date.now() + 60_000), + ...overrides, + }; + } + + function mockFetchSequence(...responses: Array>) { + const queue = responses.map((r) => ({ + ok: true, + status: 200, + text: async () => '', + json: async () => ({}), + headers: new Headers({ 'content-type': 'application/json' }), + ...r, + })); + (global as any).fetch = jest.fn(() => Promise.resolve(queue.shift())); + } + + it('redirects to failure URL when callback carries an error', async () => { + prisma.faydaVerificationSession.findUnique.mockResolvedValue(null); + + const url = await service.handleCallback({ + error: 'access_denied', + error_description: 'user cancelled', + state: 'state-abc', + }); + + expect(url).toContain('https://passenger.edr.test/verify/failure'); + expect(url).toContain('reason=access_denied'); + expect(prisma.faydaVerificationSession.updateMany).toHaveBeenCalled(); + }); + + it('redirects to failure URL when state is unknown', async () => { + prisma.faydaVerificationSession.findUnique.mockResolvedValue(null); + const url = await service.handleCallback({ + code: 'authcode', + state: 'bogus', + }); + expect(url).toContain('reason=invalid_state'); + }); + + it('redirects to failure URL when session is not pending', async () => { + prisma.faydaVerificationSession.findUnique.mockResolvedValue( + pendingSession({ status: 'COMPLETED' }), + ); + const url = await service.handleCallback({ + code: 'authcode', + state: 'state-abc', + }); + expect(url).toContain('reason=invalid_state'); + }); + + it('redirects to failure URL when session is expired', async () => { + prisma.faydaVerificationSession.findUnique.mockResolvedValue( + pendingSession({ expiresAt: new Date(Date.now() - 1000) }), + ); + const url = await service.handleCallback({ + code: 'authcode', + state: 'state-abc', + }); + expect(url).toContain('reason=session_expired'); + }); + + it('happy path: exchanges code, fetches userinfo, updates booking seat', async () => { + prisma.faydaVerificationSession.findUnique.mockResolvedValue( + pendingSession({ bookingId: 'booking-1' }), + ); + prisma.faydaVerificationSession.update.mockResolvedValue({}); + prisma.bookingSeat.updateMany.mockResolvedValue({ count: 1 }); + + mockFetchSequence( + { + json: async () => ({ access_token: 'tok', token_type: 'Bearer' }), + }, + { + headers: new Headers({ 'content-type': 'application/json' }), + text: async () => + JSON.stringify({ + sub: 'fayda-sub-1', + name: 'Test User', + phone_number: '+251911000000', + email: 'test@example.com', + }), + }, + ); + + const url = await service.handleCallback({ + code: 'authcode', + state: 'state-abc', + }); + + expect(url).toBe('https://passenger.edr.test/verify/success'); + expect(prisma.bookingSeat.updateMany).toHaveBeenCalledWith({ + where: { bookingId: 'booking-1' }, + data: expect.objectContaining({ + faydaSub: 'fayda-sub-1', + faydaVerifiedName: 'Test User', + }), + }); + expect(prisma.faydaVerificationSession.update).toHaveBeenCalledWith( + expect.objectContaining({ + data: expect.objectContaining({ + status: 'COMPLETED', + codeVerifier: '', + }), + }), + ); + }); + + it('saves to User when saveToAccount=true and no conflict', async () => { + prisma.faydaVerificationSession.findUnique.mockResolvedValue( + pendingSession({ userId: 'user-1', saveToAccount: true }), + ); + prisma.user.findFirst.mockResolvedValue(null); + prisma.user.update.mockResolvedValue({}); + prisma.faydaVerificationSession.update.mockResolvedValue({}); + + mockFetchSequence( + { json: async () => ({ access_token: 'tok', token_type: 'Bearer' }) }, + { + headers: new Headers({ 'content-type': 'application/json' }), + text: async () => + JSON.stringify({ sub: 'fayda-sub-2', name: 'Test User' }), + }, + ); + + const url = await service.handleCallback({ + code: 'authcode', + state: 'state-abc', + }); + + expect(url).toBe('https://passenger.edr.test/verify/success'); + expect(prisma.user.update).toHaveBeenCalledWith({ + where: { id: 'user-1' }, + data: expect.objectContaining({ + faydaVerified: true, + faydaSub: 'fayda-sub-2', + }), + }); + }); + + it('rejects with identity_conflict when faydaSub is on another user', async () => { + prisma.faydaVerificationSession.findUnique.mockResolvedValue( + pendingSession({ userId: 'user-1', saveToAccount: true }), + ); + prisma.user.findFirst.mockResolvedValue({ id: 'other-user' }); + + mockFetchSequence( + { json: async () => ({ access_token: 'tok', token_type: 'Bearer' }) }, + { + headers: new Headers({ 'content-type': 'application/json' }), + text: async () => + JSON.stringify({ sub: 'fayda-sub-3', name: 'Test User' }), + }, + ); + + const url = await service.handleCallback({ + code: 'authcode', + state: 'state-abc', + }); + expect(url).toContain('reason=identity_conflict'); + expect(prisma.user.update).not.toHaveBeenCalled(); + }); + + it('reports token_exchange_failed when token endpoint returns 4xx', async () => { + prisma.faydaVerificationSession.findUnique.mockResolvedValue(pendingSession()); + + mockFetchSequence({ + ok: false, + status: 400, + text: async () => '{"error":"invalid_assertion"}', + }); + + const url = await service.handleCallback({ + code: 'authcode', + state: 'state-abc', + }); + expect(url).toContain('reason=token_exchange_failed'); + }); + + it('reports userinfo_failed when userinfo response is unsupported', async () => { + prisma.faydaVerificationSession.findUnique.mockResolvedValue(pendingSession()); + + mockFetchSequence( + { json: async () => ({ access_token: 'tok', token_type: 'Bearer' }) }, + { + headers: new Headers({ 'content-type': 'text/plain' }), + text: async () => 'not-a-jwt-not-a-json', + }, + ); + + const url = await service.handleCallback({ + code: 'authcode', + state: 'state-abc', + }); + expect(url).toContain('reason=userinfo_failed'); + }); + + it('falls back to localized name (name#en) when name is missing', async () => { + prisma.faydaVerificationSession.findUnique.mockResolvedValue( + pendingSession({ bookingId: 'booking-2' }), + ); + prisma.faydaVerificationSession.update.mockResolvedValue({}); + prisma.bookingSeat.updateMany.mockResolvedValue({ count: 1 }); + + mockFetchSequence( + { json: async () => ({ access_token: 'tok', token_type: 'Bearer' }) }, + { + headers: new Headers({ 'content-type': 'application/json' }), + text: async () => + JSON.stringify({ + sub: 'fayda-sub-4', + 'name#en': 'English Name', + 'name#am': 'Amharic Name', + }), + }, + ); + + await service.handleCallback({ code: 'c', state: 'state-abc' }); + + const seatCall = prisma.bookingSeat.updateMany.mock.calls[0][0]; + expect(seatCall.data.faydaVerifiedName).toBe('English Name'); + }); + }); + + describe('getVerificationStatus', () => { + it('returns verified=true when User row has the flag', async () => { + prisma.user.findUnique.mockResolvedValue({ + faydaVerified: true, + faydaVerifiedAt: new Date('2026-01-01T00:00:00Z'), + fullName: 'Test User', + }); + const result = await service.getVerificationStatus('user-1'); + expect(result).toEqual({ + verified: true, + verifiedAt: new Date('2026-01-01T00:00:00Z'), + fullName: 'Test User', + }); + }); + + it('returns verified=false when User row is missing or unverified', async () => { + prisma.user.findUnique.mockResolvedValue(null); + const result = await service.getVerificationStatus('user-x'); + expect(result).toEqual({ verified: false }); + }); + }); +}); diff --git a/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.ts b/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.ts index d86ad98a2..55227fa6d 100644 --- a/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.ts +++ b/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.ts @@ -1,7 +1,31 @@ -import { Injectable, Logger, BadRequestException } from '@nestjs/common'; +import { + BadRequestException, + Injectable, + Logger, + ServiceUnavailableException, +} from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; -import { PrismaService } from '../../common/prisma.service'; import axios, { AxiosInstance } from 'axios'; +import { PrismaService } from '../../common/prisma.service'; +import { FaydaConfig } from '../../config/fayda.config'; +import { + generateCodeChallenge, + generateCodeVerifier, + generateState, +} from './utils/pkce.util'; +import { generateClientAssertion } from './utils/client-assertion.util'; +import { VerifaydaCallbackDto, VerificationStatusDto } from './verifayda.dto'; +import { + FaydaIdentityConflictException, + FaydaTokenExchangeException, + FaydaUserInfoException, +} from './verifayda.errors'; +import { + FaydaTokenResponse, + FaydaUserInfo, + NormalizedFaydaUserInfo, + VerifaydaPurpose, +} from './verifayda.types'; export interface VerifaydaPassengerData { fullName: string; @@ -17,38 +41,406 @@ export interface VerifaydaVerificationResult { failureReason?: string; } +export interface StartVerificationInput { + purpose: VerifaydaPurpose; + userId?: string; + bookingId?: string; + saveToAccount?: boolean; +} + @Injectable() export class VerifaydaService { private readonly logger = new Logger(VerifaydaService.name); + + + private readonly faydaConfig: FaydaConfig; + private readonly httpClient: AxiosInstance; - private readonly enabled: boolean; - private readonly apiUrl: string; - private readonly apiKey: string; + private readonly stubEnabled: boolean; + private readonly stubApiUrl: string; + private readonly stubApiKey: string; constructor( private readonly config: ConfigService, private readonly prisma: PrismaService, ) { - this.enabled = this.config.get('VERIFAYDA_ENABLED', false); - this.apiUrl = this.config.get('VERIFAYDA_API_URL', 'https://api.verifayda.gov.et/v2'); - this.apiKey = this.config.get('VERIFAYDA_API_KEY', ''); + const fayda = this.config.get('fayda'); + if (!fayda) { + throw new Error('Fayda config namespace not registered'); + } + this.faydaConfig = fayda; + this.stubEnabled = this.config.get('VERIFAYDA_ENABLED', false); + this.stubApiUrl = this.config.get( + 'VERIFAYDA_API_URL', + 'https://api.verifayda.gov.et/v2', + ); + this.stubApiKey = this.config.get('VERIFAYDA_API_KEY', ''); this.httpClient = axios.create({ - baseURL: this.apiUrl, + baseURL: this.stubApiUrl, timeout: 10000, - headers: { - 'Content-Type': 'application/json', - 'X-API-Key': this.apiKey, + headers: { 'Content-Type': 'application/json', 'X-API-Key': this.stubApiKey }, + }); + } + + // ========================================================================== + // OIDC flow + // ========================================================================== + + async startVerification(input: StartVerificationInput): Promise { + if (!this.faydaConfig.enabled) { + throw new ServiceUnavailableException({ + code: 'FAYDA_DISABLED', + message: 'Fayda integration is not enabled', + }); + } + + const state = generateState(); + const codeVerifier = generateCodeVerifier(); + const codeChallenge = generateCodeChallenge(codeVerifier); + const expiresAt = new Date( + Date.now() + this.faydaConfig.sessionTtlMinutes * 60_000, + ); + + await this.prisma.faydaVerificationSession.create({ + data: { + state, + codeVerifier, + purpose: input.purpose, + saveToAccount: input.saveToAccount ?? false, + userId: input.userId ?? null, + bookingId: input.bookingId ?? null, + expiresAt, + }, + }); + + this.logger.log( + `Fayda verification started: purpose=${input.purpose} userId=${input.userId ?? 'none'} bookingId=${input.bookingId ?? 'none'}`, + ); + + return this.buildAuthorizationUrl({ state, codeChallenge }); + } + + async handleCallback(query: VerifaydaCallbackDto): Promise { + if (query.error) { + this.logger.warn(`Fayda callback returned error: ${query.error}`); + if (query.state) { + await this.markSessionFailed( + query.state, + query.error, + query.error_description, + ); + } + return this.buildFailureUrl(query.error); + } + + if (!query.code || !query.state) { + this.logger.warn('Fayda callback missing code or state'); + return this.buildFailureUrl('missing_parameters'); + } + + const session = await this.prisma.faydaVerificationSession.findUnique({ + where: { state: query.state }, + }); + + if (!session) { + this.logger.warn('Fayda callback with unknown state'); + return this.buildFailureUrl('invalid_state'); + } + if (session.status !== 'PENDING') { + this.logger.warn( + `Fayda callback for non-pending session (status=${session.status})`, + ); + return this.buildFailureUrl('invalid_state'); + } + if (session.expiresAt.getTime() < Date.now()) { + await this.markSessionFailed(query.state, 'session_expired'); + this.logger.warn('Fayda callback for expired session'); + return this.buildFailureUrl('session_expired'); + } + + try { + const tokens = await this.exchangeCodeForTokens( + query.code, + session.codeVerifier, + ); + const userInfo = await this.fetchUserInfo(tokens.access_token); + const normalized = this.normalizeUserInfo(userInfo); + + if (!normalized.sub) { + throw new FaydaUserInfoException('Fayda userinfo missing required sub'); + } + + if (session.purpose === 'PURCHASE') { + await this.handlePurchaseSuccess(session, normalized); + } else { + await this.handleLoginSuccess(session, normalized); + } + + await this.prisma.faydaVerificationSession.update({ + where: { id: session.id }, + data: { + status: 'COMPLETED', + completedAt: new Date(), + codeVerifier: '', + }, + }); + + this.logger.log( + `Fayda verification completed: purpose=${session.purpose}`, + ); + return this.buildSuccessUrl(); + } catch (err) { + const reason = this.classifyFailureReason(err); + this.logger.error( + `Fayda verification failed: reason=${reason} message=${(err as Error).message}`, + ); + await this.markSessionFailed( + query.state, + reason, + (err as Error).message, + ); + return this.buildFailureUrl(reason); + } + } + + async getVerificationStatus(userId: string): Promise { + const user = await this.prisma.user.findUnique({ + where: { id: userId }, + select: { faydaVerified: true, faydaVerifiedAt: true, fullName: true }, + }); + + return { + verified: user?.faydaVerified ?? false, + verifiedAt: user?.faydaVerifiedAt ?? undefined, + fullName: user?.fullName ?? undefined, + }; + } + + // ========================================================================== + // OIDC internals + // ========================================================================== + + private buildAuthorizationUrl(args: { + state: string; + codeChallenge: string; + }): string { + const params = new URLSearchParams({ + client_id: this.faydaConfig.clientId, + response_type: 'code', + redirect_uri: this.faydaConfig.redirectUri, + scope: this.faydaConfig.scope, + state: args.state, + code_challenge: args.codeChallenge, + code_challenge_method: 'S256', + acr_values: this.faydaConfig.acrValues, + claims_locales: this.faydaConfig.claimsLocales, + }); + + const claims = { + userinfo: { + name: { essential: true }, + phone_number: { essential: true }, + email: { essential: false }, + birthdate: { essential: true }, + gender: { essential: false }, + picture: { essential: false }, + }, + id_token: {}, + }; + params.set('claims', JSON.stringify(claims)); + + return `${this.faydaConfig.authorizationEndpoint}?${params.toString()}`; + } + + private async exchangeCodeForTokens( + code: string, + codeVerifier: string, + ): Promise { + const clientAssertion = await generateClientAssertion({ + clientId: this.faydaConfig.clientId, + audience: this.faydaConfig.tokenEndpoint, + privateJwk: this.faydaConfig.privateJwk, + }); + + const body = new URLSearchParams({ + grant_type: 'authorization_code', + code, + redirect_uri: this.faydaConfig.redirectUri, + client_id: this.faydaConfig.clientId, + client_assertion_type: + 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer', + client_assertion: clientAssertion, + code_verifier: codeVerifier, + }); + + const response = await fetch(this.faydaConfig.tokenEndpoint, { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body, + }); + + if (!response.ok) { + let detail = ''; + try { + detail = await response.text(); + } catch { + // ignore + } + throw new FaydaTokenExchangeException( + `Fayda token endpoint returned ${response.status}${detail ? `: ${detail}` : ''}`, + ); + } + + return (await response.json()) as FaydaTokenResponse; + } + + private async fetchUserInfo(accessToken: string): Promise { + const response = await fetch(this.faydaConfig.userInfoEndpoint, { + method: 'GET', + headers: { Authorization: `Bearer ${accessToken}` }, + }); + + if (!response.ok) { + throw new FaydaUserInfoException( + `Fayda userinfo endpoint returned ${response.status}`, + ); + } + + const contentType = response.headers.get('content-type') ?? ''; + const raw = await response.text(); + + if (contentType.includes('application/json')) { + return JSON.parse(raw) as FaydaUserInfo; + } + + // Signed JWT response — decode payload (signature verification = production TODO) + if (raw.split('.').length === 3) { + const payloadB64 = raw.split('.')[1]; + const normalizedB64 = payloadB64.replace(/-/g, '+').replace(/_/g, '/'); + const json = Buffer.from(normalizedB64, 'base64').toString('utf8'); + return JSON.parse(json) as FaydaUserInfo; + } + + throw new FaydaUserInfoException( + 'Unsupported Fayda userinfo response format', + ); + } + + private normalizeUserInfo(raw: FaydaUserInfo): NormalizedFaydaUserInfo { + return { + sub: raw.sub, + fullName: raw.name ?? raw['name#en'] ?? raw['name#am'], + phoneNumber: + raw.phone_number ?? raw['phone_number#en'] ?? raw['phone_number#am'] ?? raw.phone, + email: raw.email, + gender: raw.gender, + birthdate: raw.birthdate, + picture: raw.picture, + }; + } + + private async handlePurchaseSuccess( + session: { + id: string; + userId: string | null; + bookingId: string | null; + saveToAccount: boolean; + }, + normalized: NormalizedFaydaUserInfo, + ): Promise { + if (session.bookingId) { + await this.prisma.bookingSeat.updateMany({ + where: { bookingId: session.bookingId }, + data: { + faydaVerifiedAt: new Date(), + faydaSub: normalized.sub, + faydaVerifiedName: normalized.fullName ?? null, + }, + }); + } + + if (session.userId && session.saveToAccount) { + const conflict = await this.prisma.user.findFirst({ + where: { + faydaSub: normalized.sub, + NOT: { id: session.userId }, + }, + select: { id: true }, + }); + if (conflict) { + throw new FaydaIdentityConflictException(); + } + + await this.prisma.user.update({ + where: { id: session.userId }, + data: { + faydaVerified: true, + faydaVerifiedAt: new Date(), + faydaSub: normalized.sub, + }, + }); + } + } + + private async handleLoginSuccess( + _session: { id: string }, + _normalized: NormalizedFaydaUserInfo, + ): Promise { + // LOGIN flow (User creation / login token issuance) + // The schema currently requires email/phone/passwordHash on User as NOT NULL, + // and the auth controllers haven't been wired to consume Fayda identities yet. + throw new BadRequestException({ + code: 'FAYDA_LOGIN_NOT_IMPLEMENTED', + message: 'Login-with-Fayda is not yet implemented', + }); + } + + private async markSessionFailed( + state: string, + errorCode: string, + errorDescription?: string, + ): Promise { + await this.prisma.faydaVerificationSession.updateMany({ + where: { state, status: 'PENDING' }, + data: { + status: 'FAILED', + errorCode, + errorDescription: errorDescription ?? null, + completedAt: new Date(), + codeVerifier: '', }, }); } + private buildSuccessUrl(): string { + return this.faydaConfig.successRedirectUrl; + } + + private buildFailureUrl(reason: string): string { + const url = new URL(this.faydaConfig.failureRedirectUrl); + url.searchParams.set('reason', reason); + return url.toString(); + } + + private classifyFailureReason(err: unknown): string { + if (err instanceof FaydaIdentityConflictException) return 'identity_conflict'; + if (err instanceof FaydaTokenExchangeException) return 'token_exchange_failed'; + if (err instanceof FaydaUserInfoException) return 'userinfo_failed'; + return 'verification_failed'; + } + + // ========================================================================== + // DEPRECATED: legacy stub flow + // ========================================================================== + + /** @deprecated Use the OIDC flow instead. Retained until cleanup. */ async verifyNationalId( nationalId: string, bookingId?: string, ): Promise { - if (!this.enabled) { - this.logger.warn('Verifayda is disabled - skipping verification'); + if (!this.stubEnabled) { + this.logger.warn('Verifayda stub is disabled - skipping verification'); return { verified: false, failureReason: 'Verifayda integration is disabled', @@ -62,10 +454,8 @@ export class VerifaydaService { }; try { - this.logger.log(`Verifying national ID via Verifayda 2.0`); - + this.logger.log('Verifying national ID via legacy Verifayda stub'); const response = await this.httpClient.post('/verify', requestPayload); - const { data } = response; if (data.status === 'verified' && data.citizen) { @@ -88,36 +478,24 @@ export class VerifaydaService { }, }); - this.logger.log('Verifayda verification successful'); + return { verified: true, passengerData }; + } - return { - verified: true, - passengerData, - }; - } else { - const failureReason = data.message || 'Verification failed'; - - await this.prisma.verifaydaVerification.create({ - data: { - bookingId, - nationalId, - requestPayload, - responsePayload: data, - verified: false, - failureReason, - }, - }); - - this.logger.warn(`Verifayda verification failed: ${failureReason}`); - - return { + const failureReason = data.message || 'Verification failed'; + await this.prisma.verifaydaVerification.create({ + data: { + bookingId, + nationalId, + requestPayload, + responsePayload: data, verified: false, failureReason, - }; - } + }, + }); + return { verified: false, failureReason }; } catch (error: any) { - const errorMessage = error.response?.data?.message || error.message || 'Unknown error'; - + const errorMessage = + error.response?.data?.message || error.message || 'Unknown error'; await this.prisma.verifaydaVerification.create({ data: { bookingId, @@ -127,16 +505,15 @@ export class VerifaydaService { failureReason: errorMessage, }, }); - - this.logger.error(`Verifayda API error: ${errorMessage}`); - + this.logger.error(`Verifayda stub error: ${errorMessage}`); throw new BadRequestException( `National ID verification failed: ${errorMessage}`, ); } } + /** @deprecated Use `faydaConfig.enabled` for the OIDC flow. */ isEnabled(): boolean { - return this.enabled; + return this.stubEnabled; } } diff --git a/apps/edr-passenger-api/src/modules/verifayda/verifayda.types.ts b/apps/edr-passenger-api/src/modules/verifayda/verifayda.types.ts new file mode 100644 index 000000000..7c7335c34 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/verifayda/verifayda.types.ts @@ -0,0 +1,36 @@ +export type VerifaydaPurpose = 'LOGIN' | 'PURCHASE'; + +export interface FaydaTokenResponse { + access_token: string; + id_token?: string; + token_type: string; + expires_in?: number; + scope?: string; +} + +export interface FaydaUserInfo { + sub: string; + name?: string; + 'name#en'?: string; + 'name#am'?: string; + phone_number?: string; + 'phone_number#en'?: string; + 'phone_number#am'?: string; + phone?: string; + email?: string; + gender?: string; + birthdate?: string; + picture?: string; + address?: Record; + [key: string]: unknown; +} + +export interface NormalizedFaydaUserInfo { + sub: string; + fullName?: string; + phoneNumber?: string; + email?: string; + gender?: string; + birthdate?: string; + picture?: string; +} From ac55c0cebce6a31acaf085e4a1c5022be1ceb2d6 Mon Sep 17 00:00:00 2001 From: Abubeker Yasin Date: Tue, 26 May 2026 12:02:46 +0300 Subject: [PATCH 32/38] feat(passenger-api): expose fayda verification endpoints and wire into app --- apps/edr-passenger-api/src/app.module.ts | 2 + .../modules/verifayda/optional-jwt.guard.ts | 21 ++++ .../modules/verifayda/verifayda.controller.ts | 116 ++++++++++++++++++ .../src/modules/verifayda/verifayda.module.ts | 2 + 4 files changed, 141 insertions(+) create mode 100644 apps/edr-passenger-api/src/modules/verifayda/optional-jwt.guard.ts create mode 100644 apps/edr-passenger-api/src/modules/verifayda/verifayda.controller.ts diff --git a/apps/edr-passenger-api/src/app.module.ts b/apps/edr-passenger-api/src/app.module.ts index e1626bef5..84a17f4ef 100644 --- a/apps/edr-passenger-api/src/app.module.ts +++ b/apps/edr-passenger-api/src/app.module.ts @@ -36,6 +36,7 @@ import { AgentsModule } from './modules/agents/agents.module'; import { ReportsModule } from './modules/reports/reports.module'; import { FraudModule } from './modules/fraud/fraud.module'; import { SeatClassesModule } from './modules/seat-classes/seat-classes.module'; +import { VerifaydaModule } from './modules/verifayda/verifayda.module'; @Module({ imports: [ @@ -79,6 +80,7 @@ import { SeatClassesModule } from './modules/seat-classes/seat-classes.module'; ReportsModule, FraudModule, SeatClassesModule, + VerifaydaModule, ], }) export class AppModule implements NestModule { diff --git a/apps/edr-passenger-api/src/modules/verifayda/optional-jwt.guard.ts b/apps/edr-passenger-api/src/modules/verifayda/optional-jwt.guard.ts new file mode 100644 index 000000000..5f5fac19b --- /dev/null +++ b/apps/edr-passenger-api/src/modules/verifayda/optional-jwt.guard.ts @@ -0,0 +1,21 @@ +import { Injectable } from '@nestjs/common'; +import { AuthGuard } from '@nestjs/passport'; + +/** + * Like {@link JwtGuard}, but never rejects the request. + * + * When a valid `Authorization: Bearer ` is present, `request.user` is + * populated from the JWT strategy (`{ userId, ... }`). When the token is + * missing or invalid, the request still proceeds with `request.user` + * undefined — the handler decides what to do. + * + * Used on `POST /fayda/verification/start`, which must work for both + * logged-in users (who can opt to save the verification to their account) + * and guests (anchored to a booking only). + */ +@Injectable() +export class OptionalJwtGuard extends AuthGuard('jwt') { + handleRequest(_err: unknown, user: TUser): TUser { + return (user ?? null) as TUser; + } +} diff --git a/apps/edr-passenger-api/src/modules/verifayda/verifayda.controller.ts b/apps/edr-passenger-api/src/modules/verifayda/verifayda.controller.ts new file mode 100644 index 000000000..496010b30 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/verifayda/verifayda.controller.ts @@ -0,0 +1,116 @@ +import { + Body, + Controller, + Get, + HttpCode, + HttpStatus, + Post, + Query, + Req, + Res, + UseGuards, +} from '@nestjs/common'; +import { + ApiBearerAuth, + ApiOkResponse, + ApiOperation, + ApiTags, +} from '@nestjs/swagger'; +import { JwtGuard } from '../../common/jwt.guard'; +import { OptionalJwtGuard } from './optional-jwt.guard'; +import { + StartVerificationDto, + VerifaydaCallbackDto, + VerificationStatusDto, +} from './verifayda.dto'; +import { VerifaydaService } from './verifayda.service'; + +/** Shape the JWT strategy puts on `request.user` (see common/jwt.strategy.ts). */ +interface AuthedUser { + userId: string; + email?: string; + role?: string; + passengerId?: string; +} + +/** Minimal slices of the Express req/res we actually touch (avoids a hard + * dependency on `@types/express`, which isn't resolved in this package). */ +interface RequestWithOptionalUser { + user?: AuthedUser; +} +interface RequestWithUser { + user: AuthedUser; +} +interface RedirectableResponse { + redirect(url: string): void; +} + +@ApiTags('Fayda Verification') +@Controller('fayda/verification') +export class VerifaydaController { + constructor(private readonly service: VerifaydaService) {} + + @Post('start') + @HttpCode(HttpStatus.OK) + @UseGuards(OptionalJwtGuard) + @ApiBearerAuth('JWT-auth') + @ApiOperation({ + summary: 'Start a VeriFayda 2.0 verification session', + description: `Creates a verification session and returns the eSignet authorize URL the frontend should send the user to. + +- Works for **logged-in users** and **guests**. If a valid bearer token is present, the verification is tied to that user; when \`saveToAccount\` is true their account is marked verified on success. +- For a **PURCHASE** flow, pass \`bookingId\` to stamp the booking's seats as Fayda-verified. +- The returned \`authorizationUrl\` already carries the PKCE \`code_challenge\`, CSRF \`state\`, requested \`claims\`, and \`code_challenge_method=S256\`. The frontend simply navigates to it (full page or popup).`, + }) + @ApiOkResponse({ + description: 'Authorize URL the frontend should redirect the user to.', + schema: { + example: { + authorizationUrl: + 'https://esignet.example.com/authorize?client_id=...&state=...&code_challenge=...', + }, + }, + }) + async start( + @Body() dto: StartVerificationDto, + @Req() req: RequestWithOptionalUser, + ): Promise<{ authorizationUrl: string }> { + const authorizationUrl = await this.service.startVerification({ + purpose: dto.purpose ?? 'PURCHASE', + userId: req.user?.userId, + bookingId: dto.bookingId, + saveToAccount: dto.saveToAccount, + }); + return { authorizationUrl }; + } + + @Get('callback') + @ApiOperation({ + summary: 'eSignet redirect callback (browser lands here)', + description: `Fayda/eSignet redirects the user's browser here with \`?code&state\` (success) or \`?error&error_description\` (failure). + +This endpoint is **not** authenticated — Fayda sends no bearer token. It exchanges the code for tokens, fetches the verified claims, records the result, and **302-redirects** the browser to the configured success or failure frontend URL (failures carry a \`?reason=\` the frontend can switch on).`, + }) + async callback( + @Query() query: VerifaydaCallbackDto, + @Res() res: RedirectableResponse, + ): Promise { + const redirectUrl = await this.service.handleCallback(query); + res.redirect(redirectUrl); + } + + @Get('status') + @UseGuards(JwtGuard) + @ApiBearerAuth('JWT-auth') + @ApiOperation({ + summary: "Get the current user's Fayda verification status", + description: + 'Returns whether the authenticated user has linked a verified Fayda identity to their account, when, and the name on file.', + }) + @ApiOkResponse({ type: VerificationStatusDto }) + async status( + @Req() req: RequestWithUser, + ): Promise { + return this.service.getVerificationStatus(req.user.userId); + } +} diff --git a/apps/edr-passenger-api/src/modules/verifayda/verifayda.module.ts b/apps/edr-passenger-api/src/modules/verifayda/verifayda.module.ts index c14ba3f1f..e54b94726 100644 --- a/apps/edr-passenger-api/src/modules/verifayda/verifayda.module.ts +++ b/apps/edr-passenger-api/src/modules/verifayda/verifayda.module.ts @@ -1,9 +1,11 @@ import { Module } from '@nestjs/common'; +import { VerifaydaController } from './verifayda.controller'; import { VerifaydaService } from './verifayda.service'; import { PrismaModule } from '../../common/prisma.module'; @Module({ imports: [PrismaModule], + controllers: [VerifaydaController], providers: [VerifaydaService], exports: [VerifaydaService], }) From 769294d12f93dae00aa5682424e86bd7e4cd3016 Mon Sep 17 00:00:00 2001 From: Roba Boru Date: Tue, 26 May 2026 16:25:24 +0300 Subject: [PATCH 33/38] Fare engine added --- apps/edr-passenger-api/src/app.module.ts | 2 + apps/edr-passenger-api/src/main.ts | 1 + .../src/modules/currency/currency.service.ts | 63 +++-- .../fare-engine/currency.controller.ts | 54 +++++ .../src/modules/fare-engine/currency.dto.ts | 12 + .../fare-engine/fare-engine.controller.ts | 65 +++++ .../modules/fare-engine/fare-engine.dto.ts | 72 ++++++ .../modules/fare-engine/fare-engine.module.ts | 13 + .../fare-engine/fare-engine.service.ts | 224 ++++++++++++++++++ .../modules/schedules/schedules.controller.ts | 43 +++- .../src/modules/schedules/schedules.module.ts | 2 + .../modules/schedules/schedules.service.ts | 64 +++-- 12 files changed, 570 insertions(+), 45 deletions(-) create mode 100644 apps/edr-passenger-api/src/modules/fare-engine/currency.controller.ts create mode 100644 apps/edr-passenger-api/src/modules/fare-engine/currency.dto.ts create mode 100644 apps/edr-passenger-api/src/modules/fare-engine/fare-engine.controller.ts create mode 100644 apps/edr-passenger-api/src/modules/fare-engine/fare-engine.dto.ts create mode 100644 apps/edr-passenger-api/src/modules/fare-engine/fare-engine.module.ts create mode 100644 apps/edr-passenger-api/src/modules/fare-engine/fare-engine.service.ts diff --git a/apps/edr-passenger-api/src/app.module.ts b/apps/edr-passenger-api/src/app.module.ts index 261463e27..d0dfed771 100644 --- a/apps/edr-passenger-api/src/app.module.ts +++ b/apps/edr-passenger-api/src/app.module.ts @@ -35,6 +35,7 @@ import { AgentsModule } from './modules/agents/agents.module'; import { ReportsModule } from './modules/reports/reports.module'; import { FraudModule } from './modules/fraud/fraud.module'; import { SeatClassesModule } from './modules/seat-classes/seat-classes.module'; +import { FareEngineModule } from './modules/fare-engine/fare-engine.module'; @Module({ imports: [ @@ -69,6 +70,7 @@ import { SeatClassesModule } from './modules/seat-classes/seat-classes.module'; ReportsModule, FraudModule, SeatClassesModule, + FareEngineModule, ], }) export class AppModule implements NestModule { diff --git a/apps/edr-passenger-api/src/main.ts b/apps/edr-passenger-api/src/main.ts index 4b8b6885c..4fe3d1473 100644 --- a/apps/edr-passenger-api/src/main.ts +++ b/apps/edr-passenger-api/src/main.ts @@ -214,6 +214,7 @@ Payment providers send notifications to: .addTag("Auth", "Registration and login") .addTag("Booking", "Booking lifecycle") .addTag("Dashboard", "Home dashboard aggregate") + .addTag("Fare Engine", "Distance-based fare calculator — km × rate × exchange rate, nationality-aware currency") .addTag("Fleet", "Train services and coaches") .addTag("Fraud Detection", "Fraud detection and monitoring") .addTag("Live Tracking", "Real-time trip status and crowd signals") diff --git a/apps/edr-passenger-api/src/modules/currency/currency.service.ts b/apps/edr-passenger-api/src/modules/currency/currency.service.ts index 3fcfce179..8cf931bad 100644 --- a/apps/edr-passenger-api/src/modules/currency/currency.service.ts +++ b/apps/edr-passenger-api/src/modules/currency/currency.service.ts @@ -1,4 +1,4 @@ -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable, Logger, NotFoundException } from '@nestjs/common'; import { PrismaService } from '../../common/prisma.service'; import { Currency } from '@prisma/client'; @@ -47,9 +47,8 @@ export class CurrencyService { async syncExchangeRates(): Promise { this.logger.log('Syncing exchange rates from external provider'); - - // In production, fetch from external API - // For now, using static rates + + const today = this.todayUtc(); const rates = [ { from: 'ETB', to: 'ETB', rate: 1.0 }, { from: 'ETB', to: 'DJF', rate: 3.25 }, @@ -59,25 +58,47 @@ export class CurrencyService { ]; for (const { from, to, rate } of rates) { - await this.prisma.currencyExchangeRate.upsert({ - where: { - fromCurrency_toCurrency_effectiveDate: { - fromCurrency: from as Currency, - toCurrency: to as Currency, - effectiveDate: new Date(), - }, - }, - update: { rate }, - create: { - fromCurrency: from as Currency, - toCurrency: to as Currency, - rate, - effectiveDate: new Date(), - source: 'EXTERNAL_API', - }, - }); + await this.upsertRate(from as Currency, to as Currency, rate, today, 'EXTERNAL_API'); } this.logger.log('Exchange rates synced successfully'); } + + async listRates() { + return this.prisma.currencyExchangeRate.findMany({ + orderBy: [{ fromCurrency: 'asc' }, { toCurrency: 'asc' }, { effectiveDate: 'desc' }], + }); + } + + async upsertRate( + fromCurrency: Currency, + toCurrency: Currency, + rate: number, + effectiveDate?: Date, + source = 'MANUAL', + ) { + const date = effectiveDate ?? this.todayUtc(); + return this.prisma.currencyExchangeRate.upsert({ + where: { fromCurrency_toCurrency_effectiveDate: { fromCurrency, toCurrency, effectiveDate: date } }, + update: { rate, source }, + create: { fromCurrency, toCurrency, rate, effectiveDate: date, source }, + }); + } + + async updateRateById(id: string, rate: number, source = 'MANUAL') { + const existing = await this.prisma.currencyExchangeRate.findUnique({ where: { id } }); + if (!existing) throw new NotFoundException('Exchange rate not found'); + return this.prisma.currencyExchangeRate.update({ where: { id }, data: { rate, source } }); + } + + async deleteRate(id: string) { + return this.prisma.currencyExchangeRate.delete({ where: { id } }); + } + + /** Returns midnight UTC for today — used as the date-only key for upserts. */ + private todayUtc(): Date { + const d = new Date(); + d.setUTCHours(0, 0, 0, 0); + return d; + } } diff --git a/apps/edr-passenger-api/src/modules/fare-engine/currency.controller.ts b/apps/edr-passenger-api/src/modules/fare-engine/currency.controller.ts new file mode 100644 index 000000000..1d35f6b61 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/fare-engine/currency.controller.ts @@ -0,0 +1,54 @@ +import { Body, Controller, Delete, Get, Param, Patch, Put, Post } from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiParam, ApiProperty, ApiResponse } from '@nestjs/swagger'; +import { CurrencyService } from '../currency/currency.service'; +import { UpsertExchangeRateDto } from './currency.dto'; +import { IsNumber, IsPositive, IsOptional, IsString } from 'class-validator'; +import { Type } from 'class-transformer'; + +class UpdateExchangeRateDto { + @ApiProperty({ example: 3.5 }) @Type(() => Number) @IsNumber() @IsPositive() rate: number; + @ApiProperty({ example: 'MANUAL', required: false }) @IsOptional() @IsString() source?: string; +} + +@ApiTags('Fare Engine') +@Controller('fare-engine/exchange-rates') +export class CurrencyController { + constructor(private currency: CurrencyService) {} + + @Get() + @ApiOperation({ summary: 'List all exchange rates (latest per pair first)' }) + list() { + return this.currency.listRates(); + } + + @Put() + @ApiOperation({ summary: 'Upsert an exchange rate for today' }) + @ApiResponse({ status: 200, description: 'Rate created or updated for today\'s effective date' }) + upsert(@Body() dto: UpsertExchangeRateDto) { + return this.currency.upsertRate(dto.fromCurrency, dto.toCurrency, dto.rate, undefined, dto.source); + } + + @Patch(':id') + @ApiOperation({ summary: 'Update an exchange rate by ID' }) + @ApiParam({ name: 'id', description: 'CurrencyExchangeRate UUID' }) + @ApiResponse({ status: 200, description: 'Rate updated' }) + @ApiResponse({ status: 404, description: 'Rate not found' }) + update(@Param('id') id: string, @Body() dto: UpdateExchangeRateDto) { + return this.currency.updateRateById(id, dto.rate, dto.source); + } + + @Delete(':id') + @ApiOperation({ summary: 'Delete an exchange rate record by ID' }) + @ApiParam({ name: 'id', description: 'CurrencyExchangeRate UUID' }) + @ApiResponse({ status: 200, description: 'Rate deleted' }) + @ApiResponse({ status: 404, description: 'Rate not found' }) + remove(@Param('id') id: string) { + return this.currency.deleteRate(id); + } + + @Post('sync') + @ApiOperation({ summary: 'Trigger exchange rate sync from external provider' }) + sync() { + return this.currency.syncExchangeRates(); + } +} diff --git a/apps/edr-passenger-api/src/modules/fare-engine/currency.dto.ts b/apps/edr-passenger-api/src/modules/fare-engine/currency.dto.ts new file mode 100644 index 000000000..59e863cea --- /dev/null +++ b/apps/edr-passenger-api/src/modules/fare-engine/currency.dto.ts @@ -0,0 +1,12 @@ +import { IsEnum, IsNumber, IsPositive, IsOptional, IsString } from 'class-validator'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +import { Type } from 'class-transformer'; +import { Currency } from '@prisma/client'; + +export class UpsertExchangeRateDto { + @ApiProperty({ enum: Currency, example: 'ETB' }) @IsEnum(Currency) fromCurrency: Currency; + @ApiProperty({ enum: Currency, example: 'DJF' }) @IsEnum(Currency) toCurrency: Currency; + @ApiProperty({ example: 3.25 }) @Type(() => Number) @IsNumber() @IsPositive() rate: number; + @ApiPropertyOptional({ example: 'MANUAL', description: 'Source label e.g. MANUAL, EXTERNAL_API' }) + @IsOptional() @IsString() source?: string; +} diff --git a/apps/edr-passenger-api/src/modules/fare-engine/fare-engine.controller.ts b/apps/edr-passenger-api/src/modules/fare-engine/fare-engine.controller.ts new file mode 100644 index 000000000..25718cc8f --- /dev/null +++ b/apps/edr-passenger-api/src/modules/fare-engine/fare-engine.controller.ts @@ -0,0 +1,65 @@ +import { Body, Controller, Post, Get, Query } from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiQuery, ApiResponse } from '@nestjs/swagger'; +import { FareEngineService } from './fare-engine.service'; +import { FareCalculateDto, FareBreakdownDto } from './fare-engine.dto'; + +@ApiTags('Fare Engine') +@Controller('fare-engine') +export class FareEngineController { + constructor(private service: FareEngineService) {} + + @Post('calculate') + @ApiOperation({ + summary: 'Calculate fare for a journey leg', + description: `Computes fare using the formula: + +**Fare = totalKm × ratePerKm × exchangeRate** + +- \`totalKm\` — sum of \`distanceKm\` on RouteStop records between origin and destination +- \`ratePerKm\` — \`SeatClass.basePrice\` (stored in ETB minor units per km) +- \`exchangeRate\` — derived from passenger nationality: + - **Ethiopian** → ETB (rate = 1.0) + - **Djiboutian** → DJF (rate ≈ 3.25) + - **Other / unspecified** → USD (rate ≈ 0.018) + +Age-based pricing: first child (age < 5) travels free, subsequent children pay full fare. +5% tax applied after promo discount. +Returns a full breakdown including a human-readable calculation trace.`, + }) + @ApiResponse({ status: 201, type: FareBreakdownDto, description: 'Full fare breakdown with calculation trace' }) + @ApiResponse({ status: 400, description: 'Invalid route/station combination or missing distanceKm on route stops' }) + @ApiResponse({ status: 404, description: 'Route or seat class not found' }) + calculate(@Body() dto: FareCalculateDto) { + return this.service.calculate(dto); + } + + @Get('compare') + @ApiOperation({ + summary: 'Compare fares across all seat classes for a route leg', + description: 'Returns fare breakdown for every active seat class on the requested leg. Useful for rendering a class-selection table on the booking screen.', + }) + @ApiQuery({ name: 'routeId', description: 'Route UUID' }) + @ApiQuery({ name: 'originStationId', description: 'Origin station UUID' }) + @ApiQuery({ name: 'destinationStationId', description: 'Destination station UUID' }) + @ApiQuery({ name: 'nationality', required: false, description: 'Passenger nationality (Ethiopian | Djiboutian | other). Determines billing currency.' }) + @ApiQuery({ name: 'adultCount', required: false, type: Number, description: 'Number of adults (default 1)' }) + @ApiQuery({ name: 'childCount', required: false, type: Number, description: 'Number of children (default 0)' }) + @ApiResponse({ status: 200, description: 'Array of fare breakdowns, one per active seat class, ordered by price ascending' }) + compareClasses( + @Query('routeId') routeId: string, + @Query('originStationId') originStationId: string, + @Query('destinationStationId') destinationStationId: string, + @Query('nationality') nationality?: string, + @Query('adultCount') adultCount?: string, + @Query('childCount') childCount?: string, + ) { + return this.service.compareClasses( + routeId, + originStationId, + destinationStationId, + nationality, + adultCount ? parseInt(adultCount) : 1, + childCount ? parseInt(childCount) : 0, + ); + } +} diff --git a/apps/edr-passenger-api/src/modules/fare-engine/fare-engine.dto.ts b/apps/edr-passenger-api/src/modules/fare-engine/fare-engine.dto.ts new file mode 100644 index 000000000..536ddaa3b --- /dev/null +++ b/apps/edr-passenger-api/src/modules/fare-engine/fare-engine.dto.ts @@ -0,0 +1,72 @@ +import { IsString, IsOptional, IsEnum, IsInt, Min } from 'class-validator'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +import { Type } from 'class-transformer'; +import { Currency } from '@prisma/client'; + +// Nationality → home currency mapping +export const NATIONALITY_CURRENCY_MAP: Record = { + Ethiopian: Currency.ETB, + Djiboutian: Currency.DJF, +}; + +export function resolveCurrencyFromNationality(nationality?: string): Currency { + if (!nationality) return Currency.ETB; + return NATIONALITY_CURRENCY_MAP[nationality] ?? Currency.USD; +} + +export class FareCalculateDto { + @ApiProperty({ example: 'route-uuid', description: 'Route UUID — used to look up stop distances' }) + @IsString() routeId: string; + + @ApiProperty({ example: 'station-uuid', description: 'Origin station UUID (must be a stop on the route)' }) + @IsString() originStationId: string; + + @ApiProperty({ example: 'station-uuid', description: 'Destination station UUID (must come after origin)' }) + @IsString() destinationStationId: string; + + @ApiProperty({ example: 'seat-class-uuid', description: 'SeatClass UUID — its basePrice is the per-km rate in ETB minor units' }) + @IsString() seatClassId: string; + + @ApiPropertyOptional({ + example: 'Ethiopian', + description: 'Passenger nationality. Determines the billing currency: Ethiopian → ETB, Djiboutian → DJF, other → USD. Defaults to ETB.', + }) + @IsOptional() @IsString() nationality?: string; + + @ApiPropertyOptional({ + example: 2, + description: 'Number of adult passengers (age ≥ 5). Defaults to 1.', + }) + @IsOptional() @Type(() => Number) @IsInt() @Min(1) adultCount?: number; + + @ApiPropertyOptional({ + example: 1, + description: 'Number of child passengers (age < 5). First child travels free.', + }) + @IsOptional() @Type(() => Number) @IsInt() @Min(0) childCount?: number; + + @ApiPropertyOptional({ example: 'WEEKEND15', description: 'Promo code for discount' }) + @IsOptional() @IsString() promoCode?: string; +} + +export class FareBreakdownDto { + @ApiProperty({ example: 'ADD-DJI' }) routeCode: string; + @ApiProperty({ example: 'Addis Ababa' }) originName: string; + @ApiProperty({ example: 'Djibouti' }) destinationName: string; + @ApiProperty({ example: 'Economy Regular' }) seatClassName: string; + @ApiProperty({ example: 756 }) totalDistanceKm: number; + @ApiProperty({ example: 120 }) ratePerKmMinor: number; + @ApiProperty({ example: 90720 }) baseFarePerPassengerMinor: number; + @ApiProperty({ example: 2 }) adultCount: number; + @ApiProperty({ example: 1 }) childCount: number; + @ApiProperty({ example: 1 }) freeChildrenCount: number; + @ApiProperty({ example: 0 }) paidChildrenCount: number; + @ApiProperty({ example: 181440 }) subtotalMinor: number; + @ApiProperty({ example: 0 }) discountMinor: number; + @ApiProperty({ example: 9072 }) taxMinor: number; + @ApiProperty({ example: 190512 }) totalMinor: number; + @ApiProperty({ example: 'ETB', enum: Currency }) billingCurrency: Currency; + @ApiProperty({ example: 190512 }) totalInBillingCurrency: number; + @ApiProperty({ example: 3.25 }) exchangeRate: number; + @ApiProperty({ description: 'Step-by-step calculation trace for transparency' }) calculation: string; +} diff --git a/apps/edr-passenger-api/src/modules/fare-engine/fare-engine.module.ts b/apps/edr-passenger-api/src/modules/fare-engine/fare-engine.module.ts new file mode 100644 index 000000000..fefdfb9a9 --- /dev/null +++ b/apps/edr-passenger-api/src/modules/fare-engine/fare-engine.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; +import { FareEngineController } from './fare-engine.controller'; +import { FareEngineService } from './fare-engine.service'; +import { CurrencyController } from './currency.controller'; +import { CurrencyModule } from '../currency/currency.module'; + +@Module({ + imports: [CurrencyModule], + controllers: [FareEngineController, CurrencyController], + providers: [FareEngineService], + exports: [FareEngineService], +}) +export class FareEngineModule {} diff --git a/apps/edr-passenger-api/src/modules/fare-engine/fare-engine.service.ts b/apps/edr-passenger-api/src/modules/fare-engine/fare-engine.service.ts new file mode 100644 index 000000000..b0411718f --- /dev/null +++ b/apps/edr-passenger-api/src/modules/fare-engine/fare-engine.service.ts @@ -0,0 +1,224 @@ +import { Injectable, BadRequestException, NotFoundException } from '@nestjs/common'; +import { PrismaService } from '../../common/prisma.service'; +import { CurrencyService } from '../currency/currency.service'; +import { FareCalculateDto, resolveCurrencyFromNationality } from './fare-engine.dto'; +import { Currency } from '@prisma/client'; + +const TAX_RATE = 0.05; + +@Injectable() +export class FareEngineService { + constructor( + private prisma: PrismaService, + private currencyService: CurrencyService, + ) {} + + async calculate(dto: FareCalculateDto) { + const route = await this.prisma.route.findUnique({ + where: { id: dto.routeId }, + include: { stops: { orderBy: { sequence: 'asc' } } }, + }); + if (!route) throw new NotFoundException('Route not found'); + + const originStop = route.stops.find(s => s.stationId === dto.originStationId); + const destStop = route.stops.find(s => s.stationId === dto.destinationStationId); + + if (!originStop) throw new BadRequestException('Origin station not found on this route'); + if (!destStop) throw new BadRequestException('Destination station not found on this route'); + if (originStop.sequence >= destStop.sequence) + throw new BadRequestException('Origin must come before destination in the route sequence'); + + const legStops = route.stops.filter( + s => s.sequence > originStop.sequence && s.sequence <= destStop.sequence, + ); + + const missingDistance = legStops.filter(s => s.distanceKm === null || s.distanceKm === undefined); + if (missingDistance.length > 0) + throw new BadRequestException( + `Missing distanceKm on route stops at sequences: ${missingDistance.map(s => s.sequence).join(', ')}`, + ); + + const totalDistanceKm = legStops.reduce((sum, s) => sum + (s.distanceKm ?? 0), 0); + + const seatClass = await this.prisma.seatClass.findUnique({ where: { id: dto.seatClassId } }); + if (!seatClass) throw new NotFoundException('Seat class not found'); + if (!seatClass.isActive) throw new BadRequestException('Seat class is not active'); + + const ratePerKmMinor = seatClass.basePrice; + const baseFarePerPassengerMinor = totalDistanceKm * ratePerKmMinor; + + const adultCount = dto.adultCount ?? 1; + const childCount = dto.childCount ?? 0; + const freeChildrenCount = Math.min(childCount, 1); + const paidChildrenCount = Math.max(0, childCount - 1); + + const subtotalMinor = + baseFarePerPassengerMinor * adultCount + + baseFarePerPassengerMinor * paidChildrenCount; + + let discountMinor = 0; + let promoLabel = 'none'; + if (dto.promoCode) { + const promo = await this.prisma.promotion.findUnique({ where: { code: dto.promoCode } }); + if (promo?.active && promo.validUntil > new Date()) { + discountMinor = promo.percentOff + ? Math.round(subtotalMinor * promo.percentOff / 100) + : (promo.amountOffMinor ?? 0); + promoLabel = `${dto.promoCode} (-${promo.percentOff ?? 0}%)`; + } + } + + const afterDiscountMinor = subtotalMinor - discountMinor; + const taxMinor = Math.round(afterDiscountMinor * TAX_RATE); + const totalEtbMinor = afterDiscountMinor + taxMinor; + + const billingCurrency = resolveCurrencyFromNationality(dto.nationality); + const exchangeRate = await this.currencyService.getExchangeRate(Currency.ETB, billingCurrency); + const totalInBillingCurrency = Math.round(totalEtbMinor * exchangeRate); + + const [originStation, destStation] = await Promise.all([ + this.prisma.station.findUnique({ where: { id: dto.originStationId } }), + this.prisma.station.findUnique({ where: { id: dto.destinationStationId } }), + ]); + + const calculation = [ + `Distance: ${totalDistanceKm} km (${originStation?.name} → ${destStation?.name})`, + `Rate per km: ${ratePerKmMinor} ETB minor (${seatClass.name})`, + `Base fare/pax: ${totalDistanceKm} km × ${ratePerKmMinor} = ${baseFarePerPassengerMinor} ETB minor`, + `Passengers: ${adultCount} adult(s) × ${baseFarePerPassengerMinor} = ${baseFarePerPassengerMinor * adultCount} ETB minor`, + `Children: ${childCount} child(ren) — ${freeChildrenCount} free, ${paidChildrenCount} paid`, + `Subtotal: ${subtotalMinor} ETB minor`, + `Promo: ${promoLabel} → -${discountMinor} ETB minor`, + `Tax (5%): +${taxMinor} ETB minor`, + `Total (ETB): ${totalEtbMinor} ETB minor`, + `Nationality: ${dto.nationality ?? 'unspecified'} → ${billingCurrency}`, + `Exchange rate: 1 ETB = ${exchangeRate} ${billingCurrency}`, + `Total (${billingCurrency}): ${totalInBillingCurrency} ${billingCurrency} minor`, + ].join('\n'); + + return { + routeCode: route.code, + originName: originStation?.name ?? dto.originStationId, + destinationName: destStation?.name ?? dto.destinationStationId, + seatClassName: seatClass.name, + totalDistanceKm, + ratePerKmMinor, + baseFarePerPassengerMinor, + adultCount, + childCount, + freeChildrenCount, + paidChildrenCount, + subtotalMinor, + discountMinor, + taxMinor, + totalMinor: totalEtbMinor, + billingCurrency, + totalInBillingCurrency, + exchangeRate, + calculation, + }; + } + + async compareClasses( + routeId: string, + originStationId: string, + destinationStationId: string, + nationality?: string, + adultCount = 1, + childCount = 0, + ) { + const seatClasses = await this.prisma.seatClass.findMany({ + where: { isActive: true }, + orderBy: { basePrice: 'asc' }, + }); + + const results = await Promise.all( + seatClasses.map(sc => + this.calculate({ routeId, originStationId, destinationStationId, seatClassId: sc.id, nationality, adultCount, childCount }) + .catch(() => null), + ), + ); + + return results.filter(Boolean); + } + + /** Resolve schedule → route/origin/destination, then calculate fare for one seat class. */ + async calculateForSchedule(scheduleId: string, seatClassId: string, nationality?: string) { + const schedule = await this.prisma.trainSchedule.findUnique({ + where: { id: scheduleId }, + select: { routeId: true, originStationId: true, destinationStationId: true }, + }); + if (!schedule) throw new NotFoundException('Schedule not found'); + if (!schedule.routeId) throw new BadRequestException('Schedule has no associated route'); + + return this.calculate({ + routeId: schedule.routeId, + originStationId: schedule.originStationId, + destinationStationId: schedule.destinationStationId, + seatClassId, + nationality, + }); + } + + /** Calculate fares for all active seat classes on a schedule. */ + async calculateAllForSchedule(scheduleId: string, nationality?: string) { + const schedule = await this.prisma.trainSchedule.findUnique({ + where: { id: scheduleId }, + select: { routeId: true, originStationId: true, destinationStationId: true }, + }); + if (!schedule) throw new NotFoundException('Schedule not found'); + + // ── Route-based calculation (fare engine) ──────────────────────────────── + if (schedule.routeId) { + const seatClasses = await this.prisma.seatClass.findMany({ + where: { isActive: true }, + orderBy: { basePrice: 'asc' }, + }); + + const results = await Promise.all( + seatClasses.map(sc => + this.calculate({ + routeId: schedule.routeId!, + originStationId: schedule.originStationId, + destinationStationId: schedule.destinationStationId, + seatClassId: sc.id, + nationality, + }).catch(() => null), + ), + ); + + return results.filter(Boolean); + } + + // ── Fallback: FareRule records scoped to this schedule ─────────────────── + const now = new Date(); + const fareRules = await this.prisma.fareRule.findMany({ + where: { + tripId: scheduleId, + validFrom: { lte: now }, + OR: [{ validUntil: null }, { validUntil: { gte: now } }], + }, + include: { seatClass: true }, + orderBy: { seatClass: { basePrice: 'asc' } }, + }); + + if (fareRules.length > 0) { + const billingCurrency = resolveCurrencyFromNationality(nationality); + const exchangeRate = await this.currencyService.getExchangeRate(Currency.ETB, billingCurrency); + return fareRules.map(rule => ({ + seatClassId: rule.seatClassId, + seatClassName: rule.seatClass.name, + baseFareMinor: rule.baseFareMinor, + totalMinor: rule.baseFareMinor, + billingCurrency, + totalInBillingCurrency: Math.round(rule.baseFareMinor * exchangeRate), + exchangeRate, + source: 'FARE_RULE', + })); + } + + throw new BadRequestException( + 'Schedule has no associated route and no fare rules. Assign a route or create fare rules for this schedule.', + ); + } +} diff --git a/apps/edr-passenger-api/src/modules/schedules/schedules.controller.ts b/apps/edr-passenger-api/src/modules/schedules/schedules.controller.ts index 07d0362af..1f122cd41 100644 --- a/apps/edr-passenger-api/src/modules/schedules/schedules.controller.ts +++ b/apps/edr-passenger-api/src/modules/schedules/schedules.controller.ts @@ -89,12 +89,45 @@ Origin and destination are derived from the first and last route stop — no nee // ── Fares ────────────────────────────────────────────────────────────────── @Get(':scheduleId/fares') - @ApiOperation({ summary: 'Get applicable fare for a schedule and seat class' }) + @ApiOperation({ summary: 'Get fare for a schedule and seat class from the fare engine' }) @ApiParam({ name: 'scheduleId', description: 'TrainSchedule UUID' }) - @ApiQuery({ name: 'class', required: false, description: 'Seat class name: "Economy Regular" | "Economy Bed" | "VIP Bed". Defaults to Economy Regular.' }) - @ApiResponse({ status: 200, description: 'Fare rule or default fare' }) + @ApiQuery({ name: 'seatClassId', required: true, description: 'SeatClass UUID' }) + @ApiQuery({ name: 'nationality', required: false, description: 'Passenger nationality — determines billing currency (Ethiopian→ETB, Djiboutian→DJF, other→USD)' }) + @ApiResponse({ status: 200, description: 'Live fare breakdown from fare engine' }) + @ApiResponse({ status: 400, description: 'Schedule has no route or missing distanceKm on stops' }) + @ApiResponse({ status: 404, description: 'Schedule or seat class not found' }) + getFare( + @Param('scheduleId') scheduleId: string, + @Query('seatClassId') seatClassId: string, + @Query('nationality') nationality?: string, + ) { + return this.service.getFareFromEngine(scheduleId, seatClassId, nationality); + } + + @Get(':scheduleId/fares/all') + @ApiOperation({ summary: 'Get fares for all active seat classes on a schedule' }) + @ApiParam({ name: 'scheduleId', description: 'TrainSchedule UUID' }) + @ApiQuery({ name: 'nationality', required: false, description: 'Passenger nationality — determines billing currency' }) + @ApiResponse({ status: 200, description: 'Array of fare breakdowns for every active seat class, ordered by price ascending' }) + @ApiResponse({ status: 400, description: 'Schedule has no route or missing distanceKm on stops' }) @ApiResponse({ status: 404, description: 'Schedule not found' }) - getFare(@Param('scheduleId') scheduleId: string, @Query('class') cls: string) { - return this.service.getFare(scheduleId, cls ?? 'Economy Regular'); + getAllFares( + @Param('scheduleId') scheduleId: string, + @Query('nationality') nationality?: string, + ) { + return this.service.getAllFaresFromEngine(scheduleId, nationality); + } + + @Post(':id/fares/sync') + @ApiOperation({ + summary: 'Sync fares from fare engine', + description: 'Recalculates fares for all active seat classes using the fare engine (km × ratePerKm + tax) and upserts them as FareRule records scoped to this schedule. Previous active rules are expired.', + }) + @ApiParam({ name: 'id', description: 'TrainSchedule UUID' }) + @ApiResponse({ status: 201, description: 'Fares synced — returns count of synced rules and any errors' }) + @ApiResponse({ status: 400, description: 'Schedule has no associated route or missing distanceKm on stops' }) + @ApiResponse({ status: 404, description: 'Schedule not found' }) + syncFares(@Param('id') id: string) { + return this.service.syncFaresFromEngine(id); } } diff --git a/apps/edr-passenger-api/src/modules/schedules/schedules.module.ts b/apps/edr-passenger-api/src/modules/schedules/schedules.module.ts index 9df073e74..5eca9f1be 100644 --- a/apps/edr-passenger-api/src/modules/schedules/schedules.module.ts +++ b/apps/edr-passenger-api/src/modules/schedules/schedules.module.ts @@ -3,8 +3,10 @@ import { SchedulesController } from './schedules.controller'; import { SchedulesService } from './schedules.service'; import { RoutesController } from './routes.controller'; import { RoutesService } from './routes.service'; +import { FareEngineModule } from '../fare-engine/fare-engine.module'; @Module({ + imports: [FareEngineModule], controllers: [RoutesController, SchedulesController], providers: [RoutesService, SchedulesService], exports: [RoutesService, SchedulesService], diff --git a/apps/edr-passenger-api/src/modules/schedules/schedules.service.ts b/apps/edr-passenger-api/src/modules/schedules/schedules.service.ts index 17f2b554b..eb10d6e0b 100644 --- a/apps/edr-passenger-api/src/modules/schedules/schedules.service.ts +++ b/apps/edr-passenger-api/src/modules/schedules/schedules.service.ts @@ -1,6 +1,7 @@ -import { Injectable, NotFoundException, ConflictException, BadRequestException } from '@nestjs/common'; +import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common'; import { PrismaService } from '../../common/prisma.service'; import { RoutesService } from './routes.service'; +import { FareEngineService } from '../fare-engine/fare-engine.service'; import { CreateScheduleDto, CreateFareRuleDto, UpdateScheduleStatusDto, UpdateStopTimeDto, ListSchedulesDto } from './schedules.dto'; @Injectable() @@ -8,6 +9,7 @@ export class SchedulesService { constructor( private prisma: PrismaService, private routesService: RoutesService, + private fareEngine: FareEngineService, ) {} // ── Schedule CRUD ────────────────────────────────────────────────────────── @@ -149,27 +151,51 @@ export class SchedulesService { }); } - async getFare(scheduleId: string, seatClassName: string) { - const schedule = await this.prisma.trainSchedule.findUnique({ - where: { id: scheduleId }, - include: { originStation: true, destinationStation: true }, - }); - if (!schedule) throw new NotFoundException('Schedule not found'); + getFareFromEngine(scheduleId: string, seatClassId: string, nationality?: string) { + return this.fareEngine.calculateForSchedule(scheduleId, seatClassId, nationality); + } - const route = `${schedule.originStation.code}-${schedule.destinationStation.code}`; - const seatClass = await this.prisma.seatClass.findFirst({ where: { name: seatClassName } }); + getAllFaresFromEngine(scheduleId: string, nationality?: string) { + return this.fareEngine.calculateAllForSchedule(scheduleId, nationality); + } + + /** + * Recalculate fares for all active seat classes on a schedule using the fare engine + * and upsert them as FareRule records scoped to this schedule. + */ + async syncFaresFromEngine(scheduleId: string): Promise<{ synced: number; errors: string[] }> { + const results = await this.fareEngine.calculateAllForSchedule(scheduleId); + const errors: string[] = []; + let synced = 0; const now = new Date(); - const rule = await this.prisma.fareRule.findFirst({ - where: { - seatClassId: seatClass?.id, - validFrom: { lte: now }, - OR: [{ tripId: scheduleId }, { route }, { tripId: null, route: null }], - AND: [{ OR: [{ validUntil: null }, { validUntil: { gte: now } }] }], - }, - orderBy: { validFrom: 'desc' }, - }); + for (const fare of results as any[]) { + try { + const seatClass = await this.prisma.seatClass.findFirst({ where: { name: fare.seatClassName } }); + if (!seatClass) { errors.push(`Seat class not found: ${fare.seatClassName}`); continue; } - return rule ?? { baseFareMinor: 45000, currency: 'ETB', seatClassName }; + // Expire any existing active rule for this schedule + seat class + await this.prisma.fareRule.updateMany({ + where: { tripId: scheduleId, seatClassId: seatClass.id, validUntil: null }, + data: { validUntil: now }, + }); + + await this.prisma.fareRule.create({ + data: { + tripId: scheduleId, + seatClassId: seatClass.id, + baseFareMinor: fare.totalMinor, + currency: 'ETB', + validFrom: now, + validUntil: null, + }, + }); + synced++; + } catch (err) { + errors.push(`${fare.seatClassName}: ${err instanceof Error ? err.message : String(err)}`); + } + } + + return { synced, errors }; } } From 3c6bd724f2e717500f8b6553b879c453b3210b50 Mon Sep 17 00:00:00 2001 From: Roba Boru Date: Tue, 26 May 2026 16:54:52 +0300 Subject: [PATCH 34/38] Get fare class on search --- .../src/modules/search/search.module.ts | 11 ++++++----- .../src/modules/search/search.service.ts | 9 ++++++++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/apps/edr-passenger-api/src/modules/search/search.module.ts b/apps/edr-passenger-api/src/modules/search/search.module.ts index 5228590fb..fbf907fdd 100644 --- a/apps/edr-passenger-api/src/modules/search/search.module.ts +++ b/apps/edr-passenger-api/src/modules/search/search.module.ts @@ -2,11 +2,12 @@ import { Module } from '@nestjs/common'; import { SearchController } from './search.controller'; import { SearchService } from './search.service'; import { CurrencyModule } from '../currency/currency.module'; +import { FareEngineModule } from '../fare-engine/fare-engine.module'; -@Module({ - imports: [CurrencyModule], - controllers: [SearchController], - providers: [SearchService], - exports: [SearchService] +@Module({ + imports: [CurrencyModule, FareEngineModule], + controllers: [SearchController], + providers: [SearchService], + exports: [SearchService], }) export class SearchModule {} diff --git a/apps/edr-passenger-api/src/modules/search/search.service.ts b/apps/edr-passenger-api/src/modules/search/search.service.ts index 9141da4cb..e5e585bd0 100644 --- a/apps/edr-passenger-api/src/modules/search/search.service.ts +++ b/apps/edr-passenger-api/src/modules/search/search.service.ts @@ -2,6 +2,7 @@ import { Injectable, NotFoundException } from '@nestjs/common'; import { PrismaService } from '../../common/prisma.service'; import { SearchTripsDto, FareQuoteDto } from './search.dto'; import { CurrencyService } from '../currency/currency.service'; +import { FareEngineService } from '../fare-engine/fare-engine.service'; import { Currency } from '@prisma/client'; const POINTS_TO_MINOR = 10; @@ -11,6 +12,7 @@ export class SearchService { constructor( private prisma: PrismaService, private currencyService: CurrencyService, + private fareEngine: FareEngineService, ) {} async searchTrips(dto: SearchTripsDto) { @@ -68,6 +70,11 @@ export class SearchService { const legDepartureAt = originStop.plannedDepartureAt ?? schedule.departureAt; const legArrivalAt = destStop.plannedArrivalAt ?? schedule.arrivalAt; + // Fetch fares for all seat classes from fare engine in one call + const faresByClass = await this.fareEngine + .calculateAllForSchedule(schedule.id, dto.nationality) + .catch(() => []); + results.push({ scheduleId: schedule.id, trainNumber: schedule.train.number, @@ -92,7 +99,6 @@ export class SearchService { (new Date(legArrivalAt).getTime() - new Date(legDepartureAt).getTime()) / 60_000, ), status: schedule.status, - // Only return stops within the requested leg (origin → destination inclusive) stops: schedule.stopTimes .filter(st => st.sequence >= originStop.sequence && st.sequence <= destStop.sequence) .map(st => ({ @@ -104,6 +110,7 @@ export class SearchService { })), availabilityByClass, hasAvailability: Object.values(availabilityByClass).some(n => n >= totalPassengers), + faresByClass, }); } From 4e500700ec2653db02e8c39836092899683dbb35 Mon Sep 17 00:00:00 2001 From: Abubeker Yasin Date: Tue, 26 May 2026 17:28:50 +0300 Subject: [PATCH 35/38] feat(fayda): add fayda verification endpoints and login-with-fayda --- .../migration.sql | 12 + apps/edr-passenger-api/prisma/schema.prisma | 1 + .../src/config/fayda.config.ts | 22 +- .../modules/verifayda/verifayda.controller.ts | 29 +- .../src/modules/verifayda/verifayda.dto.ts | 36 ++ .../src/modules/verifayda/verifayda.module.ts | 5 +- .../verifayda/verifayda.service.spec.ts | 422 +++++++++++++----- .../modules/verifayda/verifayda.service.ts | 244 ++++++++-- 8 files changed, 576 insertions(+), 195 deletions(-) create mode 100644 apps/edr-passenger-api/prisma/migrations/20260526110803_add_fayda_login_authcode_and_platform/migration.sql diff --git a/apps/edr-passenger-api/prisma/migrations/20260526110803_add_fayda_login_authcode_and_platform/migration.sql b/apps/edr-passenger-api/prisma/migrations/20260526110803_add_fayda_login_authcode_and_platform/migration.sql new file mode 100644 index 000000000..661ddbe85 --- /dev/null +++ b/apps/edr-passenger-api/prisma/migrations/20260526110803_add_fayda_login_authcode_and_platform/migration.sql @@ -0,0 +1,12 @@ +/* + Warnings: + + - A unique constraint covering the columns `[authCode]` on the table `FaydaVerificationSession` will be added. If there are existing duplicate values, this will fail. + +*/ +-- AlterTable +ALTER TABLE "FaydaVerificationSession" ADD COLUMN "authCode" TEXT, +ADD COLUMN "platform" TEXT NOT NULL DEFAULT 'WEB'; + +-- CreateIndex +CREATE UNIQUE INDEX "FaydaVerificationSession_authCode_key" ON "FaydaVerificationSession"("authCode"); diff --git a/apps/edr-passenger-api/prisma/schema.prisma b/apps/edr-passenger-api/prisma/schema.prisma index c72e69ef4..24ff8a192 100644 --- a/apps/edr-passenger-api/prisma/schema.prisma +++ b/apps/edr-passenger-api/prisma/schema.prisma @@ -1261,6 +1261,7 @@ model FaydaVerificationSession { state String @unique codeVerifier String purpose String @default("PURCHASE") + platform String @default("WEB") // WEB | MOBILE — recorded for audit saveToAccount Boolean @default(false) status String @default("PENDING") errorCode String? diff --git a/apps/edr-passenger-api/src/config/fayda.config.ts b/apps/edr-passenger-api/src/config/fayda.config.ts index 6e317760b..e0bce45c6 100644 --- a/apps/edr-passenger-api/src/config/fayda.config.ts +++ b/apps/edr-passenger-api/src/config/fayda.config.ts @@ -15,6 +15,8 @@ export interface FaydaJwk { qi?: string; } +export type FaydaPlatform = 'WEB' | 'MOBILE'; + export interface FaydaConfig { enabled: boolean; clientId: string; @@ -23,8 +25,6 @@ export interface FaydaConfig { userInfoEndpoint: string; redirectUri: string; privateJwk: FaydaJwk; - successRedirectUrl: string; - failureRedirectUrl: string; scope: string; acrValues: string; claimsLocales: string; @@ -36,10 +36,7 @@ const REQUIRED_VARS = [ 'FAYDA_AUTHORIZATION_ENDPOINT', 'FAYDA_TOKEN_ENDPOINT', 'FAYDA_USERINFO_ENDPOINT', - 'FAYDA_REDIRECT_URI', 'FAYDA_PRIVATE_KEY_BASE64', - 'FAYDA_SUCCESS_REDIRECT_URL', - 'FAYDA_FAILURE_REDIRECT_URL', ] as const; function decodePrivateJwk(base64: string): FaydaJwk { @@ -73,7 +70,7 @@ export default registerAs('fayda', (): FaydaConfig => { const acrValues = process.env.FAYDA_ACR_VALUES ?? 'mosip:idp:acr:generated-code'; const claimsLocales = process.env.FAYDA_CLAIMS_LOCALES ?? 'en am'; const sessionTtl = Number.parseInt(process.env.FAYDA_SESSION_TTL_MINUTES ?? '10', 10); - + const redirectUri = process.env.FAYDA_REDIRECT_URI ?? ''; if (!enabled) { return { enabled: false, @@ -81,10 +78,8 @@ export default registerAs('fayda', (): FaydaConfig => { authorizationEndpoint: process.env.FAYDA_AUTHORIZATION_ENDPOINT ?? '', tokenEndpoint: process.env.FAYDA_TOKEN_ENDPOINT ?? '', userInfoEndpoint: process.env.FAYDA_USERINFO_ENDPOINT ?? '', - redirectUri: process.env.FAYDA_REDIRECT_URI ?? '', + redirectUri, privateJwk: { kty: 'RSA', n: '', e: '', d: '' }, - successRedirectUrl: process.env.FAYDA_SUCCESS_REDIRECT_URL ?? '', - failureRedirectUrl: process.env.FAYDA_FAILURE_REDIRECT_URL ?? '', scope, acrValues, claimsLocales, @@ -98,6 +93,11 @@ export default registerAs('fayda', (): FaydaConfig => { `Fayda integration is enabled (FAYDA_ENABLED=true) but the following env vars are missing: ${missing.join(', ')}`, ); } + if (!redirectUri) { + throw new Error( + 'Fayda integration is enabled but the redirect URI is missing: set FAYDA_REDIRECT_URI', + ); + } if (Number.isNaN(sessionTtl) || sessionTtl <= 0) { throw new Error('FAYDA_SESSION_TTL_MINUTES must be a positive integer'); } @@ -108,10 +108,8 @@ export default registerAs('fayda', (): FaydaConfig => { authorizationEndpoint: process.env.FAYDA_AUTHORIZATION_ENDPOINT!, tokenEndpoint: process.env.FAYDA_TOKEN_ENDPOINT!, userInfoEndpoint: process.env.FAYDA_USERINFO_ENDPOINT!, - redirectUri: process.env.FAYDA_REDIRECT_URI!, + redirectUri, privateJwk: decodePrivateJwk(process.env.FAYDA_PRIVATE_KEY_BASE64!), - successRedirectUrl: process.env.FAYDA_SUCCESS_REDIRECT_URL!, - failureRedirectUrl: process.env.FAYDA_FAILURE_REDIRECT_URL!, scope, acrValues, claimsLocales, diff --git a/apps/edr-passenger-api/src/modules/verifayda/verifayda.controller.ts b/apps/edr-passenger-api/src/modules/verifayda/verifayda.controller.ts index 496010b30..f1eb25e8e 100644 --- a/apps/edr-passenger-api/src/modules/verifayda/verifayda.controller.ts +++ b/apps/edr-passenger-api/src/modules/verifayda/verifayda.controller.ts @@ -7,7 +7,6 @@ import { Post, Query, Req, - Res, UseGuards, } from '@nestjs/common'; import { @@ -19,6 +18,7 @@ import { import { JwtGuard } from '../../common/jwt.guard'; import { OptionalJwtGuard } from './optional-jwt.guard'; import { + CompleteVerificationResultDto, StartVerificationDto, VerifaydaCallbackDto, VerificationStatusDto, @@ -33,17 +33,14 @@ interface AuthedUser { passengerId?: string; } -/** Minimal slices of the Express req/res we actually touch (avoids a hard - * dependency on `@types/express`, which isn't resolved in this package). */ +/** Minimal slices of the Express req we touch (avoids a hard dependency on + * `@types/express`, which isn't resolved in this package). */ interface RequestWithOptionalUser { user?: AuthedUser; } interface RequestWithUser { user: AuthedUser; } -interface RedirectableResponse { - redirect(url: string): void; -} @ApiTags('Fayda Verification') @Controller('fayda/verification') @@ -77,6 +74,7 @@ export class VerifaydaController { ): Promise<{ authorizationUrl: string }> { const authorizationUrl = await this.service.startVerification({ purpose: dto.purpose ?? 'PURCHASE', + platform: dto.platform ?? 'WEB', userId: req.user?.userId, bookingId: dto.bookingId, saveToAccount: dto.saveToAccount, @@ -84,19 +82,16 @@ export class VerifaydaController { return { authorizationUrl }; } - @Get('callback') + @Get('complete') @ApiOperation({ - summary: 'eSignet redirect callback (browser lands here)', - description: `Fayda/eSignet redirects the user's browser here with \`?code&state\` (success) or \`?error&error_description\` (failure). - -This endpoint is **not** authenticated — Fayda sends no bearer token. It exchanges the code for tokens, fetches the verified claims, records the result, and **302-redirects** the browser to the configured success or failure frontend URL (failures carry a \`?reason=\` the frontend can switch on).`, + summary: 'Complete a verification (Fayda redirect / client callback lands here)', + description: `This is the registered Fayda \`redirect_uri\`. Fayda redirects the browser here with \`?code&state\``, }) - async callback( - @Query() query: VerifaydaCallbackDto, - @Res() res: RedirectableResponse, - ): Promise { - const redirectUrl = await this.service.handleCallback(query); - res.redirect(redirectUrl); + @ApiOkResponse({ type: CompleteVerificationResultDto }) + async complete( + @Query() dto: VerifaydaCallbackDto, + ): Promise { + return this.service.completeVerification(dto); } @Get('status') diff --git a/apps/edr-passenger-api/src/modules/verifayda/verifayda.dto.ts b/apps/edr-passenger-api/src/modules/verifayda/verifayda.dto.ts index 388c8b438..005a3e517 100644 --- a/apps/edr-passenger-api/src/modules/verifayda/verifayda.dto.ts +++ b/apps/edr-passenger-api/src/modules/verifayda/verifayda.dto.ts @@ -26,6 +26,42 @@ export class StartVerificationDto { @IsOptional() @IsBoolean() saveToAccount?: boolean; + + @ApiPropertyOptional({ + enum: ['WEB', 'MOBILE'], + default: 'WEB', + description: + 'Client platform. Decides where /callback redirects on completion: a web https URL (WEB) or a custom-scheme deep link the Flutter app intercepts (MOBILE).', + }) + @IsOptional() + @IsIn(['WEB', 'MOBILE']) + platform?: 'WEB' | 'MOBILE'; +} + +export class CompleteVerificationResultDto { + @ApiProperty({ enum: ['LOGIN', 'PURCHASE'] }) + purpose: 'LOGIN' | 'PURCHASE'; + + @ApiProperty() verified: boolean; + + @ApiPropertyOptional({ description: 'JWT (LOGIN flow only).' }) + token?: string; + + @ApiPropertyOptional({ + description: 'Authenticated user summary (LOGIN flow only; same shape as /auth/login).', + }) + user?: { + id: string; + email: string; + role: string; + passengerId?: string; + agentId?: string; + }; + + @ApiPropertyOptional({ + description: 'Verified full name from Fayda (PURCHASE flow).', + }) + fullName?: string; } export class VerifaydaCallbackDto { diff --git a/apps/edr-passenger-api/src/modules/verifayda/verifayda.module.ts b/apps/edr-passenger-api/src/modules/verifayda/verifayda.module.ts index e54b94726..d850b1dbf 100644 --- a/apps/edr-passenger-api/src/modules/verifayda/verifayda.module.ts +++ b/apps/edr-passenger-api/src/modules/verifayda/verifayda.module.ts @@ -2,9 +2,12 @@ import { Module } from '@nestjs/common'; import { VerifaydaController } from './verifayda.controller'; import { VerifaydaService } from './verifayda.service'; import { PrismaModule } from '../../common/prisma.module'; +import { AuthModule } from '../auth/auth.module'; @Module({ - imports: [PrismaModule], + // AuthModule re-exports JwtModule, giving us JwtService (same secret/expiry + // config as /auth/login) to mint tokens for the LOGIN flow. + imports: [PrismaModule, AuthModule], controllers: [VerifaydaController], providers: [VerifaydaService], exports: [VerifaydaService], diff --git a/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.spec.ts b/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.spec.ts index 55c670946..e4b8cb790 100644 --- a/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.spec.ts +++ b/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.spec.ts @@ -1,15 +1,10 @@ import { ConfigService } from '@nestjs/config'; +import { JwtService } from '@nestjs/jwt'; import { exportJWK, generateKeyPair, type JWK } from 'jose'; import { PrismaService } from '../../common/prisma.service'; import { FaydaConfig } from '../../config/fayda.config'; import { VerifaydaService } from './verifayda.service'; -type AnyFn = (...args: any[]) => any; - -function mockFn(impl?: T): jest.Mock { - return impl ? jest.fn(impl) : jest.fn(); -} - function buildPrismaMock() { return { faydaVerificationSession: { @@ -24,12 +19,23 @@ function buildPrismaMock() { user: { findUnique: jest.fn(), findFirst: jest.fn(), + create: jest.fn(), update: jest.fn(), }, + passenger: { create: jest.fn() }, + loyaltyAccount: { create: jest.fn() }, + walletAccount: { create: jest.fn() }, + userPreferences: { create: jest.fn() }, verifaydaVerification: { create: jest.fn() }, }; } +function buildJwtMock(): jest.Mocked { + return { + sign: jest.fn(() => 'signed.jwt.token'), + } as unknown as jest.Mocked; +} + function buildConfig(overrides?: Partial): FaydaConfig { return { enabled: true, @@ -37,10 +43,8 @@ function buildConfig(overrides?: Partial): FaydaConfig { authorizationEndpoint: 'https://esignet.test/authorize', tokenEndpoint: 'https://esignet.test/token', userInfoEndpoint: 'https://esignet.test/userinfo', - redirectUri: 'https://api.edr.test/api/v1/fayda/verification/callback', + redirectUri: 'http://localhost:4000/fayda/verification/complete', privateJwk: { kty: 'RSA', n: '', e: '', d: '' }, - successRedirectUrl: 'https://passenger.edr.test/verify/success', - failureRedirectUrl: 'https://passenger.edr.test/verify/failure', scope: 'openid profile email', acrValues: 'mosip:idp:acr:generated-code', claimsLocales: 'en am', @@ -59,8 +63,9 @@ function buildConfigService(faydaConfig: FaydaConfig): jest.Mocked; } -describe('VerifaydaService (OIDC)', () => { +describe('VerifaydaService (OIDC, client-callback)', () => { let prisma: ReturnType; + let jwt: jest.Mocked; let service: VerifaydaService; let realPrivateJwk: JWK; @@ -72,10 +77,12 @@ describe('VerifaydaService (OIDC)', () => { beforeEach(() => { prisma = buildPrismaMock(); + jwt = buildJwtMock(); const cfg = buildConfig({ privateJwk: realPrivateJwk as FaydaConfig['privateJwk'] }); service = new VerifaydaService( buildConfigService(cfg), prisma as unknown as PrismaService, + jwt, ); (global as any).fetch = jest.fn(); }); @@ -94,29 +101,42 @@ describe('VerifaydaService (OIDC)', () => { saveToAccount: true, }); - expect(prisma.faydaVerificationSession.create).toHaveBeenCalledTimes(1); const created = prisma.faydaVerificationSession.create.mock.calls[0][0].data; expect(created.purpose).toBe('PURCHASE'); - expect(created.saveToAccount).toBe(true); - expect(created.userId).toBe('user-1'); + expect(created.platform).toBe('WEB'); expect(typeof created.state).toBe('string'); expect(typeof created.codeVerifier).toBe('string'); const parsed = new URL(url); - expect(parsed.origin + parsed.pathname).toBe( - 'https://esignet.test/authorize', - ); + expect(parsed.origin + parsed.pathname).toBe('https://esignet.test/authorize'); expect(parsed.searchParams.get('client_id')).toBe('edr-test-client'); - expect(parsed.searchParams.get('response_type')).toBe('code'); expect(parsed.searchParams.get('code_challenge_method')).toBe('S256'); + expect(parsed.searchParams.get('redirect_uri')).toBe( + 'http://localhost:4000/fayda/verification/complete', + ); expect(parsed.searchParams.get('state')).toBe(created.state); }); + it('uses the same single redirect_uri regardless of platform (platform is only recorded)', async () => { + prisma.faydaVerificationSession.create.mockResolvedValue({}); + + const url = await service.startVerification({ + purpose: 'LOGIN', + platform: 'MOBILE', + }); + + const created = prisma.faydaVerificationSession.create.mock.calls[0][0].data; + expect(created.platform).toBe('MOBILE'); + expect(new URL(url).searchParams.get('redirect_uri')).toBe( + 'http://localhost:4000/fayda/verification/complete', + ); + }); + it('throws ServiceUnavailable when fayda integration is disabled', async () => { - const disabledCfg = buildConfig({ enabled: false }); const disabledService = new VerifaydaService( - buildConfigService(disabledCfg), + buildConfigService(buildConfig({ enabled: false })), prisma as unknown as PrismaService, + jwt, ); await expect( disabledService.startVerification({ purpose: 'PURCHASE' }), @@ -124,13 +144,14 @@ describe('VerifaydaService (OIDC)', () => { }); }); - describe('handleCallback', () => { + describe('completeVerification — validation', () => { function pendingSession(overrides: Partial = {}) { return { id: 'session-1', state: 'state-abc', codeVerifier: 'verifier-xyz', purpose: 'PURCHASE', + platform: 'WEB', saveToAccount: false, status: 'PENDING', errorCode: null, @@ -142,6 +163,69 @@ describe('VerifaydaService (OIDC)', () => { }; } + it('throws and marks failed when callback carries an error', async () => { + prisma.faydaVerificationSession.updateMany.mockResolvedValue({ count: 1 }); + await expect( + service.completeVerification({ + error: 'access_denied', + error_description: 'user cancelled', + state: 'state-abc', + }), + ).rejects.toMatchObject({ status: 400 }); + expect(prisma.faydaVerificationSession.updateMany).toHaveBeenCalled(); + }); + + it('throws FAYDA_MISSING_PARAMETERS when code/state absent', async () => { + await expect(service.completeVerification({})).rejects.toMatchObject({ + status: 400, + }); + }); + + it('throws FAYDA_INVALID_STATE for unknown state', async () => { + prisma.faydaVerificationSession.findUnique.mockResolvedValue(null); + await expect( + service.completeVerification({ code: 'c', state: 'bogus' }), + ).rejects.toMatchObject({ status: 400 }); + }); + + it('throws FAYDA_INVALID_STATE for a non-pending session', async () => { + prisma.faydaVerificationSession.findUnique.mockResolvedValue( + pendingSession({ status: 'COMPLETED' }), + ); + await expect( + service.completeVerification({ code: 'c', state: 'state-abc' }), + ).rejects.toMatchObject({ status: 400 }); + }); + + it('throws FAYDA_SESSION_EXPIRED and marks failed for an expired session', async () => { + prisma.faydaVerificationSession.findUnique.mockResolvedValue( + pendingSession({ expiresAt: new Date(Date.now() - 1000) }), + ); + prisma.faydaVerificationSession.updateMany.mockResolvedValue({ count: 1 }); + await expect( + service.completeVerification({ code: 'c', state: 'state-abc' }), + ).rejects.toMatchObject({ status: 400 }); + expect(prisma.faydaVerificationSession.updateMany).toHaveBeenCalled(); + }); + }); + + describe('completeVerification — PURCHASE', () => { + function pendingSession(overrides: Partial = {}) { + return { + id: 'session-1', + state: 'state-abc', + codeVerifier: 'verifier-xyz', + purpose: 'PURCHASE', + platform: 'WEB', + saveToAccount: false, + status: 'PENDING', + userId: null, + bookingId: null, + expiresAt: new Date(Date.now() + 60_000), + ...overrides, + }; + } + function mockFetchSequence(...responses: Array>) { const queue = responses.map((r) => ({ ok: true, @@ -154,52 +238,7 @@ describe('VerifaydaService (OIDC)', () => { (global as any).fetch = jest.fn(() => Promise.resolve(queue.shift())); } - it('redirects to failure URL when callback carries an error', async () => { - prisma.faydaVerificationSession.findUnique.mockResolvedValue(null); - - const url = await service.handleCallback({ - error: 'access_denied', - error_description: 'user cancelled', - state: 'state-abc', - }); - - expect(url).toContain('https://passenger.edr.test/verify/failure'); - expect(url).toContain('reason=access_denied'); - expect(prisma.faydaVerificationSession.updateMany).toHaveBeenCalled(); - }); - - it('redirects to failure URL when state is unknown', async () => { - prisma.faydaVerificationSession.findUnique.mockResolvedValue(null); - const url = await service.handleCallback({ - code: 'authcode', - state: 'bogus', - }); - expect(url).toContain('reason=invalid_state'); - }); - - it('redirects to failure URL when session is not pending', async () => { - prisma.faydaVerificationSession.findUnique.mockResolvedValue( - pendingSession({ status: 'COMPLETED' }), - ); - const url = await service.handleCallback({ - code: 'authcode', - state: 'state-abc', - }); - expect(url).toContain('reason=invalid_state'); - }); - - it('redirects to failure URL when session is expired', async () => { - prisma.faydaVerificationSession.findUnique.mockResolvedValue( - pendingSession({ expiresAt: new Date(Date.now() - 1000) }), - ); - const url = await service.handleCallback({ - code: 'authcode', - state: 'state-abc', - }); - expect(url).toContain('reason=session_expired'); - }); - - it('happy path: exchanges code, fetches userinfo, updates booking seat', async () => { + it('stamps the booking seats and returns { verified, fullName }', async () => { prisma.faydaVerificationSession.findUnique.mockResolvedValue( pendingSession({ bookingId: 'booking-1' }), ); @@ -207,45 +246,32 @@ describe('VerifaydaService (OIDC)', () => { prisma.bookingSeat.updateMany.mockResolvedValue({ count: 1 }); mockFetchSequence( - { - json: async () => ({ access_token: 'tok', token_type: 'Bearer' }), - }, + { json: async () => ({ access_token: 'tok', token_type: 'Bearer' }) }, { headers: new Headers({ 'content-type': 'application/json' }), text: async () => - JSON.stringify({ - sub: 'fayda-sub-1', - name: 'Test User', - phone_number: '+251911000000', - email: 'test@example.com', - }), + JSON.stringify({ sub: 'fayda-sub-1', name: 'Test User' }), }, ); - const url = await service.handleCallback({ + const result = await service.completeVerification({ code: 'authcode', state: 'state-abc', }); - expect(url).toBe('https://passenger.edr.test/verify/success'); + expect(result).toMatchObject({ + purpose: 'PURCHASE', + verified: true, + fullName: 'Test User', + }); + expect(result.token).toBeUndefined(); expect(prisma.bookingSeat.updateMany).toHaveBeenCalledWith({ where: { bookingId: 'booking-1' }, - data: expect.objectContaining({ - faydaSub: 'fayda-sub-1', - faydaVerifiedName: 'Test User', - }), + data: expect.objectContaining({ faydaSub: 'fayda-sub-1' }), }); - expect(prisma.faydaVerificationSession.update).toHaveBeenCalledWith( - expect.objectContaining({ - data: expect.objectContaining({ - status: 'COMPLETED', - codeVerifier: '', - }), - }), - ); }); - it('saves to User when saveToAccount=true and no conflict', async () => { + it('saves to the User account when saveToAccount=true and no conflict', async () => { prisma.faydaVerificationSession.findUnique.mockResolvedValue( pendingSession({ userId: 'user-1', saveToAccount: true }), ); @@ -262,26 +288,24 @@ describe('VerifaydaService (OIDC)', () => { }, ); - const url = await service.handleCallback({ + const result = await service.completeVerification({ code: 'authcode', state: 'state-abc', }); - expect(url).toBe('https://passenger.edr.test/verify/success'); + expect(result.verified).toBe(true); expect(prisma.user.update).toHaveBeenCalledWith({ where: { id: 'user-1' }, - data: expect.objectContaining({ - faydaVerified: true, - faydaSub: 'fayda-sub-2', - }), + data: expect.objectContaining({ faydaVerified: true, faydaSub: 'fayda-sub-2' }), }); }); - it('rejects with identity_conflict when faydaSub is on another user', async () => { + it('throws identity_conflict (409) when faydaSub belongs to another user', async () => { prisma.faydaVerificationSession.findUnique.mockResolvedValue( pendingSession({ userId: 'user-1', saveToAccount: true }), ); prisma.user.findFirst.mockResolvedValue({ id: 'other-user' }); + prisma.faydaVerificationSession.updateMany.mockResolvedValue({ count: 1 }); mockFetchSequence( { json: async () => ({ access_token: 'tok', token_type: 'Bearer' }) }, @@ -292,33 +316,29 @@ describe('VerifaydaService (OIDC)', () => { }, ); - const url = await service.handleCallback({ - code: 'authcode', - state: 'state-abc', - }); - expect(url).toContain('reason=identity_conflict'); + await expect( + service.completeVerification({ code: 'authcode', state: 'state-abc' }), + ).rejects.toMatchObject({ status: 409 }); expect(prisma.user.update).not.toHaveBeenCalled(); }); - it('reports token_exchange_failed when token endpoint returns 4xx', async () => { + it('throws 502 when the token endpoint returns 4xx', async () => { prisma.faydaVerificationSession.findUnique.mockResolvedValue(pendingSession()); - + prisma.faydaVerificationSession.updateMany.mockResolvedValue({ count: 1 }); mockFetchSequence({ ok: false, status: 400, text: async () => '{"error":"invalid_assertion"}', }); - const url = await service.handleCallback({ - code: 'authcode', - state: 'state-abc', - }); - expect(url).toContain('reason=token_exchange_failed'); + await expect( + service.completeVerification({ code: 'authcode', state: 'state-abc' }), + ).rejects.toMatchObject({ status: 502 }); }); - it('reports userinfo_failed when userinfo response is unsupported', async () => { + it('throws 502 when userinfo is an unsupported format', async () => { prisma.faydaVerificationSession.findUnique.mockResolvedValue(pendingSession()); - + prisma.faydaVerificationSession.updateMany.mockResolvedValue({ count: 1 }); mockFetchSequence( { json: async () => ({ access_token: 'tok', token_type: 'Bearer' }) }, { @@ -327,11 +347,9 @@ describe('VerifaydaService (OIDC)', () => { }, ); - const url = await service.handleCallback({ - code: 'authcode', - state: 'state-abc', - }); - expect(url).toContain('reason=userinfo_failed'); + await expect( + service.completeVerification({ code: 'authcode', state: 'state-abc' }), + ).rejects.toMatchObject({ status: 502 }); }); it('falls back to localized name (name#en) when name is missing', async () => { @@ -354,10 +372,176 @@ describe('VerifaydaService (OIDC)', () => { }, ); - await service.handleCallback({ code: 'c', state: 'state-abc' }); + const result = await service.completeVerification({ + code: 'c', + state: 'state-abc', + }); + expect(result.fullName).toBe('English Name'); + expect(prisma.bookingSeat.updateMany.mock.calls[0][0].data.faydaVerifiedName).toBe( + 'English Name', + ); + }); + }); - const seatCall = prisma.bookingSeat.updateMany.mock.calls[0][0]; - expect(seatCall.data.faydaVerifiedName).toBe('English Name'); + describe('completeVerification — LOGIN', () => { + function loginSession(overrides: Partial = {}) { + return { + id: 'login-session', + state: 'state-login', + codeVerifier: 'verifier-xyz', + purpose: 'LOGIN', + platform: 'WEB', + saveToAccount: false, + status: 'PENDING', + userId: null, + bookingId: null, + expiresAt: new Date(Date.now() + 60_000), + ...overrides, + }; + } + + function mockLoginFetch(userInfo: Record) { + const queue = [ + { + ok: true, + status: 200, + json: async () => ({ access_token: 'tok', token_type: 'Bearer' }), + text: async () => '', + headers: new Headers({ 'content-type': 'application/json' }), + }, + { + ok: true, + status: 200, + json: async () => ({}), + text: async () => JSON.stringify(userInfo), + headers: new Headers({ 'content-type': 'application/json' }), + }, + ]; + (global as any).fetch = jest.fn(() => Promise.resolve(queue.shift())); + } + + /** user.findUnique answers the faydaSub lookup and the issueLoginToken id lookup. */ + function mockUserFindUnique(bySub: any, fullUser: any) { + prisma.user.findUnique.mockImplementation(async (args: any) => { + if (args?.where?.faydaSub !== undefined) return bySub; + if (args?.where?.id !== undefined) return fullUser; + return null; + }); + } + + beforeEach(() => { + prisma.faydaVerificationSession.findUnique.mockResolvedValue(loginSession()); + }); + + it('creates a new user when no match and returns { token, user }', async () => { + const fullUser = { + id: 'new-user', + email: 'new@example.com', + role: 'PASSENGER', + passenger: { id: 'p-new' }, + agent: null, + }; + mockUserFindUnique(null, fullUser); + prisma.user.findFirst.mockResolvedValue(null); + prisma.user.create.mockResolvedValue({ id: 'new-user' }); + prisma.passenger.create.mockResolvedValue({ id: 'p-new' }); + prisma.loyaltyAccount.create.mockResolvedValue({}); + prisma.walletAccount.create.mockResolvedValue({}); + prisma.userPreferences.create.mockResolvedValue({}); + prisma.faydaVerificationSession.update.mockResolvedValue({}); + + mockLoginFetch({ sub: 'login-sub-1', name: 'New Person', email: 'new@example.com' }); + + const result = await service.completeVerification({ + code: 'c', + state: 'state-login', + }); + + expect(result).toMatchObject({ + purpose: 'LOGIN', + verified: true, + token: 'signed.jwt.token', + user: { id: 'new-user', passengerId: 'p-new' }, + }); + expect(prisma.user.create).toHaveBeenCalledWith( + expect.objectContaining({ + data: expect.objectContaining({ + faydaSub: 'login-sub-1', + faydaVerified: true, + email: 'new@example.com', + }), + }), + ); + expect(prisma.passenger.create).toHaveBeenCalled(); + expect(jwt.sign).toHaveBeenCalledWith( + expect.objectContaining({ sub: 'new-user', passengerId: 'p-new' }), + ); + }); + + it('logs in an existing user already linked by faydaSub', async () => { + const fullUser = { + id: 'known-user', + email: 'k@example.com', + role: 'PASSENGER', + passenger: { id: 'p-k' }, + agent: null, + }; + mockUserFindUnique({ id: 'known-user' }, fullUser); + prisma.faydaVerificationSession.update.mockResolvedValue({}); + + mockLoginFetch({ sub: 'login-sub-2', name: 'Known' }); + + const result = await service.completeVerification({ + code: 'c', + state: 'state-login', + }); + + expect(result.user?.id).toBe('known-user'); + expect(prisma.user.create).not.toHaveBeenCalled(); + }); + + it('links Fayda to an existing account matched by email', async () => { + const fullUser = { + id: 'acc-1', + email: 'match@example.com', + role: 'PASSENGER', + passenger: { id: 'p-1' }, + agent: null, + }; + mockUserFindUnique(null, fullUser); + prisma.user.findFirst.mockResolvedValue({ id: 'acc-1', faydaSub: null }); + prisma.user.update.mockResolvedValue({}); + prisma.faydaVerificationSession.update.mockResolvedValue({}); + + mockLoginFetch({ sub: 'login-sub-3', email: 'match@example.com' }); + + const result = await service.completeVerification({ + code: 'c', + state: 'state-login', + }); + + expect(result.user?.id).toBe('acc-1'); + expect(prisma.user.update).toHaveBeenCalledWith( + expect.objectContaining({ + where: { id: 'acc-1' }, + data: expect.objectContaining({ faydaSub: 'login-sub-3' }), + }), + ); + expect(prisma.user.create).not.toHaveBeenCalled(); + }); + + it('throws identity_conflict (409) when matched account has a different faydaSub', async () => { + mockUserFindUnique(null, null); + prisma.user.findFirst.mockResolvedValue({ id: 'acc-2', faydaSub: 'someone-else' }); + prisma.faydaVerificationSession.updateMany.mockResolvedValue({ count: 1 }); + + mockLoginFetch({ sub: 'login-sub-4', email: 'match@example.com' }); + + await expect( + service.completeVerification({ code: 'c', state: 'state-login' }), + ).rejects.toMatchObject({ status: 409 }); + expect(prisma.user.update).not.toHaveBeenCalled(); + expect(prisma.user.create).not.toHaveBeenCalled(); }); }); diff --git a/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.ts b/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.ts index 55227fa6d..7a929c3c5 100644 --- a/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.ts +++ b/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.ts @@ -3,11 +3,15 @@ import { Injectable, Logger, ServiceUnavailableException, + UnauthorizedException, } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; +import { JwtService } from '@nestjs/jwt'; import axios, { AxiosInstance } from 'axios'; +import * as bcrypt from 'bcrypt'; +import { randomBytes } from 'crypto'; import { PrismaService } from '../../common/prisma.service'; -import { FaydaConfig } from '../../config/fayda.config'; +import { FaydaConfig, FaydaPlatform } from '../../config/fayda.config'; import { generateCodeChallenge, generateCodeVerifier, @@ -43,11 +47,32 @@ export interface VerifaydaVerificationResult { export interface StartVerificationInput { purpose: VerifaydaPurpose; + platform?: FaydaPlatform; userId?: string; bookingId?: string; saveToAccount?: boolean; } +export interface FaydaUserSummary { + id: string; + email: string; + role: string; + passengerId?: string; + agentId?: string; +} + +/** + * Result of completing a verification. `verified` is always true on success. + * LOGIN additionally returns a JWT + user; PURCHASE returns the verified name. + */ +export interface CompleteVerificationResult { + purpose: VerifaydaPurpose; + verified: boolean; + token?: string; + user?: FaydaUserSummary; + fullName?: string; +} + @Injectable() export class VerifaydaService { private readonly logger = new Logger(VerifaydaService.name); @@ -63,6 +88,7 @@ export class VerifaydaService { constructor( private readonly config: ConfigService, private readonly prisma: PrismaService, + private readonly jwt: JwtService, ) { const fayda = this.config.get('fayda'); if (!fayda) { @@ -107,6 +133,7 @@ export class VerifaydaService { state, codeVerifier, purpose: input.purpose, + platform: input.platform ?? 'WEB', saveToAccount: input.saveToAccount ?? false, userId: input.userId ?? null, bookingId: input.bookingId ?? null, @@ -115,13 +142,16 @@ export class VerifaydaService { }); this.logger.log( - `Fayda verification started: purpose=${input.purpose} userId=${input.userId ?? 'none'} bookingId=${input.bookingId ?? 'none'}`, + `Fayda verification started: purpose=${input.purpose} platform=${input.platform ?? 'WEB'} userId=${input.userId ?? 'none'} bookingId=${input.bookingId ?? 'none'}`, ); return this.buildAuthorizationUrl({ state, codeChallenge }); } - async handleCallback(query: VerifaydaCallbackDto): Promise { + + async completeVerification( + query: VerifaydaCallbackDto, + ): Promise { if (query.error) { this.logger.warn(`Fayda callback returned error: ${query.error}`); if (query.state) { @@ -131,32 +161,36 @@ export class VerifaydaService { query.error_description, ); } - return this.buildFailureUrl(query.error); + throw new BadRequestException({ + code: 'FAYDA_AUTH_ERROR', + message: query.error, + description: query.error_description, + }); } if (!query.code || !query.state) { - this.logger.warn('Fayda callback missing code or state'); - return this.buildFailureUrl('missing_parameters'); + throw new BadRequestException({ + code: 'FAYDA_MISSING_PARAMETERS', + message: 'code and state are required', + }); } const session = await this.prisma.faydaVerificationSession.findUnique({ where: { state: query.state }, }); - - if (!session) { - this.logger.warn('Fayda callback with unknown state'); - return this.buildFailureUrl('invalid_state'); - } - if (session.status !== 'PENDING') { - this.logger.warn( - `Fayda callback for non-pending session (status=${session.status})`, - ); - return this.buildFailureUrl('invalid_state'); + if (!session || session.status !== 'PENDING') { + this.logger.warn('Fayda complete with unknown or non-pending state'); + throw new BadRequestException({ + code: 'FAYDA_INVALID_STATE', + message: 'Verification session is invalid or already used', + }); } if (session.expiresAt.getTime() < Date.now()) { await this.markSessionFailed(query.state, 'session_expired'); - this.logger.warn('Fayda callback for expired session'); - return this.buildFailureUrl('session_expired'); + throw new BadRequestException({ + code: 'FAYDA_SESSION_EXPIRED', + message: 'Verification session has expired; start again', + }); } try { @@ -171,25 +205,29 @@ export class VerifaydaService { throw new FaydaUserInfoException('Fayda userinfo missing required sub'); } + let result: CompleteVerificationResult; if (session.purpose === 'PURCHASE') { await this.handlePurchaseSuccess(session, normalized); + result = { + purpose: 'PURCHASE', + verified: true, + fullName: normalized.fullName, + }; } else { - await this.handleLoginSuccess(session, normalized); + const { userId } = await this.handleLoginSuccess(normalized); + const login = await this.issueLoginToken(userId); + result = { purpose: 'LOGIN', verified: true, ...login }; } await this.prisma.faydaVerificationSession.update({ where: { id: session.id }, - data: { - status: 'COMPLETED', - completedAt: new Date(), - codeVerifier: '', - }, + data: { status: 'COMPLETED', completedAt: new Date(), codeVerifier: '' }, }); this.logger.log( - `Fayda verification completed: purpose=${session.purpose}`, + `Fayda verification completed: purpose=${session.purpose} platform=${session.platform}`, ); - return this.buildSuccessUrl(); + return result; } catch (err) { const reason = this.classifyFailureReason(err); this.logger.error( @@ -200,10 +238,45 @@ export class VerifaydaService { reason, (err as Error).message, ); - return this.buildFailureUrl(reason); + throw err; } } + /** Loads a user (+ relations) and mints the same JWT shape as `/auth/login`. */ + private async issueLoginToken( + userId: string, + ): Promise<{ token: string; user: FaydaUserSummary }> { + const user = await this.prisma.user.findUnique({ + where: { id: userId }, + include: { passenger: true, agent: true }, + }); + if (!user) { + // Should not happen — we just resolved/created this user. + throw new UnauthorizedException({ + code: 'FAYDA_LOGIN_FAILED', + message: 'Could not load the verified user', + }); + } + + const summary: FaydaUserSummary = { + id: user.id, + email: user.email, + role: user.role, + passengerId: user.passenger?.id, + agentId: user.agent?.id, + }; + const token = this.jwt.sign({ + sub: summary.id, + email: summary.email, + role: summary.role, + passengerId: summary.passengerId, + agentId: summary.agentId, + }); + + this.logger.log(`Fayda login issued token for user ${user.id}`); + return { token, user: summary }; + } + async getVerificationStatus(userId: string): Promise { const user = await this.prisma.user.findUnique({ where: { id: userId }, @@ -383,17 +456,106 @@ export class VerifaydaService { } } + /** + * Resolves the User for a LOGIN flow and returns its id (the caller mints the + * JWT via {@link issueLoginToken}). Resolution order: + * 1. Existing user already linked to this Fayda `sub`. + * 2. Existing account whose email/phone matches — linked to this `sub`. + * 3. Otherwise a fresh Fayda-backed account is created. + */ private async handleLoginSuccess( - _session: { id: string }, - _normalized: NormalizedFaydaUserInfo, - ): Promise { - // LOGIN flow (User creation / login token issuance) - // The schema currently requires email/phone/passwordHash on User as NOT NULL, - // and the auth controllers haven't been wired to consume Fayda identities yet. - throw new BadRequestException({ - code: 'FAYDA_LOGIN_NOT_IMPLEMENTED', - message: 'Login-with-Fayda is not yet implemented', + normalized: NormalizedFaydaUserInfo, + ): Promise<{ userId: string }> { + let userId: string; + + const bySub = await this.prisma.user.findUnique({ + where: { faydaSub: normalized.sub }, + select: { id: true }, }); + + if (bySub) { + userId = bySub.id; + } else { + const matchers: Array<{ email?: string; phone?: string }> = []; + if (normalized.email) matchers.push({ email: normalized.email }); + if (normalized.phoneNumber) matchers.push({ phone: normalized.phoneNumber }); + + const existing = matchers.length + ? await this.prisma.user.findFirst({ + where: { OR: matchers }, + select: { id: true, faydaSub: true }, + }) + : null; + + if (existing) { + if (existing.faydaSub && existing.faydaSub !== normalized.sub) { + // The matched account is already tied to a different Fayda identity. + throw new FaydaIdentityConflictException(); + } + await this.prisma.user.update({ + where: { id: existing.id }, + data: { + faydaSub: normalized.sub, + faydaVerified: true, + faydaVerifiedAt: new Date(), + }, + }); + userId = existing.id; + this.logger.log(`Fayda login linked existing user ${existing.id}`); + } else { + userId = await this.createFaydaUser(normalized); + this.logger.log(`Fayda login created new user ${userId}`); + } + } + + return { userId }; + } + + /** + * Creates a Fayda-backed User plus the same satellite rows registration makes + * (Passenger, LoyaltyAccount, WalletAccount, UserPreferences). + * + * The user has no password — `passwordHash` is set to a bcrypt of random bytes + * so password login is impossible; they authenticate only via Fayda. When + * Fayda doesn't supply an email/phone, a deterministic placeholder derived from + * the (unique) `sub` keeps the NOT NULL + unique columns satisfied. + */ + private async createFaydaUser( + normalized: NormalizedFaydaUserInfo, + ): Promise { + const passwordHash = await bcrypt.hash( + randomBytes(32).toString('hex'), + 10, + ); + const email = normalized.email ?? `fayda_${normalized.sub}@users.fayda.local`; + const phone = normalized.phoneNumber ?? `fayda:${normalized.sub}`; + const fullName = normalized.fullName ?? 'Fayda User'; + + const user = await this.prisma.user.create({ + data: { + fullName, + email, + phone, + passwordHash, + faydaVerified: true, + faydaVerifiedAt: new Date(), + faydaSub: normalized.sub, + }, + select: { id: true }, + }); + const passenger = await this.prisma.passenger.create({ + data: { userId: user.id }, + select: { id: true }, + }); + await this.prisma.loyaltyAccount.create({ + data: { passengerId: passenger.id }, + }); + await this.prisma.walletAccount.create({ + data: { passengerId: passenger.id }, + }); + await this.prisma.userPreferences.create({ data: { userId: user.id } }); + + return user.id; } private async markSessionFailed( @@ -413,16 +575,6 @@ export class VerifaydaService { }); } - private buildSuccessUrl(): string { - return this.faydaConfig.successRedirectUrl; - } - - private buildFailureUrl(reason: string): string { - const url = new URL(this.faydaConfig.failureRedirectUrl); - url.searchParams.set('reason', reason); - return url.toString(); - } - private classifyFailureReason(err: unknown): string { if (err instanceof FaydaIdentityConflictException) return 'identity_conflict'; if (err instanceof FaydaTokenExchangeException) return 'token_exchange_failed'; From 78cf8e7cbb47142f0e68999db35ec5ed0e31c8da Mon Sep 17 00:00:00 2001 From: Abubeker Yasin Date: Wed, 27 May 2026 11:31:44 +0300 Subject: [PATCH 36/38] feat: ( fayda ) add the fayda variables --- apps/edr-passenger-api/.env.example | 18 ++++++++++++++---- .../migration.sql | 12 ------------ .../migration.sql | 3 +++ apps/edr-passenger-api/prisma/schema.prisma | 1 + 4 files changed, 18 insertions(+), 16 deletions(-) delete mode 100644 apps/edr-passenger-api/prisma/migrations/20260526110803_add_fayda_login_authcode_and_platform/migration.sql create mode 100644 apps/edr-passenger-api/prisma/migrations/20260527080312_add_platform_and_authcode/migration.sql diff --git a/apps/edr-passenger-api/.env.example b/apps/edr-passenger-api/.env.example index 75d2df681..295d6ab40 100644 --- a/apps/edr-passenger-api/.env.example +++ b/apps/edr-passenger-api/.env.example @@ -88,9 +88,19 @@ IAM_ENABLED=false IAM_API_URL=https://iam.tria-plc.com/api IAM_API_KEY= -# Verifayda 2.0 Configuration (Ethiopian National ID Verification) -VERIFAYDA_ENABLED=false -VERIFAYDA_API_URL=https://api.verifayda.gov.et/v2 -VERIFAYDA_API_KEY= +# --- VeriFayda 2.0 (eSignet) OIDC integration --- +FAYDA_ENABLED=true +FAYDA_CLIENT_ID= +FAYDA_AUTHORIZATION_ENDPOINT= +FAYDA_TOKEN_ENDPOINT= +FAYDA_USERINFO_ENDPOINT= +# Base64 of the RSA private JWK (JSON). Secret — never commit a real value. +FAYDA_PRIVATE_KEY_BASE64= +FAYDA_REDIRECT_URI= +# Optional (defaults shown) +FAYDA_SCOPE=openid profile email +FAYDA_ACR_VALUES=mosip:idp:acr:generated-code +FAYDA_CLAIMS_LOCALES=en am +FAYDA_SESSION_TTL_MINUTES=10 GITHUB_PACKAGE_TOKEN= \ No newline at end of file diff --git a/apps/edr-passenger-api/prisma/migrations/20260526110803_add_fayda_login_authcode_and_platform/migration.sql b/apps/edr-passenger-api/prisma/migrations/20260526110803_add_fayda_login_authcode_and_platform/migration.sql deleted file mode 100644 index 661ddbe85..000000000 --- a/apps/edr-passenger-api/prisma/migrations/20260526110803_add_fayda_login_authcode_and_platform/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ -/* - Warnings: - - - A unique constraint covering the columns `[authCode]` on the table `FaydaVerificationSession` will be added. If there are existing duplicate values, this will fail. - -*/ --- AlterTable -ALTER TABLE "FaydaVerificationSession" ADD COLUMN "authCode" TEXT, -ADD COLUMN "platform" TEXT NOT NULL DEFAULT 'WEB'; - --- CreateIndex -CREATE UNIQUE INDEX "FaydaVerificationSession_authCode_key" ON "FaydaVerificationSession"("authCode"); diff --git a/apps/edr-passenger-api/prisma/migrations/20260527080312_add_platform_and_authcode/migration.sql b/apps/edr-passenger-api/prisma/migrations/20260527080312_add_platform_and_authcode/migration.sql new file mode 100644 index 000000000..64c577ff5 --- /dev/null +++ b/apps/edr-passenger-api/prisma/migrations/20260527080312_add_platform_and_authcode/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "FaydaVerificationSession" ADD COLUMN "authCode" TEXT, +ADD COLUMN "platform" TEXT NOT NULL DEFAULT 'WEB'; diff --git a/apps/edr-passenger-api/prisma/schema.prisma b/apps/edr-passenger-api/prisma/schema.prisma index 24ff8a192..e0a9f80e5 100644 --- a/apps/edr-passenger-api/prisma/schema.prisma +++ b/apps/edr-passenger-api/prisma/schema.prisma @@ -1266,6 +1266,7 @@ model FaydaVerificationSession { status String @default("PENDING") errorCode String? errorDescription String? + authCode String? createdAt DateTime @default(now()) expiresAt DateTime completedAt DateTime? From 2ceb993c60ac1a2c0a772d6c38bb9608c2802657 Mon Sep 17 00:00:00 2001 From: Roba Boru Date: Wed, 27 May 2026 15:11:23 +0300 Subject: [PATCH 37/38] Segment based seat assignement added --- .../modules/schedules/schedules.service.ts | 58 ++- .../src/modules/search/search.module.ts | 3 +- .../src/modules/search/search.service.ts | 69 +--- .../src/modules/seats/seats.controller.ts | 28 ++ .../src/modules/seats/seats.dto.ts | 38 +- .../src/modules/seats/seats.module.ts | 8 +- .../src/modules/seats/seats.service.ts | 334 +++++++++++++++++- .../segments/enhanced-seats.service.ts | 70 ++-- .../modules/segments/segments.controller.ts | 127 ++----- .../src/modules/segments/segments.service.ts | 185 ++++++---- 10 files changed, 630 insertions(+), 290 deletions(-) diff --git a/apps/edr-passenger-api/src/modules/schedules/schedules.service.ts b/apps/edr-passenger-api/src/modules/schedules/schedules.service.ts index eb10d6e0b..36e8a33ed 100644 --- a/apps/edr-passenger-api/src/modules/schedules/schedules.service.ts +++ b/apps/edr-passenger-api/src/modules/schedules/schedules.service.ts @@ -102,7 +102,63 @@ export class SchedulesService { }, }); if (!schedule) throw new NotFoundException('Schedule not found'); - return schedule; + + // Compute effective seat statuses from SeatHold + JourneySegment + // (seat.status DB column is no longer written during booking) + const allSeatIds = schedule.coachAssignments.flatMap(a => a.coach.seats.map(s => s.id)); + const effectiveStatuses = await this.resolveEffectiveStatuses(id, allSeatIds); + + return { + ...schedule, + coachAssignments: schedule.coachAssignments.map(a => ({ + ...a, + coach: { + ...a.coach, + seats: a.coach.seats.map(s => ({ + ...s, + status: effectiveStatuses.get(s.id) ?? s.status, + })), + }, + })), + }; + } + + /** + * Computes effective seat status for a schedule by checking active SeatHolds + * and confirmed JourneySegments. The DB seat.status column is not written + * during segment-based booking, so this overlay is required. + * Priority: BLOCKED (physical) > BOOKED (confirmed) > HELD (active hold) > AVAILABLE + */ + private async resolveEffectiveStatuses( + scheduleId: string, + seatIds: string[], + ): Promise> { + const statusMap = new Map(); + if (seatIds.length === 0) return statusMap; + + const [activeHolds, bookedSegments] = await Promise.all([ + this.prisma.seatHold.findMany({ + where: { scheduleId, expiresAt: { gt: new Date() }, seatIds: { hasSome: seatIds } }, + select: { seatIds: true }, + }), + this.prisma.journeySegment.findMany({ + where: { + scheduleId, + seatId: { in: seatIds }, + journey: { status: { in: ['CONFIRMED', 'PENDING_PAYMENT'] } }, + }, + select: { seatId: true }, + }), + ]); + + for (const hold of activeHolds) + for (const seatId of hold.seatIds) + if (seatIds.includes(seatId)) statusMap.set(seatId, 'HELD'); + + for (const seg of bookedSegments) + if (seg.seatId) statusMap.set(seg.seatId, 'BOOKED'); + + return statusMap; } updateScheduleStatus(id: string, dto: UpdateScheduleStatusDto) { diff --git a/apps/edr-passenger-api/src/modules/search/search.module.ts b/apps/edr-passenger-api/src/modules/search/search.module.ts index fbf907fdd..baadcf90c 100644 --- a/apps/edr-passenger-api/src/modules/search/search.module.ts +++ b/apps/edr-passenger-api/src/modules/search/search.module.ts @@ -3,9 +3,10 @@ import { SearchController } from './search.controller'; import { SearchService } from './search.service'; import { CurrencyModule } from '../currency/currency.module'; import { FareEngineModule } from '../fare-engine/fare-engine.module'; +import { SegmentsModule } from '../segments/segments.module'; @Module({ - imports: [CurrencyModule, FareEngineModule], + imports: [CurrencyModule, FareEngineModule, SegmentsModule], controllers: [SearchController], providers: [SearchService], exports: [SearchService], diff --git a/apps/edr-passenger-api/src/modules/search/search.service.ts b/apps/edr-passenger-api/src/modules/search/search.service.ts index e5e585bd0..c534586dd 100644 --- a/apps/edr-passenger-api/src/modules/search/search.service.ts +++ b/apps/edr-passenger-api/src/modules/search/search.service.ts @@ -3,6 +3,7 @@ import { PrismaService } from '../../common/prisma.service'; import { SearchTripsDto, FareQuoteDto } from './search.dto'; import { CurrencyService } from '../currency/currency.service'; import { FareEngineService } from '../fare-engine/fare-engine.service'; +import { SegmentsService } from '../segments/segments.service'; import { Currency } from '@prisma/client'; const POINTS_TO_MINOR = 10; @@ -13,6 +14,7 @@ export class SearchService { private prisma: PrismaService, private currencyService: CurrencyService, private fareEngine: FareEngineService, + private segmentsService: SegmentsService, ) {} async searchTrips(dto: SearchTripsDto) { @@ -58,7 +60,8 @@ export class SearchService { for (const seat of assignment.coach.seats) { if (seat.status === 'BLOCKED') continue; - const free = await this.isSeatFreeForSegment( + // Use segment-aware check — a seat booked A→B is still free for B→D + const free = await this.segmentsService.isSeatFreeForLeg( schedule.id, seat.id, originStop.sequence, destStop.sequence, ); @@ -237,70 +240,6 @@ export class SearchService { }; } - /** - * Returns true if the seat has no active hold or confirmed booking - * whose segment range overlaps [fromSeq, toSeq). - * Overlap condition: existingFrom < toSeq AND fromSeq < existingTo - */ - private async isSeatFreeForSegment( - scheduleId: string, - seatId: string, - fromSeq: number, - toSeq: number, - ): Promise { - // Check active holds that include this seat on this schedule - const holds = await this.prisma.seatHold.findMany({ - where: { scheduleId, seatIds: { has: seatId }, expiresAt: { gt: new Date() } }, - }); - - for (const hold of holds) { - // Resolve hold segment range from its stored origin/destination via JourneySegment - // For holds we use the stop sequences stored on the hold's origin/destination - // Since SeatHold doesn't store sequences directly, we check JourneySegments - // that reference this seat on this schedule with PENDING_PAYMENT status - const holdSegs = await this.prisma.journeySegment.findMany({ - where: { scheduleId, seatId }, - include: { - journey: true, - schedule: { include: { stopTimes: true } }, - }, - }); - - for (const js of holdSegs) { - const depSeq = js.schedule.stopTimes.find(s => s.stationId === js.departureStationId)?.sequence; - const arrSeq = js.schedule.stopTimes.find(s => s.stationId === js.arrivalStationId)?.sequence; - if (depSeq !== undefined && arrSeq !== undefined) { - if (depSeq < toSeq && fromSeq < arrSeq) return false; - } - } - - // If no journey segments yet (hold just created), treat the whole hold as blocking - if (holdSegs.length === 0) return false; - } - - // Check confirmed/pending bookings via JourneySegment - const bookedSegments = await this.prisma.journeySegment.findMany({ - where: { - scheduleId, - seatId, - journey: { status: { in: ['CONFIRMED', 'PENDING_PAYMENT'] } }, - }, - include: { - schedule: { include: { stopTimes: true } }, - }, - }); - - for (const js of bookedSegments) { - const depSeq = js.schedule.stopTimes.find(s => s.stationId === js.departureStationId)?.sequence; - const arrSeq = js.schedule.stopTimes.find(s => s.stationId === js.arrivalStationId)?.sequence; - if (depSeq !== undefined && arrSeq !== undefined) { - if (depSeq < toSeq && fromSeq < arrSeq) return false; - } - } - - return true; - } - private defaultFare(seatClassName: string): number { const fares: Record = { 'Economy Regular': 45000, diff --git a/apps/edr-passenger-api/src/modules/seats/seats.controller.ts b/apps/edr-passenger-api/src/modules/seats/seats.controller.ts index 4c93b5f61..a555f2513 100644 --- a/apps/edr-passenger-api/src/modules/seats/seats.controller.ts +++ b/apps/edr-passenger-api/src/modules/seats/seats.controller.ts @@ -26,6 +26,34 @@ Shows seat status: AVAILABLE, BOOKED, HELD, BLOCKED` getSeatMap(@Param('scheduleId') scheduleId: string, @Query('coachId') coachId?: string) { return this.service.getSeatMap(scheduleId, coachId); } // ── Hold / Release ──────────────────────────────────────────────────────── + @Get('holds') + @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') + @ApiOperation({ + summary: 'List active seat holds with full leg context', + description: `Returns all non-expired holds enriched with: +- **schedule**: train number, departure/arrival, full route origin→destination +- **leg**: the specific origin→destination this hold covers (station name, code, stop sequence) +- **seats**: seat label, coach, seat class, row, col +- **ttlSeconds**: seconds remaining before the hold expires + +This makes it clear which segment of the route each seat is held for, enabling segment-based reuse of the same seat on non-overlapping legs.`, + }) + @ApiQuery({ name: 'scheduleId', required: false, description: 'Filter by TrainSchedule UUID' }) + @ApiQuery({ name: 'passengerId', required: false, description: 'Filter by Passenger UUID' }) + @ApiResponse({ status: 200, description: 'Active holds with schedule, leg, and seat details' }) + getHolds( + @Query('scheduleId') scheduleId?: string, + @Query('passengerId') passengerId?: string, + ) { return this.service.getHolds(scheduleId, passengerId); } + + @Get('holds/:holdId') + @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') + @ApiOperation({ summary: 'Get a single hold with full leg context' }) + @ApiParam({ name: 'holdId', description: 'SeatHold UUID' }) + @ApiResponse({ status: 200, description: 'Hold with schedule, leg, and seat details' }) + @ApiResponse({ status: 404, description: 'Hold not found' }) + getHold(@Param('holdId') holdId: string) { return this.service.getHold(holdId); } + @Post('hold') @UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') @ApiOperation({ diff --git a/apps/edr-passenger-api/src/modules/seats/seats.dto.ts b/apps/edr-passenger-api/src/modules/seats/seats.dto.ts index 6af6fe203..4818fe59f 100644 --- a/apps/edr-passenger-api/src/modules/seats/seats.dto.ts +++ b/apps/edr-passenger-api/src/modules/seats/seats.dto.ts @@ -1,9 +1,35 @@ -import { IsString, IsArray, IsOptional } from 'class-validator'; -import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +import { IsString, IsArray, ValidateNested } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { Type } from 'class-transformer'; + +export class PassengerSeatDto { + @ApiProperty({ example: 'passenger-uuid', description: 'Passenger UUID' }) + @IsString() passengerId: string; + + @ApiProperty({ example: 'seat-uuid', description: 'Seat UUID assigned to this passenger' }) + @IsString() seatId: string; +} export class HoldSeatsDto { - @ApiProperty({ example: 'schedule-uuid' }) @IsString() scheduleId: string; - @ApiProperty({ example: 'passenger-uuid' }) @IsString() passengerId: string; - @ApiProperty({ type: [String], example: ['seat-uuid-1', 'seat-uuid-2'] }) @IsArray() seatIds: string[]; - @ApiPropertyOptional({ example: 'fare-quote-uuid' }) @IsOptional() @IsString() fareQuoteId?: string; + @ApiProperty({ example: 'schedule-uuid', description: 'TrainSchedule UUID' }) + @IsString() scheduleId: string; + + @ApiProperty({ example: 'station-uuid', description: 'Origin station UUID — scopes the hold to a leg so the seat can be reused on non-overlapping legs' }) + @IsString() originStationId: string; + + @ApiProperty({ example: 'station-uuid', description: 'Destination station UUID for this leg' }) + @IsString() destinationStationId: string; + + @ApiProperty({ + type: [PassengerSeatDto], + description: 'One entry per passenger. Each passenger is assigned exactly one seat. Duplicate passengerId or seatId within the same request is rejected.', + example: [ + { passengerId: 'passenger-uuid-1', seatId: 'seat-uuid-1' }, + { passengerId: 'passenger-uuid-2', seatId: 'seat-uuid-2' }, + ], + }) + @IsArray() + @ValidateNested({ each: true }) + @Type(() => PassengerSeatDto) + passengers: PassengerSeatDto[]; } diff --git a/apps/edr-passenger-api/src/modules/seats/seats.module.ts b/apps/edr-passenger-api/src/modules/seats/seats.module.ts index c9394983d..014e0918a 100644 --- a/apps/edr-passenger-api/src/modules/seats/seats.module.ts +++ b/apps/edr-passenger-api/src/modules/seats/seats.module.ts @@ -1,6 +1,12 @@ import { Module } from '@nestjs/common'; import { SeatsController } from './seats.controller'; import { SeatsService } from './seats.service'; +import { SegmentsModule } from '../segments/segments.module'; -@Module({ controllers: [SeatsController], providers: [SeatsService], exports: [SeatsService] }) +@Module({ + imports: [SegmentsModule], + controllers: [SeatsController], + providers: [SeatsService], + exports: [SeatsService], +}) export class SeatsModule {} diff --git a/apps/edr-passenger-api/src/modules/seats/seats.service.ts b/apps/edr-passenger-api/src/modules/seats/seats.service.ts index 606cb4902..96cf4e1bf 100644 --- a/apps/edr-passenger-api/src/modules/seats/seats.service.ts +++ b/apps/edr-passenger-api/src/modules/seats/seats.service.ts @@ -1,11 +1,15 @@ -import { Injectable, ConflictException, NotFoundException } from '@nestjs/common'; +import { Injectable, ConflictException, NotFoundException, BadRequestException } from '@nestjs/common'; import { PrismaService } from '../../common/prisma.service'; import { HoldSeatsDto } from './seats.dto'; import { Cron, CronExpression } from '@nestjs/schedule'; +import { SegmentsService } from '../segments/segments.service'; @Injectable() export class SeatsService { - constructor(private prisma: PrismaService) {} + constructor( + private prisma: PrismaService, + private segmentsService: SegmentsService, + ) {} // ── Seat Map ────────────────────────────────────────────────────────────── async getSeatMap(scheduleId: string, coachId?: string) { @@ -14,6 +18,10 @@ export class SeatsService { include: { coach: { include: { seats: { orderBy: [{ row: 'asc' }, { col: 'asc' }] }, seatClass: true } } }, orderBy: { positionNumber: 'asc' }, }); + + const allSeatIds = assignments.flatMap(a => a.coach.seats.map(s => s.id)); + const effectiveStatuses = await this.resolveEffectiveStatuses(scheduleId, allSeatIds); + return { coaches: assignments.map((a) => ({ id: a.coach.id, @@ -21,34 +29,334 @@ export class SeatsService { name: `Coach ${a.coach.label}`, seatClass: a.coach.seatClass.name, positionNumber: a.positionNumber, - seats: a.coach.seats.map((s) => ({ id: s.id, number: s.label, status: s.status, kind: s.kind })), + seats: a.coach.seats.map((s) => ({ + id: s.id, + number: s.label, + status: effectiveStatuses.get(s.id) ?? s.status, + kind: s.kind, + row: s.row, + col: s.col, + isWindow: s.isWindow, + isAisle: s.isAisle, + bedPosition: s.bedPosition, + })), })), }; } + /** + * Computes the effective seat status for a set of seats on a specific schedule + * by checking active SeatHolds and confirmed JourneySegments. + * + * Priority: BLOCKED (physical) > BOOKED (confirmed journey) > HELD (active hold) > AVAILABLE + * + * This is needed because seat.status is no longer written during booking — + * availability is segment-scoped, so the DB column stays AVAILABLE even when held. + */ + async resolveEffectiveStatuses( + scheduleId: string, + seatIds: string[], + ): Promise> { + const statusMap = new Map(); + + if (seatIds.length === 0) return statusMap; + + // 1. Active holds — any seat in an unexpired SeatHold for this schedule is HELD + const activeHolds = await this.prisma.seatHold.findMany({ + where: { + scheduleId, + expiresAt: { gt: new Date() }, + seatIds: { hasSome: seatIds }, + }, + select: { seatIds: true }, + }); + for (const hold of activeHolds) { + for (const seatId of hold.seatIds) { + if (seatIds.includes(seatId)) statusMap.set(seatId, 'HELD'); + } + } + + // 2. Active bookings via JourneySegment — CONFIRMED or PENDING_PAYMENT → BOOKED + // (overwrites HELD if the same seat has a confirmed booking) + const bookedSegments = await this.prisma.journeySegment.findMany({ + where: { + scheduleId, + seatId: { in: seatIds }, + journey: { status: { in: ['CONFIRMED', 'PENDING_PAYMENT'] } }, + }, + select: { seatId: true }, + }); + for (const seg of bookedSegments) { + if (seg.seatId) statusMap.set(seg.seatId, 'BOOKED'); + } + + return statusMap; + } + // ── Hold / Release ──────────────────────────────────────────────────────── async holdSeats(dto: HoldSeatsDto) { + // ── Validate request integrity ─────────────────────────────────────────── + const passengerIds = dto.passengers.map(p => p.passengerId); + const seatIds = dto.passengers.map(p => p.seatId); + + if (new Set(passengerIds).size !== passengerIds.length) + throw new BadRequestException('Duplicate passengerId in passengers list — each passenger must appear once'); + if (new Set(seatIds).size !== seatIds.length) + throw new BadRequestException('Duplicate seatId in passengers list — each seat can only be assigned to one passenger'); + const expiresAt = new Date(Date.now() + 15 * 60 * 1000); + const hold = await this.prisma.$transaction(async (tx) => { - const seats = await tx.seat.findMany({ where: { id: { in: dto.seatIds } }, select: { id: true, status: true, heldUntil: true } }); - const unavailable = seats.filter((s) => s.status === 'BOOKED' || s.status === 'BLOCKED' || (s.status === 'HELD' && s.heldUntil && s.heldUntil > new Date())); - if (unavailable.length > 0) throw new ConflictException('One or more seats unavailable'); - await tx.seat.updateMany({ where: { id: { in: dto.seatIds } }, data: { status: 'HELD', heldUntil: expiresAt } }); - return tx.seatHold.create({ data: { scheduleId: dto.scheduleId, passengerId: dto.passengerId, seatIds: dto.seatIds, fareQuoteId: dto.fareQuoteId, expiresAt } }); + // ── 1. Validate seats exist and none are BLOCKED ───────────────────── + const seats = await tx.seat.findMany({ + where: { id: { in: seatIds } }, + select: { id: true, status: true, label: true }, + }); + + if (seats.length !== seatIds.length) { + const found = new Set(seats.map(s => s.id)); + const missing = seatIds.filter(id => !found.has(id)); + throw new NotFoundException(`Seat(s) not found: ${missing.join(', ')}`); + } + + const blocked = seats.filter(s => s.status === 'BLOCKED'); + if (blocked.length > 0) + throw new ConflictException(`Seat(s) ${blocked.map(s => s.label).join(', ')} are blocked`); + + const seatLabelById = Object.fromEntries(seats.map(s => [s.id, s.label])); + + // ── 2. Resolve requested leg sequences ────────────────────────────── + const stopTimes = await tx.tripStopTime.findMany({ + where: { scheduleId: dto.scheduleId }, + select: { stationId: true, sequence: true }, + }); + const seqOf = (stationId: string) => + stopTimes.find(s => s.stationId === stationId)?.sequence; + + const reqFrom = seqOf(dto.originStationId); + const reqTo = seqOf(dto.destinationStationId); + + if (reqFrom === undefined || reqTo === undefined) + throw new BadRequestException('Origin or destination station not found on this schedule'); + if (reqFrom >= reqTo) + throw new BadRequestException('Origin must come before destination'); + + // ── 3. Load active holds for this schedule ─────────────────────────── + const activeHolds = await tx.seatHold.findMany({ + where: { scheduleId: dto.scheduleId, expiresAt: { gt: new Date() } }, + select: { seatIds: true, createdBy: true }, + }); + + // Parse each hold's leg range and passenger list + const parsedHolds: { seatIds: string[]; from: number; to: number; passengerIds: string[] }[] = []; + for (const h of activeHolds) { + try { + if (h.createdBy?.trimStart().startsWith('{')) { + const meta = JSON.parse(h.createdBy); + const holdFrom = seqOf(meta.originStationId); + const holdTo = seqOf(meta.destinationStationId); + if (holdFrom !== undefined && holdTo !== undefined) { + parsedHolds.push({ + seatIds: h.seatIds, + from: holdFrom, + to: holdTo, + passengerIds: (meta.passengers ?? []).map((p: any) => p.passengerId), + }); + } + } + } catch { /* ignore malformed */ } + } + + // ── 4. Per-passenger validation with overlap check ─────────────────── + for (const { passengerId, seatId } of dto.passengers) { + for (const hold of parsedHolds) { + const legsOverlap = hold.from < reqTo && reqFrom < hold.to; + if (!legsOverlap) continue; // non-overlapping leg — no conflict + + // Rule A: seat is held on an overlapping leg + if (hold.seatIds.includes(seatId)) { + throw new ConflictException( + `Seat ${seatLabelById[seatId]} is already held for this leg. Please choose a different seat.`, + ); + } + + // Rule B: passenger already holds a seat on an overlapping leg + if (hold.passengerIds.includes(passengerId)) { + throw new ConflictException( + `Passenger already holds a seat on this journey leg. You can only hold one seat per journey.`, + ); + } + } + } + + // Store passenger→seat mapping AND leg in createdBy as JSON + const holdMeta = { + originStationId: dto.originStationId, + destinationStationId: dto.destinationStationId, + passengers: dto.passengers.map(p => ({ passengerId: p.passengerId, seatId: p.seatId })), + }; + + return tx.seatHold.create({ + data: { + scheduleId: dto.scheduleId, + passengerId: dto.passengers[0].passengerId, + seatIds, + createdBy: JSON.stringify(holdMeta), + expiresAt, + }, + }); }); - return { id: hold.id, scheduleId: dto.scheduleId, seatIds: dto.seatIds, expiresAt }; + + return this.enrichHold(hold); + } + + async getHolds(scheduleId?: string, passengerId?: string) { + const holds = await this.prisma.seatHold.findMany({ + where: { + expiresAt: { gt: new Date() }, + ...(scheduleId ? { scheduleId } : {}), + ...(passengerId ? { passengerId } : {}), + }, + orderBy: { createdAt: 'desc' }, + }); + return Promise.all(holds.map(h => this.enrichHold(h))); + } + + async getHold(holdId: string) { + const hold = await this.prisma.seatHold.findUnique({ where: { id: holdId } }); + if (!hold) throw new NotFoundException('Hold not found'); + return this.enrichHold(hold); + } + + /** + * Resolves the opaque fareQuoteId leg encoding into human-readable station + * names and enriches the hold with schedule, seat, and leg details. + */ + private async enrichHold(hold: any) { + // Decode leg and passenger→seat mapping from createdBy JSON + let originStationId: string | null = null; + let destinationStationId: string | null = null; + let passengerSeatMap: { passengerId: string; seatId: string }[] = []; + + try { + if (hold.createdBy) { + const raw = hold.createdBy; + // Guard: only parse if it looks like a JSON object, not a plain number/string + if (typeof raw === 'string' && raw.trimStart().startsWith('{')) { + const meta = JSON.parse(raw); + originStationId = meta.originStationId ?? null; + destinationStationId = meta.destinationStationId ?? null; + passengerSeatMap = Array.isArray(meta.passengers) ? meta.passengers : []; + } + } + } catch { /* ignore malformed createdBy */ } + + const seatIds = hold.seatIds as string[]; + + const [schedule, originStation, destinationStation, seats] = await Promise.all([ + this.prisma.trainSchedule.findUnique({ + where: { id: hold.scheduleId }, + include: { train: true, originStation: true, destinationStation: true }, + }), + originStationId ? this.prisma.station.findUnique({ where: { id: originStationId } }) : null, + destinationStationId ? this.prisma.station.findUnique({ where: { id: destinationStationId } }) : null, + this.prisma.seat.findMany({ + where: { id: { in: seatIds } }, + include: { coach: { include: { seatClass: true } } }, + }), + ]); + + let originSequence: number | null = null; + let destinationSequence: number | null = null; + if (originStationId && destinationStationId) { + const stopTimes = await this.prisma.tripStopTime.findMany({ + where: { scheduleId: hold.scheduleId, stationId: { in: [originStationId, destinationStationId] } }, + select: { stationId: true, sequence: true }, + }); + originSequence = stopTimes.find(s => s.stationId === originStationId)?.sequence ?? null; + destinationSequence = stopTimes.find(s => s.stationId === destinationStationId)?.sequence ?? null; + } + + // Build seat map keyed by seatId for quick lookup + const seatById = Object.fromEntries(seats.map(s => [s.id, s])); + + // Merge passenger→seat mapping with seat details + const passengers = passengerSeatMap.length > 0 + ? passengerSeatMap.map(({ passengerId, seatId }) => { + const s = seatById[seatId]; + return { + passengerId, + seat: s ? { + id: s.id, + label: s.label, + seatNumber: s.seatNumber, + coach: s.coach.label, + seatClass: s.coach.seatClass.name, + row: s.row, + col: s.col, + } : { id: seatId }, + }; + }) + // Fallback for holds created before this change + : seatIds.map(seatId => { + const s = seatById[seatId]; + return { + passengerId: hold.passengerId, + seat: s ? { + id: s.id, + label: s.label, + seatNumber: s.seatNumber, + coach: s.coach.label, + seatClass: s.coach.seatClass.name, + row: s.row, + col: s.col, + } : { id: seatId }, + }; + }); + + return { + holdId: hold.id, + expiresAt: hold.expiresAt, + createdAt: hold.createdAt, + ttlSeconds: Math.max(0, Math.floor((hold.expiresAt.getTime() - Date.now()) / 1000)), + schedule: schedule ? { + id: schedule.id, + trainNumber: schedule.train.number, + trainName: schedule.train.name, + departureAt: schedule.departureAt, + arrivalAt: schedule.arrivalAt, + fullRouteOrigin: schedule.originStation.name, + fullRouteDestination: schedule.destinationStation.name, + } : null, + leg: { + originStationId, + originStationName: originStation?.name ?? null, + originStationCode: originStation?.code ?? null, + originSequence, + destinationStationId, + destinationStationName: destinationStation?.name ?? null, + destinationStationCode: destinationStation?.code ?? null, + destinationSequence, + }, + passengers, + }; } async releaseHold(holdId: string) { const hold = await this.prisma.seatHold.findUnique({ where: { id: holdId } }); if (!hold) throw new NotFoundException('Hold not found'); - await this.prisma.seat.updateMany({ where: { id: { in: hold.seatIds }, status: 'HELD' }, data: { status: 'AVAILABLE', heldUntil: null } }); await this.prisma.seatHold.delete({ where: { id: holdId } }); - return { released: true }; + return { released: true, holdId }; } - async confirmSeats(seatIds: string[]) { await this.prisma.seat.updateMany({ where: { id: { in: seatIds } }, data: { status: 'BOOKED', heldUntil: null } }); } - async releaseSeats(seatIds: string[]) { await this.prisma.seat.updateMany({ where: { id: { in: seatIds } }, data: { status: 'AVAILABLE', heldUntil: null } }); } + async confirmSeats(seatIds: string[]) { + // No-op for status — availability is segment-scoped via JourneySegment + // seat.status = BLOCKED is the only hard gate; BOOKED is not used as a booking flag + } + async releaseSeats(seatIds: string[]) { + // Only reset seats that are physically BLOCKED back to AVAILABLE if needed + // For segment-based bookings, releasing is handled by JourneySegment deletion + } async autoAssignSeats(scheduleId: string, count: number, seatClassName: string, eligibility?: string): Promise { const seats = await this.prisma.seat.findMany({ diff --git a/apps/edr-passenger-api/src/modules/segments/enhanced-seats.service.ts b/apps/edr-passenger-api/src/modules/segments/enhanced-seats.service.ts index 275ab077f..88fd636b6 100644 --- a/apps/edr-passenger-api/src/modules/segments/enhanced-seats.service.ts +++ b/apps/edr-passenger-api/src/modules/segments/enhanced-seats.service.ts @@ -9,7 +9,6 @@ export interface SeatHoldRequest { passengerId: string; originStationId: string; destinationStationId: string; - fareQuoteId?: string; } export interface BookingConfirmRequest { @@ -27,28 +26,42 @@ export class EnhancedSeatsService { async holdSeats(request: SeatHoldRequest) { return this.prisma.$transaction(async (tx) => { - const segments = await this.segmentsService.getJourneySegments(request.scheduleId, request.originStationId, request.destinationStationId); + const segments = await this.segmentsService.getJourneySegments( + request.scheduleId, request.originStationId, request.destinationStationId, + ); + const reqFrom = Math.min(...segments.map(s => s.fromSequence)); + const reqTo = Math.max(...segments.map(s => s.toSequence)); for (const seatId of request.seatIds) { const seat = await tx.seat.findUnique({ where: { id: seatId } }); if (!seat) throw new BadRequestException(`Seat ${seatId} not found`); + // Only BLOCKED seats are hard-rejected — BOOKED/HELD are fine if the + // segment does not overlap (another passenger may occupy a different leg) if (seat.status === 'BLOCKED') throw new BadRequestException(`Seat ${seat.label} is blocked`); - const overlaps = await this.segmentsService.getOverlappingReservations(request.scheduleId, seatId, segments); - if (overlaps.length > 0) throw new ConflictException(`Seat ${seat.label} is not available for the requested segments`); + + const free = await this.segmentsService.isSeatFreeForLeg( + request.scheduleId, seatId, reqFrom, reqTo, + ); + if (!free) throw new ConflictException(`Seat ${seat.label} is not available for the requested leg`); } const expiresAt = new Date(Date.now() + 10 * 60 * 1000); - // Encode origin/destination into fareQuoteId so confirmBooking can resolve the leg range - // Format: "leg:{originStationId}:{destinationStationId}" (or preserve actual fareQuoteId) - const legKey = request.fareQuoteId ?? `leg:${request.originStationId}:${request.destinationStationId}`; const seatHold = await tx.seatHold.create({ - data: { scheduleId: request.scheduleId, seatIds: request.seatIds, passengerId: request.passengerId, fareQuoteId: legKey, expiresAt }, + data: { + scheduleId: request.scheduleId, + seatIds: request.seatIds, + passengerId: request.passengerId, + // Store leg in createdBy JSON — no fareQuoteId needed + createdBy: JSON.stringify({ + originStationId: request.originStationId, + destinationStationId: request.destinationStationId, + }), + expiresAt, + }, }); - await tx.seat.updateMany({ where: { id: { in: request.seatIds } }, data: { status: 'HELD', heldUntil: expiresAt } }); - + // Do NOT set seat.status = HELD globally — status is segment-scoped this.eventEmitter.emit('seats.held', { holdId: seatHold.id, scheduleId: request.scheduleId, seatIds: request.seatIds, segments }); - return { holdId: seatHold.id, expiresAt, segments, seats: request.seatIds }; }); } @@ -68,19 +81,16 @@ export class EnhancedSeatsService { }); if (!schedule) throw new BadRequestException('Schedule not found'); - // Resolve the passenger's leg range from the hold's fareQuoteId (encoded as "leg:originId:destId") - const legKey = hold.fareQuoteId ?? ''; + // Resolve the passenger's leg from createdBy JSON let originStationId: string | undefined; let destinationStationId: string | undefined; - if (legKey.startsWith('leg:')) { - const parts = legKey.split(':'); - originStationId = parts[1]; - destinationStationId = parts[2]; - } else { - // Fall back to booking's own origin/destination if available - originStationId = (booking as any).originStationId; - destinationStationId = (booking as any).destinationStationId; - } + try { + if (hold.createdBy) { + const meta = JSON.parse(hold.createdBy); + originStationId = meta.originStationId; + destinationStationId = meta.destinationStationId; + } + } catch { /* ignore */ } const originStop = originStationId ? schedule.stopTimes.find(s => s.stationId === originStationId) : undefined; const destStop = destinationStationId ? schedule.stopTimes.find(s => s.stationId === destinationStationId) : undefined; @@ -122,11 +132,10 @@ export class EnhancedSeatsService { } } - await tx.seat.updateMany({ where: { id: { in: hold.seatIds } }, data: { status: 'BOOKED', heldUntil: null } }); + // Do NOT set seat.status = BOOKED globally — availability is segment-scoped await tx.seatHold.delete({ where: { id: request.holdId } }); this.eventEmitter.emit('booking.confirmed', { bookingId: request.bookingId, scheduleId: hold.scheduleId, seatIds: hold.seatIds, segments }); - return { bookingId: request.bookingId, confirmedSeats: hold.seatIds, segments }; }); } @@ -171,6 +180,8 @@ export class EnhancedSeatsService { async getSeatAvailability(scheduleId: string, originStationId: string, destinationStationId: string) { const segments = await this.segmentsService.getJourneySegments(scheduleId, originStationId, destinationStationId); + const reqFrom = Math.min(...segments.map(s => s.fromSequence)); + const reqTo = Math.max(...segments.map(s => s.toSequence)); const schedule = await this.prisma.trainSchedule.findUnique({ where: { id: scheduleId }, @@ -181,13 +192,20 @@ export class EnhancedSeatsService { const availableSeats = []; for (const assignment of schedule.coachAssignments) { for (const seat of assignment.coach.seats) { - const overlaps = await this.segmentsService.getOverlappingReservations(scheduleId, seat.id, segments); - if (overlaps.length === 0 && seat.status === 'AVAILABLE') { + // Hard-blocked seats are never available + if (seat.status === 'BLOCKED') continue; + // Availability is determined purely by segment overlap — not global seat.status + const free = await this.segmentsService.isSeatFreeForLeg(scheduleId, seat.id, reqFrom, reqTo); + if (free) { availableSeats.push({ id: seat.id, label: seat.label, coach: assignment.coach.label, seatClass: assignment.coach.seatClass.name, row: seat.row, col: seat.col, + kind: seat.kind, + isWindow: seat.isWindow, + isAisle: seat.isAisle, + bedPosition: seat.bedPosition, }); } } diff --git a/apps/edr-passenger-api/src/modules/segments/segments.controller.ts b/apps/edr-passenger-api/src/modules/segments/segments.controller.ts index 5a45e38c5..cd62a3064 100644 --- a/apps/edr-passenger-api/src/modules/segments/segments.controller.ts +++ b/apps/edr-passenger-api/src/modules/segments/segments.controller.ts @@ -1,132 +1,51 @@ -import { Controller, Post, Get, Body, Query, Param } from '@nestjs/common'; +import { Controller, Post, Get, Body, Query } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; import { EnhancedSeatsService } from './enhanced-seats.service'; -import { HoldSeatsDto, ConfirmBookingDto, SeatAvailabilityDto, ReleaseSeatsDto } from './segments.dto'; +import { ConfirmBookingDto, SeatAvailabilityDto, ReleaseSeatsDto } from './segments.dto'; @ApiTags('Segment-based Seats') @Controller('segments/seats') export class SegmentSeatsController { constructor(private enhancedSeatsService: EnhancedSeatsService) {} - @Post('hold') - @ApiOperation({ - summary: 'Hold seats for specific journey segments', - description: 'Reserve seats for a partial journey (e.g., Addis Ababa → Dire Dawa) with 10-minute expiry' - }) - @ApiResponse({ - status: 201, - description: 'Seats held successfully', - schema: { - example: { - holdId: 'hold_123', - expiresAt: '2024-01-15T10:10:00Z', - segments: [ - { fromName: 'Addis Ababa', toName: 'Adama', fromSequence: 0, toSequence: 1 }, - { fromName: 'Adama', toName: 'Awash', fromSequence: 1, toSequence: 2 }, - { fromName: 'Awash', toName: 'Dire Dawa', fromSequence: 2, toSequence: 3 } - ], - seats: ['seat_1', 'seat_2'] - } - } - }) - @ApiResponse({ status: 409, description: 'Seats not available for requested segments' }) - async holdSeats(@Body() dto: HoldSeatsDto) { - return this.enhancedSeatsService.holdSeats({ - scheduleId: dto.scheduleId, - seatIds: dto.seatIds, - passengerId: dto.passengerId, - originStationId: dto.originStationId, - destinationStationId: dto.destinationStationId, - fareQuoteId: dto.fareQuoteId, - }); - } - @Post('confirm') - @ApiOperation({ - summary: 'Confirm booking and convert hold to reservation', - description: 'Convert seat hold to confirmed booking after payment success' + @ApiOperation({ + summary: 'Confirm booking — convert hold to reservation', + description: 'Call after payment succeeds. Converts the SeatHold (created via POST /seats/hold) into JourneySegment records scoped to the passenger\'s leg.', }) - @ApiResponse({ - status: 200, - description: 'Booking confirmed successfully', - schema: { - example: { - bookingId: 'booking_123', - confirmedSeats: ['seat_1', 'seat_2'], - segments: [ - { fromName: 'Addis Ababa', toName: 'Adama' }, - { fromName: 'Adama', toName: 'Awash' }, - { fromName: 'Awash', toName: 'Dire Dawa' } - ] - } - } - }) - @ApiResponse({ status: 400, description: 'Hold expired or not found' }) - async confirmBooking(@Body() dto: ConfirmBookingDto) { + @ApiResponse({ status: 200, description: 'Booking confirmed, JourneySegments created for the held leg' }) + @ApiResponse({ status: 400, description: 'Hold expired or booking not found' }) + confirmBooking(@Body() dto: ConfirmBookingDto) { return this.enhancedSeatsService.confirmBooking(dto); } @Post('release') - @ApiOperation({ - summary: 'Release seats when train reaches station', - description: 'Automatically release seats for passengers who have reached their destination' + @ApiOperation({ + summary: 'Release seats when train reaches a station', + description: 'Called by the live tracking system when the train departs a station. Frees seats for passengers whose journey ended at that station.', }) - @ApiResponse({ - status: 200, - description: 'Seats released successfully', - schema: { - example: { - releasedSeats: ['seat_1', 'seat_2'], - stationId: 'st_DRE' - } - } - }) - async releaseSeats(@Body() dto: ReleaseSeatsDto) { + @ApiResponse({ status: 200, description: 'Seats released for passengers who reached their destination' }) + releaseSeats(@Body() dto: ReleaseSeatsDto) { return this.enhancedSeatsService.releaseSeats(dto.scheduleId, dto.currentStationId); } @Get('availability') - @ApiOperation({ - summary: 'Check seat availability for journey segments', - description: 'Get available seats for a specific origin-destination pair' + @ApiOperation({ + summary: 'Get available seats for a specific leg', + description: 'Returns seats that have no overlapping reservation for the requested origin→destination leg. A seat booked A→B is shown as available for B→D.', }) - @ApiResponse({ - status: 200, - description: 'Seat availability retrieved', - schema: { - example: { - segments: [ - { fromName: 'Addis Ababa', toName: 'Adama', fromSequence: 0, toSequence: 1 }, - { fromName: 'Adama', toName: 'Awash', fromSequence: 1, toSequence: 2 } - ], - availableSeats: [ - { id: 'seat_1', label: '1A', coach: 'A', seatClass: 'Economy Regular', row: 1, col: 'A' }, - { id: 'seat_2', label: '1B', coach: 'A', seatClass: 'Economy Regular', row: 1, col: 'B' } - ], - totalAvailable: 2 - } - } - }) - async getSeatAvailability(@Query() dto: SeatAvailabilityDto) { + @ApiResponse({ status: 200, description: 'Available seats with coach, seat class, row, col, window/aisle/bed flags' }) + getSeatAvailability(@Query() dto: SeatAvailabilityDto) { return this.enhancedSeatsService.getSeatAvailability(dto.scheduleId, dto.originStationId, dto.destinationStationId); } @Post('expire-holds') - @ApiOperation({ - summary: 'Expire old seat holds (background job)', - description: 'Release seats from expired holds and make them available' + @ApiOperation({ + summary: 'Expire stale seat holds (background job)', + description: 'Removes holds past their expiry time. Called by the scheduler every minute.', }) - @ApiResponse({ - status: 200, - description: 'Expired holds processed', - schema: { - example: { - expiredHolds: 5, - releasedSeats: ['seat_1', 'seat_2', 'seat_3'] - } - } - }) - async expireHolds() { + @ApiResponse({ status: 200, description: 'Expired holds removed' }) + expireHolds() { return this.enhancedSeatsService.expireHolds(); } } \ No newline at end of file diff --git a/apps/edr-passenger-api/src/modules/segments/segments.service.ts b/apps/edr-passenger-api/src/modules/segments/segments.service.ts index 8fe525bcb..2eef0302e 100644 --- a/apps/edr-passenger-api/src/modules/segments/segments.service.ts +++ b/apps/edr-passenger-api/src/modules/segments/segments.service.ts @@ -26,7 +26,7 @@ export class SegmentsService { }); const originStop = stopTimes.find(st => st.stationId === originStationId); - const destStop = stopTimes.find(st => st.stationId === destinationStationId); + const destStop = stopTimes.find(st => st.stationId === destinationStationId); if (!originStop || !destStop) { throw new BadRequestException('Origin or destination station not found on this schedule'); @@ -38,22 +38,126 @@ export class SegmentsService { const segments: Segment[] = []; for (let i = originStop.sequence; i < destStop.sequence; i++) { const fromStop = stopTimes.find(st => st.sequence === i); - const toStop = stopTimes.find(st => st.sequence === i + 1); + const toStop = stopTimes.find(st => st.sequence === i + 1); if (fromStop && toStop) { segments.push({ fromStationId: fromStop.stationId, - toStationId: toStop.stationId, - fromSequence: fromStop.sequence, - toSequence: toStop.sequence, - fromName: fromStop.station.name, - toName: toStop.station.name, + toStationId: toStop.stationId, + fromSequence: fromStop.sequence, + toSequence: toStop.sequence, + fromName: fromStop.station.name, + toName: toStop.station.name, }); } } return segments; } - /** True if two segment ranges overlap: [a.from, a.to) ∩ [b.from, b.to) ≠ ∅ */ + /** + * Checks whether a seat is free for the requested leg [reqFrom, reqTo). + * + * Overlap rule (strict): existingFrom < reqTo AND reqFrom < existingTo + * + * This means two journeys that TOUCH at a boundary do NOT conflict: + * P1: A(1) → B(2) reqFrom=1, reqTo=2 + * P2: B(2) → D(4) reqFrom=2, reqTo=4 + * Check P1 vs P2: 1 < 4 AND 2 < 2 → true AND false → NO conflict ✓ + * + * P3: A(1) → D(4) reqFrom=1, reqTo=4 + * Check P3 vs P2: 1 < 4 AND 2 < 4 → true AND true → CONFLICT ✓ + * + * Sources checked: + * 1. Active SeatHolds — leg decoded from createdBy JSON ({ originStationId, destinationStationId }) + * 2. Active JourneySegments — per-leg rows for CONFIRMED / PENDING_PAYMENT journeys + */ + async isSeatFreeForLeg( + scheduleId: string, + seatId: string, + reqFrom: number, + reqTo: number, + ): Promise { + // ── Load stop-time sequences once ──────────────────────────────────────── + const stopTimes = await this.prisma.tripStopTime.findMany({ + where: { scheduleId }, + select: { stationId: true, sequence: true }, + }); + const seqOf = (stationId: string) => + stopTimes.find(s => s.stationId === stationId)?.sequence; + + // ── 1. Active holds ─────────────────────────────────────────────────────── + const activeHolds = await this.prisma.seatHold.findMany({ + where: { scheduleId, seatIds: { has: seatId }, expiresAt: { gt: new Date() } }, + }); + + for (const hold of activeHolds) { + // Decode leg from createdBy JSON: { originStationId, destinationStationId, passengers } + let holdFrom: number | undefined; + let holdTo: number | undefined; + try { + if (hold.createdBy) { + const meta = JSON.parse(hold.createdBy); + holdFrom = seqOf(meta.originStationId); + holdTo = seqOf(meta.destinationStationId); + } + } catch { /* ignore */ } + + if (holdFrom !== undefined && holdTo !== undefined) { + if (holdFrom < reqTo && reqFrom < holdTo) return false; + } else { + // Cannot resolve leg — conservative block + return false; + } + } + + // ── 2. Active JourneySegments ───────────────────────────────────────────── + // Each row is one leg (e.g. A→B, B→C). We group by journeyId to get the + // full range [min(depSeq), max(arrSeq)] per journey for this seat. + const bookedLegs = await this.prisma.journeySegment.findMany({ + where: { + scheduleId, + seatId, + journey: { status: { in: ['CONFIRMED', 'PENDING_PAYMENT'] } }, + }, + }); + + // Group legs by journeyId → find the full range each journey occupies + const journeyRanges = new Map(); + for (const leg of bookedLegs) { + const depSeq = seqOf(leg.departureStationId); + const arrSeq = seqOf(leg.arrivalStationId); + if (depSeq === undefined || arrSeq === undefined) continue; + + const existing = journeyRanges.get(leg.journeyId); + if (!existing) { + journeyRanges.set(leg.journeyId, { from: depSeq, to: arrSeq }); + } else { + journeyRanges.set(leg.journeyId, { + from: Math.min(existing.from, depSeq), + to: Math.max(existing.to, arrSeq), + }); + } + } + + for (const { from, to } of journeyRanges.values()) { + // Strict overlap: existingFrom < reqTo AND reqFrom < existingTo + if (from < reqTo && reqFrom < to) return false; + } + + return true; + } + + /** Legacy wrapper used by EnhancedSeatsService.getOverlappingReservations */ + async getOverlappingReservations( + scheduleId: string, + seatId: string, + requestedSegments: Segment[], + ): Promise<{ type: string; id: string }[]> { + const reqFrom = Math.min(...requestedSegments.map(s => s.fromSequence)); + const reqTo = Math.max(...requestedSegments.map(s => s.toSequence)); + const free = await this.isSeatFreeForLeg(scheduleId, seatId, reqFrom, reqTo); + return free ? [] : [{ type: 'conflict', id: seatId }]; + } + segmentsOverlap(segments1: Segment[], segments2: Segment[]): boolean { for (const s1 of segments1) { for (const s2 of segments2) { @@ -62,69 +166,4 @@ export class SegmentsService { } return false; } - - /** - * Returns conflicts for a seat on a schedule for the requested segment range. - * Checks: - * 1. Active SeatHolds — resolved to sequence range via JourneySegment if available, - * otherwise treated as full-schedule block. - * 2. Active BookingSeats — resolved via JourneySegment sequence ranges. - */ - async getOverlappingReservations( - scheduleId: string, - seatId: string, - requestedSegments: Segment[], - ) { - const overlaps: { type: string; id: string }[] = []; - const reqFrom = Math.min(...requestedSegments.map(s => s.fromSequence)); - const reqTo = Math.max(...requestedSegments.map(s => s.toSequence)); - - // ── 1. Active holds ────────────────────────────────────────────────────── - const activeHolds = await this.prisma.seatHold.findMany({ - where: { scheduleId, seatIds: { has: seatId }, expiresAt: { gt: new Date() } }, - }); - - for (const hold of activeHolds) { - // Resolve hold range from JourneySegments created at hold time - const holdSegs = await this.prisma.journeySegment.findMany({ - where: { scheduleId, seatId }, - include: { schedule: { include: { stopTimes: true } } }, - }); - - if (holdSegs.length === 0) { - // No journey segments yet — conservative: treat as full-schedule conflict - overlaps.push({ type: 'hold', id: hold.id }); - continue; - } - - for (const js of holdSegs) { - const depSeq = js.schedule.stopTimes.find(s => s.stationId === js.departureStationId)?.sequence; - const arrSeq = js.schedule.stopTimes.find(s => s.stationId === js.arrivalStationId)?.sequence; - if (depSeq !== undefined && arrSeq !== undefined && depSeq < reqTo && reqFrom < arrSeq) { - overlaps.push({ type: 'hold', id: hold.id }); - break; - } - } - } - - // ── 2. Active bookings via JourneySegment ──────────────────────────────── - const bookedSegments = await this.prisma.journeySegment.findMany({ - where: { - scheduleId, - seatId, - journey: { status: { in: ['CONFIRMED', 'PENDING_PAYMENT'] } }, - }, - include: { schedule: { include: { stopTimes: true } } }, - }); - - for (const js of bookedSegments) { - const depSeq = js.schedule.stopTimes.find(s => s.stationId === js.departureStationId)?.sequence; - const arrSeq = js.schedule.stopTimes.find(s => s.stationId === js.arrivalStationId)?.sequence; - if (depSeq !== undefined && arrSeq !== undefined && depSeq < reqTo && reqFrom < arrSeq) { - overlaps.push({ type: 'booking', id: js.journeyId }); - } - } - - return overlaps; - } } From c838e77349398e1a4a8a2d61b8cf4999ac4c238a Mon Sep 17 00:00:00 2001 From: "Stephanos A." Date: Thu, 28 May 2026 10:13:11 +0300 Subject: [PATCH 38/38] fix: add missing properties to IStation interface - Add 'country' property to match shared types package - Add 'createdAt' property to match shared types package - Add 'updatedAt' property to match shared types package This fixes the TypeScript type mismatch error in StationsPage.tsx where the local IStation type was missing properties required by the shared @edr/types/passenger package during the Docker build. Fixes: https://github.com/Tria-plc/edr-platform/actions/runs/26325256104/job/77502650459 --- .../portal/src/types/index.ts | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/apps/edr-passenger-web/portal/src/types/index.ts b/apps/edr-passenger-web/portal/src/types/index.ts index 09b7c9fc2..b206daa6a 100644 --- a/apps/edr-passenger-web/portal/src/types/index.ts +++ b/apps/edr-passenger-web/portal/src/types/index.ts @@ -1,22 +1,25 @@ -// ── Enums ────────────────────────────────────────────────────────────────────── +// ── Enums ──────────────────────────────────────────────────────────────── export type TripStatus = 'SCHEDULED' | 'BOARDING' | 'EN_ROUTE' | 'ARRIVED' | 'CANCELLED' | 'DELAYED'; export type SeatStatus = 'AVAILABLE' | 'HELD' | 'BOOKED' | 'BLOCKED'; export type ServiceClass = 'ECONOMY' | 'BUSINESS' | 'FIRST'; export type BookingStatus = 'DRAFT' | 'PENDING_PAYMENT' | 'CONFIRMED' | 'CANCELLED' | 'COMPLETED' | 'NO_SHOW'; export type PaymentMethod = 'TELEBIRR' | 'CBE_BIRR' | 'EBIRR' | 'CARD' | 'WALLET'; -// ── Station ──────────────────────────────────────────────────────────────────── +// ── Station ──────────────────────────────────────────────────────────────── export interface IStation { id: string; code: string; name: string; city: string; + country: string; timezone: string; lat: number; lng: number; + createdAt: string | Date; + updatedAt: string | Date; } -// ── Trip / Schedule ──────────────────────────────────────────────────────────── +// ── Trip / Schedule ──────────────────────────────────────────────────────── export interface ITripStation { id: string; code: string; @@ -62,7 +65,7 @@ export interface IStopTime { station: IStation; } -// ── Seat ─────────────────────────────────────────────────────────────────────── +// ── Seat ──────────────────────────────────────────────────────────────────── export interface ISeat { id: string; number: string; // label from API @@ -81,7 +84,7 @@ export interface ISeatMap { coaches: ICoach[]; } -// ── Segment-based seats ──────────────────────────────────────────────────────── +// ── Segment-based seats ──────────────────────────────────────────────────── export interface ISegment { fromStationId: string; toStationId: string; @@ -119,7 +122,7 @@ export interface ISegmentConfirmResult { segments: Array<{ fromStationId: string; toStationId: string; fromSequence: number; toSequence: number }>; } -// ── Booking ──────────────────────────────────────────────────────────────────── +// ── Booking ──────────────────────────────────────────────────────────────── export interface IBooking { id: string; bookingRef: string; @@ -140,7 +143,7 @@ export interface IBooking { payment?: { method: PaymentMethod; status: string }; } -// ── Ticket ───────────────────────────────────────────────────────────────────── +// ── Ticket ───────────────────────────────────────────────────────────────── export interface ITicket { id: string; bookingId: string; @@ -158,7 +161,7 @@ export interface ITicket { qrPayload: string; } -// ── Fare quote ───────────────────────────────────────────────────────────────── +// ── Fare quote ───────────────────────────────────────────────────────────── export interface IFareQuote { tripId: string; serviceClass: ServiceClass; @@ -171,7 +174,7 @@ export interface IFareQuote { currency: string; } -// ── Passenger ───────────────────────────────────────────────────────────────── +// ── Passenger ────────────────────────────────────────────────────────────── export interface IPassengerProfile { id: string; fullName: string; @@ -181,7 +184,7 @@ export interface IPassengerProfile { bookings: IBooking[]; } -// ── Loyalty ──────────────────────────────────────────────────────────────────── +// ── Loyalty ──────────────────────────────────────────────────────────────── export interface ILoyaltyAccount { id: string; passengerId: string; @@ -192,7 +195,7 @@ export interface ILoyaltyAccount { tierProgressPercent: number; } -// ── Wallet ───────────────────────────────────────────────────────────────────── +// ── Wallet ───────────────────────────────────────────────────────────────── export interface IWallet { id: string; passengerId: string; @@ -200,7 +203,7 @@ export interface IWallet { currency: string; } -// ── Notification ─────────────────────────────────────────────────────────────── +// ── Notification ─────────────────────────────────────────────────────────── export interface INotification { id: string; passengerId: string; @@ -212,7 +215,7 @@ export interface INotification { createdAt: string; } -// ── Promotion ────────────────────────────────────────────────────────────────── +// ── Promotion ────────────────────────────────────────────────────────────── export interface IPromotion { id: string; title: string; @@ -225,7 +228,7 @@ export interface IPromotion { active: boolean; } -// ── Live tracking ────────────────────────────────────────────────────────────── +// ── Live tracking ────────────────────────────────────────────────────────── export interface ILiveStatus { tripId: string; trainName: string; @@ -241,7 +244,7 @@ export interface ILiveStatus { updatedAt: string; } -// ── Dashboard ────────────────────────────────────────────────────────────────── +// ── Dashboard ────────────────────────────────────────────────────────────── export interface IDashboard { user: { firstName: string; greetingKey: 'MORNING' | 'AFTERNOON' | 'EVENING' }; upcomingTicket: {