From 7ce0de4e919d0ea7bc4617f0bb4bf13c61674bb1 Mon Sep 17 00:00:00 2001 From: Rayyan <60314224+RayyanHermanto@users.noreply.github.com> Date: Sun, 2 Aug 2026 00:25:36 +0700 Subject: [PATCH] feat(identity): redesign identity module and introduce RBAC foundation - Redesign the Identity module with a richer domain model. - Extend the User entity to support username, Authentik integration, activity tracking, and storage information. - Add Role and Permission domain models with many-to-many relationships. - Implement RBAC foundation using UserRole, RolePermission, and UserPermission mappings. - Add user storage quota and usage fields with default values. - Introduce Authentik identifiers and synchronization metadata. - Refactor user domain logic for role and permission management. - Update Prisma schema to support the new identity architecture. - Improve JWT authentication and permission guard integration. - Update repositories, handlers, controllers, mappers, DTOs, and Swagger configuration. - Refresh environment configuration and project dependencies. --- .env.example | 60 +- .vscode/launch.json | 20 + Target V1.txt | 25 + changes.patch | Bin 0 -> 830508 bytes docs/How To Dev.txt | 46 + my-project.bundle | Bin 0 -> 122257 bytes package-lock.json | 5455 ++++++++++++----- package.json | 7 +- playwright.config.ts | 17 + postman/RayLab.postman_collection.json | 58 + .../20260730165554_permission/migration.sql | 93 + .../20260801084138_change/migration.sql | 16 + .../migration.sql | 2 + .../migration.sql | 11 + .../migration.sql | 10 + .../migration.sql | 15 + .../migration.sql | 17 + .../20260803_add_storage/migration.sql | 7 + prisma/migrations/migration_lock.toml | 3 + prisma/schema.prisma | 104 +- src/app.module.ts | 2 + src/common/constants/permission.constants.ts | 16 + src/core/auth/guards/jwt-auth.guard.ts | 60 +- .../authenticated-request.interface.ts | 16 +- src/core/auth/interfaces/identity-data.ts | 8 + src/main.ts | 7 +- src/modules/auth/auth.controller.ts | 65 + src/modules/auth/auth.module.ts | 46 + src/modules/auth/auth.service.ts | 193 + src/modules/auth/dto/login.dto.ts | 2 + src/modules/auth/pkce/redis-pkce.store.ts | 42 + .../auth/refresh/inmemory-refresh.store.ts | 38 + .../presentation/guards/permission.guard.ts | 20 +- src/modules/identity/application/README.md | 13 +- .../application/config/env-auth-config.ts | 15 + .../application/config/i-auth-config.ts | 5 + .../identity/application/handlers/README.MD | 1 + .../handlers/create-user.handler.ts | 37 - .../handlers/delete-user.handler.ts | 28 - .../application/handlers/find-user.handler.ts | 24 - .../handlers/find-users.handler.ts | 15 - .../permission/create-permission.handler.ts | 21 + .../permission/delete-permission.handler.ts | 14 + .../permission/get-permission.handler.ts | 11 + .../permission/get-permissions.handler.ts | 11 + .../permission/update-permission.handler.ts | 18 + .../role/assign-permission.handler.ts | 23 + .../handlers/role/create-role.handler.ts | 30 + .../handlers/role/delete-role.handler.ts | 14 + .../handlers/role/get-role.handler.ts | 11 + .../handlers/role/get-roles.handler.ts | 11 + .../role/remove-permission.handler.ts | 16 + .../handlers/role/update-role.handler.ts | 18 + .../handlers/update-user.handler.ts | 51 - .../user/assign-permission.handler.ts | 26 + .../handlers/user/assign-role.handler.ts | 23 + .../handlers/user/create-user.handler.ts | 31 + .../handlers/user/delete-user.handler.ts | 14 + .../handlers/user/disable-user.handler.ts | 14 + .../handlers/user/enable-user.handler.ts | 14 + .../handlers/user/get-current-user.handler.ts | 10 + .../handlers/user/get-user.handler.ts | 11 + .../handlers/user/get-users.handler.ts | 27 + .../user/remove-permission.handler.ts | 16 + .../handlers/user/remove-role.handler.ts | 16 + .../handlers/user/restore-user.handler.ts | 14 + .../handlers/user/sync-identity.handler.ts | 86 + .../identity/application/services/README.md | 12 - .../application/services/user.service.ts | 20 + .../identity/domain/entities/README.md | 12 +- .../domain/entities/permission.entity.ts | 40 + .../identity/domain/entities/role.entity.ts | 64 + .../identity/domain/entities/user.entity.ts | 210 +- .../domain/events/user-created.event.ts | 3 +- .../domain/events/user-deleted.event.ts | 6 - .../domain/events/user-disabled.event.ts | 7 + .../domain/events/user-email-changed.event.ts | 7 + .../domain/events/user-enabled.event.ts | 7 + .../events/user-username-changed.event.ts | 7 + .../identity/domain/repositories/README.MD | 1 + .../repositories/permission.interface.ts | 9 + .../domain/repositories/role.interface.ts | 12 + .../domain/repositories/user.interface.ts | 29 + .../repositories/user.repository.interface.ts | 17 - src/modules/identity/identity.module.ts | 119 +- src/modules/identity/infrastructure/README.md | 13 +- .../identity/infrastructure/mappers/README.MD | 1 + .../mappers/prisma-permission.mapper.ts | 23 + .../mappers/prisma-role.mapper.ts | 27 + .../mappers/prisma-user.mapper.ts | 80 +- .../infrastructure/persistence/README.md | 1 + .../infrastructure/repositories/README.md | 12 +- .../prisma-permission.repository.ts | 53 + .../repositories/prisma-role.repository.ts | 109 + .../repositories/prisma-user.repository.ts | 263 +- .../controllers/permissions.controller.ts | 67 + .../controllers/roles.controller.ts | 88 + .../controllers/users.controller.ts | 177 +- .../presentation/dto/create-permission.dto.ts | 19 + .../presentation/dto/create-role.dto.ts | 23 + .../presentation/dto/create-user.dto.ts | 19 +- .../presentation/dto/update-permission.dto.ts | 21 + .../presentation/dto/update-role.dto.ts | 20 + .../presentation/dto/update-user.dto.ts | 14 +- .../presentation/guards/current-user.guard.ts | 27 + test-results/.last-run.json | 7 + .../error-context.md | 193 + .../error-context.md | 136 + tests/README.md | 12 + .../domain => tests/api/permissions}/.gitkeep | 0 .../events => tests/api/roles}/.gitkeep | 0 tests/api/users/enable-user.spec.ts | 11 + tests/api/users/get-current-user.spec.ts | 20 + tests/api/users/get-user.spec.ts | 11 + tests/api/users/get-users.spec.ts | 23 + tests/fixtures/user.fixture.ts | 11 + tests/helpers/auth.ts | 91 + tests/helpers/env.ts | 7 + tests/helpers/index.ts | 3 + tests/helpers/request.ts | 73 + tests/integration/user.integration.spec.ts | 188 + .../mappers => tests/output}/.gitkeep | 0 tests/output/latest-result.txt | 1 + tests/reporter/custom-reporter.js | 72 + tests/reporter/custom-reporter.ts | 78 + .../failed-login-1785604157244-cookies.json | 1 + .../failed-login-1785604157244-page.html | 1 + .../failed-login-1785604157244.png | Bin 0 -> 6969 bytes .../failed-login-2-1785604169592-cookies.json | 1 + .../failed-login-2-1785604169592-page.html | 1 + .../failed-login-2-1785604169592.png | Bin 0 -> 6969 bytes tests/unit/user.service.spec.ts | 41 + 132 files changed, 7754 insertions(+), 2037 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 Target V1.txt create mode 100644 changes.patch create mode 100644 docs/How To Dev.txt create mode 100644 my-project.bundle create mode 100644 playwright.config.ts create mode 100644 postman/RayLab.postman_collection.json create mode 100644 prisma/migrations/20260730165554_permission/migration.sql create mode 100644 prisma/migrations/20260801084138_change/migration.sql create mode 100644 prisma/migrations/20260801101438_add_role_is_default/migration.sql create mode 100644 prisma/migrations/20260801101841_add_authentik_id/migration.sql create mode 100644 prisma/migrations/20260801104311_add_deleted_at/migration.sql create mode 100644 prisma/migrations/20260801132311_add_authentik_fields/migration.sql create mode 100644 prisma/migrations/20260802_add_authentik_fields/migration.sql create mode 100644 prisma/migrations/20260803_add_storage/migration.sql create mode 100644 prisma/migrations/migration_lock.toml create mode 100644 src/common/constants/permission.constants.ts create mode 100644 src/core/auth/interfaces/identity-data.ts create mode 100644 src/modules/auth/auth.controller.ts create mode 100644 src/modules/auth/auth.module.ts create mode 100644 src/modules/auth/auth.service.ts create mode 100644 src/modules/auth/dto/login.dto.ts create mode 100644 src/modules/auth/pkce/redis-pkce.store.ts create mode 100644 src/modules/auth/refresh/inmemory-refresh.store.ts create mode 100644 src/modules/identity/application/config/env-auth-config.ts create mode 100644 src/modules/identity/application/config/i-auth-config.ts create mode 100644 src/modules/identity/application/handlers/README.MD delete mode 100644 src/modules/identity/application/handlers/create-user.handler.ts delete mode 100644 src/modules/identity/application/handlers/delete-user.handler.ts delete mode 100644 src/modules/identity/application/handlers/find-user.handler.ts delete mode 100644 src/modules/identity/application/handlers/find-users.handler.ts create mode 100644 src/modules/identity/application/handlers/permission/create-permission.handler.ts create mode 100644 src/modules/identity/application/handlers/permission/delete-permission.handler.ts create mode 100644 src/modules/identity/application/handlers/permission/get-permission.handler.ts create mode 100644 src/modules/identity/application/handlers/permission/get-permissions.handler.ts create mode 100644 src/modules/identity/application/handlers/permission/update-permission.handler.ts create mode 100644 src/modules/identity/application/handlers/role/assign-permission.handler.ts create mode 100644 src/modules/identity/application/handlers/role/create-role.handler.ts create mode 100644 src/modules/identity/application/handlers/role/delete-role.handler.ts create mode 100644 src/modules/identity/application/handlers/role/get-role.handler.ts create mode 100644 src/modules/identity/application/handlers/role/get-roles.handler.ts create mode 100644 src/modules/identity/application/handlers/role/remove-permission.handler.ts create mode 100644 src/modules/identity/application/handlers/role/update-role.handler.ts delete mode 100644 src/modules/identity/application/handlers/update-user.handler.ts create mode 100644 src/modules/identity/application/handlers/user/assign-permission.handler.ts create mode 100644 src/modules/identity/application/handlers/user/assign-role.handler.ts create mode 100644 src/modules/identity/application/handlers/user/create-user.handler.ts create mode 100644 src/modules/identity/application/handlers/user/delete-user.handler.ts create mode 100644 src/modules/identity/application/handlers/user/disable-user.handler.ts create mode 100644 src/modules/identity/application/handlers/user/enable-user.handler.ts create mode 100644 src/modules/identity/application/handlers/user/get-current-user.handler.ts create mode 100644 src/modules/identity/application/handlers/user/get-user.handler.ts create mode 100644 src/modules/identity/application/handlers/user/get-users.handler.ts create mode 100644 src/modules/identity/application/handlers/user/remove-permission.handler.ts create mode 100644 src/modules/identity/application/handlers/user/remove-role.handler.ts create mode 100644 src/modules/identity/application/handlers/user/restore-user.handler.ts create mode 100644 src/modules/identity/application/handlers/user/sync-identity.handler.ts delete mode 100644 src/modules/identity/application/services/README.md create mode 100644 src/modules/identity/application/services/user.service.ts create mode 100644 src/modules/identity/domain/entities/permission.entity.ts create mode 100644 src/modules/identity/domain/entities/role.entity.ts delete mode 100644 src/modules/identity/domain/events/user-deleted.event.ts create mode 100644 src/modules/identity/domain/events/user-disabled.event.ts create mode 100644 src/modules/identity/domain/events/user-email-changed.event.ts create mode 100644 src/modules/identity/domain/events/user-enabled.event.ts create mode 100644 src/modules/identity/domain/events/user-username-changed.event.ts create mode 100644 src/modules/identity/domain/repositories/README.MD create mode 100644 src/modules/identity/domain/repositories/permission.interface.ts create mode 100644 src/modules/identity/domain/repositories/role.interface.ts create mode 100644 src/modules/identity/domain/repositories/user.interface.ts delete mode 100644 src/modules/identity/domain/repositories/user.repository.interface.ts create mode 100644 src/modules/identity/infrastructure/mappers/README.MD create mode 100644 src/modules/identity/infrastructure/mappers/prisma-permission.mapper.ts create mode 100644 src/modules/identity/infrastructure/mappers/prisma-role.mapper.ts create mode 100644 src/modules/identity/infrastructure/persistence/README.md create mode 100644 src/modules/identity/infrastructure/repositories/prisma-permission.repository.ts create mode 100644 src/modules/identity/infrastructure/repositories/prisma-role.repository.ts create mode 100644 src/modules/identity/presentation/controllers/permissions.controller.ts create mode 100644 src/modules/identity/presentation/controllers/roles.controller.ts create mode 100644 src/modules/identity/presentation/dto/create-permission.dto.ts create mode 100644 src/modules/identity/presentation/dto/create-role.dto.ts create mode 100644 src/modules/identity/presentation/dto/update-permission.dto.ts create mode 100644 src/modules/identity/presentation/dto/update-role.dto.ts create mode 100644 src/modules/identity/presentation/guards/current-user.guard.ts create mode 100644 test-results/.last-run.json create mode 100644 test-results/user.integration-Integrati-096a0-ser-and-issues-internal-JWT/error-context.md create mode 100644 test-results/user.integration-Integrati-8202b-ed-user-issues-internal-JWT/error-context.md create mode 100644 tests/README.md rename {src/modules/identity/domain => tests/api/permissions}/.gitkeep (100%) rename {src/modules/identity/events => tests/api/roles}/.gitkeep (100%) create mode 100644 tests/api/users/enable-user.spec.ts create mode 100644 tests/api/users/get-current-user.spec.ts create mode 100644 tests/api/users/get-user.spec.ts create mode 100644 tests/api/users/get-users.spec.ts create mode 100644 tests/fixtures/user.fixture.ts create mode 100644 tests/helpers/auth.ts create mode 100644 tests/helpers/env.ts create mode 100644 tests/helpers/index.ts create mode 100644 tests/helpers/request.ts create mode 100644 tests/integration/user.integration.spec.ts rename {src/modules/identity/infrastructure/mappers => tests/output}/.gitkeep (100%) create mode 100644 tests/output/latest-result.txt create mode 100644 tests/reporter/custom-reporter.js create mode 100644 tests/reporter/custom-reporter.ts create mode 100644 tests/test-artifacts/failed-login-1785604157244-cookies.json create mode 100644 tests/test-artifacts/failed-login-1785604157244-page.html create mode 100644 tests/test-artifacts/failed-login-1785604157244.png create mode 100644 tests/test-artifacts/failed-login-2-1785604169592-cookies.json create mode 100644 tests/test-artifacts/failed-login-2-1785604169592-page.html create mode 100644 tests/test-artifacts/failed-login-2-1785604169592.png create mode 100644 tests/unit/user.service.spec.ts diff --git a/.env.example b/.env.example index c2b7a5c..f74dde0 100644 --- a/.env.example +++ b/.env.example @@ -1,10 +1,56 @@ -APP_ENV=development #development / test / prod -PORT=3069 -DATABASE_URL=postgresql://USERNAME:PASSWORD@HOST:5432/DATABASE?schema=public +# Application +BASE_URL=http://localhost:3069 PORT=3000 NODE_ENV=development -JWT_SECRET=GANTI_DENGAN_SECRET -JWT_REFRESH_SECRET=GANTI_DENGAN_REFRESH_SECRET +# Database (PostgreSQL) +DATABASE_URL=postgresql://user:password@localhost:5432/Database?shema=public -SWAGGER_ENABLED=true +# Authentik (OIDC discovery base) +# Used by OIDC discovery and token exchange (AuthService) +AUTHENTIK_URL=https://auth.raylab.site -LOG_LEVEL=debug \ No newline at end of file +# Authentik Admin API (provisioning identities & groups) +# Example: https://auth.raylab.site/api +AUTHENTIK_API_BASE=https://auth.raylab.site/api + +# Bearer token for Authentik Admin API (admin service account) +AUTHENTIK_API_TOKEN=changeme_admin_api_token + +# Default group name format: RL-{object} +# RayLab will use this group to gate access (default RL-RayLab-Users) +AUTHENTIK_DEFAULT_GROUP=RL-RayLab-Users + +# OIDC / JWKS / Issuer settings for verifying Authentik tokens (if needed) +AUTHENTIK_JWKS_URI=https://auth.raylab.site/.well-known/jwks.json AUTHENTIK_ISSUER=https://auth.raylab.site/application/o/ray-lab-core/ AUTHENTIK_AUDIENCE=ray-lab-core + +# OIDC client credentials (used when RayLab needs to call token endpoint) +AUTHENTIK_CLIENT_ID=raylab-client AUTHENTIK_CLIENT_SECRET=raylab-client-secret + +# RayLab internal JWT (used to sign internal tokens) +RAYLAB_JWT_SECRET=replace_with_a_long_random_secret + +# Token lifetime in seconds +RAYLAB_JWT_EXPIRES_IN=3600 + +# Sync / reconciliation +# Interval in seconds for reconciler to retry PENDING/FAILED syncs +AUTH_RECONCILE_INTERVAL_SECONDS=3600 + +# Auth / sync behavior +# Disable auto-creation of users on login (must remain false per design) +AUTH_AUTO_CREATE_USER=false AUTH_SYNC_EMAIL=true AUTH_SYNC_USERNAME=false + +# Test accounts for integration tests (must exist in Authentik and RayLab DB before tests, +# or be provisioned via RayLab Admin endpoints during test run) +ADMIN_USERNAME=admin@example.com ADMIN_PASSWORD=changeme_admin_password + +OWNER_USERNAME=owner@example.com OWNER_PASSWORD=changeme_owner_password + +EMPLOYEE_USERNAME=employee@example.com EMPLOYEE_PASSWORD=changeme_employee_password + +# Optional: integration test user (overrides defaults used by tests) +TEST_USER_EMAIL=test-integration@example.com TEST_USER_USERNAME=test-integration TEST_USER_PASSWORD=StrongP@ssw0rd! + +# Optional: adjust logging or other runtime flags +LOG_LEVEL=info + +SWAGGER_ENABLED=true \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..5cab610 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug NestJS", + "type": "node", + "request": "launch", + "runtimeExecutable": "npm", + "runtimeArgs": [ + "run", + "start:debug" + ], + "console": "integratedTerminal", + "restart": true, + "skipFiles": [ + "/**" + ] + } + ] +} \ No newline at end of file diff --git a/Target V1.txt b/Target V1.txt new file mode 100644 index 0000000..602ac97 --- /dev/null +++ b/Target V1.txt @@ -0,0 +1,25 @@ +RayLab Core +│ +├── Identity +│ ├── User +│ ├── Group +│ ├── Role +│ └── Permission +│ +├── Authentication +│ +├── Authorization +│ +├── Audit +│ +├── Scheduler +│ +├── Media +│ +├── Storage +│ +├── Configuration +│ +├── Workflow / Events +│ +└── Registry \ No newline at end of file diff --git a/changes.patch b/changes.patch new file mode 100644 index 0000000000000000000000000000000000000000..bcd6328dfffcdee4463535bf28d14421cd246995 GIT binary patch literal 830508 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
oo-a|Oyll2@&FP1ccT#zM0WBRf%PQ~x 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

#Tf^_D;^DYdYD&HUKZz9m*d>qU=2|1#yj}U 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%0A}v0rz6oRJ3e^UmW;{#@GcD}ClQo#I^U;)@l! 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

+!G>J4SUC=ihF1zPWF_ zJGeuxGYjEa#&NS8UC(I6Rr47*a2@%!48NF{ z-0U<;r(t?rf~D3zv_8fF@=yKr4!!e`Hk2+%`6 zV{EPFXr-WO#xoO?lFb?vR%M(ABN`=F@!ge4q9Q(=>~r`9>fKAC*?R5Mj$H4jJ2ulQRAu%sa~YXAxeq$rL>`Pn z!7EU*Sq9FaTQfgcLCO^x<9+Wq;+oqnz0COO{#t9gd_tF6gmTTn5j^;2G1EHw&R>1( zGtiBz-U}RatjOaXpvidk@{khktjaA8=r|_CmDd-|vE&5y@ z>w_<+xpw2%<2l!##od?mH`KqMc6?X%4Bmm&@t(THdz%>#pMdXr>8!=OfGn|I{4Bg; zw0&6rlw+*g)XRUPt3rKeV_ufwU8AOsM)odU32nYtcgYMgQxUAFm6mJMPme505vzIZsq5iseCp{LNfR*- zQ8)FKs&VskuhO4=KjH1aTtsX8=hF@^8}B)-Rq7S&j*jB~*{|Tzd#KWN{*ckztlyL9 z8`dPZ4z1Nj+y!U!xi;|y=++CB9-uwzw>5*9ep~kluhT}PG(Nx##f$V*M>nE<9{e+t zqj|uLvmFC(jaeE7H}yyvwQvYN_VMX~*2d3%$UI0ZkI=h+9Zo(LKcvsr_~Em4KT~-| zlJ@=c8T?{&pz8){XHdZ27;T%^sN}V{f|*CD?(E|6?#mD`f2?^1?X2!PoaoML?YI98 zMW#4OWl8x{FIxTq;ma+hxJs1XZt>~K>D}80Q=DQFco0+%d zi}zb*$p=I!${Sm@+hd;B)&ivz-$tXXY;NBfbyfBM-KeZ;o_}>}tGe%Ms;lbZ8?B0x zFYgm5skJ5=V`R%m2>N03xo|wsNu69R-?JIz!&u$ad+S~C_w!r(B+}2*^mV0zJf1-UE+7$SIX;0-y~y8fbawMnnCaKLAosL)op&ACs}^H*5+ld0F``C(#~CvS znq%55JR4Ao`&zXWtZHaYh8xarGnOkiO7amTzcml_e3&aWc-a?`#d=iqhvublkq+wO zVem9p;b5N2!}@YNiJhNGph{H(wT}6|j=kr+vWi*xdcj#Sv=@^pkdKMb3 z;O-z(^@#cRUWG*Mygkpq@{zxTD&)zxN~;{r`hM}g>uO+n4D=4Ta&DEnZ)hVM@bv(A zu>#%o!TtIK#gPyEo`V@ym~gFc5>zsi@(Q2K3ckoEbAwx%a)aaV!ITrmGY`%!81jKp z&OnkguIXNP_e*_b3^VC0(o*m3INHA7K4Jsx(#l=$0~~eK*W+n5@6C5G)Lk&mb$j(U zwp$NwhdYgwk?jneDr% z!vF3gLF0TQ-!~q6jyf@}R&K-98*r)?{282S+~z%6g%s*OBlG)x1_S2dIc;}$w^%3k zJ^Z`R`QwbAkKt=Qj%FY}=gFyYyoaCF1dJd%<9iQ%`*@%3epknEH>5k0?ip_h?ZlV> zS8g8AJdA%fzDESQr)OMG$$N|#<>PQjNgoqNi!*W){6I1SJJM)S@-bK4>&~LG3v#9+`I6Pbpl*>oP&q@_`43L zT64g9%4W5lrJcKet*fSg{XO5z(5>X{=eV)lJ^VEW=7t_q@T|21&DO0|px$dP&@njI zY?EL4djLmU-{6wgVu7Bx4SKtq`1MHIzjGHN*cHeXcYY^%*!UjH*Np#H;L`6+C zNNedqO^vnCSQ>LhtGrTJ1CX5sB$p|82iK_0X+Pk0k?$ooH z@_ky(B={AY+lM~oKJ>D8Q8j|PfR<6H6Y=a?%v#iyXeAltnmxx{jiG2Dl&5b4ws+ZLAc0|87JMx zJ3)J+=sxjtLB9uDex$eiHq5g7k>dxT#3#<^EzrkcPD3jy_H$h`{h#u`k^8IeyRKy~ zMFgtwomN@+8|>=$nUs$EpW<=rs+vv#d7jGWII^5Xz248cTHl_Mem~ zGKiw?STLh-sGkzzY|HO9y|Ly~UQ_%IpdH<1_LIA~-PtC6^+RoDO}j+{ zGT)k3mzq|{z_f(kW&X7zv@!E5d_jA1C*3eVvs`C^<6dV0+%O_xfb)7V?-|4W;L@@l z6C=GFHKyYI*430=W(_3l0nsXnSpE<0D%T0mZl2-2%l zRD0S=a(84%{w|AX)ef1gO0^IAMR{Jt&$?JtK2CmazbE>nnK$E2I`=#XGXTQqNpVk- z`_ayM7gk3z-@`s=am(>BWU#gB&B(sTw>@yD2YguOogIT8##DabEhRG+v$E*(rAk+u0t0%Q5L#sY$pa(wGb1HYaQmbEeg^`Ted`$?`Xs^kk zH{6q1@7*io_eSfXz2pnnlOI#xmbFx#I?`k8zrPdx{st5q$bN?L1*wU?;mx@!X4L?X zjBv!3@9CuTsSi?LYhbN+?Zk~mh+cn0p=WWCCo@#n#eSeqH znpRH4pT?D`0p?U+!+iZ%EQL1OkB`OT@^SKS;`hYjH1lRGPUoHni?2b*J@~@>w8ovR z!%fDQTAOknUhC!C9mxC%4zrS#*$z%Pt~XpCx%r%}%F>4hXDzCaAkIf{_b21*aejoq z*NpaoQ69L$2XNQ5Z7a}P=XVg)UZKSxZS|6!aCRQVa(~e$&YKr{kYmp7^=NzfojT3l zGuK)|6_u)bXaQ{+@i(ESF^GEf1=n za99+Umduv@6`HYzqh6YX$93=IX^3o%D7E8|U-67jzAZDe1)151&{12C{+_(oA?lp@ zqfd?R?~b;dpHtOL+j%R>?e>VUZ;`u+l6s-durDCK(f{DxmaVr2N_Q7c@YHCx#XkCv zl0T*sx!CSr>Uv&U-BVFg#U~N&sJ+)E|5of({${G5&~wb7S$FEpx-w72SANQ=rJiL~ zHb&#qt&VkVj~dUlmL2vMdFMqb9`ELPB)Hj8to5irocaO2b8mYOlJ}Z3BUnG<^e{?f4Jm$tls^R7uaU@ywAtp@ z{1D2ZYg(I2?+0zBxRMzmK4XDh)56RV>l{0NRn}C!HK06A20l%1yC|m{Wl5mZ_AA@T z^Qj-zHM5AZ5hIOhtG7xXszY`nb^mqjkOOFUA1V*A199cAh_7|gt9qwT+C`hH(e&9pA0JY9^04@K2AFIY#wJ8%wgu898Qzk<|vbXeGYhFazUs zKXWB_#O2rRi|_aM@jdcCOs6uqTvj3PzU zkJ2gje6F>qIO`&($K%h#;fGM&W#&7$fcFOZv;%*cL4OiXHb?#{f4BLz&3Sjum_gNi zK;{!RGte5`Jx4F=PHjNZM);hhQf6n*9H z8@PRj);I9>1T6;PajXtR{Bc@PCu8U7=y%kL+TBevcD8=9&x5H`pyWsJZ4y1_CmMWBO>+bqE4c@HpMbN+jHvZ^M^AS-%`yH5K5M}k=X^u!f3K`XZ0qHT#q18NX(*D2{^?R^>nv-95K$76phpV!;JB|l!CYr`DkUAZG#J0V(9DVn?0K7-;I?NI+; z2dT@g|HmP7tFiL$v^5g9@?Jcjm#sMaBJvi`N2Cq2?bfc62Y6IV>N67bCm3fPx;2n+ z1l@B8d^2m_5}M>FXz2ejaMrb~Iestr`-8swoUtar0!Vt7eVPCl#pMb3UvxG0!RXa< z#{2?`npbszD_99YZFrv1wm7G)IstzF1YHL~;axrrWthHSK-v_m7kI7AK5gcz^4#KO z-u&Nly~8_7lpVe7=~*;JSs86-bb89_@Dz)%^=N5M;cfhWwqf)9i~QEyB63_n`fhRD zS9Az#xb(vf_i&s0o2{k&9)590hQ6J#?3}C7)?(e@s4+u&aPE*qSMZ9_;H&V8erdhm zMk9Wvy)j1SHQz;#v0}zI`VXP0T%b=`ZAxGE8ST7+Qf-NGP8roWB`XtK$zzKvS%c;^ z?U;TZoxyBZdQ-meo10~M%EvqI ztxC6QCDp^M(s)&4bfV*h%86#@drTaI5v}|5bj?1#tE4%{%r}EApO0_Z-9GslgiL;a zfH|G4JNu?xi_@bT-*-_0zGItU*?1%QOhN^T{EAB@Jw))!wcxByYGcj3VK*`&i`8eLwUwwBGkA?M8 zSK&OhgwI@MlIz_ebp_ zxAWZF8R{gNqHIVqvkKYktq<25H9zm)5p}BXqlh}yEuRN&%_H1%?>Q zYJN8>bcMXn)|EKOwB99pPJk?ZoU=}aYuGdNHwVlTvP@5EFMnST>O4LsCgD|#jw#|) zE4e8rG+OBY#yn$g!+zEB9kzMw=oItRT(yLK&I$9LqG##TZZ~Fr&c7$#mET1(+LgC^ z9;~wpo3#iB!7OXws>go-t$uFYxnIC*j&VIJbi04by1Q10n*!+u>0=C{Su)%KFvkC{ zoPA9iR&xZuc89U*dN!ozgkWNq`8xgE+N)lkHuB=!4dY%@=U+3<9GtHju=nKwUw!eoLJCBH+qIl!#ThRkiS5Ivo zBR{9#6Q#qfn^8F&e;yQ`2TR4r9Z;_aT~NFCBiytD7Fws-yq;RZX6QHP=M^^W546t* z5ORj2{UGURhMvYi4RY38ma`n`p_hIRI8-ylkqbt4#d{0f)JK>{ru=$J`3iJ1$CbBx zj+JUHuc|zs<=1PsC#~GVitoMA0?zYY)I^QUX?`MA8cw^}Ec2G?=~^*pPKB2J?4h&Jh2w8O2(^IXzA8j&;2#ZSMZg(4@VxtH--IvY7G_(!{? z6U@UQoA8NyC$ucISZ+8n&b+=s+j7GdI)Gd=$&dS}TytB4SH}5SptU)6tR}DnPn_|0 z1nx1%gSAYq`M-p8mv>y_^GDsnh#YGi_H%^=`sr!9Mg}ayS!O}q$uxyau6V;(?l*l+ zu{4kOk9RxHqd6uk>IiYSXx`tR{6Xe!7{mM1&)W?CAam>J4;ny!Yn|00PuJ;+K_73Q zAt&Ge54gmPL)yO0u`}&QYv)m_uPOZwF&%kS>s;SyL=-)l^&>s%>p-1eBY#i7KT?O- zld>n*4#TUS`17E9h*W$4!+XJ6<0KbA_>b_f8vO{G%N?Iw2c5$XGo#}dc>WZ0p5SMl z7JJBtIZ$|xvnOD)S%FSL>RH-<2j8doIc0a{zffw2>YNhN8=dZL&mUnIT{l#J}ol1PR`p_>ygdXJ>T&}v{s@{8lSMb zsJVQ@>hHfAO2<8m;b}b9nitW^MtUts9p_$-)$#1}p!Ffv`56d#3})VfjkDmgdr>Ap z;U$n^6;15~yj_HT$2eoGhO3looc#&zuJJQQZ)0nR!Q&7CJ_Wvh0ng_dQ=fn_CExk9 z%=bA)nMB9i2ldyWee*k+4`rBZeW3pgKcifKf%aA$4_-G{AYPBY*BGnu90>ayyME1l zVXYhYGsGCxq?1rkd2QNVTjJgS}AHNr*ou%FirHxz)865Yx^Y8fk{wwqP ztJ%ZE%7*1ZZ+2LkITi`7m>Mm{&}!@9h&R|370|4E0Ayk%(N1RnQY!;pRa+1M$>bATIA>nc)AK^8y{j;8f(stfvnbYHOkJlT+!W#5-t5nMjhdt zk$snpVExHGS}oARm69I*yX#?;)~B3Z;i!3c^Q*7L_p1lv=1=a5l|uqwCQrY8!Wvao zy{Y`FU0ACv^QScG68V{gYcxma={rokA0qPfJGRTOD^~8&SMRnqeXu#*NtX5&iJ*?? zZ$DS5#-sea&KdQZQC+E5cf9AnE2{3kGvDl8VaECKlQwN8G<9dIe(IAIpZ)z$-f=r^ zTF=52voLDWy0{^`?K$7_Pt0c(cFVQ8zs@rVRzE9uMt+B;l8qmqv%2)ZRFY53k+f5%|sIePFc-#)=t!|>@4pI!4haa&Mg|n;ST|a56Kv{1DjO@ffR5q%eh)M`#GF4e=P&3WR^mAW`9hv&SB&qN{bz9W zGxst_-!XpNKc}W?Ec6=q`V%eoJ)c*($3?KsdJkV2{WBP-r(y(j?L{A*09U8@tiQRR z(FXW$1kNlijporS;hw!bG8XT*T3;=;)aPub3cayOhcu`5#y@qvVjo*SewV+IgH|5w zEPBvb2|Y8u$yjT%jE)0MDpyh!%_1c_cXO6l4fl^f5vP~?*RvVC(qGJBF#XG8p1+B))&+&KEfr_&)>O#fy&!ZDr^Tn)vb8zY|`pGQ% z$}KctjdXYHYpa?U{uAfEaCQWn)_6PXApe9Td*SGQJ|Dt4vuHX8oD&TuLAY&NsLQM~ z)&qR(K3Zwes>_@7*#TdyM5EuZACwql2CfvjQ}>c1MgSi2e}sOo%~FjXvZw7}uyUZg z&Q5tM=BG+X^$&0)Xa;G2SDxkrBGl828m-Pj-ilVI)m(zr=_*dNLv7iN0pVJ%X@#se z$tG8i(#mW-%g!y#<~c--qUf2Zio$60Hst%nCs+RL16DQn2))X+i5MxHo3f5$OxD-%Lu2morhOO&^>PXIYz@c zf+oGv5J8X(8$yDi06yvP5Msc zrF7(R61kO@-b{my9GR}%8DACq{f_)poa0}ekBawO#y`QvF1CCcr-UpCVy@hoAG?{t z1D*W}efu)g?hin;5Fu{8iBP4sOv>et#rsIu(-?W5GT9}6>*I9o>XCeI>F0OUwDWT> z>e>0T&!c4zBA3jLU=*gYm7kDWn@FpE-n2V(_xQa+Dy^YU8-G8+QTNGNtsv~f`-v2r zpw$|()SMdYe4AwzM|o$SZF6Q>vBXT2=AHS7%roZR|K_ti=1TL7uDt8zdg|pj^j_z> z+I}DS-p8!+dt1_b^;4@|c8UH%OKJJ}*Ml0h?9L;X@^=^J{nFmdM$LOT)3c433Yxds zCBh2*5O3y9%Nn)hbVXmhE>uSNlVQk1O~p-a+31zx6q! z`NZsuudkkBo?bfhdo)M2Jr;*up=``r8OF)a?e|3CH1lQ*PUoHnfsK5BfS*K9*JGyn zwgmpU$8Uq*8LS7b2(u9Sba(Jlo*;$$;H6Js<2^_G`Hr<=z41B5+5lmv;X3n>&eOji z6kTJCX)xOi+-5!0-WkojACt7$LkkgU#c8pBiGJo5)8DGC^MP?+*NS{v@kzRVp5QvC^xxkIB{1c9uE)ei-W zZLT>Rt0_*+!6VjT`N;oGKJ{^I7c_I7XB})ZMs$gulc3Tde@Ezb4klS?%bX7r95=e< zjNbxdax70=c4TaayrZ`L%p2Oq_Sey-dY`B}W*YCAB`>-8dr@)~HMpjK}tpiQ8> z=DwX#U{(KU(VgjS{Qo|5vBTs{5{{%&H!(?49yHfx^O` zT{Fy`!i#Z*PiYhN9i)Mb2#cTz1na}1d8Dg|qT6{uZ)Uq%i(hS$tS{Uc^C$Qgjjt8WoS>d!nR`^+C zv_sAq3!nGA6z{hhk;+=Oi>}T03H;sY`B3{6(W1O6*T~zA@|fLZ?Z>QF;jC<&#O>+6 z8d0{)2OXY`wI;MIyd$G{gRd!#(w?UxhTcJIjeC8AccwAIxNPRuhl~5q^sAWD(8%62 zgSc{+B9+U=i8BxOjWKW5jZdT0y^l0bJ=?AIT#AtnozKVG(At5GyI({SPoX+TZEe`#&vm&vf#%+ucLmJZSCirHX>W zlW3m_Ek3pMzvy@LOz~Kxv7|G)Dx@~(4hQ{P`uqd!7H8O6L-|3!C>M%7!#$N-?J-&< z?aatyLicr!Fw>}Ogl{3rL7$NG$wxU9=Tle1&||mESbNC&V?Ny?;V-bBN0Iqj&DLdg z*ZL{;_X0fA1GV3A{0kaHh+f!4o0OBRI`*A2$NV?@&QJQf2K159hiTzHpU1QO-13mR$?Q*S4yjr~(zvO*U#rrMO zucf5aE>co6rmB5>|ED%qM8)>>R@OgV*H2aJInr9I=(_Hssx%en+el~eSfH^mr*6^M zE${j+vy#T3k006RU1&q3b4TPn=Qfzt6i0TU3VoD)(ApyB$1}gA_-KzKTDelX2(5|K zCyXV9TEpNQG_%3eG!LbF>t~_HbB_FkdZxIpnNPm+BgVSF?}8)8v^~wJa0^7T4nw2A zGf_%-hpl`>379L&^m#2}?FX+Kxr(crPYE*G0V*3T<3R{Z$_h=t;{TB^YCzM4y!`(GVUth*IaB_*BZ=I z)?4mc393Dq&g3-{=`PBY;#HsSYpvR4QctG+VD9g@hil%+S9m6_f_5s~T8~qo^MaS8 zJbL9hIInr$i3^+01&)lKoV-<0yvMqF)gVvbl{K?&t-}%D;SIB{Y`~4*k!ha0f`814 z^_A~C@Y*%JdIXo;(CQja(Jy%jzny@VMw6{(t*nb^PFLfjHyL}2cK3Y#40r#4?=LbQ zo@NBc-h*fFIIHwL<;r95;V}QLNq)(dKQdCI%q!k+6-TCakq45r47O@`&PkHJgATPV z17(`iFvL1}{DL1nmXEV()x{n4Dc4H(a zx1^LS%QMiTwF`XT?me33zg4DYIrfEX9znrY5Z#BKe}KMHX{foPC2&EX&m6Im$`o>` zmo{bvpJa?(db!_i2tF}8#yMPd40RvCNjtPRUs4}*zrZ+FaG8S_%#&oTml66|anPNP z?qAGX+QoPLRGv_S@oufJs7J>v57FyV<(p||g#;?8KXUP&;`PmP61}Hyd0rvE#LLrr z>pLk@ck9;g8t$Wew7dtlnrn3k3Ufz{SqL^j>m}aqH1F3K@NZC-UL!L#nU(b#+S8{K z>RE0xFYB{Of!10xhHQ@B=d?1~<5R{VX6M$T*0(>AVWhcFdZC`>td;w9rCq&PX8RgN zpEDlh0~BVIa(-Q^_}-sR%jQP05=n~TQbrmLVU?11%q#3#H8Y=?3Du~iv2gw|KFo;s zMvQgq+QsKm&JWQp{uTW2w0mvln5T^wYTk5LXPU_Ll^;+|5A@`&QS*qJMQIEApMi3e zA7-&L(sC%X}U z7Lf_J^c#j_R{3TXic_wC4L_L~#Qp!9{8hWs>Uln$Y3Pxbu{@RUTaTud^Fh|XtbRVk z8+pfX#DgKerMYwqr`@%@3dI;1@CAC9~f&F6TPQJ(p_PB}jdy$y3@n=@1N zd0;Mc;I(Rh4mT@Cxz2$z6GWiptJ{rA2c`G>D z1^J^-ji+r@zp1`$e9QAU_gY*_d%P5CHBvqPi>smoyydc;8P8=O7iXU5#^Tv`(0y3F z)qB+)8+kdiWbfd>J`mQd-+S=TI-F&6%_2InD`x#@Jyz~Ezmr*|PvB^IbBNZTnU&GA z+PZt7w>8Sv;MooM+I%DK$Z~gpv2^;ndbrMcCJUw+Wr5FD%&-EAD|A!L!Q2VvP?+ZL zB%JCF%3OH^oN2dH${ir-N=l3n zogJ@~=ejU+eR$Pb>joJwj~(`UKK$~&<81Tj7-k#t3&neEhj?j(<{8(q8jGCX%bS#H zzWl9uCxBGwx~jZ>EO4))KGL%A1y_imLv?nNTBLD_6?L3ah2f=OT(XpV6^ZHAgFugm-*EfU~c<;^f}|ZjS>hI@7#5N2Vz?7&Ky?ymU}WBJ_kQXc!S22 z&!c;O8AG5ydyTeckhUVr2v@z~(;zLkIXceu ztb=&~{kK{TP3ZYpj%&o{Vgy03G|HcJprGfb@@DJxd2k{x-NQAWjt^y{cKXEfV+1@% z$081-BhR7DMP0fRZ7y+cxfc6t(IY*t@UH*rs8PIMHTQOrNBKVCIkiWNvR<9iyw^%U z^&*C!&KMRBb>CPc~Yy-}7suX%0o%Se#2;>NeuvwJKvad$_mvd>X-K z_=zkt-e4XHc7T-h|a}SLA zo?}*eo?+}>EFO1Lt#EXN9v(N=!Q8P{Q#fU0_g9%e=Y8f4T}8ub^sVP5R6v&J&P&s6 zO*Q|{0_{Cr0+o&WGTc}tGum-uzF&U+Rotj2>19_Znl;rlhi-A>9(-^FuNdXJl<9)5 zMSMh)H1_`soYo6BY3;lJ{|Eo?IW~!2d&XyfKft%gaG04)?%Z8}T(|dMBFLRZe z17n|W*5!E*ov%RA%1J+e;?pTIC|G-g{2zky&$;#?WA$=P+nvB$?kyf+G`SJPJ@9OeMR51|Iuxtt_y8)O;fbF^>D$n_6{@b# zr^dkfpPaP@iL`wNdT;T4J=3+8(XUqFmRsJGQK!a;yPJLm`o5r_`QpdB?HiXG<2qN- zVs3@_<$deZdhk%b4Cbe~23k+wpJV5Ov2d*2NH~B}q#|p+@GMVxN8efNdj*uxgw2=1A z>$%9dgN$diy#B%mxWxSm#?P6xa~2+G<*O^F;nz;si3}LWvlPd zr%_A`^!)-&4nyC=^q->rPulk~;x0cM9CIad0&2bblWSb}a4mF*k@12LMxtQyh2jO#@qHlQ3egM^CN56!1xMD{+r)T_MhMPZe{(`?swg<35 zUtTY7cn7&T3H4YHYJ@j`!h7xq8}85+FF+7ixONz4le@CU=>y-tf<$YKYE?U0L1hb)~^=Hv2NbT(#v ziWE6s%EoSg4~ZIEKfgeYVeZ|c#1Y>8Y4+=z+ksNtjlT(1S$q5&bTY;H0ci0n-+w?s z)&|pWG?_^v?Q8efnDIheW1oHl(DVrHAD}2@n{^r|pfl@*7*8u@S(#j4)K6MH(B5d7 zz3hr=cxzn6UEj(seO2bl$a|`a@4Cz`uS2sTQ&Y$rrO!L%!tPA}Z#PbHzU63X))S@D z%OPdiydyo9oeLRS!W_FrgYNL!fqsTTk8NncS~Kh5)BwL~{=J~m4&SDsm}zvTW$@74 zZ^nZfpJ+aT0ebX6N!J|hgSw8PMDsWsC9ulK*0wVe&RD4r(B=nvShs0|KE_*F(|Lfu zVzBmw8DK!UG3_c0n-itlagT@OuywH4}Dzns;TW}I*&#wf?^BXLgMLXaCc^#mTBhR%nOJz9JF zaPT#sb~$cdNxj4$kVhiLJ*aY+S!oNIM0*cLD7B`MR42%>L!^_smOGY>_l)i~`Ru+m zb*Dur(wcDRQ1TG+(mK|zhnSVgofLillwF-uUim(Nr_f%j5$jQ3e2Xu&LePlgQdaQ} z%IUAz>N!>uCV1CFP=wi$&FStcv)Q`bUu+d3_p@z6MOM7%0S)J%mO(ISoufn0sOx9e z9$KRPB===*8EwZ)sPj9cg{(5xV^_CQ+j1Aq8FaP9w=eWP;qx8Xcfhsu!-|I1Mf#at z+srcV#58MDi2QgA1*SNd$7MTdet*>?)}uhBYw#fb8vF~IikhAEHC*oue$G5f7F(sb zT<6~%44i_>+z~kqMXW%9=DrQ}rj1gt?$HV}oQ7_OpipJz0+eHAt93N-Z4mSTDY^-@ znDOf;$Bm!ZhsM<4H!@n4BF%NO2x@LZzq>s9utuhz)OZMMFnjcvXW>&BVSgluxitnXryn594>+!E~{#CTs*ycH~Z;kh>2jLt#G6(no zbl{$uuY6KJ(;LrrFG!jwI>*st4bJN2GX6?5@Cz>zK5oI{=N^)kP~Bs6MOzzHbKXstQuvk!c`%y81(j7D&+^7jx5 z+5-2~Cd?Og27S5LWrr(_(Px?83Fy!G79%;03Q)rDXF8-><~VZ_7cZI3HZ9ycW8Tdf zXm^>vtMq>gHoCXR=U`rtZeU~8c*VC+?nR5#_$zGQpc^*MzlsJM+a$_!y`(!*S&iRS z1~U+t5#g41BSOydri_3U9mO~^Ye-M$eAmt}v+)|V^qE$!k*`3X-=V%9-tIj#Gt2K6 z&Rdh&nnp%xN%JH0bLa0zS{lJM#gG1fGhUuSU$=}d)oYb}q-76B%;IS_g~#cI?jZZl z70f9W{agP(dvDqlx3Vs3?w{iDr|#x>gP9EX!|erT#>_J}?ml6#0W;4A;>7*!{XEK* zJ4-655Jgd5UVWkhN+l^%naX#{cWj>?R`*sP>Ri2U`IYA-+WhFtU@m`0fVeQ;PC?u) zFmTMente+MI0ufNGU{W#4SmSX&hdpSN`oq;+|O>c*quZ%zdL!!(-^( zG~aUPS$Z_vq|&214lQR(^r|n&eb!SiF!#h&V|MlR`%K#ddfMbJ{nLf%K`33^iPYEQ zzEooLZHLNtuce3OJ=KTFklFoL>`~IltKc!bp#Y0voSlM2Iq4%qbpEDt)<$Y%w?>UcLh{xZwU$S1u>?_cTJ-LhVm7eH;4^~y|m<{h+Mmgo_T8_=9r?;tjS*_7y{W#-@#*iv{GTv^V`a@}3xu&-sxb8gnX!-7g z?z-bvHa&oM8J}rP#RN~*5@@uly;v{8SX6aL(;QdR(e6ahm1mA?^ux=`#KKyH+&mo* z^u8Ubp?M7L$PA7-(8##Q%8xH%NqDcFt8djf`T*mNXM(?Aq}_S=t{PumS~-q9tliKU z=g)l409oc;vp$Jh^(~;#3PNicw400Gnr*AV`yTBkxbg&tH&gv#cIG3!Xww#ge;{Az z*I^A>eK53chuwW2@NTsSJqwLdm`1XA&>$+(wgz}pS;Nn-k7m3jWwFh z7u9KRyF^{pzPYmP$Tg{#AQ`oiY8qj^T!QkQRq>=|oGq?OXJwkk(Y_2IG}L&lRaWKBNJ-`JAMrPQS3#vaJ1KUzthou_(x{8lQo0hNAj0@M zB{3O^VD7k6@c9tGC&pZ!zX*L1s;^;aB zch-tBhwFU?eMZWt$8c2odR_u^PskU8K#!I*bsxq-oPn9Qv{^xh(Nom=B&S?CN9Hi1 zS?@b@K+hq)oB>68@|lTdkuwXx_YeB(N1B=A{2DEd`1fd!QH*fx-tC5d&Var-pj4LoY|8Wc0KIi3 ztKV<7<&ssW;;D`2Y<{2hu-m8&?H?alMZL77`|V)$bNv*tvRwNwtx~?}o~Ej7+!2e* zu7xZLVT?synBU*l$6jNh-Mt%?w*syxlUU(*AFgHw1Z)19r)C|zRTf&}x{)?|Hm&l$ zw2bKyGRQBvmwBB=kjggsv$oI#_`6PTdTwf`3fyr6UU34pZ*Y(F!YW%|=v$3|84>lE z*CL=F)fUH>NN&+$-wbVk=h?n3_O@RSHF=q6$xw2!n&uBy%D7H_9^1p@=$rC)Ym$A%_|EX^LvTs&SF?kD0xx&LRsE)WS+Py7?Lz&|!NptdFeCRO z|9^1xk~NlJ?{QxLL1kns!f4Cx1H-LQya}!@arZXozjMz9{merZ^pUl0@>ia@!t>OC zuk%}9F|~R(&<67`SUb4~UOvh1vyNcF0WZ2#-&2=jY}y4*g(d+@=vy3N@usYF#z z^=N}R9pw7mxa*n2k{&0|HPg8uipV9X6v;Qx87G;oMwO$wS-f^+IRk&m&;1v zrx{lgUVDJuF?iZCf5u~O)2m)6dTZ&qr+3K(yUZD$Il$_hb0xyqYb49xZ?@&Urc?XE z*GQJWORY$1O1Fs~1M=Zuz>D zafWbbk)BCw-#+)f)yVY*kNn1LdT}RTwKs7M-@_YS`DSd0wP)-l<{B=_Wp9P!!doj0 zPveOEH=Sv1&uE77R(9a3ck>btH#wf~FmdBF*02Jd<;Klp4jA5iK1hCHY(@Moj%rawmaSyi)yFCttGkcZBR^_s{m`gJmb0<+mzSOfDW}h$6)IueVRwzdcrrriE%AHTPsnDCM{yq z-*>jhgh8sRwqMgmufP!#Ta&s!D)TluJzKkfCj>NPf;fC=h=_i~t8-8RnV|$Y^sT%8WOk08f{> z=Lb~4+B84FSoOSmN@^P&f*M%!L(ffpW6tPv2MVC&#U0lQM?X2Uk{y|yaSjUb849vT zPwv$x>1~r|8>cbPZ{sZWWj0FgFzc%ml;HQ9?OWky$XeY>)=robW$grGdKpD{jW*V} z18IjhCrfR)Q#gV;%s^^LEerdEMjhPj&-@(Znjf4Tm3St zF~q*s><{Ju*@6EWooZfQJtB;V-T;ecIlIH%`VT2%uk+TdBeF#+_s7QG_i$EzZT>ke zH{NUR-kyxN_d^3_IkKA73V%=8j@z87A31*D>K428A=+4b&S*j_)I~j5faL^5VNJWS zPfpO9_{sYWW+FW;_crJb_T?d39YuL~6*$#%!m7rLV48Iw2H?KR=VsyC z0n@aUPG>mVDgvi$Z(F9DF1zooFyVC^=se>>uhZsM_fZcIf}Sk+BZjwBY}ff+Vt&jC z6Y}R%G@3E&`JH2NjCHw=mDi4eR4r-ee9S%&_IT=RhQSQ2a^}}C22D-uC3joZK+WzG z+-I2oQ$VZHy5<0sLzweGJIYXY&lNqX!BHbL#Q70^DvXOhn;$G@KI7`-2~vmbaD4~*JM3i_F<9f|w1e`S0~>EILRn(;A8Ux}`}cCU>n z`hWg>Rvr%O@}2-^jnVlpmHMiB$d9Lr_xQHtKi#ySG>*84ap6sb9a_pTVT@=NBXns>vjR0P0;dZ#xtzL^~7&?SQDI^ z0HgM}$E^Bhx7Jc&Hsg=D*lcdndw7^URBx3fxR`l!mskaLp+<#F zz&*`&rA6m6a=*G5^G6!fu>%J*V)mH6w5eJLMyu%!{Q3wC)(6J=k$UJH)7rfGR_s$} zGe}G0XO(Bq=>LH}%_I2y!6-E$r_%+j87~yXoXOfV_7cY_ew3Fto|MO6EA61dFU|qgBxg z+y|N5ISt+zJ8}Z{h>KhBQ|p51>ncZePiICZwXH@BinGej>Og0Bq83iGu0L>fhbLRn zY?^a@{L*(~1_@hSJ_Z6#`8L8U>P7>^CW;>DY_~KljZ`#Ax9*Qx(ep6IvV1anB1BIa zwG4UuuwCR~ot2IMC)Dm8Z@!v~rsp+}pbmG8P}|A}LH$ni8!gJ&;q8^{MSb)BxyLT2 zWp9J2k!R*HHJ%N-(lD+frl$8A=2cfpmV233?+3VGhKNbDBxVZNTgd(95_%Y`U#mgU z5^=_Rk>9E%HBQpneYf1V13sCxYM7Sua7}F>R-T;zx0g7tZqq%exmc#@;T!#!ky(7V zYR57?sEg4vQNP2ZjDPOKO$WI$PA~agsk2O<_H&N3f|Wcqh)=7MzM5gCs{LOLcB;nt zcZZ>>dAFkafC!pN?hJY&>%El3+MCr{j%rf+cwkP&|BxEvxq6-yPjr5-*dCC zUGg6P2XC`Tty}Yk^49rrRN<{0)}2$L^~H9b#@963Naxd;5K$P$Q>5|5an;4oDX41? zZ&qE#IRDKqZM=}$kX_D5%a?fvhfs1eRh{u|MF%UQ4)JXypqk2i)<}&?4|f}j^chJ? zUE~c?ig827oYj~6i8I#E8Q^2Joe8M=I>%~M%pVl8Jq*!rFCQyc$ZyoAlBG^TpUz=^ZSzs% zuWV(;%~7t6fm33NUfKF|ilw(19&d4n_0$?QiRrDELxffX>jSkH;a%Q3J=3EqiYtUj zb-T9@PNR*GlFkH(3FGM$#N4rF2h8t*_1$Hq^rbZh`wJ^(l$NX3%WpNrtNd0^JP5tD zZkQBvoX-_!tyM7xlvvAEKZ0>um^C5L@IH?9Bw7IOrnxds-)g?B^twYUEkrl0vXML1 zB)H-}tC;B7mFM|=u(dplQM=#`dI78vnd^bDCKz zd9!|h>CJ}KDd(83YIw)xE7R#rm957gC}itIj9+Zzb%I!uX2(I?22N-|Fs=dVmN0GV}#n&ZIN* zrXRzjpP+=Ffrnjw>9?^BWXORBIl2b^tRP?%juCq1N;2c!G*rg=DZTu;t8zv43$&)$ z9nkifHhXaEReqU&cn#PaWyLS)rI%~N+;<8#=%u8FTF)l+V77_+>Sj7z-&Xwl&9;1R z^?HrPYkhfz+zU909Q%>=-~W?qzC?S`x{rDot3)kEbW5Uc9&^Ii{QC&fbr@R_TZ?n6 zi>*6gg_#j1!5l08>cO!F?yiEfMzyblP4Wouxqy0WBhuqym-DA!xAOB>c*-Ha&5+~1 zQTweLXzL>EgT?E#G*g26GBqWu+-Y?;H6Z3bvpV54Sh>wFb0=MLyaVo9TUZT;^{36y z(CAfIoNv3FB2*R->b~(&a`jl-c97X#27UE|kY8S@WDTuNTua@tFjL!6C ztGv$&@A4kZuJMs$^#kUC`V4$bL4A6lQ0J^vKM-Ng$3Ez!5{eeSC$4IT*Bi}Urf_dv z82zEoXy4Bhw2bSWZPc(bushgE`n3k!0Ai?lCY3H!26>jZ{)hfmNSee2YED{lwQxOF4tk=Bd0;@M@! zVJE?Stx*fmFKOE@ywki@=FqaD#Uz~figPopk6!cg>3yh~`EaFaQbs)s)iq3TUH!X} zPRq3EgT@)FVid|feQh$D4fyeQdV5<*Pd$~eNVbtHd6YiGADnep$ z^hJ0qUQgP6N82f$Y^K#kAi^ALgTRTI?#;@!!YZkKva*jA1s8zYe)#kjcU}TXu3bNn zrhaJ-*wV%)k3I&ztgB+|#T@q-MLY|fX_eL9ddj(d;L>QSGvM%n&l%F;5YVTF%UXqM zkB4Y=3yfQ3`T>|WUwY#XBvCe3y1Fu3o(GiQ_f~uIprLN2;zbHxMXlux?NR7r%X-+* zC{=`aQfwzocCOBla)WQN~H_jdztN&tc7iEDl=N>#i=Gv z{p?phW|vcEw#?O8u1_-iz=!YX?;E}7wa^;MegAKrPfG7_qn5ri-T-|@$-cy1QqNN$ zu6}$*^b&~Y8~p_GSRC;sfA+QVZIEcoJxs;n1bgxMi3SCJby(wlPwDQpB>H2P4Cwi2mc-|jUB`2CeD=Do1L;6>qn)aoW`@Sf<^x~66^9_OCV z{LMls%#LAw0%b2FcJ=Qt;$n+)7f^!FP@tdCp`VN{>N3iAo>h9bA|{mG_f}jk?7AX+ zwae`;c_$x$c`KH^4s)LGsUFru`M-OTVfn}-#*|-8c^W$>6Iz4UIG`tRW(yt{B6*Mg zloPFpbO;|ahrjtxtzs=!jB>XXHtv9SW13dMqdoA%9g0>bt1gX!5gXin2|g^raYy+3 z2wr^xU+&?z+K85U`XrDr!m+s>Z)jl_sx@fX5AIyy&ROoYvfs=1D&=_94Za$=!3XC4 z9Xb>FUdq)N;~VnW9Jx*YY$v!~jBd!|Lp|wKXgq~_9sW6wqMoDm4z9d)ejHWYEJ~@} z#mg|)MqCVMlC;`6{1cyc;UyD5{#LdF)7~nc^nw-UBMy;$`mCC*>5%)i@O%RY&%r-y zkL|P9GHc5dc=$k@32^8mc%vUm4|rw1mSFWUNB&nZYlU;h>MONw(Bg{UdL%6HYk^+B zfOAib#~6I|^y*;q_?P6NAdS2nt85W`m#k3|F=U=XW@(wDc~6 zM(bRvTYSgecie66Z!-?s+dt{AoCnG+pVLIIMy}8`;95TQ7c2e$uDqB?;trZLIviFl(J|`K5mTGF;m+fWm z*!LgCkot*wlt{tyv#Uc8bXvsK(zsaQ_eE$&-A_J|Wz{-!}P4r481MUhk0#focmnuoyT3Tt%&T$;Jb%IH(T z`v@>;CLDK*=HO5RuXlz17V$XI?>F0W8vT0js!r^2^N=jW znRhpMN(WB*G9K3m_tm}C!|H$~ayxB;;Vl+hcAC>wkG~AF^D_)yyC1=WU`Nb*ytIqm zTj1a)_{A46ZV+5ktFz6YRp$1$mS-n6P=*P-;hg>(3!OY8MeKU`$8YjIVj(MtHUHi}xD;k&?)$v$|@;mpx zJ{QODH`}+u?%+EqY@~8d^8KD!|eS(jjp5nsp2jEp(>;5(rXPWggQ`a|WiI%EG{%+y@ z?%I2x99A9I6I}hZxmX9`H@oyQ4+VM3WR@N1(L8H^0Nv3uTRW>&QPjX%O?rtw^wQY{ zI=;|eZ}0;sky5@n|MbL@BAJ6ki;*@peMw(WnSQ_7meYvW%N-wi@5y#kMx8vDFe>f~ z5(hLQONfjy_afPEfO&&l=?6<6_|w8{K4(;7~ za`a^5YvpGlk9cbfv|K1ate)ygj~4fGFSAC!9t(qf(7v`@3{(fv9%n7KEJ9#8|MXo2 z+R;5MbEFBc{Ph;mb*Di4SK!%P<~`tt`C+XsxdPV`L-xV0d7$52`VtWT6;5RhAT!$S z@=?d6UTGIR(7R4aeGEMK$`!Nrn1joDC3?0W((;KpedSq?ocqBJ!Ptuh&Mxs>@%AIn zQa3il|6cG@@8U~vT&ez7W0F4eAu2i9nhI90yJob%NAEEuLK&V~^YMgd~_K^(wjXgEfm41IioF4?9_3+a}=@4kPHo!c0 zo0VZ68N!TnLyYY!t@X2Sgzw@SR{J0%>BKhO%Z6emlzg`QXq%B*M%zWwvO2mbQRUBe z!utBM>?^-wziCW`@$*shbB&B(W`cHor1IYG?M4RMi#**tZ`#Pz@cTQ;2}PMUz*sq# zG=f39Nz!^1*E!DJym3ixe$Sh@<)a+-Kfn`foGSw=UyF^8^m)!zGYQ>rtQAsxsvdi! zE>&~;0G7tF7AZ|}%ynhb6>!*y8tYx^5w4BwE|U}WymeQp&(sW~UT6FhTsJ?5aVejm zBJK<)Xko3sE2z>>=#e#q`Z8J4j7s0>;hygao)D^v7`ru2Z|+a^1Tjw7Dj~D`Du;>#sM~kU@#(gk!5ovT5X~AgBP?6^oxMfCLPV+L4w_&Os?IABVC;Yy%MXHVR`+Rl#G!BodsGXc6O0a=T6x(%H ziph^R(7F7%;E@u>)F}$L4s}@qqs&XMg>9NYvoLB`UxX5cTnE-R8w0wGW*XwpUB8se z9QNi{FmBwK4RazGkKDumjZ88#kM=Ya&m27=MoZb{lKZFV-zd8~{%d=m=ZOm(=`CkO zhqm`^e(S+92Q|#ca1__#ueC3FWUl)_?FBHbUhjMMm+&%Dx^C}|^i%w+%R!yq9|at8 zJ&YS^N5j&phaw!7?}(yzZ51W&wB%GAaU(TJZz6fw3Xh%9vwYz#FM{E>V63&Q#-T6n zQp{p81l5>?Dl9@rT#XCxU7y=EsLKiWSjBu7YG5rkGZ(7C-{YP+{?55`nBQj6xrEA0 z^Mp^(2eVwB^51M;S5T34WGeG)T06`7s(P!M^Upe2)3iQ=icK>TD|!4r5>uWJBswCG za_!tD)!*H`p1=S9m5u~0M0o#2jmUGdNORkIv?J_-gCx~0IV6lVQH}6BSn#4$-5GkZ zinMT^Nf+i+vaYI{lTmg=17N9|{}Yas01o&i#+w7j-I6@^2%2FwoO@b6fcdNZ)@R7f zIeHs?r^QEpsga%LIpbW_J5~=McT(H5S^|552fuX*K0|{BpkKykt2eP`^3RO&O|z=lN*W*duOK zT@N<8DCczsSEhkoeM7VxsFkormD-n70 zr=Bvu4{ucxF+WJib(FGaMD3w#_%f;a_53wrZXPS@?V5#1b*UeqV#ZKJjmXRRRqI~z z%iqN=w6L zMiajA>?t5&8g91&pWEeW(f}hot@H3ZVdx)>-24e@+j=uv6f|!7R$2i%awRb~=2olP zX$iU78L#=MHwzw?Nurj+1kF!5%!c+6vqDUD#5eVb;=VCmTC?44h9|_QHEIZjydb}~ zdXgG2{R6CApq3_B=Zsu4zlEC5{Ma3Tq#k*T$=lgnqYqEL=lu%XO6PS7kv=x&kZX^^ zHuq4Ex<*JH00O$RFUZfiNLj-?g4`oq`^OG}b7VZ5ez{s%Pr36a63sD3N1QPNVLGFr#sG^+Mi1y`)W_Y! zjQP3$V;APi8ish1V_dIR>jf za!n1N)u@)~b1{>!ejv#hML*0_^{`*!sq0+d=9m6h=7+JSs99;Ovpt;kv-58(4RBke zN{;ufeQ}Gc6r<3ChT7@`k*iDPAF{u4Dj(z#`_qRgNkU=QQXNqm+FAF-TBk}E%2E2$ zq&`w*mFV4A#KE`4{OD=hOiim~nU~2H(fS(SwVp=Cw_711zU};s<6CRY8(Z{QYV75o znY8L&AW$K>j8dmLKaW{6VNFS0$u92I@^sB7*4_8zG5i>A*Ph)pPeI&A7JG73=~K1; z3+q=6gKwd&DSHQ1G%(ETEpq*AKyl`wOcT&7GyL2^kCvca>R)>K+W{`_fP_b`y2mq4 zS*xgZ@GiNd2WU8;{T#UY3D_`8i26_S%YNgIn~bu4<^D-1ocSUbp>^~8cQ_8QMMlXIh{=2y_dxR(k!CA68E$tP+p+|%jP6SXj9lCF^W zp0`qj+u$|WOj8qGi+Y^|%O16dZ{<&W>7F1DzpeVrkGTp5Mk&H+T^Z#wI5-Mc7)5*!Cd`8)>Js{qKl=D(c3G71)3MaWF(<^ewD9wm_}o~EVK{J{EGn4`-~={;bs zdk>=_&XG=rxi-sF^rPs+PU3f)?XQz3@?1B{7YWV+eNj3H8l&Ko9JMbm#q!qu)Wht^ zU8^)*Z-Lp(<4)Mzd@XU-W(+RQu`UK1RXqyVdSvgfU*<6wxd%R)wa(Zm&rgAmMj4qO zAb2G8f`ir!{{q+h0#2@h<7a3=t!H3vyc@9aCp~ZSxrGv_U;WDW6%yJlcxp|AGqCd( z+}28IPI31aBRtCpka6&Tfj$Q5-MR>$z~{VwL4qV_UTz0$mUGMRdn+ud(&N1ZH^d7y zm3w>#EoHktH}Y+@G8znUgl&f1i0K<&lTjs2>40}NN6*#cY`kt}V)*E-0HCo`BnXHE3q2|Rq z;>sMDW`;X?;u^n4xhfakc zcdG4~FTwQ2e4Fj@zvdq5VREp~ba!7FFgc94h`Hfx^3H9>)Z)DAay#=FtCv~Kc##zV z9yxNy^aR$pSK0w*N5CUv1Jqj?J^K?(5~r*YWi3JTWEszUz`Y+iXZEWb?%L+cJiYAD z{s>$%BIy!*)z@woZaTxW`)RYm)hpy)tJbb_6g&j9SDIV-h-cYQ5DTMkfF-b)c?T648e|JGO)+o@v;yx1O6{?DS`%KM&=wR5b+Q5W$c%_ng$boYpeFY91mAf4$2v%@E3 zdcEYRpR;<`SmX63!;m@F_6lBf%9$D9-w4EOp1PFn)xLv=(?Grw<|R+~3MSlh&8R!8 z)QVw^I8mH$6;7o4TJJ)FcX?PfvjklN0sjNpvOQYdy0pb%aimgWR zhC3&@?*TlIuvw4eH`*3n3SZ4_>p@eHQ@YFL!&npSgx|qh7Nn<6QL%Z}O6%1mvhyS> zd;%Zh;;uvJjF|?E$T6dov10w%HSJIn`QHqUrW$KbHvUAiRR2Zr>{mCJgrGup`hB;@}mJ_ZRO<@HcYiXDtX%YIN-^C$EdjEdn zc#&R|DvfC!&8V7Hu)pwZW7M~S>3Mp1Ac-ZC& zq($vZxhxeuvQo@>vEAFiOd4|@V$%5!yvN{C<98ljies!RM_Fg72P(0`nppSV96VAN zYuf2K^PROcBFAjJ8_B)OA3t)Hjpabr%QY3@Ad>1Lql<9T^_DbBY_j!Kr>){z;l;3oCa ziq=F;tWmb*d-q=lH)(7|xGB!9F5IjFGe7z4gU@%+1M3ohWWDyGBSXN)D(e|`#A=bW zTv}aWpS$Eq18^1XEIr(%H>x#{t%z{K%HOflT3v*UAJB|x;K3?DR>(8vR88VJ{VW4Z zANgoYUFH8cZP)p)hDt8^6S%d?avpAq^DTp$^3`i66UOVkpPcziqPkw@`_Slh*qnEz zz7KPBWuo`~ z`T#7akreT@IHJ1vs-04-<>EYf*b;H~|#{$PFqiqx_7GB!0PUm1P$q|qP2oj{uM6 z_D0N(rPLI%UIfUtALYNW%W2h*7#3}gG3!NHZee>=ItabS9{>2qAMDt*#0_L``9Jt? z-r9Gp$}mTtc=P`OT)2C9$Gv}Kain=z3-d9ziP^e?ubLJfXB0ixd}~sT17Ii3FiI^| zHka75bCeJ3Ie(G8wbV!CV6FR5C*^9H4JD4rUuO-YiF^I%^^xZYaYvIs`<@Xww{m(E z-;>ti05@^mp;cqG#dvS{uIFPC`i%B8qc8(3S{KJ-X>XZtYMR4yvQMBp!CqIt|NLC4 z^g*tEEBNlbh59A$t4Mq6yn`TzhdFhMK2L#%14uW@-PX9=c^ZcLVZq^#n?4_w@Da>9f$ToN=4UMoI`$y+|PEn{3{b2m#vHJ123hwe@~Caz+c*9j4`LpgdthB{n!4DpK$Dp`Pr(9r818|uX=klP zqwuU(DyEoAdLEg^XYKHWb$UDoDrYjx)Uv(;?pa-Nm~-0P_W5Pxx_4<$aCaXus-9dd z#di+lyQp)vrS(jHamAJX%vW*-1gKM=V_o-I z?Fr;tD-@Y;T+OObU_RJStgcy3u7IXJ&aVS!>M`^bdf?kU;`6lm$ehg9rRU!TH2aSG zt^8*8H|UGxuf5!p-`f^t<+8o4FqY&3SG~L5Meo3b z_IHJ5c>lnA6Dr!F!d30-Lw}HFqFh~U*J)bYINk{TjpqXNM+qyh5iE{PsYtr}c z(maJ1+&Ra+chKb<&dF0B_$4e~1NUa{SKnu*f?H_qPcTpIPuMvM^Tz&uLAE3t(_V72hU3_<+`ZX>y=vhJtX?jyc=pQz=1I+p7z`w zpnsdAelX}5j`S6LIpSN-J2}N2cdT-(1yQ?;xdB$dlN~TmJI*YB=J2zjfrJA8?rRp zMs2dxATR0Uxm;N7{8}_}hUU9p23J+>|4Q&xHO9X?oK?-c8s4f}xSCa3#qu@*inMRX zjDjHxgc_(s-J3K1wdyT-RfT$A?wKO&m+f%N`wBbV=4+9bH(z-V23OA`(BD0L*Co=?5%*m2 z+lU2yt53OZMDr5d(u~oY(C}%ftyx8kMY`m^&5S;}Z`E#QE&}68^^G&CaF}~WIX}&} z_FcW+^f&p$xB2Gh>EG%`+RGa0ch$VRhgZeSl?kI7Ilp_E^0Bsq17+D2+kyS4?N0u0 zf9u&%e6-uq`j<`z(@wndAtm8hS9b*rqnk6q`= z7a-T1pT^i}-|PXR&6NI$vlH1>Yj=L3uQ71Ix_TSHvA)MzowtB!Jrk^YeU@Ru2H%(T zWtHqZp0AeWgtp?-B>1oi)LZlG0o)lb$SPIy?k=o{%!&!h1kfAdsZ?*j8`56yz7C!e*Z^~G01Z%ucrvg>2K2W`KB z(rQapLuBT>PwarrooBwiLvX_Sa8uyI8F(oM^#jH8{NIQETYJ)7u)g?a@mry{J)STH zWLw#;hkh==jd^fom^+MJGY{A&M)p^v>-lW%(P9}jEA3GAX02Ac@>zcG5_);5T$b-6 z%3b-hW*-Z-(va7y5fAfshB3swbfgjgla>9od-!sBs(Kz(d--NrF+cxK^U3mYw<{wS z$6A+${I0TLalX}jvh2?1_V)QU5&M*35@nAV5Oilz3)D;j{;qhJm-AkZZ_V;){;hW! z-}2*apA%|KdQIGtSZ}3xfc9a_&T=EAz6G+d8*X> z-a4aAFG|EOrwNU_>hgEpS$$`5#En!TQTkRgeEv=U{bl#!e7i#z^m=Kmyi_Ku=SS8I zycVnFope2Fzm8DyBfnl`Cu8P30z&hymfaYr0#z7pb$;s}eH zpW;aCa#-s-_n@UQ`@1n|<{Z;gVkol=n_tC|m_g!^ov!ifeY{=uL%SSJv8Odc%tmAGpj}OW%ak9{xL^G-t=twp1FN9GXSF8-m#wPrPr4i>;yfJY zd5>6Fg`0JKTbsuapByU1Hu|~d-*VNHUr!bKfu(YPl5#$luO?~aQF|+LkimdnQtFJ7 zl_pBpRZ$!HRcU@NttEoy6|hQgBNY68bSurE6$Oj4d>dN!6K$MTw|_!M%o@D|-I|83 z=x3&ddmByiBY(FUB|GPAA9O|Q`~cUqotuMd5okKf;6WSB1LyRd-N>|lC)|GyBNFmdwp1-ivx2*PO5er|6)vbMJK_;dF@Je4G|PI5x|) zwkiG8v^R<4H{4+?{uMII9=iBVt{gJjK0d~%uJQjTEk8jOzHwd}F$2B$N?-PEr4Mah z#!VY*&;y2>fikbDFV45VjA9(^4Kzy`<(6Y>+L(h|`PMuD0pr~7TaU7Q^~-6)0==%& zzPwG5uhw~v)xN`h|Er{KU4UTYuBE|6MVj*GU%tVwIHUtqb1=CjA$mcUi2K zmec%MHSxxwrYM&@k9Qt{nxs{IDc^5RXA;$Fh4qdwzeg#y>nzrnRYr~+zIi@@uZQs! zvA;OZy4bHzwY!I9AZQitdBG~J@cjk6J7*uU%F#4ejg#rkXn|RKhPiUZz2<;DqP;b` z&AMzJ1!YD3GEOq6G91Nhd{!WtF&<{ffYfALk$T=RPd z%zT2n3~{B}PFL=q-3(*p_myMo>##$Jk5w6j`ZBz%&p)k@qnBTM9^FDxc@IUXDUWC{ z8qj!KHILz472CZ9R-_R(VnjL{vJ!=HbqX7-i?GOQJ@MIuHyPDryzUWv@e=sFgS!dg z2mDgz9RzxngOA~5dmLGT*-S;&8}iOaFy{&EFlPURGmGGfejnC(Sf|%zS{Yk92lei! zpB37Vfqlj^41!-h;M5N|vk8 zE4(y<{UuL)dmVc5y)?h6|ChI9{HijGds+Eu`5dHr2|ptjP5vB4;Ko&WL>qIE^%pXz z1WBVPC%2Z&>-3ez<59KDEjAmYl>EYqEqz)ibM#e>zDRS5Z%Ro#jkZ(tXBj%7r?|B$ z^?g}{0$6+1ECS{yTIJ11EtIZD;hUS#gbR+pKuyfhZl?B4ejRfE9Br?lBi2JuT7TfZ zSqF27CzyxmjyJ8x%>&r*lyTW*=+y;R`gzCtv7hnZd@F1{WN=Ol#R$)$M|%!8K-f4%%tiV3!cYiduqn#Fs?f9CjaiApHH9z z&8w<@@uWCT2_s@u2lUQtojL^HTv3o&Q@q&=hrs; z?f_iU_suw4^IVv9#B5T=tDhkk7>|ApmdW?`X>kq~8k-VyVQRdFft?|+@(B#S;yL;(W{S?d_!Ds@-Y%6W?AM)=sEa?gV~ajt?)BhSS@PSf0*2C)<|czj&8E zRnlzWgn3?=T6xrYi?@6iPdU_m&jLJnUzNkj#Zh@;bqE}oA9t> zIM4#eCvd=Hc-Ior;~w1X8{BP~k97#u^IXBB`eIE1`boE_16JJ!J00eU7Y}U=@->`ZIdE6{l;Z7s~Uvux3>fYyRG_#%9WD zT$eIl_&$>x&EMB3IVC6!Jq4P~39>qwaS5w|~od2_z6X3Pz} z*Vju#JczQkFla@`Z@`B9#rau3@>l31f)wMz z7DJx$FsgjJy1Gj})s*wCb@LN=z2;5(wh!BssOt5XA8RWL9c&WiJHEG|&(-5k6ubJK zK*OUQC2#-B)1LR)TdtGK!m6=WveC2X23oA8PH!*ulGd}i=DO5VUE~2Lpiv4x$dCXCs3>_o-#pyL+}H${Fg%HCnTDO~5}EGhM|oy+pfyGmiY7XIozitFjOl^?8lh@jhE^=|-fBjTucNUgT+U zZ2z8h?L>W7DJ)%EQv)1ti%O^x$y zq@nR#@R>Xg*0*3`<{MlPyty+Z;WLmP966l`Aj5!PBg>Q|1(S%+)n&@Jv8LX%H;GSCdK!eFe*MZ*neZJM!YY4*O#3hSji8} z=o_E-R*GXt&u-2kU^&XmM8)~l)g#Fl zj38bBi`UpmPVnbWb&$_-wif313YA2zxL29h{5rSXDV~~@>l!>h<4C%1Jo6)c%|kQH z*`+o45v&%6#qvGc^+HhwxjGJRYXer2nuC6P<9LI2ZH{aPJLV+r7WO# z)p;HkIat2udK^qnZoEg}$&oI+6bq{RD8h5OMKb7C8ue<$cAdwA{FoCa;ZG;=KTq*UjTg<@RJ>&_>yN?tI}wqTmH~NpCgSA&$ zRa3vJCGe>g=juEzl-Vu*SBX3*bQEE<5n`Hm%t3qT4)RAv9fDT2j621CI<<3_7MbP5 zPnm4%^UCGhm(Q}*?l$iA@>HVkY+Lo*yl*x#!ZnQqqEJzG`q<-EGsD$YB6 zSMle7``z3tJI+9hJc`t(vpeHWo?vCiEwFzbtp5ZBnS&#nxy}4MR`N5uZa)xv#1$)9 ztN&ZbxTiI>PB=fv6?3o|LG%f%Qj#8~=Lvc-&QaTvK2O{HGTZ(J)MS9??$X|xY{n;; z9n1V$R&yBuPt1#D_UQ*GlG)+%JL6v=IlF6>&IO2e-)f$lXwh-^D{lz=p$yW?F}o94 zbCiFpIDZ*k(~6*+CuOhJ?MJ-m6!klWGilknX3g7`)Pp5YT9WsKGzW3WI%MujwHfWm zFYWdo-&AV~BIdeMdb4&z*Y=XxL^`95t=`)WnGC{wI<+&fV)th-XoWxPc0WP|v?5!L z=>p1RzTj=BNk25?BecUcw_36pgRSwT-S~n z$0bl=bd$8pUC99Fuc2AS{vNZh7^Kw}=as)UpjuAk) z{j!aUG1|>2f9ntLWzeDD!Z1*v&+st3%{nye@GRj#{oEvXDm5Dea|w*91GX;M9LM(e z1l&vmO=hMZ16uT%{S1#Y>gyU975X0NZHRNmE%b7?*-?jp4o^mKWTB!D@!oDv7iDjT=d8eqwVEt1~*LzsqNK z#p(~Le2SJp;cDBKr_t@qc@l}_^$a#4;y<4y5MRq z5h<@4^K(`w%){*-s*HdRtj=tWL$eiYw8Y8`bgQL~$WXOY|H&vrtdj*)=v zN~x}UbG$%NOVP>_)T)Pi)FMPCbW@{T9CM@>`F9~#*VjA3XlL|jM#$*5XzaT7`o2tp zI|e_kRk;IXErW@Ef8pus+}w+9@Ug1LUpL=|Rk(gYj}D+=b398ca-$xtxRzCVv~*vD`Xm7b zy01;9Si90UAL~TE9Qx|?m&WB$mAvU%t3RotN1f+f&b(^;jc{3YPl#3xW9}4JGdqJ3 zOmlkPFbS=k=3TiLGE2(^zqD7F6>1}E`8Ri}{ zLhS-`J3y{ctmdei1nQ1CqqcVx-em=AwYWbyYc7@^U{i>krk#-{pO8mK`Iefu*7bIS zt0~W`HPjO~dB%juuds`*l7a#p>Rn)4cV7R=EY&}T$~|%C)u^wj+6RTc?&wRalU2Ip z(at|s$cVfuc`bC``WdC#JTBI;`2>osE!XN}mu*S40n^HQ$dBha+8~ebhE}9F=R7rt z^GNuwhNCk)%BW1eCr7|DB_=b$X%V>MzxmYfvmN0sRKYCgePHk!xO&6&C$RjA7G{n! zK2%SK4em3}T*`0uu;#^Y+;C;wDa;~$h0El zR7tM+(KL_bdD$>wZL9dSs<%^=2EuxkTV#EMa`42xi*L+z?p$nW^OysUHlI)4363$3 zrNuGU)eu>KpeMt{NwCK%r@Q>t(s2uZJu*`(rz$7PjSs-CAvoy+5V+0pHW)jTane!R zXuGx2hxHAv_$+bf3IDZt7&&A6UD}wtX^`h0ab<^NbNHz#KjNKRne_oqdsNaS4k5jA5&fX-iGvpD8Go5Ml6;(I!0{gg^>;Z}LA zkz=gSbCo9Y)Uh3nlDxNdPmU^ms(7%JN(|~Q4{jcLBQI{g`hoGqaTc+?$a(5w`w&=n zz)D<$U1n)r0x#E*rnN>YEg$hrHN%@6%OTCoFatLB@Jp{DW8*@;)&+X_#`O&##;k_c zIGN_^9Q^bc`e5dnY4Caue73JKekM2mgMveLH=y8SB(-$=TkDODj!kxo_65y@dZpYfZw=JiUC2-E-N<6LyweP1c%b ziMcr5y4d*V0DQ2@`Dd^~J+68ft${=AW-q}a^(*d|&3S5dA!AdYpww!D&ETZX z&y1v6b#}qv6;@>ktTUg(B>kwnF(=|Yc)g6KMt|aEo^l4}8U?UN|8jvno^}E@?t+<* zw6SjXC09myQlnO6}EaoB_s+ zIk^Gytvvh%hwyZt%Se%w7VOeS8~w${%Z3n7@2E|!>WK>skHQfAj0t_{-UNbd~x}301-Sxd` zg=IYlWpz;!1nJV!O^`X{#9|Y;AQ{ zk`$Zwg~jpL#ag|i$H5@;6KIRv1fP0YF>3)>LtZJ)yvcJw^gVaZXZSe@&#-E|o+C!s zZo$K@`LlxF8m+`fD@;DnoB92BxyP8Q3$Sp2-;eZbZm?5+iSue7gKzL79IThKN~K#o z^N_ZKv>xVZ^?g$s?UU*^)dL22)Ed~Ho%T?+mc5q*hpq1m z8VV&i|MD7&;@s;(qP`{ipv*$QjeWS`_b6wC%5Ry*&?w(C;Kd9TOVD_IJAc3njL9D3 zx3*rTA+6+J6X}u_{L2}aYE1g zz+Er!x61E%TFbe5{tb!c+QBjnMP4@X4RtquLV6eTQt|x6+dsMu`3S0{veL4Q`oQ$mHG~aRDv<8ZwQ)bmh%Ik@`8^MdegxDGO)P= z#D3&^gR{e2vwHLmoK|?((^-$?E#O$HZWd&{!Ninf?!V8VdJTM-z#~UehqB_xIqkKnMN8ZYhB;cI-+_HUZ zl(gcmIgGHZhp_WiGw*nnZnVGMW%5q4ngwVGzV+qypD-R}@>@9U2i|4$p-jC9@nUXO z#B1o|hNl}@s61`t@E$U{=s9`JlCG7?i_P;e{FRrb-8Lg+0*5q^I=A|7+87WM0>~%Oz zzD=5QBaY<96DVbKyU?~={s~z}8#PN+?ep)V(^wN{QjRzAYRC~4G#5pgsA}AGF-VWM zLtuX%$kzk&8*ptU2x~p)8=%ec8xU7z_*?XUpO}k4ozed&N%JO z9dH7@(2GeA1bOEIQkHtBYg)~L9n-+nI#4yk{e582GIwkLya&^c>C3D-%2n=UtOAwS zpH|JgOhytyo9_>nxXyFIx2R8^hr&c{V}11IJR!vv5thn1)XQ+C_|Edr`s?9HalC(b z+$hes3@6H^u};|RUt{%tj>@N*y+o!egMA@BeX69Y7>}3iYN?G!Z=qExdk4?)hcwP2 ze<+T(F6>`I<9ngmJ5Xrj>25Pg=#e8cWEh33uZ=nXK5|X#^CC2TmT%*B%~C$ew_c=! z9BHvI=WB?GnxSnkT*Mf;UG6YzhZYK>GVkFrBlKl7uhDfE@E`LK+;iU@JYo(>+lqqf zo_4r*upn9G>3q3l)x0MvzwfPZq-uwhm!z7ds3Nre6B*UKL(1gI1GczxtdA+J`YXaw zxm@L5T{)%7^R_sH&hm=l_{*@Scu&y2hB0>vcb0%ry}XPD)#Jl#GJ~8s2dCEfW&HXW z_qa1L--dQIBM?q9h(6-3NpRsi*Uhl01ZI8ARqh=HGu&^iaOMasaBuPj%$nf7DfTPw zbH1=!S>aiO^ybd)nh~5Mz3Bz6u2*}Z5%+3e^ZKUW0e4akr^E|{&3b-S<{dC*?Vzol zdU@-5m=X8q-P5+F(MCK-XVP9=jO~ogVJ?G5^FIie+LNdFm=9dP3;iwhW3)cj0+8x% zAVk?d0na0FjxS(~v3OQo+=f5&1Jh=U(2Gi|nh^^6J`QkxnBQ^*b3Ki6?n}lyw2qmT z@h4AHA2z@^zCj^pdFnTKjJ3em`PCZgm1bYI!?s2A_D>XTl@UZ}dk6nggXoSZcniLR z1{i%H?S97!T=4&%`M+Z(_V*5)^_)@dAvWCm^7_e;!JwQ=)!A$3A=h8;SreaV_JxqK z?O#xzV40GpH*?O&rSjMq>w{JAHp0_<1MwZjCk9Ps%o|t#iN8XVsFutsr~7=jFZVt` z-K%u;t+{t|%lw*F$+fPj-nHGMMq#9p5`|wMGS~{^=oA%_+v@8z3hhw;7HpNf(1>B6 z`U3vB2)0R`tVXcMxAn8OIJ3tptaHDf+B@923#ItX2$g7!ntJ3eB~&ZquE0;Ny>$)e zH70+AYa={C{izwY)iYWlVVq~J@@tS^YAFwR>HHY;(`(N>iLHF zHa^gL&sy=di5Xe%Zmf^r#tfQ`_3(yDp^#>|5`RyCafL)BV5@@H(hIJp8wo5|=4I>S#$duHD;o<)!4Sul5& zyVdE;@HwQ#cJ?t3${x7$4cSt>H;0fpn)<;-rN(KncO`2z&DDE;na6L2{`)xI1LLo< zJH$yn@uK%cen(QyYpetuR=QmK(3+c+w=TZna!881YO7KN>?^iYLP_?Wq$_IA2giI? zajp@1(wVfomhR^vCUIv+Sf2`-4_&VpGp+9dHD7=XJt%isUv2(Ztn6bZtt>&itqWz% z#~aq~GcaSWyCYV4nsYszb%(tJe^`TC7_ViOEcJrs&eJPk1DgC1o-xZk-=Oq8K+`=v z_VFxp?;Z2Y%79_z0?07G)fm6jjol)Z&A|gs!OIOWdkAbcAHg>F7#b2#sQxC5mEO`gZzx8Gwt>6-_O0Y-kZ5T1pR>1?ToVTP_!Ee(Xqp@x9_HXod z`{N&f@D%g&4rdbXfACfZS%Y`bSfl#<^&kB1hu**A-aiVvya+k&fLi6QHPc{xdg}~I zVFz=|n-X@THr)1c=E`Sz{_iNF43OXJcS6pM8UB(kH2;jE|5)=#>d=;6_+rR9)$GGn zgq<>tPZb4fhO+$VJH2;JV+|B2{SK0AfcPQ>Dvqfx1=@o;e1cA#0)NVwU->i7vz67X z)}-WWT!&i5E94BNl>y+&tj&5S{s6|up%&qL4*IgewME((Kc{SQPaA8x^&w>#DQ;#Z z_qh}Nw&vd?&mZI2#=@G(&v+2?OsnmmQf-+l=D^X{=$PN5^sT+s3`0ZEJR?2zIWnW_C_Vl_CNtY)q=9np>e&Z= zT7JFiT9F4QC}{=f@viV4`bg)R;XUk)Qv8=XY_;+Ge@a+IzT7#!-%2`2Gb}#exwMiC z@_16@!M_SGisSfu<3XBjgtv6&Irw=F5)&-9f&}Gqt8{nITT{utZ0u>zT6Q%=1;>#V zscCVpb)iPeq(pbc&eBLPYc*)~R_9~=U$X#-2@6PjH&9C@Kr0DOL1(Q5Xg;o0_PQs~ zy+gk5xKr9|9rQ)|p5W>bl+rkNtEDXPq*bI!eTBxjL)xh%Y6g|ntgmt8%u~)k(Dww? z)hrSVj383aAVKEoW02yjATKAM6Uw!^kY}Z--;+mF?JkgZ0tF7d-;&|&)lzHC1 zRm#>_)iKs#3t4Fr=}F7U1-NXasM`8@uwKp1GUu;oV@|(e?lQOU0avYhc8~mafIKw= ztrwIwh-St#lt4y zAYb4W+pPQ+Yh(@y<#02RTQ$!J0ey;xfuIrogaLgZ=YftP;6&cG!~X#wWfN#M)B6l} zJ^-tiz^4@uLQShhdOxMTeCZlGV}&ELk$s1g{Qxrc?RFm#YVv8*+2+d6toJ$kdI`jt zbI<&iQZgeQjXXAUb5RqYxLa#^scwJupssPxT*j$74|T1^AK|XmJ#Rtl%;#e^A!|Nr z`*YW)f8jN&ZbnA6WM)j&k6#~;>x^QV7tt!sR@OQMiY|dfEdYb8xPF26{J#NK&RBJ= z&(>$#g8o@w&8iw|`@V8)WjAY5`s87L-_fUX+b8~;g=LRX^kw6jC`eDmHC7_J|8o~- zq|6<^f1RAA$4MjX%PFl2_weTk&8!mRNTSq`u)w)B?ANlem)axgM^x zsvr9@OnJVidUz7_1l{zXFCTftlJcujOW-&=C0`8#^}|4_857l?nuB$nqbXqcCes@% z0?Ag2lk12X)}qsTZFQbo_?4DSJ?RI*4l`S*Auvz>ci?;;?x}<|2DZ)8@(gSigQz3J>}dFFl3OscQ~G+{|)*Q|I9iTedvE3?|OYUFr&_nneRSt?gO*c@7cYE zzvGTQ)=!pp8%144w*$wks>J+(cNuaU<@=PfK4+n>f;^?u%fc96)89{KZT^(1exoJ4 zNMGKHo&`&IRn&Uj-XOg#9tFY5v|-WFKq6SQTQ05$U=3t38r_4W(|D$=+_S^568z z$|#N8qcha1xyMMs!*|tA>#swr!VI3HRN=0-pi@T1XgN2F#~~C&za(o{+(K8rK~MUi zD`p8Xo2yFHNJD)#Yi+H^-rQ6x{dCLnWu6m#fe0y4;(-wbe;`k=~qIB`z3U(*MN_v+|It zsEr^6zMj^pe~I#FtQV<_5N-c)Eb0ZT{QkpOUMk;e%ldDs*=;GWO!n>!^{npsWmL2Z z;=3pD}M_aDgOJbmoc0|6OAkR1}(m(rLhi!P@nJgb;*$)PG*xiw(_s4QlNvXyJ#Q)o3qD-s)TIsy$=0#9k$tU z^sUmXVHIkrSAIWNcR6eH^*zT%0v?KhPDn6zajr+{x zIi){m&;ja?re)dR?ZK6CD^5jyl0q@k-*?%~7Pq`PJpud#vX) zpVMr`SHSCWR{D{3IA^u>i!*DCehubLn$A{SPliXXF3`q0)vN5GX6R=QXwvU^nBLUc zi~>s=tmY#e*_@=-=bfePcX+*UtA@zzjCwp+-#XOGHczSbv@dycyIdsd6k*4qxmm9;I7t2OoNp1({SYlN=&J5eb)XlJODIm}m}5z1=X(A`xJXKTL3 z6Mk}L5a_yvZV7qQ+%?Y{sMoWC`U>|NJva_5Uhr!l+NNAM#JM$kHO_d4?~q}_YA)79 zSH64X&wb$uEqmzm2`Jj+&X8AZEQ8=jV9UJf3&3Unzo}HYt)>d5^1A-+=Btgi|NI#0 z*)!G9yIT&s_*6yUW&FE!FZJNx9LerEs;oSnr?btYj+oGV#aPTZzE0sp@GgD;KJS44 zZJ@m$Ojze=3<_ub{Q{pYIJaE)20E$U=NrfKK=B%@){{|FcRgF+zz$c{iO)fIjq*1x zUk%MQy_hS{JhWoXB5l8MW|WUL$jppqt{3&~QgG#h0j^jj?35>nxxac}WJHJ18DLcl ztZ~g{R=wzXlZU#x*r4a~K0UuiKdUyZx|jU8s-zAnZ>yS0Z-EWPQ73FDUI}sQVSJs! zh7IVoS?|mdaRxk}f)i#@J^`YQH(y7pGzYU5qaAQ$gEQKJroaU~d+&hbHR$>_&>N%( zD~6fl_61N@oo zIWKi2xz&{|r~J)3(DM7rZMBY98>^a+7`YtZ=@b?yX1YV zpHV;kax5)xogYUPHb%**>J4-r7t?4X&ZRR+l55`G6lrp??JN)`g4@W@aXYL$hOgpq01UI+-&AZAt(%*NsZ^c*NL92u! zJ;0maXkENiqvqcC0I9RROylZzTlG>8Pa~!39?xtZb;8%;e3GV1J#S~U5)H&(i|k>^+k`+ zNmkbkCUS~tT4|Y|1ULKO6Jy}M-l*0siJT>u9=+ zls7K%10ynGUO(1$xWjY(6vtbx0gJIa!;B$dY_XmETuvEktETKr?dInz8+U}jvTG?; zM{e917}Wdi1j>BR>dyiZ!>qkA&DJ1RKdRp9E`yJG;LwOceLJRr45JCnfU}#ys{0=E z;A=tDuYZ(&KV@9tF5^FDXN@%gwYz@hi5J=4>Izu=%u_!Bfks@r=NW-dne9st7HcyP za6PXDD6UNz4E{Q)OgKpq&1%g9JuzlYC<<{qmw!UL7Q+aAQN}9nklu=iq}+M=H(HN- z2&L+ejDBn%clF(|uE{svj=FE-`hs_lk$zH$a;o5ntE9f5%L_7V`MY}yY<_+wjrjfi z-2vkxXUt=K9zyD8>AV8(R{5B_WffdAdf)7M)<2ggsL8v67EHn!PBR&96x{9SUaMwk zeY57~7C3na?%!uJqt&X^fS8ZjnB*ZOK6NC^^lC5e}XUOfVhO# zOQYoqU!lmxZSI0^kKoo2XY^0jr`YP{asd73jPo2|HMJJ0DOcB~$J-Wn9f8k!FCX*k zj;H9s`~}+3!+*2Dn(4x<;l_6!bDy~`&{pb2deIftpbwzK1ewXj)#F5~Y74bRo|IkkS>gO20q3x0uJOIA0;*xlE|}Her2ZH3j_(lAb)krP+hEafF>$ zH6Kg;zFdlo&|q9?IbPJ`OtFGKy;m!(8I!CF_#OB(PDUG(zsG?5Q=V(p8DYE^4%iFt(zEAx(oraFIrB!1M8u2` zN!@A(6Y(q1{>yCV-smZ*P9xZilHDj_lC7JuDfIbz+4QwKjRg7bIlgs(mwkZBmGxA_ zh;lv_Em+;tj5l)hH1aasPgj#=t8*H1d4v2(?VsM4`fKWmWM&_&zSrR0E-Pd{Z7XV9 z-&dM{37t^OVg4y=iX4Hh>McHT$0q!z7wPqwe#SYgRBN6e<kv%Fet_q)ie#c|i=^uMdTTAXhye9zw-@gmkhtS6`D`v{Pl&PC3e&gkJ$ z#i@(FTy^$m&G;L7$zxEJb~MTb-Sf3=o_n5`HO}Y5zvUM3F~1Kh&aW<9TbJHQ1S1h= zprltwqf_vY&(P8-DCr9PNH6j=_>VHHdn5HK7yMp=_ZY+d9gZ^$Z_~<#MSzHs#Xak4Fe&#;Ql}takCPxsUu?tirmuhpghz zo%e%ESQp0JjC0|9+B3Scox!*PAYXscsSJ;9krnk}HBNT`Z1@2-&haGWM75s!q0b@# zYU5J>Igsu6#*p@`MY>Fj1MtTxGHX!Mb=GhbY_gJ^IT+UH+gf&3HJAgx&8=(YyHzkx zFJLp-X;D9;k6G~Snz4=Z484P&%lT4f*DkYQl->7MTEi$W0dMe9P5vy z#>8ENxMxlGGj>MDaGGQAX9Z}#1^TuAO~PqrGY+H;PyL`Zf3+8%f_LWG*9U5fUs_=| z>GwO&(h6-P)gb+?qPu(otG3{ITl9ViW(`1HPq=GontJf~>m$k2l!nR2Qe{b==rXt30UVyl3f)ntL_4N*j4>t|x71y$!i7^k!AMXotSE z?j=92s-11Z=kD!oo5vk#P4ksTiqlCcT;IA`aOM-T!V>&gdT|Y{xPkJl^Q({DsQFL& zft(&Ff&SF`+nho}ZlMlF6X+{vWlvq3Auvr9%l4O{2W2Vs!l_F1zgYRe!BV!NRJGao#u56nR&%J? zJPPF>;*7ha))kwbsk?W4U6RmD|8E6!zC!rDp zNJH09j|J9U*t|i0uzLCo@`M;X4bv5rH(RQ|fpXaV4`dHz))%%MGPvvp!ah$@sk!-`Eq}~ zMo(sW2w774Ilh6DXdg9ewXyJHe6+Ui(9%2*`uXK`!Ns+##+N)N30AVV_T_1m8O`IN zwoO}!u{=`ND4hivv=y{D&-a-`CtsBlL>+Ly;53RXkwkR7CKuNV3#?$Yz`Hez7$ zJ^IGmk@o7nn|7qY@Fp7HMt;n3UY)j-J~yL)&(GZz{Ko?<6tTN%9(B3m1b8?M>>1r> z+}|l!wGAXrAU$qyWM-myaJC;jTga?G#-?laJO?AKRXhehuX8jC9Z)N!hq!(T=Ih+% zSQ+#S5HSdZ8u8^0b0DJ=RyHzXM5$;O2sQ(~etwg*T;$uV^;&2bpdR|3|GrXV;!#3c zQC^LBlfMGc4DOrDQ+ zM;0_nBlu+N4^h+sx+dMWjzrr?9@^_$4I1H0pAI>@(xq#!wEKv>8hnBD4AE1lapuK6 z>dWx9-RI@!T7}tiy|^M}+R{!-jzKbS_kC93{!89bkUGPhi&AItoz>--+7HYnb`CyT zAJb@KGXxxh`(}Jt=FdDeMuD9`6SklvBjBv{+Lpl)V-d~U{GEFS*!#J+?1!FQ(bqU1 zHJ*27v*ZR;X9q*n$ z-t+IK6+GtW8=x|bzf%xtrSe5!MLzKZzF`gKXdlxv)#&;eR$aN%`W0q3AEx~T@H)xgIM8MVlwtbWjvN>P#y3GWEu6%c-)N)AA)7tm{FdKA?;OMs0`Yyv~;aeyfV0Fs9>dHB< zno7CI1plAYTIM-bSc5#YM*XetBiS?F{o}v*yeqsVqeiSU`1Q~6=CQdBAGB>dyWZw@ z`Da&2!S3AELw1XjgmDI15spI)R~SR5sKErdreEz6)LqAz#1b~-PC*CI!1Dj9;kxeyYie3t{!pE3jAgUjJE=)yw82{Ip?e?XQd?T&6u6z z0eQEVQ7l21?zv(FnD!7e<>*nb1>Ot=)jH62sDV2)bHr&!N?9+LpmpDX*1T+U!x=pU z-enMb&9|`kop0^Xw|wXKEcW;x*K!xq!P^e~ zhmmMM@t*J`=j1qx^ZzGjmU)`_s2tZjMsmq0!`t)fT6QMx*?f{ZDc@Sv`?R{8vyu*k zcMx)Ag(vt1{;#b6cU-qZP4vr>CpkjjL9hY--&rsAmEN;{8P4#Kvp@dv2Y*kD{GaeB z?M&s=u#W8}Pb&fy^nG9O?yYbTX<$D0Wq4j$+XF^rT@1(igLmreqx7U5N^B4N&^YR{ zUaH$S@})3}#8LpG zY8rPf&NuOmav#nxhoUS{XXWy3!pfaNdGa%8*TUu+rQJ^Rv%>R&R;W|Cb{j_@_(bEG zq{Hx?cGlm@EX`N^X}5j^*9V~EU%=9S=zunIwUu+gkoxsiR5|=Uzq?9)4bnY5Qto&Y(K`N;9aWSdTKP(q!+&1Z ztCEN!rYE>Bw)?BVdvRP+Ti^2`v@3AeNVly~XT<<(Fn$1be>XTU=WKPop^DJ(K9e%e z!L)sN)Hmoz_dTN$F6CFTh`Ui!k?v}xL$8BndA?PJ1<|8bj4$K!oz`_#jXdrYf}f@S z-Hp^E<$sV<<+(v|o^`Rqx;4_97BK4px2wo@Q>{B&yo5U z`Tc`4>YUA>YaLUobGQdEUayyNTWR$Y>aDlaX{N(6N14)`oI=gj5P!EopAOLKU0fl~4|SfukML%LToqc0teCD6{0DAhe5erO)(j$LyC%YQ_jesi#^0 z-;9l+$Jg`L_U&};bzDK~G-;7@twV<0@LpcVTkG_df2UOx#5Wn_{PH#IJO!y5d!!*% z*F$V@+>>;Mil`AB&!ogl@bnrfdXlyI3T&C>(+WV>P=e_{Y0DSh)DY0Dgt*0BY8Ld( z>f_!Oq{M6RLkf98n^~yBcj%4#)CKM{-^>vGe4_35Ofz96ttp;kPK>YgFwfB_xHb>v z*`;A?f`S8pkzXVKv2Ez45*5AY0Itv_|pIVu1hdVccdiC{_ zz`1#ptnj=KHmJ9|pskg0j)C=0JmZ)iH|blSlSe*_@E>&q?$vK-r$^*sw&z>tTt8}o!r@+Y}QdCaOBs~B2mU#CX-Cm(ss9T08S%#XC) zM{h6$H(3R`joN-hq8tTRjAB3K>MXtgf9<^ocN{sAuC1TK(Ywgp3v3 zuiEGJc6zJFT7Zx3c`B_YTjQN;W!TH%sT{5kev5n*=Bvhwjz)_o`-4`~Y=9aS=g(ZT zjk(>eRpoT8pJE@UN49JFy4wFP+34Pvpy0CJY$?~r=+e;O4liSyN=tZ#Qs*Jj&wj1R zHOZ`1Nt;iimp7uM50Yy5_O6KDzKX)IF_C90Ds#1=-W8Q(H81M>dA&U(s(UN?<+g>d zYKs^QXqCHK*ty1kiR@cb=_l%q`-*vcNVNP+_7Zt&E{i&`QHiJGBq{M&WW2bkPvh;% zA-MEvOTV-Gw9xgi1^G6O9yYACa;@_HFPE9Vo3OY&&~E4*54%guBYFaD=(=!${iLJP z(~gMSpVbN-5QZU7I9Gf_e4bkZxX1UH>S`LeJZi;FWN z*M(U`=d1|ZxS@odKW?VKs$TBt-9cgMX+2{Xko+naRhF9$iI(7;7^lcMi}FrT{5ZOq zRVscBvsMjUNBB{4F z2SK^Dw;@r0w@>fetvMa0@4XV`y%TL*7cF52JraEp{fgXpAxb+e3MI41iZGB>A}4_P zAK5GCrjN&>srRBZi%@tV$|rgOS;HwV?)rEs=|Pr|&uZnMsC`A+9FbGpFogB>K-7Ct zEgTahMlr*`zgou2$z8=U@(@nTaIxk?QV)Her+`M zFQOoB_~i~1JD+`B-;avoKI;Dkc_-HOj@!Dq7x;~SHbrAZ5D`CrNwm2l`ohNB5FN8O zd|98#-U02AZ|JFNTviKY^CbV+s>-c2b{R682-{EM6r8{&^X_$V3GN5vKYI+hHW>DS zVRP=W>%t=|JH$hf&!^Qpsc{o2<9V>yBVixty);UE7_@sok*(oh>+^t2m)Weg*J4m2 z3Hdpu*~4?<8Fn0RkWX#?=XTfZxrFCB>EaZ1?ljJFb^hU_P4k-h+~*^+xg!3{?aJMf z8F=!DBLA!KlKVN>y~c*UC*ELQDt3y9!{Xi=aDly}* zm)p$Giof8IhXWB0NxuBU(q707!FOWsUy4T&1IWEi#8#u}d=X#VR4doj9=C{Y%AUQa zcgMu(UaOa1RC2Fcf1!HRdMI8<{!}cDP1S$9&DVz5uJ9htyO9};_^xTBWnUY^u*Nyb zLG@qbL-W9zeB6OQ`E%25@s;tLYq#athDylGTDNOjCw!>KwQ}5FN0xRt1iN2*wW6FD z`6x_aC+m>PvBv1S+>d-yKj*dnSJetPEa0&`FYLG|9C<65$8Ojs{T@`UkE;7r?X%}j zjP60b2Xlz|Me5)$WryLTu$C;IhCzFURp-^JYqz#0rG!K}mHY5*IZ*d@)_L@>xEI?8 zZe#6`d_Y5Jf(TD;Z{nQR2dz1j(Ix-;V^$`&RN_$Gj|1-Y?R?ChKI)J=mDJx_#yIym z&4yO439Gr|fICDUizkvb@~yZqH@R-;`BmXKCE&rAgyGM`aW9E(4vN4S7aWVGm7RM`4hU{66u54iZoBk1tSW47Jn)lt#cCRoYgWX^5Y5MJiLPb&NfhAn zJ-WP&VLRgBr{!w#w#R8dUG;}j>xl+_pWDSqv=ru)PJJGr&J?a$Ni%X392NCFm;5*) z8apR?BJ&n^tP(BuQqKG&Dx^7-yfq2m`+A-F49%H(;I;Ri4u?*|;`DUnd%> zJF8l&!V*qk-xfWdS4qydaq}Mc5*-mmlb!3FN?`&1rZ?O#dr3S4@9bB#d#iyexA)4m ztVy%F+*^cYcuzcrJ59+4VJC;3Ml6O5iGcl6!!1U(TeHR41T4w8JHX=9IJ;sw4v?g1 zE!ZUwwI0z2?W2`-MM+v8#NHCgKzsM}8S5q5V9y$F@QH0W{VW4nG|1ufv)1Z>ptaLT z$MuYSvHSIelDVw*^(f=lFnWa8Xj%}jTZ5-V^p%06@Y8j5cYIJyVSJ_Q!))Ux@$D+-ps8zQvhU5IV zgea$v#X{0eON)gAoq^L1_(uFR_F^IEqST#20S@LrrOnCP@|ojv=q>1}XqSGPuTFoH z{YO5|mF<@PDbCN{5NAzT2P8wOUDbO7@-EMPO=rv{((JuVCDhaDiY1i4cO9`DZ%sF> zYdW*=8O?LoZ8p1S7qHy0)xJ?xSfxbCpo>P&)D%mYc!}z zyR017P+B8G^qhWP%eLa4&I_`SUP|}vIaI5u?6o+?GBeC6MPWxHB0Q|Z%O7SEC=_BqJOj2 z9y{0VO(LcM%@rMw*f=7x9PjPKZyFUqn_VY>Oa}G02Q_rJ7hWWKJ|LeF7NmKRIBj-V zPY%g;?DrxuFGR#}@|L|><|XgdeLvl^LRLn<-IV<};Nuu#JxY3tH$eq}8T-APL+-+T0YSu27Z`u0=gHJM_)<(dvN@=0{n)t+H(qRcl&86vQo0AgGVqjEqQ;# zac}4T6!N%n*Hg`x0xj5nX!xc>T7!>)(RQ^QoO+cfkce)tGx3cwpZt@x4sqNHWhdO`iU!i$G0rom>*#GesoY99zJd{ul*Ar{)8QRDi^#dX_tM@z>fJ~A z+}Xt;Tjd?;gk+ZZRc|-+h8z<_2$1WN7$>q#+>ke(`+wN|J})W9sd9@sf3MHSRcBMJ zpH)42`Kq@kq%p2)|KOOk$s>Bh`Hov^=bc)4-sqOc1?P`*h64@7ZiM8#eX9GQaS+AP zucK^gX3)&ZIdNZ_4(pFk0`Bkp(X>m`dFmJo{&F)AdIonsmifh;Psd(os{P^dXAhB` zL)ZVfW%6g~fJ8U+Yk;}d5-^+ngFhrBOipJ8b*T|Y3*qly#Li)wMa*C@-W0y56#6dS z!c4VJDJSK(SI7|8@PM5GAc}!6kd_!&0A2nN4*SKqbAmm=Vyi4Ww8+?4w zAv;YEx9E5pY%<*@YqzBfuND`R!UgC?R}?IQrG(f=HVJgz-jenD;rX1$7vcRT)%e>qa1IyEGSD3^E;+1 z;XKo7{vI<|)@^9#EN!YvHJ0&I)z-YqHJU9|rO=MkxJtN&Qq_;DX_e!Js!DIGQ^R_q zg_qgg$!x^%>6hHfowh{;UnbBw5-ejYE$2NypTOU~^yA zn=Kue-VCGV@~Pd!Xg6q)k{!?K zATq=Dd%L>Zi}M9w{0sfS3BVlh!|{c9ROdN4wiqSs9LltX$#CWOH9+sVo$557KOM&P z@;d$Fo5sW9JIOJl?H;Yy+46~Wh7FU9Q?#F3_E}&1*?L>JcjlwKCs#z3oC10z563U! z4rG8O8!G3?kVIS;<{+||Aun$1=KlwGuqxoLX zFN#x;>xJ7EFQ_b;YH#ZeIf)8@NB51U)A3iwa;yE+#pVz%TD9_+iP0K$u@pX z!v1M+&i9{UXP^z=ym793Tx~q;E*tw)v-boZZm{vV@Q|#?$0T{!Pyaov*DJHp)qYT==NAL%WgNN#)EFRI96ox0YtX8pB!CF{Nu-$fcJQ+id# zXj*;#iZ+ij303xII9xwl)#kgUPWnCa+Y-j%y4jD(XUp-{aJX*K?A-U-cXB!4ay}kU z=7Hti9B@45x4D17{^N7~ax6nBbgM(v~K)8$Vq> zX>i=KBGm1a*`I+Rw=FTEVQ<@a(@+eSSy|ezq%oY6^gkiJffyJvl#(q5O@oM;8;$P4 z&3Lb+hrH4MhmAh+P8!OpAbhF6ob11+-?M6gyT?!K6FE1?#`r>ejpSP72HE@4SU&0b z8MRMl-z$yw^Fg()OaHkbJ>;fJUeeEo;6Y9| zb>7y`U;Qjfy_JB0PhHppUiZa~%pQB%P&*#A-&j^GgKt(CMJ|R1TESOZZ|<%BBrEDy zVa`)oN!*KYSMTtytO_^23J2~B|9+F6d%XGOEc8LyabzDlppxY0`z%bri}+c!$-BN+ zWr@u{CrrX$L*8y~Lnh-ix-l8^$kRfOo@XjWo;NbRv(tS^n)C_b?kjzBjH>(6y18HA znyozAUDqyma4aiJtCPH=Ic8Zs^9uV-azv4bFNJf_76H5Hyn9QU^EfMzQzmei+J8T_ zGB>OpH-GMgUc1`K=e3Jsof_g4c3E$>+PwSZEaJe&U(#$krnpxDS&(~CN?3>LEc-?Hp>84oXs7T@R>zw1#^>XRk{@jxR1kP~;rA&AmECOW1~ z?hMOsEGcP`c`ElQ+S9mt~Pz99>#D z)FnmubHBmIpqmvvaN3Mpt4;|&!RHr}FWgjcztM~?2sbx`uaAYPFNFErj7N4Ne1S(r z17QAd!o!Ec*aOmr?h0?oPj*8s?G-(7tHEJuUa$2QdH6&vY>3MCOIBVI&AnEi>_V_> zaZ9~kkY+@td3MRai1NtJM~}a1RdOlzBhUkUpswTB?eB4UTEEqa(V(P$N+zCpC(^B~ zAN}@GFw|kWQx-4RfViYyo>?TXLp3YP#c#?zaAeeZC#t$7dcrb+qKM%CAp3+o^5pg7 z4v34QsIRJVRqvnbhg@L?Rq|Ey>8)t>l1jV~C7)0m7gdX#)a(|1P`&G->C@6hxrL7V z><%{+dO}b4s&%}toGRpYAo6qW*Bbn)cVrOcmZ0=(KuNia&??!N<5b&St%d6$5%&+* z9~P-kJJEvU_wHT)S955QwPar$L-RYAx~7|QN?>Ptshx!&`q@wAO(T7~S{X*YtOUPt z=Ao=NADuLXI;Y_DjY(jGZ&p;iqWL~8nRixn!_B4VCGp7P$BFG{qN)p`CT{gQEbM)# zl6W!5twp9!vMzHg*F|CFZ=%X8qSWUq#qD>jBYP!K=sA5_)$=22{hH|UlM!?ayM+SQ}?t6$;>5~EJ3CrmvL02mQ1E0DyI!^O& zp8t?a)a~E-U{nfqj#23wyZ6W7n-xYq)mk2Cun4YwMtDQEH>3pXO)gln#=dXl0=5Xz z^knP?Q=Y2cDb?bH6Svf#5S~5M^E3M4ToIq&3Jcj=JKSL5jV->qA#6D(8FW~Ca}5tVx+d|R|eH!MQa;(iQYJ<5vtV%;2va&L#>A0;f4qV1m5 zTFBqG?KP*Sy!~0+FXEZzx=!8ZvcusBS-o4lg~&C_mT8$a$J2Cw8^b6XNli?{;%K@J zwNZ5Yxy5}rbhDyp?s5E8^H1Jo{0gV^4ZZTUsOg3%@s==?n}N7Xc*BW^S}C|!z7KKu}mc|gB-)-UV%0a4>K(H^R`0at z<*R7zw0@pQ686g6-|p+#N8v2DaB+(kr(Ma1d`LggEjP3tQt3-7$=zI> zO}(#{$t%Dhw=b`gFPu8<@CZbQv*ibpE3sj|l#h#siUsy?HcbN5$RV5R)~ z{f@RSyLaw4Axpv-&hmTk&VCT);Rj=vx$Vaq$CoCzG>jXez4UqCW*s@uH3!av>f_oc zY;iber897DgKRE0wI08SzV~ZwI7P6x;U(9lgL6a6E%A=~;ulXO_dkoraL*r6vE0mp zM+fiCQ(hb5;E3koedMNn38^BD2A5@wNvl{YYBMZE>z+;!XGTpV)*u zlEJs6J8%o|P3a-$Rr0vrz805qy*`(Vbt{nw8cthyE|jrYRjWM=laOn!F)T*2jIjpx zIQ)^n1DJ9xb6Q#TT5I=3^5ULWi@VeC&67$0w$}KP{$JNh?$zf*`hQicOH4F(jPv%W zKC#Qpy=oV=&e!x5YY*SwQMJpRlXvv_x>k=Z zxU21rpenk|0PW=3=sP=()1r+*KXy2MC`NdMIcA$gXA)T~A~oAp2^(z}v%{+IL%O zU(0cOY8M^XxCA}Byw3UY_;HingtannFfnX98Ee^Ej4xj~BBJ6BSt4?Y)I}GnbF+ER zLJG~!W*}`TM&G_0mt4@@qe2SgEBoKobs2Vs(=j#vvkSo<$X%^FX8>KlBa<@vyZQBe zCZe8y+O74%@*rLodf^1Wdqijh?ah8`W31z@@6Xh|m(lYWp6=8=?VUjIgq_?H*p1JY z7n&TdOX9H}spc_8K3e-f%wNU1=;`-z>a}w?y7py(pWir7S=O8FzAXIK$Ldl$p7@Pi zhJm@RUcxn0Dsv+(5&lHY;UBu8v2uQq=$hBfw=MpUk&tNEw;H<-o&L6- zqOZSF9lo<;^F)7d3d1hw6PU(b$QShUP_p=eT05vuSJWOFKl(mCUnJ8dec~oT_HRF^ z+(pSLY~54ht7&{rIo|n5Wm+}q$tPqeqj7#cxQ`i_uSHHYdM@<^y0Sd;&x5C=fdfyyF}Q&v)f@g zEBrnqj|Vqteh_|hTli;T@oV8TxiensKYN-lMGNeE9ui((lcYMTTE7X)kvprRtS9pyfDmtwvShU2|a0=t1%3jf%M|$#A<({b@{3siu!iRcCyf|47xv%=N+BhpZJ}xL| z6TZ#a9!|c8pEg$4C0N-0Xn{6|#0U~w#=VR#S4&-V2(ERv6L9cp5|%BFE7!)K<5xbW zz$_>t=hQK?HpZcx`nA@a8w@`-D^Bi8ZX)OARHCuCAMs7YZLVo;pKG;=Z@w+u;N&^G za(L`t2`|`N!%y;1KivPyt{pKnuk{zZ>NnL|72c9vtYr$G3HgVb1-$CbBJff_LNhO9$I)m&9-X} zrBc(A7pXlNtWKHs4O$FHW<`xq;T=&KH{7rfw;~R_BA!b|5(L=#s<4^Z1Hac}mv zALY+_s(*GNJw<KjotWIJEeciMa?p72Vo92YG=Qp>^TW6j6$o*!?tb!yCQb)$wZFUxMN(0l#7 z)(ZVq>y=yfeHO6UMz6FE-0E0^#Abim_BoM9)(7r(u5pAei+X4zQA+XH;Y4x0*ZA%B z7JM1VEaFtWWZSAAqREcCoo9@uF-^-S9f|S0p`|19Q(HeN=V7RR!YwY` z2gcsdhWHfR?lyH;}i#{*YVVF+t@Ga8D7a=BT>Yh1v#j`H>InP z_4~8>9cxKWmasPSWP04UMK4e%JD|@+qxeL|&_-M%60m_yd2zpjdzMnYnWlTe)TFi8}Y<@dL7V;Q^v+Z4Olty8W$-2eQlI@Tjxs$wlIK5 zxkKXet}B(bXU&~T$ekyZ&#@c~M;*dhSr6PxbVPEF+a(@r9f+7EQi8K5Z^WUn0NA0t zCJMWuok^k~Ug+rwmARrfzo;ZpIavIs#Z5N#iTz6?A2F+NxjU-)TyMF1;;itQDBio` zH>V^!*#Z4cHF)<#pPw}Rj(8d(d>`ovv7!6*JoOTl_&iiI`0++t)7fW1zh=vKpST{P zXRtEUoPC7q%bF#nb(;utolf0 zbVY+S=n}Zir-r`T_SR18Q#&OJI4>>jwj?{}M)nK74N394diGdUK>$M0xu~hsPV* z`Y5V7D`;-%{SiUTck&5v7L90?710;B#@rJ{ahCbCG}0q#dqe-x8*Ye}zpBMmX%d`o zd86NTeIrZhD}90+aC+^KAX!rzD}shIGOn|>Ev?;}&zIr{%q-FvdFhhso!Yyr{*f5_ z1lf-^+WFF9S7hyED#X@#F8n~>7_Z%T)gDfbXitmE9FRh56q!B=PxtJy-*858MdLfG z-{->Kdy;g|L?`=2ZAiAun)gqlqi2$2ze*mG)y!^jVct*bW zH!4X43%Mu2Y<4hCt7W1~@%M1v|E+qyrPfm({w+8&{*uF*9oO3aZ?g`pMOQR2tFl{= zPv#chW`2uAPCc|X#9t3q5gYe-DxIfRx5Tcx{bAk?^!~+o2x6Q;GdAvdoXI^UTwK#i zlh^Nn{@&JS?w@=veBZCXhlKTbyzdA@4r~6&ok@H%(O6*lc~Qe1)ncdrjrit!VLRC^ zum-M(LvtSgsoLUx=G$uVnJ9q${LiAHi)!nR%AQw=vwDj~^GMHLix$bibaw0iQ}ugK zbd*v`xpv=|ZxS1mGp#jGpnJ|j2Qdn$TN}f6&HT2oeOi|s(>?l=SYV3=%geMay7~DJ zm&6mN*YGT!dY|wE@8KhjXByk5zm*cJ>KwuM^B3ha{G{=M-|5($H?-e`rvkY@8+rOb z6njOIYhCnuSNws!wZp>k8{!@K{O;)48Ob%g2V^=tto6bBa8B~?t>~CN2<}SfbRK(i zoWdeA8yNXXZ}G}pkqqTlc5<}g(SUw9dGSD8gIg=O=k}1K>t6NF-o}Ln5~MQwZ=B6I zBkAj&if?D>n0Lu`9H2E;=>4|T@+fZP>p@Ar|D&I!RNj$4huN%or zEZl8=eLP;qOb)3O4v*Ng4Fe!@_g+$M38C zw<^0X?0zBa|3&R^W7mehJ<$JOMOmNK<0I95Dhk}&wDeIu5)(}xKw?Ze-8bHgHU!s< z?;^4BJ#i*!Y!pVUPOXh$__pXPiZuY_ZtrGt=LkL)A+8{CBJy;F_*4TkL%R*>Twd?haVgK8cS<~?t;kB6#H=GV`9 z^Irci2p3P^V_7Ro9SUAJ! z-c+<1iw*APX<+K^rY`$K#9`F6B0K3cv>k4$bjZTXK>lFouWgy-QX#jzX0fx{y{B52 zh_y)2(l6)~KIt56{bVG565AzO5uTUS_n%si*P;Y?6B6P-gx%9yX4d*^;l}h_uB`2& zxBq<_ChNU8-%N}(=WM_qaxHySW#Ttn%b3<>mx#*+I%46j!<> z9(6L*Can(<+BaM|O&_Xdj9vz)_%PBJy77J2^zB zk(R^TELWp$=R0RxBzE$RSr7oI#4 zCX&has&J3&%S0_)6{ZqF!96`>SAW{HfdzA|k(gJ71LySas%qec|JYz3zIRUfaL47E zFyf}ZJ<`tu{lBBK#4?htd0lV8*V`(0Q%}hlkoy42wXWGW-%h$d(d@B1WPjn=L`{T5 zgS+8x!W&>v=HuZT($zd-aD2}OD7O9Eehr?RthaqB z_knO`8{H_E;Q45Wct7A-K<;rsrCjaX@vYa*Vd#=Yi{=&qt8s<+-bejm5gXl#P~Q+G;-@DAFE_A17OmsWyCB@eBlud91??JNAz4^9MXeiZ z({6@izm|Qd4auByYV)(W!*O8`IoMCDwR?JdSuL?sK*ld}E8rDe(=&XChs9UkiUX`l zx}|cc)bxJ8qn!r@Ly_L_!?Yn@@UfF%V?5J*LmEM0M{)f1IPmPybnU zIK^^R6t*cE#j}1$YlQ_(zA~bk_UmU=y>ipRMYX-6@0@Jm49$jWko|hETIZBFd);K} zM9K<54^$oZb|6 zvY+ysq{|y=f7hjlk_Yy%B+X^;?4-i z{$ZFy)Uo?h#^@@nLc8uTj5#1Emz&?N7>`*;RR^?zF9tnUb3ijIY#|nmU6;>VQ*M7@ zov{#z$h<7P;Jg#31yAe!Wnsg6VbU#O!J1ZiMe|DBH4#B;!i7u1j5}J@--KB&)Yd8C z3i|d5mBJq41U5I5vTK9Za$aq7Z!WhMlHUM)B)W}fU-gdrC6zrQ z41ibstQ9(=k=SnnqulAPNC^)L;wZ(P&y!`cj4OZm)pS#tSI)~xRNamO6?Hm^+A zo_H{iMdAN!##$BCpVJ#MJ)Ba%4}|G&#P#sLyp!x>hvik{ z3FKzh2jZri!cX$J5c_yok{8|a7nQ|2BpT_iTEJt3JieeFo~vErNuKK4SCzvDM4n9U z+2i&+&d?I8i(PnGW&2|%Yn-!96^q@+ju`i8Y^mw&sJzxN3b1pB_-^VvdG`2EMh9*m z`6A5l8-mR9H5;tn5H_*r{76{Dtpgu~MfZi@=Wh4G!zU-La;wco2a4NjAB%ueES0)<$7kC`0D`zN(C z4DU^kL4#Nn-q+xEN~pcF`xW8#v$L$wcF9ftQNJ&R;rIj4m|qDy&ue|iB4F7CzUVEP z5+CcA_zL{amxcGog}Z3hXH|>6?iY=3AD;ndrPx2eCQ4v$hsgI^;_o-~d0nlN72~v? z676?c6iU3`swf4``jOhgcftLRL>wOc0coS#uTb~c&3|V&-}&XN8>@)F+|SVxtNlSw zO{beg)uH#fzGwf*+{2l0bnksyOLiodw5lt@0Pfu+LIbUSS@Iq)?n}LeXLh}%AA=KI zA-gL)7Tcd3Rm=K;M}w{0%S~)0b5DMj!}_5%aKKOdU@#3~ue6QH(70tmhOeL14>pB; zKBmvPHGu_jUo*_D4`6lbB?{hTb_N=8?B00X_L4?r9wz9EoHQ@D=B~}F(sur;dJja~ zZgJ52KGpSTaC>X3WEj8-d}`K%`Le8>CsURX^*u#9{Dsx8{o6*5r{(F~P@? z+oWcR*Y(J}B~INlk7ZU6B8*Hb(m_6?;q_pjP&Q4CD^>BvU^>ZMAk1^W%IH61C zoyeV(L)Z*itY59)vL4y2xoOt%En>Jr-*>z?oZ!U~!S=IYtm8%GW3wFGtbkjm9<^(; z;c-~@%`LDqnu|%DBf2p*=w*ZLiv-wo~|GmZ0Mj`@)g~qO{%++)Y=RJBD9LuE8-= zoX?{t+LEvfANn{48UeE3BvFhI4*@fNXd8?A^gSdO(Y0t^tTy%o-(Bb3Uu*fL$`Et!ZQB2|Zv&6D4t{Yu&NL~qfvq+8m$v?&4L+tAvDDjwQ^1gxn3*m}ZVEO| zkJz0>`H0&vSxeC#cn2Mp^pTDXI!nhDwd<6U!%(kX!U2ZDeeqbr$BA`ydLY{cd9%P% z?C&-%vc}M$(LlO#UHqRBZIipmwJ7*-f7(_4VK^4Z*bof@4cTG6*+;x z!<1Ls{5UmpT9^|5*!ABD^`k#xKZD`;vFuC(HND>TN{MI#2wa*vcBj(Rdv(dX2%hNo zw%GXNZ#si@+NW&EZ@hk5JLVm1O7(A>!JN;uSBu#`qnaT#t(TIY)F_!c=&d!L@_kZW z%of-TzReCx9l!dq)I6#+{H)dc16O^fz{>9(r*h6W3?CR*j*G*%T{j+ieeXZVA@8fL zQ3Y-IIJ(M2NpCH9G<*VW899ZH0vF#S?t;~c=axGVmc;qJCVl+3d<#oWEpDQqwn-^3 z`((Qet--C39_S>rby_{a_w1IwRFCj+ENOqrB+gLiyym>1iy1UOpq=^XmdiEnTiO<` z`x1$y~TN9$sc%*CvFiud?=p(muTXunTuY_k8AcAen_GP*wHlK>*R9ugFgZ*hnRu= z@*UilZ{m>tTg<=%`G_Cr^F2Mm57Fl%9@by#9UfK#S;|hf@0RRsK6wlQ-kTSi2ix;Q zFI!TS4E|o55v*5c7Ebj-pMFwn`Q8@x&)+ea&!4jsKBX&G(=T6Z~D@`j`9ewbk)fX%8#F zTBkqz1g!_XM7+Y1{8w<4bQPc{(@f{d$)G?il)w~DvwslYkf#ldwjKF>2`0t+8qb?W zi_BKa9f_KP6S8m1-X14}_(mRG;<$%#$5}yE{&un^L4( z!-m0UgrA1YRC5F-U;@0i$;B5J2s`aRO7s)^;wT{khF#V$M%-_StHZ8~D(L87t zc8>Kg>H(|9N0LkHuBad%iSKn;6c;p$%}$%P!peHvom*nvY^vn&F(YxP`D$~nWLMAHDHkm5wA?Gaxsck$dBGDxutm`!$>eRZj~ zu2qKD92M_gZh8Zw%s-4y$*en-Fp5|as0#Sj_5X_^hq*H)9VPv_H)BbZK;+!xro|=I zBeL4+?> z)+F7Gb=Cs3h@XqP7NcntmGcI?Vg_^m-1w5U{^tfB z_vFCe%D!lsSaMo}rr7}kn{H{9uqpngC-%uKf+0NM?`n%IspN9!ob{4UOvX3UXLFBl zeU?(_T_YHq1*?pNpDSa5V%G{73L64B1zitm4K%KAJ4!?%HBY1hB0 zXY3o}EzCD``$cgT%y`L*QvRKeAzj;YBrc0DXhzKU3kPFfp^})R<%T1AiFcYwujx`8 z>N3e~GiSZJW^u5Iq4gLa@>c%bL?SJ1Y4j!~-KI-*)Y54sII8vi<|p zvUul)DByx9^Q!)@Nr(97wzT=D-jOTHvD`Vm^=YvT=hOpxd&nR-ERxYOgPGRh5-g-i zTVAHptxqaizqE@S%tvW_DuV^W6KK@!wnflS+~W9<242X|w&*Fnbll$R^1-P&5&AFzAr82b>&W6@Z@esG<4o(RYuVMmKDa ziKksNWV3``ivIJq;VNUWiF?w>TXa@)U~;j&3iJV0;NJo>!Be=`n0~T=Z9wTru&c2OT^zJ|ymBBo5DTC@*Ti{95Y0^r=!!UfZok&s^+ zDaPCpZNQrGiTF47HAlRI)iUkKX%)SJ2rG0|ypLe<<_@7rW3y({XFiWUe@JcC4Nf~D6@10|rgc+s0t7Av`)UnO+%m34w>w3nips-qL=o~G}PVBJywyIrRj~}JL1u++Q&5scuW6pijSNY-#RPVSguP* zjwMy#2IQNuC; zd7nfGyey@GQEf`&b!mY{<@$lsdfK~bhO@PG#&D^C#cdp(*yqVRpCY0~-^e@Q0?X`FH)nMo$|K0>Zv3$O<&$UM z_Jr2^fM6Z6L%aAf4Bf40uK_;gS*#*6>D~vSw8!Y4 z#p@brYV#Sj8#gf90lH2#c;hTqBDiW_DQF(wYG0XJbc6XU)4quk_x@eiXz#OZG}8F( zR#bfVZi4M8*k5)!eE+_-r?8^8?AhB1da^0GFUFr$(lOC?M!5gvIYinQnL4rrEYh>Ybi~R@q0eq=^pW=(_F0Av##!rxAm#v&h z64Ttv88BT8U7Wrmf&$HNUb`V~%NWEyGwI$9nZV5lg_g&h=6YL~OwP50up>%Y-S12F zS&RBMcdMEov#!{wz^4yXV3Xs2ItJcxdhvOqB{RD|r@m_Gd{dhJdiHGWe9#y1FK~&` zPo58UV%zYTrsB|XY9%NtMpv(EbL4g1&unw!Qhc8A0#5lg`JBIFB&qzgY$xpEbJ7QH zgDia@S#VI#u&Rd0&vqX*`PMEK@`q>@+gG>96+YWrY!%;av1~WCdN%b(vo-^i229k~t|dY1j_Mb-_z5 zk2&&n0xK-j2Qg=Sp8Y!cSl|}Ef68j$X=iPnsu;b^e!8;kZgIAdb>t?=XaijSkHW@J z@xb@Ka?ct2L_f(Fa$DY!^ZLP)`%nG7+IUOIA$+D;P1@#%cseiigNJ^x1Omuxh?r?pVkD+s++qXKeOZ zSFRBHR0^TNe>20bG%jperIAZ`4au~g*WRP&@E7yNq!^mcQ4P0&tFKq%IGq0kPYr6K zXy_^WEJx!#h21>7k5%H{BD@hhAVB0@C?l!}W*h1>bT!bsgkeLgXARkKFdmS#3Kz=wwZj ztc)tMJu;)L)55%VG*DXN?1cD}bjNLM6r%BwbK-hr@Wp~KFCcw-Jl4*m7Tfb<7T?3h ze)s4m+Zhh)tRCME4ZD0cDHv;mv~h0;xK5m>=ld@0*EAC2y4oyHkEK@5G;v(Ey8aia zyLQdIjN2PFD$|g7mvUO#N$u$1w;r)HO`K3@XCYS>)2sWq&BNQ)5Xg?+Bh&A7R7CIN=fa4MO;ZuvTuP<~`@w5UXbpT(7KQS1*Qb(Rz36N32^qPT;Jq z(-1C?UWUZNM@vpu_N^_t1rJTv+=Xph#suZF;`Wu(6RYK#rTw3;uO-(YN`D#Nd31ej z>NJXArP)hgm2GfERwE~Wut?LLlu`@bNz0`^_dpVid~fF0L7!vC3|($KD3WhHii3GipQ z*AwA|QNG<@f;1xT#iWv-&0rq@i9~b=ec8Dnlj^hsFNcP?Ne3PXPXxk8jh03xQTLfy zkJyOrp(A@7wcw_B!SJkE=?{uvF%86`-+f2tv})tsB?maZTFdk6<40<=p*LUKzHMoN z&cPh`2+cyW*`_`qK<&HSeD z>bp%OKF^-&4f(c#&OCwKlgipt%g;T48zvHV_d8~7O$UU}LB@0ca* zX3AL)Sk2V7_6_^MVP@WXv6(XJuwKd2?ByM^Z3JL8ZQN^m_jg3Ng1JzDwT3jePxMc3 z;0^O@dxESmaYnRiurfAe+A}?6BnBxXf1%F~t3CCxaepl(UT(Kyaaha>`SYPqpkO}m ztndk*N3ZtugZ@9(Q=;_KwrviHE2AxIX;~$}@$XXtqF=zNY-WvvK`V@eJDqcVCrTOx z&q`YE3<_o!O_?zOHB#L99oUa70W(Vf2zbmJq85%w_HvsInMOTo!8}&>*LfbaY&lRp zNBXpqYUg8iS-sMXf}8OCd=1d1QkJZHL=v#4<94%+sN4;=r|55MYOU_yU=G+rwEY;9 zoA0GT)jbRQnz-;u)_-}r-KAIwAN>Y?ZZvep&OLIj?Pox%TG20myS;>)O>Ja%w47qT zy?5V4?WCr|(GNi?SH?#K^!2+gEN)A;|Iv)3^PbK|4h!SX>$js6+GW0IUZJ5}g2p@< zF7=LzwWc+{e$LvAbuuMlZF|8=lwCr8!h##~Kv$7&BwuGNiV}jbS;b=QXe|c^f{L z+9>gUd~V9o3c04vHd+R{mXColroBGj-XlzB0l3`GOg^E z=1VbraUA@feJO2yCe_JOd777;w41IH1mvkxF*S|*ja0mWS@Gk8^g$zk4C;IP0~4aO~Q@Q#Q<~{7w24SvMuM?)7W3mnJm&Swe9ev{+Jd~YEynYt7r@qv*7xhvWJK{J1iZVdy>Be z*B?9P;e4MvLWl8vvjD-~+3j%C+GO90?~ar<#7-s5YptloYdAl!eZsaZOLu@L?}vA- zmhDu(!Se}m$_W&-@DukYK6vX{#~ak-t%MFiO;t-Uq%^eoqow$ld9c& zzdMnzzd!%5@9yVo7;BV92#`7U-zujiY&G+ee^RtQaSI=|c7W5jd0$_N2fWT)mZLw=?l&|d#oR-}}O{@Su81A>{MDPBE=;T93 zHeB=ebD8bf(so});r6%hbjGl#e`3lV`{P`Oov|R2fS4L0w$sQ8(;-s-yGQ98RK_Ly zPECwIBLV%jDNwT<~uAzeHxrV zb46o=0pD_RzW?8b0P zfOw6u`%>nmh z?bm1K0*^I&yWIXp40{>P&z>$AIW9VXI!K*6jyo$jU0-P&Kl6c?gTFjCI&9CcJ-5Go zeDHg{K029 zWBXihi21Qw7ig8Xh@0jFH<%u$rpVTSrW+>#SsnCtn@O?))=qd4fzRzxz)iF_r<;iR z<<`b~%_$D#AiRU#C`HfdJD+);d;Uc}b28|;dbiqfp6aREf#XAO%uahQY{t;q$-QJU zY&~(iW5(Qc|JUO zQm-j@KBDybo}>CyG;qR+#1RSwK(u>6Tiy(Df~v zI@7cOo#cM!-C9W^XpHi5OxV4hX`}7iMV^#7Rr>od-Ol6%9K`rpVC9!x(H}f}uX>m? zSJ9)**|f(Anvt{MNF5xN^H;%iCwnyNNEnbeu(l`jPqK|c)Jaw3G)Ya~ zQ#q&9yZI0BZr~4CZ|3VkLW?Hz&=fW`e#=XP4YfC<&F4~M!#NIZstYpszul6)nwB?uktmjw~SoN=zv6p*1v8KosiVbM< z=XtBWH6ZP);WrtxLhbeG+BpqMs?EZ`l2tKZlHJ|bo=4|IHgo>opZbjYdAs&p`aW#T zV%Lg!n>L4k7Ou7FthV!gRx`|8lE-@YHYSk8nGB2OW5QE}h05+Y-o0g&bj&Yv-vy+; zLaaA-2AQ7%!yMjdCswFz)5cuW`^m9hvlPGzoAXo)@%f$>gKIs_2AgXw55sJuJHzaB z-n!?kK4UdJA42V^c5_dX)mO)%YC!x>qRf~Uax$`+EkTt`|FK#$~|{=+HziJ9H~~%OE`xbFA-|3c5z4VZD+Eg z)+49OC&`Uc2Z1go^NElkuPgKJBbu~+JJF%ih{>EHccMiwdi#kv2<^kTXnZ%0VCDO@ znX8iBreQhF)Hu9pGNFwI3|`A1@NdqMfFK?9Mx&vHo#K%v@ua)=&>W+8)3>9xK~X;K zpA95`_@Lm0Zev?S8t>{}D0o>3uk{r($lV~XtmuJnm?IV$qC^W z*uM%bBdE6C6WL>*H~gVCF8bXGS3V=SJd;asWwaV@bW7h(ny1uO-)y|`!&Zn9>}(DK z?wm`lX_bwOk@J4?{CAJQd@nnle@2?`81?g5i$!^@F~G}8yrH#jP8(E2xwb3FEYC4abJOed;IkpX#_T`?KwUh1#Ook_K%e0-%t(hIxQYmG9?t?CZ3;25W z%Uy4w+>P$+sN4y?jvXatFP+CD!Lht+iIt+)yZj?uOPVX>Vw~pg136 zmruGjzB=7a(^5%slXp|6}3%RJZj*M`n|4wrM7osF*D%FwYzO-9D)g*JD}b>p_~2>0T20ogv+_1`o| zr!>5qw9UAEml*FysU@WTMYIK??$~<_jmukv$N7nTG$-(wTTFAm7H#x~M z)7R(gon(WZc|*H2c!_KU&Q!9uSC?_7D_qkr>fSKsb2ckq=eu<*n5DOp5iA-bYV$h} z?C6@)=`qFp)i;H?5uwBl5!h|kTk5xFrw_Y2Egjr`k1WwI4Gox00YCHmHEZ0%DKTm- zDZeEgZ5SQqTsh#dXm{SSA4=TU-y5#9UuQvc%1QY_&|uzfa9d7P2dq1Vk^7up>c{d} z8k}%p+hGP8i$kwNQyWRw2-2B>JI5IMxkzobeKx-BT00cet#phZ%t)nGKG!jC)2wyC zn6ET)4}XEh2zB*1W__clF{^8ozusUR=j8BaKr1QjTYgn!^r~#swM5T=1C({^KAcoX zFqw2$vg~E^>o=wk!CX9)UFCcRQhbKC)4o4wd}eJLw`L7qszrNN>MdRCVi-d#7W(HE z)dnVFl{^pa9?9xSaNYA^*&}d;sXDbtQK=&yw0S1z=u{* z(;w?T9eR(t^)j{An0ul{+?$-YQ@*XW5Y}d1H=fsOxt3`1C?JpLwOVy4oA+BUQ){iX z`|@_mx3w19HecRG`+cpIn!T5|Q!7zxDW?tEsNov;_C^{%|P=Pd-j*LtHJ!;lhp z^Hw$*9IIn9ZM1n$UvJ%w}t%-r#*$Gl_ZCtPLJ7kAhk7$a=WK{y^G5zI)*9rX)L(6?wNHgP{NA=`z!w+Y3 z)^>X6XLHtT`u_dY7q^C6zDd77+}^ZLO`Q=1Tg?2+E(uvi;5n`W`sM zs>e6HpGaaPgx_Z9IlAoJg57q5mhx8Rkn6^)z(b>ZA`w%JjeAV6_&H&UZq1G&JyEY~ zT*k|cZmq@iG?hy*(-$Hmecro6Z@a3Yh2-bo^4*$tUw99`2<}(Kg9jTOU-G2%jf`9E9!sfjeHghZ~AjeK{*%A z^?^n4?n%AEyYn*e4?78u9mh%Z8pkgAJ$QXUWoMfse>O8~`Zzou4WIG!-EGJz+aWg_ zcJr#m@Le2#D%Nl=!M9yJ|Y%Mk#yKM#rrk?D*WIjp@m;l3(hSjk%3O$ecuF0`Y*?F}{*kgH9OuLSzGc<+kJ}-N z%-i&TU0M#71Rf9WvGSQ_FMn9OU4fMh;M%hpQ?b>Fa=53^w7BLOAGH(6%<+hnGgyG*F525XjIGD}!g8%(1@uT1|bvjpzn@m~$lf`jcH>8(H8|9mz;s zm&cogybtaLwb%5Z8i%VvjeO^Z1kM*)bY7d+*0gFMbN*3VyPNVVaK33xJS4TSX3OVd z{oZZ$2N%zK?4pVq)TbpC$edviJ6-gzqG^6Z)+zSYurN}Zi1qB7(^OAgZ|oCdu-jTv zdj*k|v(eAoLLhRf-SbfBYqr9oM^dMnv7=f`qPlAweW>;n^U6Ba_q1ymyH-5|R>y#$ zu+(Q}EL^U|off8I8IVn<4p*1dGaK1zg1@1^5oZ#u_F>&w_5E>Mqns5i@Q05B;6cx= zt=f6f&iifMYSy|zaK-ZGhHf2UGL-Y;+$D@-__fVroomk<-fnJQ*TQNu40ifCY?n6k zf*YLmzEasU99pwiy^VRpYj&*nHZ8=V$Il<$=xaJ?k%0Iv&BmWMyhys}Z90fo)dCsr z9tpQxBbgWerdfLSN&B#~XJfbp^NW9;qp--q8n-rS$}Cv*v#_9v!@}_I4V+SR2V~d1MXJ{&9@qMk(+7R%6L|YHhq@MwIf`Z#ANv@9uO& zDG&ZuBg%R6m=XEOiIZ8Z#hxrOF69$;M(!V5r(}qt;-|fHW*$T0*ReYAmFI1GP5j-4 zVRj1#UT{t&V68y$=6hLI54U&S+VxNE*q>F@1~>TK+B!`Y@m#d&_Q^HzclV&DxvTQh z)Uaqm?$M&pHQ6@Aq5afEkN;Hd!_RR=Tg39GF=Ku+ij^?$RT&{dFaJoqLguZ?OL;ps zTQ)aD8L-}O1+BG#-zi|ROl*uM?$vPX(pEdlru@ars3mWUPwc{e>p7EIRrEZ0}YH3jb}uTxw5 zvi%|6x)QRp8mW7N9KQa(hWM(i7as|yCBlO9N=B^Xnz+e6uX?rR%vNyGujsc^rWCADThB`<%xrmXJCOlWKT5 zi}CjuK;Pq%ulY7@g%eabT{-iZ*fTP^%f$Q z&t}T{_P-w_s~$*K_A}7*na<$k{=Fskam%$}q&Y9>g3(v1Y=QEVVD!2}=4dA{*05q4 zcx&y9fjwqCJ(=WB+c@--?4V!td$qBR&d7SXsWo2Jx6`{W==r+r7#l}WcFg-P(z3Xb z-tf^+dG|-Ga`wA6Gi}(`wl&vuAHG(%h6U(=^__fc!RI7!(?;kPQ|O`jlbS7?mzdsK z{!W zzM}t}wjs86>?xCR?K3W5g3FR;a=%Vx-qSbk$%}KDN0rs$gihK3&unskjGYHt1v>*i z{~1Zo;2hY##d%35Z%%H>DlCmn@d9E4i83tX>Lx{$F&;nf2Zq0FZe=&wL#*>(xB6KV z7UWqru&|$K9qqiIWqm!zn=msA%munbg%VG-VfSJ<(%2hPIlLxVBJg;haK zlx2zow7ez=bH4FxtE5|fUsQ+r1(zm|75dA^!79c0@x454pm@~$wU+U~u##{kq!6u` z=aKnxYVcJxxYH9JjGYyt@o3?Ke`oY!v;b1M&dF2!^CxDMiTOps?vSc;+BsTRN+H9}NbeYP=VbJh-WjxcK zCZ5kq15v8|9NfxZ!D(b}QciWC)HWbDMA+!HNai?^mhxcE>LH1SXSJxs9&L!X!uif< z)lJW6N1M;Hf45?0)BjuX6u67+=GolD>CW2tYc|qsU@M6>zY~-zD4|}HUKP7Eh zjxneJ?InKRYCTLsp(*;E0-mqL%X!XtzV96VSV8k{gpF=Cx9x>Fw%G1wiHYO^v5ZdX zj9F$~a13qAZs(>XT90vO^6jFHF`quSw1W;+LgS<7e-4@TOgqt|%~_14t9A|ZY>a)_ zo{smevI%$H>e)T&x6R!kT{WgUGCt*a!1{{rU`et5|J70W|e7aFVz?FRQo1 zf6weSsXZ@O^EsvM@fpqLomLyk9gzc*dZ^bL(qF#UyDD0o)K|O4kbcrwm&otfw+ihV zllqD1hdK^;HvQ5sp7S8*pyTi>Z=>WE1zv2?Bd7iyPW%_Jia~`K-0$)Q!X8H zyw2zPCDb@x-3Qb3xX+x|VIM{lj?2tiUt3NvrSq~-m2ZQOpU-Yu_Z z%{lb4g?1?)&6+s4>rZK)?HXxG*O_Y&eb}g6kdzmM3I~Rw*t!hIm`LzDmUbAymSU8x8pNmH?LgPZ2R3(xxLuc6819C1(-_}|v zxn$l#`PO+1JN;#Ae$R;6XXDq$#)NM&JWOrtueNUOQnmH-9@BNK*KA8^hY)EE z#DQntDn20eaQ6f)>yzaQ3mqbD#d)D)m$y@^N3S*h?iAGS$>E$u>)wXrbBZ$oby=zp z-oWyDTk*cHl@j0UZIz`Qr=7R;^-#*(dJko(z82f^w%%sDTwkj-SzB+nR&rR&mW>Ii z<h||#*%E5n#<2eC^@sPlq0up`!$+9*=(W50 zb1t3B)$bvrbpL)KTt1Jl@r?ZQj{h3dGg^GQ*LqL;e-HFa4rZbVmK7s*L_h4b9@MkN z?6r;^!8~?X$HI{Aryfw80QUj#m*>nfxeU56!rt3ow8HUmV(qrcN}r&I$iz;pm&QY?xE2|-)w?w;LIN4tjE^hZ5>6c*b-Z=Ct!DcUblJe)B))s*p_ zy{MP&8MDXed&XoXPv_{gtZ?4VGKMT|ANf#=&suM-AhV3l$vC^Bj6Cv;*=R>&F{}Bw zW4(OT=+GC`KGv7VR<&cZxa|rk?l&#cZVfA}&Akn7SZo(1BaX>NLsS@Wyi}Byt*N)p zcd!DCc)9hL+TVY~QF}I=BX`Aev}=Hg)7;_LM|Ufgb($VB@YpcLVtu*M@1Agi=$S); zo_+lz;_yeBr(~WlW18j>J=31aosDp@9Dh81unMU};1)%b2tP}XGXEhNu+!7{Nn&i) zL|ad_Qh3w+)Mq>1rk0iTh1!BUdPcxn>nRt%sa_&Wd%F)X#_uCcKabD+PF~V-oTmM~ z)d_)8Ho{ql$M{#`HX7R^S!6 zRPyoHVvu~j+-e>JO^kKeJWRq|hb50Ls^g4nBw)hOXhfd}k9j&-rAp5JnC{Sh3MHjC zhq{jOZ5;xSOn)7Z)R|xZDfU@!W{t%jvEOyT?#Le5J?MlV#ks&N(?f{VgfBgpu93(1 zV>hNVlyjs%>usFVpRfVluf;`=(c9ZTYN7XRowpM{!)B_i~z09 z`nMH!Z&i%jPwR0~;y?6zS35-PFA)_NcQ)I6*zFq2(kz`LnID}D^Jr4s_>BLz=E?n} zIC5~;c2$rNzzX%Hc5^zqbO*NW2Vl+}tDKhmZ?p1Jwb-z9KJID!jL+sHU03ffrB}46 zS6fj8-JWpoyKA2|?SHdb`MZrb0?id{V`Z2#Bz4>~{4>8Xt49t@JV8(t^?quo&2~3l=o{s^B{#)cA5W}B zJh4&dV^7yQ9Y54Co&wVrobu|cQiB-|!D+(}8naVo4y}*H=h*y!M!)U4?X{@&0QZC! zlzXzVQni+Ab*SOHuO`X=r&*))b8Xy=s@C45(bekIV5s%!oX%&|aOvM0X^?Vw-oqy& zj&~Rj%Hximl7i!SzdLU`#koyU!=JL~ERQY@JTfVV_SDWIl5(z^G+ftAAbCqlN+kt) z1J=CX4Y;QAAu;&I8s##PC(J9c+SKJ%!t(Y%-?0pO%ID5*Ta35N@E$=sD+!vnOzU+i z%2<5887-Jq!$4YKq{JiCIAcmlwfe^U+I!Qn()8dM$7dknZHnLN%DMh9=C(**mDra} zIjYYC@@+gfb$F2QNM7ft(HCQCuR^|8^iS0`x#K%ru_Ad(7K;Nfbcti~3p_LZZ&TUP zytSXSwieH9k|Mi_F$mh6 zGhNk3TKo5juJ4#WoWE@})E|5NlQd!P!L`SoP*lxA$mhLHRZq4!x5LrL+iH47&XnQ0vpBOTdsu4>9Y(<#LJX zD@hJW*XGA-H!fiUf4b})FqWT)AH*8QmSJ^2HP0V3|Ig|P&#?Y~+O{ky3l`pOG8V8K zg+GAv<+iJ^tg-=3j&J$M$B#0&wbP&XWb@uHSyLS?S^~?Q3-nvd!5d;NQ#qTqKRe4M z`eKZ3PXhI@`Ma*w!9Ql&AR1>Lk(OI-b?zDxBIYfg0n21f(&yM$E@m@uHl0nU3opND zPMga%hbBhdB`g2ny7RGNXUlbm(N1nZ=JZ|Kcu?mbJeOHWc}RMmBY4L&JlD8H+O}IJ zX!NU+KgclOkFb*wSe~`#({U_fBSUI_@BFJi@;|s%NE_1`zMZZZkc6(7`hHT5@~3TY zhRZ{=wp^cb%i8>BWlMS4Y51SZz<|Je0@8j<&1sc=B#Rk(A)Ns_w4ITd3*KYb{b%!* zG5NWMv^RQuE`E!wc|V{m)+_zq7mu)(Q;j93?6My;r}PYr)z3X+{Vn9akn#21?!wv| z13h@f9JAV~R}b55Q}aO_LduJMWjW>f?<&JS4rT0QRk{|e_aqMJD`}cry6&90v{m*U zm#(+;L4+dbow~{}f&-bq73@fL$-tBvEa_X@|H*qw-*>~4mNJO;Z^M*ZK`CUpg`e+j z#qLR7-?fY!$`r$6e>3QcIf>qucU@C_hRw!5lHFHI`43p)G@nM<^W4S&ZlLcPC3nMP zxv%2<_)lB4kk(ixe!9$jcwI6Ixad3A%)b>hP)NQmZ4L;;_0=kQN_ddl=dtQE(%pi~ zfgxDXZUxUkzLI5`os2u@gyTouRe#c$>#LBr#(bp|lD}OQmKwc)aW5Or2%US+U~M@w ztUr4T(B`nVy|uEXF}RgViy=7R<$ZsE@x5#0h3|ichY$(GsB;YQ7TgR$c2U z_fB%IOk06>H9MCQ!~F`B_7!m*t6o3Kv8Jqht(W;~$jop0+ckbhwP>#{eY$72y=L#^ z@g#>1b7y)jdMo)V(MO=Xzvwsgg07JvMai2RR(hwev*dt?9ifXPV4ya<2%p81x^MXq?tHFz2n74>WXlTZ7t(dg6BQ=bKi~m|1CP zJhx})@nOS1O->m-x@X<+zJG?XEtx-XbGo_RXk=t@CztPY!Bgj3HU8f2i*fz_B*^@w zN8l=-dO4o51M;y9?6TOE&$)Zf+%`Ch?DdmM1-1;y+(G}a0YSd(Ku0VAxn!>A|G_6sYw^GH*AN4@=+iaC zcv@<1L4`Rk8sD1+3*9GmP8393P?yK6i|4jliW8|_QS$epXQb@D(l|{QHXz)WvkF~4 zIJ1AzvB(X9E=GAcwB-)ulwddP-Vc(_z0i(bJ_q>;D)s~WN`(I@PDc4DC!`iq*LFF( zp{j9%eh6zd7*8GAdg*}twQ8E@j4ZWJG&eQKbNFoqt>uS}Kjwv6sjmlfkXmF$xtug7 z(<5sQC6h6N{W(_9?uJU^pvaVgBxV=S)}C^BgV1AAT8#C|As*tj`QIHQAigKC)z7Hf znM~%&X767G=E0+Ep6&}mVq7h1DD`>dFj6C>wY=WC=EgJfL;LB7UaNKH2W@Y88)Lo3 z@>bTxP2C%3G;62#a%~O0$#EV0W8M6FPzU&dMBz911(5sC(Okm zF{gs927fs_Rt6X(R)!QaIoDo;Zti)# z;Y!4_8Sk1*MP9=tCw+b|vcO?8{%Ir1Ih~hCPpss+%ImEeNykTf!E^iPH*h=pGDx~w z9w#HbRU6|hWrVlvxKN)t@3&7z^o?|u@**If2egAGyQ2AZj#DllOxgY;%0VMG9`umh4}F6Cc@!~R?hXVu`;D^bzc9Dg9)4o)D$EDVaadSNyX+ z9cpq_M&9BwYa=UUdkv?BX~e;%7-v*$@6T(U-fvlQ_T;*1u#b?II-^oxEB0IZ{JL}r ze8VrYryC9KpO+ltEpjleb4u-RZd;GuCse{|9)ldcja$h%eux0-G9q2t z%U3kpU7S6Kz9vs=BdFtS>i;xadMk|e+3A|)9D>|ZO>gs#a%1PQhD+@go^JlIAq^{- zZ|2@|fP#_vYMQ;7m-Ug<=Cg(ow?xaVQP*6yM@4_maa@kWCGmujl?&Xc!Ad=LTB4-G z>QQxV96q-tU488@G`(zY=?ncZTUPh*x7kk5ia0BfdKv&jyVfS}v&QL6tMS#C7e#&$H-pn5vC#-) zUb-oBGPLud$!=J?ct|&-rzL@7ciCroQE+$5^ExlAjpM8&fXCP^3Vv*0?=vuE%1f^hv~u z_sRW1*6SGjX1>dqgn2{FY)yjTW4Z?4Vl?@Bj2Vqv=_d=T zKh5#?uF2tNo|Tizz2Ei-Q5wtPiKO~R`IlBC>rBe$b&VT@ElT`Nmp8zCC2gB1YTK<0 zd*$8ff~gG!rN=^1m)rrzP)IG3pZiJPia!!VMl>Dt@17&9*4kM76qM~cgiV;=$q-&U z%HeD1zo8-3PHj%!7W@t$eogz$sWbJ?4eQx$$L?NB`*7Ahmf9^NE&D9Xj2~yJi+7K; zrt8DbG(ywg)f<%C%=Uy zmC_Lp?)R}o+pMJDj+Dy(JsOSgH!&JwKd`2lxwLJkVe>`V%tY&qKD3iGe&j#&CXHQ* zsE-s1Z$0Oq%cA4Y`o)KVA9l|cY!N?bvu+a2*TQ5MYgAv0+H?2oFDL8dclo-uX?=C= zpLMU$<;D+T*(yRe#?PI$oUV^+Nq+ak$z&(d*2wOYaxAc@+E|m2-szec_iV?e#)|ao z4(-(lD11fSs$j18q0hLj#ZF-OJNpk#-`5WuyB6VV`@CMq-p#Sl;$(f_A1qC!rBT|+EsFyw_*e15 z&6d=wapY2JIyWvcva4?G`D8Bd5KoWifo=CBZ!L33zce=7BYQRR;9z^imM~{NW7Zb5 zj&6&M&q=%B`oRrTuJ7EekMFy@ah#nbg@GvWnmJ2p)?2$K_>6j|8;@}VT2IFl^V_Xi z*o;m;8v2B)Q_1z?)2Gd6N}qu-DZ>{2VL|Nu>$>3*(ns?mX>me$7x^V>!xxq ztvy!y8Fhv9%PqZ{eCm>U{}e8s(b?d&T~}MOb9zZ-)6Nai7RN?&DL)5>K| z7iY-5W8X7x$o+FexkEm_Z^s{UIR4-eb~3hBy011=zNI^MlUF^pz?i!(A8HDTuk!3Xs42|e`ViX3&_58~Z+E=sjvpUi&WlyRL7;O``RFjXN(pW<~RL+`0XlLju%e zwC?F@hu&S*@8?cGj$Lcs@t~X3y2I zLG5|%ep+YVb04#78U0$Sml~prq?)Kxq1PX;i==P`Z7eBc=`inbswa-6kD8S}Pi^#M zcB(PgA)K$Rh%!?=_8AVYxU*f`S?d#S38Z{3PMCfW4+GxRcVZ)f&V9cfdFJixjMwF! z^l}~pM)+0tPJux*T(z@b)rinMW?k^ z_H9MR{FmCeDjOAf%)MNkxaSkrDjsWgU9rFLU|UWwPNP|bmgx-ayF6^(?$a6CNBTy+ zyQ1ND(nRm;Kf30oAf+a>{Y2krmwXiOrIq&OqcFeVq!Y}Bb7m_^)}U`UdwGVSG(QlZd21SCJHy19R{gB- zi~D|`H+n8lz~}eP^Vbc2p||k-roMTc63;F-Sola!AM0D0(I!qs?bBH@A{fD2sDg7- zeP`y)D!;B$uePKZSl;fT%m!4?UsF2)J-c!H+z{jK`C%BVKVNI;ly6rWEN_ou*gVxn zQJ*LJs=p~=Y{N2aMm;K+Xzuzcxb8^v`~;jw;FN1^(bu$3PAT#R+dY~;>6GCsVcScM zksEy;WR|*llTNm972gyTkiIW*+{>6}h*%_Ss6Vx=?o@kr{bN#TpD+3!KVt9Yq~J;C z!!pFZ=$wI|Yad(iiKD_#IO$&TQa&G0#x~;=ePM_V0hhbGv8%{vl-9vRd-9>_|G1- zoYwHYEb@LmXwD^Ayt&NYvvz>TgEGVhFW zdd+Sz8eOWnrg;)fdzqI;H>6i)FV*M{Xtu$j6T+ppLk=ktgX$NO^OzR2IA52lcl_!i@}E7lm&vW#bm!1x5V{2be^VMZ)InCgqB@c6buGE3snq(^b+H*g>wl_Pdd@QrlOz=vSOO*&I1PxMj15}H;yr^-FS>>|3};+II<*~?6Wm qSugs&N9S`=!ylgkD>DmyXm;AcA6ikI;_F*G*Y7AZz2-MmEBb$vl2XzD literal 0 HcmV?d00001 diff --git a/docs/How To Dev.txt b/docs/How To Dev.txt new file mode 100644 index 0000000..68eccff --- /dev/null +++ b/docs/How To Dev.txt @@ -0,0 +1,46 @@ +Note : +- pastikan berada di branch yang benar. +- + +Requirement : +- Node.js 22 LTS + +Step : +1. jalankan "NPM Install". +2. generate prisma client "npx prisma generate". +3. jalankan "cp env.example env" atau buat file .env baru. +4. sesuaikan isi dari .env + +Run Server : +- npm run start:dev + +Command Dev : +- npm test +- npm run lint +- npm run format +- npx prisma studio {untuk cek db} + +Test API : +- menggunakan postman : + arahkan ke file /postman/RayLab.postman_collection.json +- menggunakan swagger : + - masuk ke http://localhost:port/apilist + - klik authorize dan masukkan jwt token + +Controller Requirement : +- diatas deklarasi class controller pastikan ada ini : + - @ApiTags('object') + - @Controller('object') + - @UseGuards(JwtAuthGuard, PermissionGuard) + +- diatas deklarasi method controller pastikan ada ini : + - tipe api : @Post(), @Get(':id'), @Patch(':id'), @Delete(':id') + - @Permissions(PermissionType.SOMETHING) + - @ApiOperation({ summary: 'penjelasan singkat api' }) + +Table : +- untuk table akan dibuat otomatis oleh schema.prisma, disana hanya perlu ditambahkan model atau diubah, jalankan commandnya, setelah itu otomatis tablenya dibuat +- command : npx prisma migrate dev --name {Nama Perubahan} + +Use case: +- penentuan use case ditentukan siapa pemiliknya dahulu, dan harus konsisten. \ No newline at end of file diff --git a/my-project.bundle b/my-project.bundle new file mode 100644 index 0000000000000000000000000000000000000000..0d4559c98b12eb74bc2d5aa03c0ad65bd2cff3b1 GIT binary patch literal 122257 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

6ke-ov7p6v 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 literal 0 HcmV?d00001 diff --git a/package-lock.json b/package-lock.json index 1056868..53a6213 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,32 +1,95 @@ { "name": "raylab-core", "version": "0.1.0", - "lockfileVersion": 1, + "lockfileVersion": 3, "requires": true, - "dependencies": { - "@babel/code-frame": { + "packages": { + "": { + "name": "raylab-core", + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "@nestjs/common": "^10.4.20", + "@nestjs/config": "^3.3.0", + "@nestjs/core": "^10.4.20", + "@nestjs/jwt": "^10.2.0", + "@nestjs/mapped-types": "^2.1.0", + "@nestjs/passport": "^10.0.3", + "@nestjs/platform-express": "^10.4.20", + "@nestjs/swagger": "^7.4.2", + "@prisma/client": "^5.22.0", + "bcrypt": "^5.1.1", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.2", + "dotenv": "^16.6.1", + "ioredis": "^5.3.2", + "jose": "^6.2.6", + "jsonwebtoken": "^9.0.2", + "openid-client": "^6.5.0", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1", + "pino": "^9.7.0", + "reflect-metadata": "^0.2.2", + "rxjs": "^7.8.2", + "swagger-ui-express": "^5.0.1", + "uuid": "^11.1.0" + }, + "devDependencies": { + "@eslint/js": "^9.21.0", + "@nestjs/testing": "^10.4.22", + "@playwright/test": "^1.62.1", + "@types/bcrypt": "^5.0.2", + "@types/jest": "^29.5.14", + "@types/node": "^22.13.10", + "@types/passport-jwt": "^4.0.1", + "@types/supertest": "^6.0.3", + "@types/swagger-ui-express": "^4.1.8", + "@typescript-eslint/eslint-plugin": "^8.25.0", + "@typescript-eslint/parser": "^8.25.0", + "eslint": "^9.21.0", + "globals": "^16.0.0", + "jest": "^29.7.0", + "prettier": "^3.5.3", + "prisma": "^5.22.0", + "supertest": "^7.0.0", + "ts-jest": "^29.2.6", + "ts-node": "^10.9.2", + "ts-node-dev": "^2.0.0", + "typescript": "^5.8.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@babel/code-frame": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/compat-data": { + "node_modules/@babel/compat-data": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", - "dev": true + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, - "@babel/core": { + "node_modules/@babel/core": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, - "requires": { + "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", "@babel/helper-compilation-targets": "^7.29.7", @@ -43,289 +106,409 @@ "json5": "^2.2.3", "semver": "^6.3.1" }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "@babel/generator": { + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "dev": true, - "requires": { + "dependencies": { "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-compilation-targets": { + "node_modules/@babel/helper-compilation-targets": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "dev": true, - "requires": { + "dependencies": { "@babel/compat-data": "^7.29.7", "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-globals": { + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", - "dev": true + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, - "@babel/helper-module-imports": { + "node_modules/@babel/helper-module-imports": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "dev": true, - "requires": { + "dependencies": { "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-module-transforms": { + "node_modules/@babel/helper-module-transforms": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-module-imports": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7", "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "@babel/helper-plugin-utils": { + "node_modules/@babel/helper-plugin-utils": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", - "dev": true + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, - "@babel/helper-string-parser": { + "node_modules/@babel/helper-string-parser": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", - "dev": true + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, - "@babel/helper-validator-identifier": { + "node_modules/@babel/helper-validator-identifier": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", - "dev": true + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, - "@babel/helper-validator-option": { + "node_modules/@babel/helper-validator-option": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", - "dev": true + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, - "@babel/helpers": { + "node_modules/@babel/helpers": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "dev": true, - "requires": { + "dependencies": { "@babel/template": "^7.29.7", "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/parser": { + "node_modules/@babel/parser": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "dev": true, - "requires": { + "dependencies": { "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" } }, - "@babel/plugin-syntax-async-generators": { + "node_modules/@babel/plugin-syntax-async-generators": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-bigint": { + "node_modules/@babel/plugin-syntax-bigint": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-class-properties": { + "node_modules/@babel/plugin-syntax-class-properties": { "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-class-static-block": { + "node_modules/@babel/plugin-syntax-class-static-block": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-import-attributes": { + "node_modules/@babel/plugin-syntax-import-attributes": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-import-meta": { + "node_modules/@babel/plugin-syntax-import-meta": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-json-strings": { + "node_modules/@babel/plugin-syntax-json-strings": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-jsx": { + "node_modules/@babel/plugin-syntax-jsx": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-logical-assignment-operators": { + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-nullish-coalescing-operator": { + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-numeric-separator": { + "node_modules/@babel/plugin-syntax-numeric-separator": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-object-rest-spread": { + "node_modules/@babel/plugin-syntax-object-rest-spread": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-optional-catch-binding": { + "node_modules/@babel/plugin-syntax-optional-catch-binding": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-optional-chaining": { + "node_modules/@babel/plugin-syntax-optional-chaining": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-private-property-in-object": { + "node_modules/@babel/plugin-syntax-private-property-in-object": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-top-level-await": { + "node_modules/@babel/plugin-syntax-top-level-await": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/plugin-syntax-typescript": { + "node_modules/@babel/plugin-syntax-typescript": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/template": { + "node_modules/@babel/template": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "dev": true, - "requires": { + "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/traverse": { + "node_modules/@babel/traverse": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", "dev": true, - "requires": { + "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", "@babel/helper-globals": "^7.29.7", @@ -333,108 +516,144 @@ "@babel/template": "^7.29.7", "@babel/types": "^7.29.7", "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/types": { + "node_modules/@babel/types": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "@bcoe/v8-coverage": { + "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, - "@borewit/text-codec": { + "node_modules/@borewit/text-codec": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.2.tgz", - "integrity": "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==" + "integrity": "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } }, - "@cspotcode/source-map-support": { + "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, - "requires": { + "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, - "dependencies": { - "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - } + "engines": { + "node": ">=12" } }, - "@eslint-community/eslint-utils": { + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@eslint-community/eslint-utils": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", "dev": true, - "requires": { + "dependencies": { "eslint-visitor-keys": "^3.4.3" }, - "dependencies": { - "eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true - } + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "@eslint-community/regexpp": { + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { "version": "4.12.2", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } }, - "@eslint/config-array": { + "node_modules/@eslint/config-array": { "version": "0.21.2", "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", "dev": true, - "requires": { + "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "@eslint/config-helpers": { + "node_modules/@eslint/config-helpers": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", "dev": true, - "requires": { + "dependencies": { "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "@eslint/core": { + "node_modules/@eslint/core": { "version": "0.17.0", "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, - "requires": { + "dependencies": { "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "@eslint/eslintrc": { + "node_modules/@eslint/eslintrc": { "version": "3.3.6", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", "dev": true, - "requires": { + "dependencies": { "ajv": "^6.14.0", "debug": "^4.3.2", "espree": "^10.0.1", @@ -445,193 +664,288 @@ "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" }, - "dependencies": { - "globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true - }, - "ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true - }, - "js-yaml": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", - "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - } + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "@eslint/js": { + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/js": { "version": "9.39.5", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", - "dev": true + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } }, - "@eslint/object-schema": { + "node_modules/@eslint/object-schema": { "version": "2.1.7", "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", - "dev": true + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } }, - "@eslint/plugin-kit": { + "node_modules/@eslint/plugin-kit": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, - "requires": { + "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "@humanfs/core": { + "node_modules/@humanfs/core": { "version": "0.19.2", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", "dev": true, - "requires": { + "dependencies": { "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" } }, - "@humanfs/node": { + "node_modules/@humanfs/node": { "version": "0.16.8", "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", "dev": true, - "requires": { + "dependencies": { "@humanfs/core": "^0.19.2", "@humanfs/types": "^0.15.0", "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" } }, - "@humanfs/types": { + "node_modules/@humanfs/types": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", - "dev": true + "dev": true, + "engines": { + "node": ">=18.18.0" + } }, - "@humanwhocodes/module-importer": { + "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, - "@humanwhocodes/retry": { + "node_modules/@humanwhocodes/retry": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, - "@istanbuljs/load-nyc-config": { + "node_modules/@ioredis/commands": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.10.0.tgz", + "integrity": "sha512-UmeW7z4LfctwoQ5wkhVzgq8tXkreED2xZGpX+Bg+zA+WJFZCT6c062AfCK/Dfk81xZnnwdhJCUMkitihRaoC2Q==", + "license": "MIT" + }, + "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, - "requires": { + "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", "get-package-type": "^0.1.0", "js-yaml": "^3.13.1", "resolve-from": "^5.0.0" }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "js-yaml": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.0.tgz", - "integrity": "sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } + "engines": { + "node": ">=8" } }, - "@istanbuljs/schema": { + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.0.tgz", + "integrity": "sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "@jest/console": { + "node_modules/@jest/console": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", "dev": true, - "requires": { + "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", "jest-message-util": "^29.7.0", "jest-util": "^29.7.0", "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "@jest/core": { + "node_modules/@jest/core": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", "dev": true, - "requires": { + "dependencies": { "@jest/console": "^29.7.0", "@jest/reporters": "^29.7.0", "@jest/test-result": "^29.7.0", @@ -660,71 +974,97 @@ "pretty-format": "^29.7.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "@jest/environment": { + "node_modules/@jest/environment": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", "dev": true, - "requires": { + "dependencies": { "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "@jest/expect": { + "node_modules/@jest/expect": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", "dev": true, - "requires": { + "dependencies": { "expect": "^29.7.0", "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "@jest/expect-utils": { + "node_modules/@jest/expect-utils": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", "dev": true, - "requires": { + "dependencies": { "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "@jest/fake-timers": { + "node_modules/@jest/fake-timers": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", "dev": true, - "requires": { + "dependencies": { "@jest/types": "^29.6.3", "@sinonjs/fake-timers": "^10.0.2", "@types/node": "*", "jest-message-util": "^29.7.0", "jest-mock": "^29.7.0", "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "@jest/globals": { + "node_modules/@jest/globals": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", "dev": true, - "requires": { + "dependencies": { "@jest/environment": "^29.7.0", "@jest/expect": "^29.7.0", "@jest/types": "^29.6.3", "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "@jest/reporters": { + "node_modules/@jest/reporters": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", "dev": true, - "requires": { + "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@jest/console": "^29.7.0", "@jest/test-result": "^29.7.0", @@ -749,58 +1089,81 @@ "string-length": "^4.0.1", "strip-ansi": "^6.0.0", "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "@jest/schemas": { + "node_modules/@jest/schemas": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, - "requires": { + "dependencies": { "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "@jest/source-map": { + "node_modules/@jest/source-map": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", "dev": true, - "requires": { + "dependencies": { "@jridgewell/trace-mapping": "^0.3.18", "callsites": "^3.0.0", "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "@jest/test-result": { + "node_modules/@jest/test-result": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", "dev": true, - "requires": { + "dependencies": { "@jest/console": "^29.7.0", "@jest/types": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "@jest/test-sequencer": { + "node_modules/@jest/test-sequencer": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", "dev": true, - "requires": { + "dependencies": { "@jest/test-result": "^29.7.0", "graceful-fs": "^4.2.9", "jest-haste-map": "^29.7.0", "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "@jest/transform": { + "node_modules/@jest/transform": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", "dev": true, - "requires": { + "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^29.6.3", "@jridgewell/trace-mapping": "^0.3.18", @@ -816,74 +1179,86 @@ "pirates": "^4.0.4", "slash": "^3.0.0", "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "@jest/types": { + "node_modules/@jest/types": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, - "requires": { + "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "@jridgewell/gen-mapping": { + "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, - "requires": { + "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, - "@jridgewell/remapping": { + "node_modules/@jridgewell/remapping": { "version": "2.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "dev": true, - "requires": { + "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, - "@jridgewell/resolve-uri": { + "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true + "dev": true, + "engines": { + "node": ">=6.0.0" + } }, - "@jridgewell/sourcemap-codec": { + "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "dev": true }, - "@jridgewell/trace-mapping": { + "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, - "requires": { + "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "@lukeed/csprng": { + "node_modules/@lukeed/csprng": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", - "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==" + "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", + "engines": { + "node": ">=8" + } }, - "@mapbox/node-pre-gyp": { + "node_modules/@mapbox/node-pre-gyp": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", - "requires": { + "dependencies": { "detect-libc": "^2.0.0", "https-proxy-agent": "^5.0.0", "make-dir": "^3.1.0", @@ -893,109 +1268,193 @@ "rimraf": "^3.0.2", "semver": "^7.3.5", "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" } }, - "@microsoft/tsdoc": { + "node_modules/@microsoft/tsdoc": { "version": "0.15.1", "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.15.1.tgz", "integrity": "sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==" }, - "@nestjs/common": { + "node_modules/@nestjs/common": { "version": "10.4.22", "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-10.4.22.tgz", "integrity": "sha512-fxJ4v85nDHaqT1PmfNCQ37b/jcv2OojtXTaK1P2uAXhzLf9qq6WNUOFvxBrV4fhQek1EQoT1o9oj5xAZmv3NRw==", - "requires": { + "dependencies": { "file-type": "20.4.1", "iterare": "1.2.1", "tslib": "2.8.1", "uid": "2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "class-transformer": "*", + "class-validator": "*", + "reflect-metadata": "^0.1.12 || ^0.2.0", + "rxjs": "^7.1.0" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } } }, - "@nestjs/config": { + "node_modules/@nestjs/config": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-3.3.0.tgz", "integrity": "sha512-pdGTp8m9d0ZCrjTpjkUbZx6gyf2IKf+7zlkrPNMsJzYZ4bFRRTpXrnj+556/5uiI6AfL5mMrJc2u7dB6bvM+VA==", - "requires": { + "dependencies": { "dotenv": "16.4.5", "dotenv-expand": "10.0.0", "lodash": "4.17.21" }, - "dependencies": { - "dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==" - } + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", + "rxjs": "^7.1.0" } }, - "@nestjs/core": { + "node_modules/@nestjs/config/node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/@nestjs/core": { "version": "10.4.22", "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.4.22.tgz", "integrity": "sha512-6IX9+VwjiKtCjx+mXVPncpkQ5ZjKfmssOZPFexmT+6T9H9wZ3svpYACAo7+9e7Nr9DZSoRZw3pffkJP7Z0UjaA==", - "requires": { + "hasInstallScript": true, + "dependencies": { "@nuxtjs/opencollective": "0.3.2", "fast-safe-stringify": "2.1.1", "iterare": "1.2.1", "path-to-regexp": "3.3.0", "tslib": "2.8.1", "uid": "2.0.2" - } - }, - "@nestjs/jwt": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/@nestjs/jwt/-/jwt-10.2.0.tgz", - "integrity": "sha512-x8cG90SURkEiLOehNaN2aRlotxT0KZESUliOPKKnjWiyJOcWurkF3w345WOX0P4MgFzUjGoZ1Sy0aZnxeihT0g==", - "requires": { - "@types/jsonwebtoken": "9.0.5", - "jsonwebtoken": "9.0.2" }, - "dependencies": { - "jsonwebtoken": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", - "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", - "requires": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^7.5.4" - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/microservices": "^10.0.0", + "@nestjs/platform-express": "^10.0.0", + "@nestjs/websockets": "^10.0.0", + "reflect-metadata": "^0.1.12 || ^0.2.0", + "rxjs": "^7.1.0" + }, + "peerDependenciesMeta": { + "@nestjs/microservices": { + "optional": true + }, + "@nestjs/platform-express": { + "optional": true + }, + "@nestjs/websockets": { + "optional": true } } }, - "@nestjs/mapped-types": { + "node_modules/@nestjs/jwt": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@nestjs/jwt/-/jwt-10.2.0.tgz", + "integrity": "sha512-x8cG90SURkEiLOehNaN2aRlotxT0KZESUliOPKKnjWiyJOcWurkF3w345WOX0P4MgFzUjGoZ1Sy0aZnxeihT0g==", + "dependencies": { + "@types/jsonwebtoken": "9.0.5", + "jsonwebtoken": "9.0.2" + }, + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/@nestjs/jwt/node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/@nestjs/mapped-types": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.1.1.tgz", - "integrity": "sha512-SCCoMEJ6jdeI5h/N+KCVF1+pmg/hmEkNA5nHTS8Gvww7T/LCl4o1gFLinw2iQ60w7slFkszHcGLKGdazVI4F8A==" + "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/passport": { + "node_modules/@nestjs/passport": { "version": "10.0.3", "resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-10.0.3.tgz", - "integrity": "sha512-znJ9Y4S8ZDVY+j4doWAJ8EuuVO7SkQN3yOBmzxbGaXbvcSwFDAdGJ+OMCg52NdzIO4tQoN4pYKx8W6M0ArfFRQ==" + "integrity": "sha512-znJ9Y4S8ZDVY+j4doWAJ8EuuVO7SkQN3yOBmzxbGaXbvcSwFDAdGJ+OMCg52NdzIO4tQoN4pYKx8W6M0ArfFRQ==", + "peerDependencies": { + "@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": { + "node_modules/@nestjs/platform-express": { "version": "10.4.22", "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-10.4.22.tgz", "integrity": "sha512-ySSq7Py/DFozzZdNDH67m/vHoeVdphDniWBnl6q5QVoXldDdrZIHLXLRMPayTDh5A95nt7jjJzmD4qpTbNQ6tA==", - "requires": { + "dependencies": { "body-parser": "1.20.4", "cors": "2.8.5", "express": "4.22.1", "multer": "2.0.2", "tslib": "2.8.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/core": "^10.0.0" } }, - "@nestjs/swagger": { + "node_modules/@nestjs/swagger": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-7.4.2.tgz", "integrity": "sha512-Mu6TEn1M/owIvAx2B4DUQObQXqo2028R2s9rSZ/hJEgBK95+doTwS0DjmVA2wTeZTyVtXOoN7CsoM5pONBzvKQ==", - "requires": { + "dependencies": { "@microsoft/tsdoc": "^0.15.0", "@nestjs/mapped-types": "2.0.5", "js-yaml": "4.1.0", @@ -1003,162 +1462,270 @@ "path-to-regexp": "3.3.0", "swagger-ui-dist": "5.17.14" }, - "dependencies": { - "@nestjs/mapped-types": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.0.5.tgz", - "integrity": "sha512-bSJv4pd6EY99NX9CjBIyn4TVDoSit82DUZlL4I3bqNfy5Gt+gXTa86i3I/i0iIV9P4hntcGM5GyO+FhZAhxtyg==" + "peerDependencies": { + "@fastify/static": "^6.0.0 || ^7.0.0", + "@nestjs/common": "^9.0.0 || ^10.0.0", + "@nestjs/core": "^9.0.0 || ^10.0.0", + "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 } } }, - "@noble/hashes": { + "node_modules/@nestjs/swagger/node_modules/@nestjs/mapped-types": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.0.5.tgz", + "integrity": "sha512-bSJv4pd6EY99NX9CjBIyn4TVDoSit82DUZlL4I3bqNfy5Gt+gXTa86i3I/i0iIV9P4hntcGM5GyO+FhZAhxtyg==", + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", + "class-transformer": "^0.4.0 || ^0.5.0", + "class-validator": "^0.13.0 || ^0.14.0", + "reflect-metadata": "^0.1.12 || ^0.2.0" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, + "node_modules/@nestjs/testing": { + "version": "10.4.22", + "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-10.4.22.tgz", + "integrity": "sha512-HO9aPus3bAedAC+jKVAA8jTdaj4fs5M9fing4giHrcYV2txe9CvC1l1WAjwQ9RDhEHdugjY4y+FZA/U/YqPZrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nest" + }, + "peerDependencies": { + "@nestjs/common": "^10.0.0", + "@nestjs/core": "^10.0.0", + "@nestjs/microservices": "^10.0.0", + "@nestjs/platform-express": "^10.0.0" + }, + "peerDependenciesMeta": { + "@nestjs/microservices": { + "optional": true + }, + "@nestjs/platform-express": { + "optional": true + } + } + }, + "node_modules/@noble/hashes": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", - "dev": true + "dev": true, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } }, - "@nuxtjs/opencollective": { + "node_modules/@nuxtjs/opencollective": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@nuxtjs/opencollective/-/opencollective-0.3.2.tgz", "integrity": "sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA==", - "requires": { + "dependencies": { "chalk": "^4.1.0", "consola": "^2.15.0", "node-fetch": "^2.6.1" + }, + "bin": { + "opencollective": "bin/opencollective.js" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" } }, - "@paralleldrive/cuid2": { + "node_modules/@paralleldrive/cuid2": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==", "dev": true, - "requires": { + "dependencies": { "@noble/hashes": "^1.1.5" } }, - "@pinojs/redact": { + "node_modules/@pinojs/redact": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==" }, - "@prisma/client": { + "node_modules/@playwright/test": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.62.1.tgz", + "integrity": "sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.62.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@prisma/client": { "version": "5.22.0", "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.22.0.tgz", - "integrity": "sha512-M0SVXfyHnQREBKxCgyo7sffrKttwE6R8PMq330MIUF0pTwjUhLbW84pFDlf06B27XyCR++VtjugEnIHdr07SVA==" + "integrity": "sha512-M0SVXfyHnQREBKxCgyo7sffrKttwE6R8PMq330MIUF0pTwjUhLbW84pFDlf06B27XyCR++VtjugEnIHdr07SVA==", + "hasInstallScript": true, + "engines": { + "node": ">=16.13" + }, + "peerDependencies": { + "prisma": "*" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + } + } }, - "@prisma/debug": { + "node_modules/@prisma/debug": { "version": "5.22.0", "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.22.0.tgz", "integrity": "sha512-AUt44v3YJeggO2ZU5BkXI7M4hu9BF2zzH2iF2V5pyXT/lRTyWiElZ7It+bRH1EshoMRxHgpYg4VB6rCM+mG5jQ==", - "dev": true + "devOptional": true }, - "@prisma/engines": { + "node_modules/@prisma/engines": { "version": "5.22.0", "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.22.0.tgz", "integrity": "sha512-UNjfslWhAt06kVL3CjkuYpHAWSO6L4kDCVPegV6itt7nD1kSJavd3vhgAEhjglLJJKEdJ7oIqDJ+yHk6qO8gPA==", - "dev": true, - "requires": { + "devOptional": true, + "hasInstallScript": true, + "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/engines-version": { + "node_modules/@prisma/engines-version": { "version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2", "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2.tgz", "integrity": "sha512-2PTmxFR2yHW/eB3uqWtcgRcgAbG1rwG9ZriSvQw+nnb7c4uCr3RAcGMb6/zfE88SKlC1Nj2ziUvc96Z379mHgQ==", - "dev": true + "devOptional": true }, - "@prisma/fetch-engine": { + "node_modules/@prisma/fetch-engine": { "version": "5.22.0", "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.22.0.tgz", "integrity": "sha512-bkrD/Mc2fSvkQBV5EpoFcZ87AvOgDxbG99488a5cexp5Ccny+UM6MAe/UFkUC0wLYD9+9befNOqGiIJhhq+HbA==", - "dev": true, - "requires": { + "devOptional": true, + "dependencies": { "@prisma/debug": "5.22.0", "@prisma/engines-version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2", "@prisma/get-platform": "5.22.0" } }, - "@prisma/get-platform": { + "node_modules/@prisma/get-platform": { "version": "5.22.0", "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.22.0.tgz", "integrity": "sha512-pHhpQdr1UPFpt+zFfnPazhulaZYCUqeIcPpJViYoq9R+D/yw4fjE+CtnsnKzPYm0ddUbeXUzjGVGIRVgPDCk4Q==", - "dev": true, - "requires": { + "devOptional": true, + "dependencies": { "@prisma/debug": "5.22.0" } }, - "@sinclair/typebox": { + "node_modules/@sinclair/typebox": { "version": "0.27.12", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.12.tgz", "integrity": "sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g==", "dev": true }, - "@sinonjs/commons": { + "node_modules/@sinonjs/commons": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, - "requires": { + "dependencies": { "type-detect": "4.0.8" } }, - "@sinonjs/fake-timers": { + "node_modules/@sinonjs/fake-timers": { "version": "10.3.0", "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", "dev": true, - "requires": { + "dependencies": { "@sinonjs/commons": "^3.0.0" } }, - "@tokenizer/inflate": { + "node_modules/@tokenizer/inflate": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.2.7.tgz", "integrity": "sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg==", - "requires": { + "dependencies": { "debug": "^4.4.0", "fflate": "^0.8.2", "token-types": "^6.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" } }, - "@tokenizer/token": { + "node_modules/@tokenizer/token": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" }, - "@tsconfig/node10": { + "node_modules/@tsconfig/node10": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", "dev": true }, - "@tsconfig/node12": { + "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", "dev": true }, - "@tsconfig/node14": { + "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", "dev": true }, - "@tsconfig/node16": { + "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true }, - "@types/babel__core": { + "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, - "requires": { + "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", @@ -1166,329 +1733,325 @@ "@types/babel__traverse": "*" } }, - "@types/babel__generator": { + "node_modules/@types/babel__generator": { "version": "7.27.0", "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", "dev": true, - "requires": { + "dependencies": { "@babel/types": "^7.0.0" } }, - "@types/babel__template": { + "node_modules/@types/babel__template": { "version": "7.4.4", "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, - "requires": { + "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, - "@types/babel__traverse": { + "node_modules/@types/babel__traverse": { "version": "7.28.0", "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "dev": true, - "requires": { + "dependencies": { "@babel/types": "^7.28.2" } }, - "@types/bcrypt": { + "node_modules/@types/bcrypt": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.2.tgz", "integrity": "sha512-6atioO8Y75fNcbmj0G7UjI9lXN2pQ/IGJ2FWT4a/btd0Lk9lQalHLKhkgKVZ3r+spnmWUKfbMi1GEe9wyHQfNQ==", "dev": true, - "requires": { + "dependencies": { "@types/node": "*" } }, - "@types/body-parser": { + "node_modules/@types/body-parser": { "version": "1.19.6", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", "dev": true, - "requires": { + "dependencies": { "@types/connect": "*", "@types/node": "*" } }, - "@types/connect": { + "node_modules/@types/connect": { "version": "3.4.38", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, - "requires": { + "dependencies": { "@types/node": "*" } }, - "@types/cookiejar": { + "node_modules/@types/cookiejar": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", "dev": true }, - "@types/estree": { + "node_modules/@types/estree": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "dev": true }, - "@types/express": { + "node_modules/@types/express": { "version": "5.0.6", "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", "dev": true, - "requires": { + "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^5.0.0", "@types/serve-static": "^2" } }, - "@types/express-serve-static-core": { + "node_modules/@types/express-serve-static-core": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.2.tgz", "integrity": "sha512-d3KvEXBSo/lOAMc2u6fkyDHBvetBHeqD7wm/AcXfLpSOQwlmG9D/aQ0SFswVjv05p7ullQS7Mjohj6/VdbZuTg==", "dev": true, - "requires": { + "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, - "@types/graceful-fs": { + "node_modules/@types/graceful-fs": { "version": "4.1.9", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", "dev": true, - "requires": { + "dependencies": { "@types/node": "*" } }, - "@types/http-errors": { + "node_modules/@types/http-errors": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", "dev": true }, - "@types/istanbul-lib-coverage": { + "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", "dev": true }, - "@types/istanbul-lib-report": { + "node_modules/@types/istanbul-lib-report": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, - "requires": { + "dependencies": { "@types/istanbul-lib-coverage": "*" } }, - "@types/istanbul-reports": { + "node_modules/@types/istanbul-reports": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, - "requires": { + "dependencies": { "@types/istanbul-lib-report": "*" } }, - "@types/jest": { + "node_modules/@types/jest": { "version": "29.5.14", "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", "dev": true, - "requires": { + "dependencies": { "expect": "^29.0.0", "pretty-format": "^29.0.0" } }, - "@types/json-schema": { + "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, - "@types/jsonwebtoken": { + "node_modules/@types/jsonwebtoken": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.5.tgz", "integrity": "sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==", - "requires": { - "@types/node": "*" - }, "dependencies": { - "@types/node": { - "version": "26.1.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.2.tgz", - "integrity": "sha512-Vu4a5UFA9rIIFJ7rB/Vaafh9lrCQszopTCx6KjFboXTGQbPNasehVR5TEiithSDGyd1DEiUByggTZsg8jukeIg==", - "requires": { - "undici-types": "~8.3.0" - } - } + "@types/node": "*" } }, - "@types/methods": { + "node_modules/@types/jsonwebtoken/node_modules/@types/node": { + "version": "26.1.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.2.tgz", + "integrity": "sha512-Vu4a5UFA9rIIFJ7rB/Vaafh9lrCQszopTCx6KjFboXTGQbPNasehVR5TEiithSDGyd1DEiUByggTZsg8jukeIg==", + "dependencies": { + "undici-types": "~8.3.0" + } + }, + "node_modules/@types/methods": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", "integrity": "sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==", "dev": true }, - "@types/node": { + "node_modules/@types/node": { "version": "22.20.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz", "integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==", "dev": true, - "requires": { - "undici-types": "~6.21.0" - }, "dependencies": { - "undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true - } + "undici-types": "~6.21.0" } }, - "@types/passport": { + "node_modules/@types/node/node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true + }, + "node_modules/@types/passport": { "version": "1.0.17", "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.17.tgz", "integrity": "sha512-aciLyx+wDwT2t2/kJGJR2AEeBz0nJU4WuRX04Wu9Dqc5lSUtwu0WERPHYsLhF9PtseiAMPBGNUOtFjxZ56prsg==", "dev": true, - "requires": { + "dependencies": { "@types/express": "*" } }, - "@types/passport-jwt": { + "node_modules/@types/passport-jwt": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/passport-jwt/-/passport-jwt-4.0.1.tgz", "integrity": "sha512-Y0Ykz6nWP4jpxgEUYq8NoVZeCQPo1ZndJLfapI249g1jHChvRfZRO/LS3tqu26YgAS/laI1qx98sYGz0IalRXQ==", "dev": true, - "requires": { + "dependencies": { "@types/jsonwebtoken": "*", "@types/passport-strategy": "*" } }, - "@types/passport-strategy": { + "node_modules/@types/passport-strategy": { "version": "0.2.38", "resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.38.tgz", "integrity": "sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA==", "dev": true, - "requires": { + "dependencies": { "@types/express": "*", "@types/passport": "*" } }, - "@types/qs": { + "node_modules/@types/qs": { "version": "6.15.1", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", "dev": true }, - "@types/range-parser": { + "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", "dev": true }, - "@types/send": { + "node_modules/@types/send": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", "dev": true, - "requires": { + "dependencies": { "@types/node": "*" } }, - "@types/serve-static": { + "node_modules/@types/serve-static": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", "dev": true, - "requires": { + "dependencies": { "@types/http-errors": "*", "@types/node": "*" } }, - "@types/stack-utils": { + "node_modules/@types/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", "dev": true }, - "@types/strip-bom": { + "node_modules/@types/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", "dev": true }, - "@types/strip-json-comments": { + "node_modules/@types/strip-json-comments": { "version": "0.0.30", "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", "dev": true }, - "@types/superagent": { + "node_modules/@types/superagent": { "version": "8.1.11", "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.11.tgz", "integrity": "sha512-KA7srSW/HENDtOw9DOqaFLgWuMqN9WgjEw62lh9dpvRaZDkhdOkazASd7X7i2eMUYLHa1U37ZttnePsH5zTDHw==", "dev": true, - "requires": { + "dependencies": { "@types/cookiejar": "^2.1.5", "@types/methods": "^1.1.4", "@types/node": "*", "form-data": "^4.0.0" } }, - "@types/supertest": { + "node_modules/@types/supertest": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-6.0.3.tgz", "integrity": "sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==", "dev": true, - "requires": { + "dependencies": { "@types/methods": "^1.1.4", "@types/superagent": "^8.1.0" } }, - "@types/swagger-ui-express": { + "node_modules/@types/swagger-ui-express": { "version": "4.1.8", "resolved": "https://registry.npmjs.org/@types/swagger-ui-express/-/swagger-ui-express-4.1.8.tgz", "integrity": "sha512-AhZV8/EIreHFmBV5wAs0gzJUNq9JbbSXgJLQubCC0jtIo6prnI9MIRRxnU4MZX9RB9yXxF1V4R7jtLl/Wcj31g==", "dev": true, - "requires": { + "dependencies": { "@types/express": "*", "@types/serve-static": "*" } }, - "@types/validator": { + "node_modules/@types/validator": { "version": "13.15.10", "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.10.tgz", "integrity": "sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==" }, - "@types/yargs": { + "node_modules/@types/yargs": { "version": "17.0.35", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", "dev": true, - "requires": { + "dependencies": { "@types/yargs-parser": "*" } }, - "@types/yargs-parser": { + "node_modules/@types/yargs-parser": { "version": "21.0.3", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true }, - "@typescript-eslint/eslint-plugin": { + "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.65.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.65.0.tgz", "integrity": "sha512-IEgob78X12rHpUmtcwFsXhZdVGJtwTVP8FiCLZkR6GlYVrl2PcuB+KhCE5BlVC/eQpQnu8WXRtkHZuPar+gCRA==", "dev": true, - "requires": { + "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.65.0", "@typescript-eslint/type-utils": "8.65.0", @@ -1497,73 +2060,141 @@ "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.65.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "@typescript-eslint/parser": { + "node_modules/@typescript-eslint/parser": { "version": "8.65.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.65.0.tgz", "integrity": "sha512-CZ4nMxWwgu1HEEFNkeaCptra9QCtkmKdgf3sWh1rl1trIhmxLilgTV4cwcbQ4wemnT4sWQN8CaKOmdYx+g2gMA==", "dev": true, - "requires": { + "dependencies": { "@typescript-eslint/scope-manager": "8.65.0", "@typescript-eslint/types": "8.65.0", "@typescript-eslint/typescript-estree": "8.65.0", "@typescript-eslint/visitor-keys": "8.65.0", "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "@typescript-eslint/project-service": { + "node_modules/@typescript-eslint/project-service": { "version": "8.65.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.65.0.tgz", "integrity": "sha512-SxnPhbTsGahizDgbu7oqFH/xVtzIqMd/s+WtnSxNxJZJpLbdT5IPdzg8EZxO3+PoKahXmwJLeNQOpKJb3/bi7Q==", "dev": true, - "requires": { + "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.65.0", "@typescript-eslint/types": "^8.65.0", "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "@typescript-eslint/scope-manager": { + "node_modules/@typescript-eslint/scope-manager": { "version": "8.65.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.65.0.tgz", "integrity": "sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg==", "dev": true, - "requires": { + "dependencies": { "@typescript-eslint/types": "8.65.0", "@typescript-eslint/visitor-keys": "8.65.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "@typescript-eslint/tsconfig-utils": { + "node_modules/@typescript-eslint/tsconfig-utils": { "version": "8.65.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.65.0.tgz", "integrity": "sha512-j6GzGqCiRdA7Qhur2VVmKZAkBLfnHFQfx4TaJGL9RMveZqCo48jSHHO0DTgizEnGhtWnqmbtCUSrqSkdiY/0Hg==", - "dev": true + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } }, - "@typescript-eslint/type-utils": { + "node_modules/@typescript-eslint/type-utils": { "version": "8.65.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.65.0.tgz", "integrity": "sha512-YjaZ7PRI5qY7ax2L3PbvX0rRyGtipAReCWs0mhhDBHjH/vl0g0BonaGXrKdKpMbIIsMIwDgbk/xzkBTyAltS5g==", "dev": true, - "requires": { + "dependencies": { "@typescript-eslint/types": "8.65.0", "@typescript-eslint/typescript-estree": "8.65.0", "@typescript-eslint/utils": "8.65.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "@typescript-eslint/types": { + "node_modules/@typescript-eslint/types": { "version": "8.65.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.65.0.tgz", "integrity": "sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg==", - "dev": true + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } }, - "@typescript-eslint/typescript-estree": { + "node_modules/@typescript-eslint/typescript-estree": { "version": "8.65.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.65.0.tgz", "integrity": "sha512-JboAE2swaYt4tb1fHhHTABE2K+OLy09XfcTbhnk4Pw96f9dd2e9iYsJ28gBggHlo5z5x1rkyWvcPoTuNTd4oGg==", "dev": true, - "requires": { + "dependencies": { "@typescript-eslint/project-service": "8.65.0", "@typescript-eslint/tsconfig-utils": "8.65.0", "@typescript-eslint/types": "8.65.0", @@ -1574,200 +2205,298 @@ "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, - "dependencies": { - "balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true - }, - "brace-expansion": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", - "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", - "dev": true, - "requires": { - "balanced-match": "^4.0.2" - } - }, - "minimatch": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", - "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", - "dev": true, - "requires": { - "brace-expansion": "^5.0.8" - } - } + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "@typescript-eslint/utils": { + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "dev": true, + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { "version": "8.65.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.65.0.tgz", "integrity": "sha512-gXiwIHsYreboxeJucHKPvgwl7dXt50mF8s1/c00cP/WoVTyWKFdtfhRWwZiXYFU5H2O8vVoSLNrexFZjYS/SGA==", "dev": true, - "requires": { + "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.65.0", "@typescript-eslint/types": "8.65.0", "@typescript-eslint/typescript-estree": "8.65.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "@typescript-eslint/visitor-keys": { + "node_modules/@typescript-eslint/visitor-keys": { "version": "8.65.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.65.0.tgz", "integrity": "sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==", "dev": true, - "requires": { + "dependencies": { "@typescript-eslint/types": "8.65.0", "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "abbrev": { + "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, - "accepts": { + "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "requires": { + "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" } }, - "acorn": { + "node_modules/acorn": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", - "dev": true + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } }, - "acorn-jsx": { + "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } }, - "acorn-walk": { + "node_modules/acorn-walk": { "version": "8.3.5", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", "dev": true, - "requires": { + "dependencies": { "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" } }, - "agent-base": { + "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "requires": { + "dependencies": { "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" } }, - "ajv": { + "node_modules/ajv": { "version": "6.15.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, - "requires": { + "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "ansi-escapes": { + "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, - "requires": { + "dependencies": { "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "ansi-regex": { + "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } }, - "ansi-styles": { + "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { + "dependencies": { "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "anymatch": { + "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, - "requires": { + "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" } }, - "append-field": { + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/append-field": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" }, - "aproba": { + "node_modules/aproba": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==" }, - "are-we-there-yet": { + "node_modules/are-we-there-yet": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", - "requires": { + "deprecated": "This package is no longer supported.", + "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" } }, - "arg": { + "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true }, - "argparse": { + "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, - "array-flatten": { + "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, - "asap": { + "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "dev": true }, - "asynckit": { + "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, - "atomic-sleep": { + "node_modules/atomic-sleep": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", - "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==" + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "engines": { + "node": ">=8.0.0" + } }, - "babel-jest": { + "node_modules/babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", "dev": true, - "requires": { + "dependencies": { "@jest/transform": "^29.7.0", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", @@ -1775,60 +2504,76 @@ "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" } }, - "babel-plugin-istanbul": { + "node_modules/babel-plugin-istanbul": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, - "requires": { + "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.2", "istanbul-lib-instrument": "^5.0.4", "test-exclude": "^6.0.0" }, - "dependencies": { - "istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - } - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } + "engines": { + "node": ">=8" } }, - "babel-plugin-jest-hoist": { + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-jest-hoist": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", "dev": true, - "requires": { + "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", "@types/babel__core": "^7.1.14", "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "babel-preset-current-node-syntax": { + "node_modules/babel-preset-current-node-syntax": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", "dev": true, - "requires": { + "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", "@babel/plugin-syntax-class-properties": "^7.12.13", @@ -1844,49 +2589,74 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" } }, - "babel-preset-jest": { + "node_modules/babel-preset-jest": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", "dev": true, - "requires": { + "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "balanced-match": { + "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, - "baseline-browser-mapping": { + "node_modules/baseline-browser-mapping": { "version": "2.11.7", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.7.tgz", "integrity": "sha512-APw5YuIQAg6L9w4sHDI6j26DGFJI6RpYOhnkMPdC9lWbkKvsyPHzDsve1yd73lk21yz7Y09Kci8B2Pp9FonzWA==", - "dev": true + "dev": true, + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } }, - "bcrypt": { + "node_modules/bcrypt": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", "integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==", - "requires": { + "hasInstallScript": true, + "dependencies": { "@mapbox/node-pre-gyp": "^1.0.11", "node-addon-api": "^5.0.0" + }, + "engines": { + "node": ">= 10.0.0" } }, - "binary-extensions": { + "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "body-parser": { + "node_modules/body-parser": { "version": "1.20.4", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", - "requires": { + "dependencies": { "bytes": "~3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", @@ -1900,336 +2670,472 @@ "type-is": "~1.6.18", "unpipe": "~1.0.0" }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "brace-expansion": { + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/brace-expansion": { "version": "1.1.18", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", - "requires": { + "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, - "braces": { + "node_modules/braces": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, - "requires": { + "dependencies": { "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" } }, - "browserslist": { + "node_modules/browserslist": { "version": "4.28.7", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz", "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==", "dev": true, - "requires": { + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { "baseline-browser-mapping": "^2.10.44", "caniuse-lite": "^1.0.30001806", "electron-to-chromium": "^1.5.393", "node-releases": "^2.0.51", "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "bs-logger": { + "node_modules/bs-logger": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", "dev": true, - "requires": { + "dependencies": { "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" } }, - "bser": { + "node_modules/bser": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, - "requires": { + "dependencies": { "node-int64": "^0.4.0" } }, - "buffer-equal-constant-time": { + "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" }, - "buffer-from": { + "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, - "busboy": { + "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "requires": { + "dependencies": { "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" } }, - "bytes": { + "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } }, - "call-bind-apply-helpers": { + "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "requires": { + "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" } }, - "call-bound": { + "node_modules/call-bound": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "requires": { + "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "callsites": { + "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "camelcase": { + "node_modules/camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "caniuse-lite": { + "node_modules/caniuse-lite": { "version": "1.0.30001806", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", - "dev": true + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] }, - "chalk": { + "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { + "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "char-regex": { + "node_modules/char-regex": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true + "dev": true, + "engines": { + "node": ">=10" + } }, - "chokidar": { + "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "requires": { + "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", - "fsevents": "~2.3.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "chownr": { + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } }, - "ci-info": { + "node_modules/ci-info": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } }, - "cjs-module-lexer": { + "node_modules/cjs-module-lexer": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", "dev": true }, - "class-transformer": { + "node_modules/class-transformer": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" }, - "class-validator": { + "node_modules/class-validator": { "version": "0.14.4", "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.4.tgz", "integrity": "sha512-AwNusCCam51q703dW82x95tOqQp6oC9HNUl724KxJJOfnKscI8dOloXFgyez7LbTTKWuRBA37FScqVbJEoq8Yw==", - "requires": { + "dependencies": { "@types/validator": "^13.15.3", "libphonenumber-js": "^1.11.1", "validator": "^13.15.22" } }, - "cliui": { + "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, - "requires": { + "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, - "co": { + "node_modules/cluster-key-slot": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.1.tgz", + "integrity": "sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } }, - "collect-v8-coverage": { + "node_modules/collect-v8-coverage": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", "dev": true }, - "color-convert": { + "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { + "dependencies": { "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "color-name": { + "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "color-support": { + "node_modules/color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "bin": { + "color-support": "bin.js" + } }, - "combined-stream": { + "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, - "requires": { + "dependencies": { "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, - "component-emitter": { + "node_modules/component-emitter": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", - "dev": true + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "concat-map": { + "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, - "concat-stream": { + "node_modules/concat-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", - "requires": { + "engines": [ + "node >= 6.0" + ], + "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.0.2", "typedarray": "^0.0.6" } }, - "consola": { + "node_modules/consola": { "version": "2.15.3", "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" }, - "console-control-strings": { + "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" }, - "content-disposition": { + "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "requires": { + "dependencies": { "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" } }, - "content-type": { + "node_modules/content-type": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } }, - "convert-source-map": { + "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, - "cookie": { + "node_modules/cookie": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==" + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "engines": { + "node": ">= 0.6" + } }, - "cookie-signature": { + "node_modules/cookie-signature": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==" }, - "cookiejar": { + "node_modules/cookiejar": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", "dev": true }, - "cors": { + "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "requires": { + "dependencies": { "object-assign": "^4", "vary": "^1" + }, + "engines": { + "node": ">= 0.10" } }, - "create-jest": { + "node_modules/create-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", "dev": true, - "requires": { + "dependencies": { "@jest/types": "^29.6.3", "chalk": "^4.0.0", "exit": "^0.1.2", @@ -2237,231 +3143,329 @@ "jest-config": "^29.7.0", "jest-util": "^29.7.0", "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "create-require": { + "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, - "cross-spawn": { + "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, - "requires": { + "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" } }, - "debug": { + "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "requires": { + "dependencies": { "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "dedent": { + "node_modules/dedent": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", - "dev": true + "dev": true, + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } }, - "deep-is": { + "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "deepmerge": { + "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "delayed-stream": { + "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.4.0" + } }, - "delegates": { + "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" }, - "depd": { + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } }, - "destroy": { + "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } }, - "detect-libc": { + "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==" + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "engines": { + "node": ">=8" + } }, - "detect-newline": { + "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "dezalgo": { + "node_modules/dezalgo": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", "dev": true, - "requires": { + "dependencies": { "asap": "^2.0.0", "wrappy": "1" } }, - "diff": { + "node_modules/diff": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.3.1" + } }, - "diff-sequences": { + "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } }, - "dotenv": { + "node_modules/dotenv": { "version": "16.6.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==" + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } }, - "dotenv-expand": { + "node_modules/dotenv-expand": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", - "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==" + "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", + "engines": { + "node": ">=12" + } }, - "dunder-proto": { + "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "requires": { + "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" } }, - "dynamic-dedupe": { + "node_modules/dynamic-dedupe": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", "dev": true, - "requires": { + "dependencies": { "xtend": "^4.0.0" } }, - "ecdsa-sig-formatter": { + "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "requires": { + "dependencies": { "safe-buffer": "^5.0.1" } }, - "ee-first": { + "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, - "electron-to-chromium": { + "node_modules/electron-to-chromium": { "version": "1.5.398", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.398.tgz", "integrity": "sha512-AsvhAxopJGh6museTDMIjn6JpDYOfgu4RLlygomt87MUwBUqTfd/1EiPtx10/LZE8xpTvkP2E9Gafq7lkLtodQ==", "dev": true }, - "emittery": { + "node_modules/emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } }, - "emoji-regex": { + "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, - "encodeurl": { + "node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "engines": { + "node": ">= 0.8" + } }, - "error-ex": { + "node_modules/error-ex": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", "dev": true, - "requires": { + "dependencies": { "is-arrayish": "^0.2.1" } }, - "es-define-property": { + "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==" + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "engines": { + "node": ">= 0.4" + } }, - "es-errors": { + "node_modules/es-errors": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } }, - "es-object-atoms": { + "node_modules/es-object-atoms": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", - "requires": { + "dependencies": { "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" } }, - "es-set-tostringtag": { + "node_modules/es-set-tostringtag": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dev": true, - "requires": { + "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "escalade": { + "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "escape-html": { + "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, - "escape-string-regexp": { + "node_modules/escape-string-regexp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "eslint": { + "node_modules/eslint": { "version": "9.39.5", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", "dev": true, - "requires": { + "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.2", @@ -2497,109 +3501,183 @@ "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, - "dependencies": { - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true - }, - "ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true } } }, - "eslint-scope": { + "node_modules/eslint-scope": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, - "requires": { + "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "eslint-visitor-keys": { + "node_modules/eslint-visitor-keys": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true + "dev": true, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } }, - "espree": { + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/espree": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, - "requires": { + "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" }, - "dependencies": { - "eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true - } + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "esprima": { + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } }, - "esquery": { + "node_modules/esquery": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, - "requires": { + "dependencies": { "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" } }, - "esrecurse": { + "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "requires": { + "dependencies": { "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" } }, - "estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true + "dev": true, + "engines": { + "node": ">=4.0" + } }, - "esutils": { + "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "etag": { + "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } }, - "execa": { + "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, - "requires": { + "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", @@ -2609,32 +3687,44 @@ "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "exit": { + "node_modules/exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.8.0" + } }, - "expect": { + "node_modules/expect": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", "dev": true, - "requires": { + "dependencies": { "@jest/expect-utils": "^29.7.0", "jest-get-type": "^29.6.3", "jest-matcher-utils": "^29.7.0", "jest-message-util": "^29.7.0", "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "express": { + "node_modules/express": { "version": "4.22.1", "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", - "requires": { + "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "~1.20.3", @@ -2667,104 +3757,132 @@ "utils-merge": "1.0.1", "vary": "~1.1.2" }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "path-to-regexp": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", - "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==" - } + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "fast-deep-equal": { + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/express/node_modules/path-to-regexp": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==" + }, + "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "fast-json-stable-stringify": { + "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, - "fast-levenshtein": { + "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, - "fast-safe-stringify": { + "node_modules/fast-safe-stringify": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" }, - "fb-watchman": { + "node_modules/fb-watchman": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, - "requires": { + "dependencies": { "bser": "2.1.1" } }, - "fdir": { + "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true + "dev": true, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } }, - "fflate": { + "node_modules/fflate": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz", "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==" }, - "file-entry-cache": { + "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, - "requires": { + "dependencies": { "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" } }, - "file-type": { + "node_modules/file-type": { "version": "20.4.1", "resolved": "https://registry.npmjs.org/file-type/-/file-type-20.4.1.tgz", "integrity": "sha512-hw9gNZXUfZ02Jo0uafWLaFVPter5/k2rfcrjFJJHX/77xtSDOfJuEFb6oKlFV86FLP1SuyHMW1PSk0U9M5tKkQ==", - "requires": { + "dependencies": { "@tokenizer/inflate": "^0.2.6", "strtok3": "^10.2.0", "token-types": "^6.0.0", "uint8array-extras": "^1.4.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" } }, - "fill-range": { + "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, - "requires": { + "dependencies": { "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "finalhandler": { + "node_modules/finalhandler": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", - "requires": { + "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", @@ -2773,122 +3891,162 @@ "statuses": "~2.0.2", "unpipe": "~1.0.0" }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } + "engines": { + "node": ">= 0.8" } }, - "find-up": { + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, - "requires": { + "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "flat-cache": { + "node_modules/flat-cache": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, - "requires": { + "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" } }, - "flatted": { + "node_modules/flatted": { "version": "3.4.4", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", "dev": true }, - "form-data": { + "node_modules/form-data": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", "dev": true, - "requires": { + "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.4", "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" } }, - "formidable": { + "node_modules/formidable": { "version": "3.5.4", "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz", "integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==", "dev": true, - "requires": { + "dependencies": { "@paralleldrive/cuid2": "^2.2.2", "dezalgo": "^1.0.4", "once": "^1.4.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" } }, - "forwarded": { + "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } }, - "fresh": { + "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } }, - "fs-minipass": { + "node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "requires": { + "dependencies": { "minipass": "^3.0.0" }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "requires": { - "yallist": "^4.0.0" - } - } + "engines": { + "node": ">= 8" } }, - "fs.realpath": { + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, - "fsevents": { + "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, - "optional": true + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } }, - "function-bind": { + "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "gauge": { + "node_modules/gauge": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", - "requires": { + "deprecated": "This package is no longer supported.", + "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.2", "console-control-strings": "^1.0.0", @@ -2898,25 +4056,34 @@ "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" } }, - "gensync": { + "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true + "dev": true, + "engines": { + "node": ">=6.9.0" + } }, - "get-caller-file": { + "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } }, - "get-intrinsic": { + "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "requires": { + "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", @@ -2927,395 +4094,586 @@ "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "get-package-type": { + "node_modules/get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true + "dev": true, + "engines": { + "node": ">=8.0.0" + } }, - "get-proto": { + "node_modules/get-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "requires": { + "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" } }, - "get-stream": { + "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "glob": { + "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "requires": { + "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", + "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "glob-parent": { + "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, - "requires": { + "dependencies": { "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" } }, - "globals": { + "node_modules/globals": { "version": "16.5.0", "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "gopd": { + "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "graceful-fs": { + "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, - "handlebars": { + "node_modules/handlebars": { "version": "4.7.9", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", "dev": true, - "requires": { + "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", - "uglify-js": "^3.1.4", "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" } }, - "has-flag": { + "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } }, - "has-symbols": { + "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==" + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "has-tostringtag": { + "node_modules/has-tostringtag": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, - "requires": { + "dependencies": { "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "has-unicode": { + "node_modules/has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" }, - "hasown": { + "node_modules/hasown": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", - "requires": { + "dependencies": { "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" } }, - "html-escaper": { + "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, - "http-errors": { + "node_modules/http-errors": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "requires": { + "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "https-proxy-agent": { + "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "requires": { + "dependencies": { "agent-base": "6", "debug": "4" + }, + "engines": { + "node": ">= 6" } }, - "human-signals": { + "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true + "dev": true, + "engines": { + "node": ">=10.17.0" + } }, - "iconv-lite": { + "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { + "dependencies": { "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" } }, - "ieee754": { + "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "ignore": { + "node_modules/ignore": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", - "dev": true + "dev": true, + "engines": { + "node": ">= 4" + } }, - "import-fresh": { + "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, - "requires": { + "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "import-local": { + "node_modules/import-local": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, - "requires": { + "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "imurmurhash": { + "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.8.19" + } }, - "inflight": { + "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "requires": { + "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.", + "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, - "inherits": { + "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "ipaddr.js": { + "node_modules/ioredis": { + "version": "5.11.1", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.11.1.tgz", + "integrity": "sha512-ehuGcf94bQXhfagULNXrJdfnWO38v070jxSx/qE87Kjzmu2fU7ro5EFAb+OPituLqgfyuQaym5DlrNydW2sJ9A==", + "license": "MIT", + "dependencies": { + "@ioredis/commands": "1.10.0", + "cluster-key-slot": "1.1.1", + "debug": "4.4.3", + "denque": "2.1.0", + "redis-errors": "1.2.0", + "redis-parser": "3.0.0", + "standard-as-callback": "2.1.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" + } + }, + "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } }, - "is-arrayish": { + "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, - "is-binary-path": { + "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, - "requires": { + "dependencies": { "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" } }, - "is-core-module": { + "node_modules/is-core-module": { "version": "2.16.2", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", "dev": true, - "requires": { + "dependencies": { "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-extglob": { + "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "is-fullwidth-code-point": { + "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } }, - "is-generator-fn": { + "node_modules/is-generator-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "is-glob": { + "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, - "requires": { + "dependencies": { "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "is-number": { + "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.12.0" + } }, - "is-stream": { + "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "isexe": { + "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, - "istanbul-lib-coverage": { + "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "istanbul-lib-instrument": { + "node_modules/istanbul-lib-instrument": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, - "requires": { + "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" } }, - "istanbul-lib-report": { + "node_modules/istanbul-lib-report": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, - "requires": { + "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", "supports-color": "^7.1.0" }, - "dependencies": { - "make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "requires": { - "semver": "^7.5.3" - } - } + "engines": { + "node": ">=10" } }, - "istanbul-lib-source-maps": { + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/istanbul-lib-source-maps": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, - "requires": { + "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" } }, - "istanbul-reports": { + "node_modules/istanbul-reports": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, - "requires": { + "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "iterare": { + "node_modules/iterare": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", - "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==" + "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==", + "engines": { + "node": ">=6" + } }, - "jest": { + "node_modules/jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, - "requires": { + "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", "import-local": "^3.0.2", "jest-cli": "^29.7.0" }, - "dependencies": { - "jest-cli": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", - "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", - "dev": true, - "requires": { - "@jest/core": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "create-jest": "^29.7.0", - "exit": "^0.1.2", - "import-local": "^3.0.2", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "yargs": "^17.3.1" - } + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true } } }, - "jest-changed-files": { + "node_modules/jest-changed-files": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", "dev": true, - "requires": { + "dependencies": { "execa": "^5.0.0", "jest-util": "^29.7.0", "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "jest-circus": { + "node_modules/jest-circus": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", "dev": true, - "requires": { + "dependencies": { "@jest/environment": "^29.7.0", "@jest/expect": "^29.7.0", "@jest/test-result": "^29.7.0", @@ -3336,14 +4694,17 @@ "pure-rand": "^6.0.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "jest-config": { + "node_modules/jest-config": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", "dev": true, - "requires": { + "dependencies": { "@babel/core": "^7.11.6", "@jest/test-sequencer": "^29.7.0", "@jest/types": "^29.6.3", @@ -3366,110 +4727,151 @@ "pretty-format": "^29.7.0", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" + }, + "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": { + "node_modules/jest-diff": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dev": true, - "requires": { + "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^29.6.3", "jest-get-type": "^29.6.3", "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "jest-docblock": { + "node_modules/jest-docblock": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", "dev": true, - "requires": { + "dependencies": { "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "jest-each": { + "node_modules/jest-each": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", "dev": true, - "requires": { + "dependencies": { "@jest/types": "^29.6.3", "chalk": "^4.0.0", "jest-get-type": "^29.6.3", "jest-util": "^29.7.0", "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "jest-environment-node": { + "node_modules/jest-environment-node": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", "dev": true, - "requires": { + "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "jest-mock": "^29.7.0", "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "jest-get-type": { + "node_modules/jest-get-type": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } }, - "jest-haste-map": { + "node_modules/jest-haste-map": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", "dev": true, - "requires": { + "dependencies": { "@jest/types": "^29.6.3", "@types/graceful-fs": "^4.1.3", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", "graceful-fs": "^4.2.9", "jest-regex-util": "^29.6.3", "jest-util": "^29.7.0", "jest-worker": "^29.7.0", "micromatch": "^4.0.4", "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "jest-leak-detector": { + "node_modules/jest-leak-detector": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", "dev": true, - "requires": { + "dependencies": { "jest-get-type": "^29.6.3", "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "jest-matcher-utils": { + "node_modules/jest-matcher-utils": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", "dev": true, - "requires": { + "dependencies": { "chalk": "^4.0.0", "jest-diff": "^29.7.0", "jest-get-type": "^29.6.3", "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "jest-message-util": { + "node_modules/jest-message-util": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", "dev": true, - "requires": { + "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.6.3", "@types/stack-utils": "^2.0.0", @@ -3479,37 +4881,57 @@ "pretty-format": "^29.7.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "jest-mock": { + "node_modules/jest-mock": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", "dev": true, - "requires": { + "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "jest-pnp-resolver": { + "node_modules/jest-pnp-resolver": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } }, - "jest-regex-util": { + "node_modules/jest-regex-util": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", - "dev": true + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } }, - "jest-resolve": { + "node_modules/jest-resolve": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", "dev": true, - "requires": { + "dependencies": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "jest-haste-map": "^29.7.0", @@ -3519,24 +4941,30 @@ "resolve": "^1.20.0", "resolve.exports": "^2.0.0", "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "jest-resolve-dependencies": { + "node_modules/jest-resolve-dependencies": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", "dev": true, - "requires": { + "dependencies": { "jest-regex-util": "^29.6.3", "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "jest-runner": { + "node_modules/jest-runner": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", "dev": true, - "requires": { + "dependencies": { "@jest/console": "^29.7.0", "@jest/environment": "^29.7.0", "@jest/test-result": "^29.7.0", @@ -3558,14 +4986,17 @@ "jest-worker": "^29.7.0", "p-limit": "^3.1.0", "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "jest-runtime": { + "node_modules/jest-runtime": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", "dev": true, - "requires": { + "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", "@jest/globals": "^29.7.0", @@ -3588,14 +5019,17 @@ "jest-util": "^29.7.0", "slash": "^3.0.0", "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "jest-snapshot": { + "node_modules/jest-snapshot": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", "dev": true, - "requires": { + "dependencies": { "@babel/core": "^7.11.6", "@babel/generator": "^7.7.2", "@babel/plugin-syntax-jsx": "^7.7.2", @@ -3616,28 +5050,47 @@ "natural-compare": "^1.4.0", "pretty-format": "^29.7.0", "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "jest-util": { + "node_modules/jest-util": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, - "requires": { + "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "jest-validate": { + "node_modules/jest-util/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-validate": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", "dev": true, - "requires": { + "dependencies": { "@jest/types": "^29.6.3", "camelcase": "^6.2.0", "chalk": "^4.0.0", @@ -3645,21 +5098,28 @@ "leven": "^3.1.0", "pretty-format": "^29.7.0" }, - "dependencies": { - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - } + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "jest-watcher": { + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", "dev": true, - "requires": { + "dependencies": { "@jest/test-result": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", @@ -3668,86 +5128,153 @@ "emittery": "^0.13.1", "jest-util": "^29.7.0", "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "jest-worker": { + "node_modules/jest-worker": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", "dev": true, - "requires": { + "dependencies": { "@types/node": "*", "jest-util": "^29.7.0", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jest/node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true } } }, - "js-tokens": { + "node_modules/jose": { + "version": "6.2.6", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.6.tgz", + "integrity": "sha512-HwMtbJjMw8rC8dUTwCNilHJD+fxTeKM3JV1eprSmTjS41qwXSSt6exJXgyPK1QOu0jB9eDYLESRDkB3qaT3jnw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, - "js-yaml": { + "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "requires": { + "dependencies": { "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "jsesc": { + "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } }, - "json-buffer": { + "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true }, - "json-parse-even-better-errors": { + "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, - "json-schema-traverse": { + "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, - "json-stable-stringify-without-jsonify": { + "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "json5": { + "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } }, - "jsonwebtoken": { + "node_modules/jsonwebtoken": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", - "requires": { + "dependencies": { "jws": "^4.0.1", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", @@ -3759,312 +5286,393 @@ "ms": "^2.1.1", "semver": "^7.5.4" }, - "dependencies": { - "jwa": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", - "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", - "requires": { - "buffer-equal-constant-time": "^1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", - "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", - "requires": { - "jwa": "^2.0.1", - "safe-buffer": "^5.0.1" - } - } + "engines": { + "node": ">=12", + "npm": ">=6" } }, - "jwa": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", - "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", - "requires": { + "node_modules/jsonwebtoken/node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, - "jws": { + "node_modules/jsonwebtoken/node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jwa": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz", "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==", - "requires": { + "dependencies": { "jwa": "^1.4.2", "safe-buffer": "^5.0.1" } }, - "keyv": { + "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, - "requires": { + "dependencies": { "json-buffer": "3.0.1" } }, - "kleur": { + "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "leven": { + "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "levn": { + "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, - "requires": { + "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" } }, - "libphonenumber-js": { + "node_modules/libphonenumber-js": { "version": "1.13.10", "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.13.10.tgz", "integrity": "sha512-xJxrdqvbl2rtn2MaUJrUejz8J7/uZNC0V77oks2LxYrO/+ZtVpRmz+fEQMuu6VusnEB1fmpByiLS1WXecOnAnw==" }, - "lines-and-columns": { + "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, - "locate-path": { + "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, - "requires": { + "dependencies": { "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "lodash": { + "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "lodash.includes": { + "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" }, - "lodash.isboolean": { + "node_modules/lodash.isboolean": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" }, - "lodash.isinteger": { + "node_modules/lodash.isinteger": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" }, - "lodash.isnumber": { + "node_modules/lodash.isnumber": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" }, - "lodash.isplainobject": { + "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" }, - "lodash.isstring": { + "node_modules/lodash.isstring": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" }, - "lodash.memoize": { + "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", "dev": true }, - "lodash.merge": { + "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "lodash.once": { + "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" }, - "lru-cache": { + "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, - "requires": { - "yallist": "^3.0.2" - }, "dependencies": { - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - } + "yallist": "^3.0.2" } }, - "make-dir": { + "node_modules/lru-cache/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "requires": { + "dependencies": { "semver": "^6.0.0" }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" - } + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "make-error": { + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, - "makeerror": { + "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, - "requires": { + "dependencies": { "tmpl": "1.0.5" } }, - "math-intrinsics": { + "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "engines": { + "node": ">= 0.4" + } }, - "media-typer": { + "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } }, - "merge-descriptors": { + "node_modules/merge-descriptors": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==" + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "merge-stream": { + "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, - "methods": { + "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } }, - "micromatch": { + "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, - "requires": { + "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" } }, - "mime": { + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } }, - "mime-db": { + "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } }, - "mime-types": { + "node_modules/mime-types": { "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { + "dependencies": { "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" } }, - "mimic-fn": { + "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "minimatch": { + "node_modules/minimatch": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "requires": { + "dependencies": { "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "minimist": { + "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "minipass": { + "node_modules/minipass": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==" + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "engines": { + "node": ">=8" + } }, - "minizlib": { + "node_modules/minizlib": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "requires": { + "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "requires": { - "yallist": "^4.0.0" - } - } + "engines": { + "node": ">= 8" } }, - "mkdirp": { + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "requires": { + "dependencies": { "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" } }, - "ms": { + "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "multer": { + "node_modules/multer": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz", "integrity": "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==", - "requires": { + "dependencies": { "append-field": "^1.0.0", "busboy": "^1.6.0", "concat-stream": "^2.0.0", @@ -4072,262 +5680,394 @@ "object-assign": "^4.1.1", "type-is": "^1.6.18", "xtend": "^4.0.2" + }, + "engines": { + "node": ">= 10.16.0" } }, - "natural-compare": { + "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "negotiator": { + "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } }, - "neo-async": { + "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, - "node-addon-api": { + "node_modules/node-addon-api": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" }, - "node-fetch": { + "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "requires": { + "dependencies": { "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, - "node-int64": { + "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", "dev": true }, - "node-releases": { + "node_modules/node-releases": { "version": "2.0.51", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=18" + } }, - "nopt": { + "node_modules/nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "requires": { + "dependencies": { "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" } }, - "normalize-path": { + "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "npm-run-path": { + "node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, - "requires": { + "dependencies": { "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "npmlog": { + "node_modules/npmlog": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", - "requires": { + "deprecated": "This package is no longer supported.", + "dependencies": { "are-we-there-yet": "^2.0.0", "console-control-strings": "^1.1.0", "gauge": "^3.0.0", "set-blocking": "^2.0.0" } }, - "object-assign": { + "node_modules/oauth4webapi": { + "version": "3.8.6", + "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.8.6.tgz", + "integrity": "sha512-iwemM91xz8nryHti2yTmg5fhyEMVOkOXwHNqbvcATjyajb5oQxCQzrNOA6uElRHuMhQQTKUyFKV9y/CNyg25BQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } }, - "object-inspect": { + "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==" + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "on-exit-leak-free": { + "node_modules/on-exit-leak-free": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", - "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==" + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "engines": { + "node": ">=14.0.0" + } }, - "on-finished": { + "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "requires": { + "dependencies": { "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" } }, - "once": { + "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { + "dependencies": { "wrappy": "1" } }, - "onetime": { + "node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, - "requires": { + "dependencies": { "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "optionator": { + "node_modules/openid-client": { + "version": "6.8.4", + "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-6.8.4.tgz", + "integrity": "sha512-QSw0BA08piujetEwfZsHoTrDpMEha7GDZDicQqVwX4u0ChCjefvjDB++TZ8BTg76UpwhzIQgdvvfgfl3HpCSAw==", + "license": "MIT", + "dependencies": { + "jose": "^6.2.2", + "oauth4webapi": "^3.8.5" + }, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, - "requires": { + "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" } }, - "p-limit": { + "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, - "requires": { + "dependencies": { "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "p-locate": { + "node_modules/p-locate": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, - "requires": { + "dependencies": { "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "p-try": { + "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "parent-module": { + "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, - "requires": { + "dependencies": { "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "parse-json": { + "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, - "requires": { + "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "parseurl": { + "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } }, - "passport": { + "node_modules/passport": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz", "integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==", - "requires": { + "dependencies": { "passport-strategy": "1.x.x", "pause": "0.0.1", "utils-merge": "^1.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" } }, - "passport-jwt": { + "node_modules/passport-jwt": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", - "requires": { + "dependencies": { "jsonwebtoken": "^9.0.0", "passport-strategy": "^1.0.0" } }, - "passport-strategy": { + "node_modules/passport-strategy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", - "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==" + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", + "engines": { + "node": ">= 0.4.0" + } }, - "path-exists": { + "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "path-is-absolute": { + "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } }, - "path-key": { + "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "path-parse": { + "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "path-to-regexp": { + "node_modules/path-to-regexp": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", "integrity": "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==" }, - "pause": { + "node_modules/pause": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" }, - "picocolors": { + "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true }, - "picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, - "pino": { + "node_modules/pino": { "version": "9.14.0", "resolved": "https://registry.npmjs.org/pino/-/pino-9.14.0.tgz", "integrity": "sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w==", - "requires": { + "dependencies": { "@pinojs/redact": "^0.4.0", "atomic-sleep": "^1.0.0", "on-exit-leak-free": "^2.1.0", @@ -4339,304 +6079,537 @@ "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" + }, + "bin": { + "pino": "bin.js" } }, - "pino-abstract-transport": { + "node_modules/pino-abstract-transport": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", - "requires": { + "dependencies": { "split2": "^4.0.0" } }, - "pino-std-serializers": { + "node_modules/pino-std-serializers": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==" }, - "pirates": { + "node_modules/pirates": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true + "dev": true, + "engines": { + "node": ">= 6" + } }, - "pkg-dir": { + "node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, - "requires": { + "dependencies": { "find-up": "^4.0.0" }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - } + "engines": { + "node": ">=8" } }, - "prelude-ls": { + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/playwright": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.62.1.tgz", + "integrity": "sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.62.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.62.1.tgz", + "integrity": "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.8.0" + } }, - "prettier": { + "node_modules/prettier": { "version": "3.9.6", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz", "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==", - "dev": true + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } }, - "pretty-format": { + "node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, - "requires": { + "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "prisma": { + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prisma": { "version": "5.22.0", "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.22.0.tgz", "integrity": "sha512-vtpjW3XuYCSnMsNVBjLMNkTj6OZbudcPPTPYHqX0CJfpcdWciI1dM8uHETwmDxxiqEwCIE6WvXucWUetJgfu/A==", - "dev": true, - "requires": { - "@prisma/engines": "5.22.0", + "devOptional": true, + "hasInstallScript": true, + "dependencies": { + "@prisma/engines": "5.22.0" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=16.13" + }, + "optionalDependencies": { "fsevents": "2.3.3" } }, - "process-warning": { + "node_modules/process-warning": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.1.0.tgz", - "integrity": "sha512-jQSaVHsPgtyw60e1rQ/A+/ArPEj/S8pS/vFnyGa/gYFXrKk/6RuDkoqVDQ5NI5MmS01698ltlAk0NoDBNLujRw==" + "integrity": "sha512-jQSaVHsPgtyw60e1rQ/A+/ArPEj/S8pS/vFnyGa/gYFXrKk/6RuDkoqVDQ5NI5MmS01698ltlAk0NoDBNLujRw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ] }, - "prompts": { + "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dev": true, - "requires": { + "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" } }, - "proxy-addr": { + "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "requires": { + "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" } }, - "punycode": { + "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "pure-rand": { + "node_modules/pure-rand": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", - "dev": true + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] }, - "qs": { + "node_modules/qs": { "version": "6.14.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", - "requires": { + "dependencies": { "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "quick-format-unescaped": { + "node_modules/quick-format-unescaped": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" }, - "range-parser": { + "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } }, - "raw-body": { + "node_modules/raw-body": { "version": "2.5.3", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", - "requires": { + "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, - "react-is": { + "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, - "readable-stream": { + "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "requires": { + "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, - "readdirp": { + "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, - "requires": { + "dependencies": { "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" } }, - "real-require": { + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/real-require": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", - "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==" + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "engines": { + "node": ">= 12.13.0" + } }, - "reflect-metadata": { + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "license": "MIT", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/reflect-metadata": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==" }, - "require-directory": { + "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "resolve": { + "node_modules/resolve": { "version": "1.22.12", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", "dev": true, - "requires": { + "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "resolve-cwd": { + "node_modules/resolve-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, - "requires": { + "dependencies": { "resolve-from": "^5.0.0" }, - "dependencies": { - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } + "engines": { + "node": ">=8" } }, - "resolve-from": { + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true + "dev": true, + "engines": { + "node": ">=4" + } }, - "resolve.exports": { + "node_modules/resolve.exports": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", - "dev": true + "dev": true, + "engines": { + "node": ">=10" + } }, - "rimraf": { + "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "requires": { + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dependencies": { "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "rxjs": { + "node_modules/rxjs": { "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "requires": { + "dependencies": { "tslib": "^2.1.0" } }, - "safe-buffer": { + "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "safe-stable-stringify": { + "node_modules/safe-stable-stringify": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", - "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==" + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "engines": { + "node": ">=10" + } }, - "safer-buffer": { + "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "semver": { + "node_modules/semver": { "version": "7.8.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==" + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } }, - "send": { + "node_modules/send": { "version": "0.19.2", "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", - "requires": { + "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -4651,243 +6624,327 @@ "range-parser": "~1.2.1", "statuses": "~2.0.2" }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - } - } - } + "engines": { + "node": ">= 0.8.0" } }, - "serve-static": { + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/serve-static": { "version": "1.16.3", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", - "requires": { + "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" } }, - "set-blocking": { + "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, - "setprototypeof": { + "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, - "shebang-command": { + "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, - "requires": { + "dependencies": { "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "shebang-regex": { + "node_modules/shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "side-channel": { + "node_modules/side-channel": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", - "requires": { + "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.4", "side-channel-list": "^1.0.1", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "side-channel-list": { + "node_modules/side-channel-list": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", - "requires": { + "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "side-channel-map": { + "node_modules/side-channel-map": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "requires": { + "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "side-channel-weakmap": { + "node_modules/side-channel-weakmap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "requires": { + "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "signal-exit": { + "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, - "sisteransi": { + "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "dev": true }, - "slash": { + "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "sonic-boom": { + "node_modules/sonic-boom": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", - "requires": { + "dependencies": { "atomic-sleep": "^1.0.0" } }, - "source-map": { + "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "source-map-support": { + "node_modules/source-map-support": { "version": "0.5.13", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, - "requires": { + "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, - "split2": { + "node_modules/split2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } }, - "sprintf-js": { + "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, - "stack-utils": { + "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dev": true, - "requires": { + "dependencies": { "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" } }, - "statuses": { + "node_modules/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==", + "license": "MIT" + }, + "node_modules/statuses": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==" + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "engines": { + "node": ">= 0.8" + } }, - "streamsearch": { + "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } }, - "string-length": { + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, - "requires": { + "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" } }, - "string-width": { + "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "requires": { + "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" } }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "strip-ansi": { + "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { + "dependencies": { "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "strip-bom": { + "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + } }, - "strip-final-newline": { + "node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "strip-json-comments": { + "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "strtok3": { + "node_modules/strtok3": { "version": "10.3.5", "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.5.tgz", "integrity": "sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==", - "requires": { + "dependencies": { "@tokenizer/token": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" } }, - "superagent": { + "node_modules/superagent": { "version": "10.3.0", "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.3.0.tgz", "integrity": "sha512-B+4Ik7ROgVKrQsXTV0Jwp2u+PXYLSlqtDAhYnkkD+zn3yg8s/zjA2MeGayPoY/KICrbitwneDHrjSotxKL+0XQ==", "dev": true, - "requires": { + "dependencies": { "component-emitter": "^1.3.1", "cookiejar": "^2.1.4", "debug": "^4.3.7", @@ -4898,66 +6955,93 @@ "mime": "2.6.0", "qs": "^6.14.1" }, - "dependencies": { - "mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "dev": true - } + "engines": { + "node": ">=14.18.0" } }, - "supertest": { + "node_modules/superagent/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/supertest": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.2.2.tgz", "integrity": "sha512-oK8WG9diS3DlhdUkcFn4tkNIiIbBx9lI2ClF8K+b2/m8Eyv47LSawxUzZQSNKUrVb2KsqeTDCcjAAVPYaSLVTA==", "dev": true, - "requires": { + "dependencies": { "cookie-signature": "^1.2.2", "methods": "^1.1.2", "superagent": "^10.3.0" }, - "dependencies": { - "cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "dev": true - } + "engines": { + "node": ">=14.18.0" } }, - "supports-color": { + "node_modules/supertest/node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "dev": true, + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { + "dependencies": { "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "supports-preserve-symlinks-flag": { + "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "swagger-ui-dist": { + "node_modules/swagger-ui-dist": { "version": "5.17.14", "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.17.14.tgz", "integrity": "sha512-CVbSfaLpstV65OnSjbXfVd6Sta3q3F7Cj/yYuvHMp1P90LztOLs6PfUnKEVAeiIVQt9u2SaPwv0LiH/OyMjHRw==" }, - "swagger-ui-express": { + "node_modules/swagger-ui-express": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-5.0.1.tgz", "integrity": "sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==", - "requires": { + "dependencies": { "swagger-ui-dist": ">=5.0.0" + }, + "engines": { + "node": ">= v0.10.32" + }, + "peerDependencies": { + "express": ">=4.0.0 || >=5.0.0-beta" } }, - "tar": { + "node_modules/tar": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "requires": { + "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", + "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", @@ -4965,104 +7049,134 @@ "mkdirp": "^1.0.3", "yallist": "^4.0.0" }, - "dependencies": { - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" - } + "engines": { + "node": ">=10" } }, - "test-exclude": { + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, - "requires": { + "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" } }, - "thread-stream": { + "node_modules/thread-stream": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.2.0.tgz", "integrity": "sha512-zLBvqpwr4Esa0kRjcrzGU6zL25lePWaCLMx0RQFrmteozIfeNdaMLpG5U7PeHzvlFkAWaRKA9/KVW4F60iB+qw==", - "requires": { + "dependencies": { "real-require": "^0.2.0" } }, - "tinyglobby": { + "node_modules/tinyglobby": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "dev": true, - "requires": { + "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" }, - "dependencies": { - "picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "dev": true - } + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "tmpl": { + "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "dev": true }, - "to-regex-range": { + "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, - "requires": { + "dependencies": { "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" } }, - "toidentifier": { + "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } }, - "token-types": { + "node_modules/token-types": { "version": "6.1.2", "resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.2.tgz", "integrity": "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==", - "requires": { + "dependencies": { "@borewit/text-codec": "^0.2.1", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" } }, - "tr46": { + "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, - "tree-kill": { + "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true + "dev": true, + "bin": { + "tree-kill": "cli.js" + } }, - "ts-api-utils": { + "node_modules/ts-api-utils": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", - "dev": true + "dev": true, + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } }, - "ts-jest": { + "node_modules/ts-jest": { "version": "29.4.12", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.4.12.tgz", "integrity": "sha512-Ov6ClY53Fflh6BGAnY2DlTq1hYDrTycz2PVTXBWFW2CU+9zrEqAp9fWdGXl42EXO5RLSFAcAZ2JFKbP+zBTFfw==", "dev": true, - "requires": { + "dependencies": { "bs-logger": "^0.2.6", "fast-json-stable-stringify": "^2.1.0", "handlebars": "^4.7.9", @@ -5073,21 +7187,60 @@ "type-fest": "^4.41.0", "yargs-parser": "^21.1.1" }, - "dependencies": { - "type-fest": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", - "dev": true + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" + }, + "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", + "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-node": { + "node_modules/ts-jest/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, - "requires": { + "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", "@tsconfig/node12": "^1.0.7", @@ -5101,14 +7254,36 @@ "make-error": "^1.1.1", "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "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 + } } }, - "ts-node-dev": { + "node_modules/ts-node-dev": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz", "integrity": "sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==", "dev": true, - "requires": { + "dependencies": { "chokidar": "^3.5.1", "dynamic-dedupe": "^0.3.0", "minimist": "^1.2.6", @@ -5120,287 +7295,418 @@ "ts-node": "^10.4.0", "tsconfig": "^7.0.0" }, - "dependencies": { - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } + "bin": { + "ts-node-dev": "lib/bin.js", + "tsnd": "lib/bin.js" + }, + "engines": { + "node": ">=0.8.0" + }, + "peerDependencies": { + "node-notifier": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true } } }, - "tsconfig": { + "node_modules/ts-node-dev/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-node-dev/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/tsconfig": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", "dev": true, - "requires": { + "dependencies": { "@types/strip-bom": "^3.0.0", "@types/strip-json-comments": "0.0.30", "strip-bom": "^3.0.0", "strip-json-comments": "^2.0.0" - }, - "dependencies": { - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true - } } }, - "tslib": { + "node_modules/tsconfig/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/tsconfig/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, - "type-check": { + "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, - "requires": { + "dependencies": { "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" } }, - "type-detect": { + "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true + "dev": true, + "engines": { + "node": ">=4" + } }, - "type-fest": { + "node_modules/type-fest": { "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "type-is": { + "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { + "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" } }, - "typedarray": { + "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, - "typescript": { + "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } }, - "uglify-js": { + "node_modules/uglify-js": { "version": "3.19.3", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", "dev": true, - "optional": true + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } }, - "uid": { + "node_modules/uid": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz", "integrity": "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==", - "requires": { + "dependencies": { "@lukeed/csprng": "^1.0.0" + }, + "engines": { + "node": ">=8" } }, - "uint8array-extras": { + "node_modules/uint8array-extras": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", - "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==" + "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "undici-types": { + "node_modules/undici-types": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==" }, - "unpipe": { + "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } }, - "update-browserslist-db": { + "node_modules/update-browserslist-db": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, - "requires": { + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" } }, - "uri-js": { + "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "requires": { + "dependencies": { "punycode": "^2.1.0" } }, - "util-deprecate": { + "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, - "utils-merge": { + "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } }, - "uuid": { + "node_modules/uuid": { "version": "11.1.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", - "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==" + "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/esm/bin/uuid" + } }, - "v8-compile-cache-lib": { + "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, - "v8-to-istanbul": { + "node_modules/v8-to-istanbul": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, - "requires": { + "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" } }, - "validator": { + "node_modules/validator": { "version": "13.15.35", "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.35.tgz", - "integrity": "sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==" + "integrity": "sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==", + "engines": { + "node": ">= 0.10" + } }, - "vary": { + "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } }, - "walker": { + "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, - "requires": { + "dependencies": { "makeerror": "1.0.12" } }, - "webidl-conversions": { + "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, - "whatwg-url": { + "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "requires": { + "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, - "which": { + "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, - "requires": { + "dependencies": { "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, - "wide-align": { + "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "requires": { + "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } }, - "word-wrap": { + "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true + "dev": true, + "engines": { + "node": ">=0.10.0" + } }, - "wordwrap": { + "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", "dev": true }, - "wrap-ansi": { + "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, - "requires": { + "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "wrappy": { + "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, - "write-file-atomic": { + "node_modules/write-file-atomic": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", "dev": true, - "requires": { + "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "xtend": { + "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } }, - "y18n": { + "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true + "dev": true, + "engines": { + "node": ">=10" + } }, - "yallist": { + "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, - "yargs": { + "node_modules/yargs": { "version": "17.7.3", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", "dev": true, - "requires": { + "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", @@ -5408,25 +7714,40 @@ "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" } }, - "yargs-parser": { + "node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true + "dev": true, + "engines": { + "node": ">=12" + } }, - "yn": { + "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true + "dev": true, + "engines": { + "node": ">=6" + } }, - "yocto-queue": { + "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 48b8469..2cc6cd2 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "scripts": { "start": "node dist/main.js", "start:dev": "ts-node-dev --respawn --pretty --transpile-only src/main.ts", + "start:debug": "nest start --debug --watch", "build": "tsc -p tsconfig.json", "lint": "eslint \"src/**/*.ts\"", "format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"", @@ -37,6 +38,8 @@ "class-transformer": "^0.5.1", "class-validator": "^0.14.2", "dotenv": "^16.6.1", + "jose": "^6.2.6", + "openid-client": "^6.5.0", "jsonwebtoken": "^9.0.2", "passport": "^0.7.0", "passport-jwt": "^4.0.1", @@ -47,6 +50,9 @@ "uuid": "^11.1.0" }, "devDependencies": { + "@eslint/js": "^9.21.0", + "@nestjs/testing": "^10.4.22", + "@playwright/test": "^1.62.1", "@types/bcrypt": "^5.0.2", "@types/jest": "^29.5.14", "@types/node": "^22.13.10", @@ -56,7 +62,6 @@ "@typescript-eslint/eslint-plugin": "^8.25.0", "@typescript-eslint/parser": "^8.25.0", "eslint": "^9.21.0", - "@eslint/js": "^9.21.0", "globals": "^16.0.0", "jest": "^29.7.0", "prettier": "^3.5.3", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..5b753de --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,17 @@ +import { defineConfig, devices } from '@playwright/test'; + +export default defineConfig({ + // only run Playwright tests in the integration folder to avoid running Jest unit tests + testDir: './tests/integration', + timeout: 30 * 1000, + expect: { + timeout: 5000, + }, + forbidOnly: !!process.env.CI, + retries: process.env.CI ? 2 : 0, + workers: process.env.CI ? 1 : undefined, + reporter: [["list"], ["./tests/reporter/custom-reporter.js"]], + use: { + baseURL: process.env.BASE_URL || 'http://localhost:3000', + }, +}); diff --git a/postman/RayLab.postman_collection.json b/postman/RayLab.postman_collection.json new file mode 100644 index 0000000..f94df2a --- /dev/null +++ b/postman/RayLab.postman_collection.json @@ -0,0 +1,58 @@ +{ + "info": { + "_postman_id": "e1e605cc-a2c6-4410-a7aa-4692b594d42d", + "name": "RayLab", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "45313893" + }, + "item": [ + { + "name": "User", + "item": [ + { + "name": "Create User", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer ", + "description": "Bearer ", + "type": "text", + "disabled": true + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"username\": \"rayyan\",\r\n \"email\": \"rayyan@example.com\",\r\n \"password\": \"Password123!\",\r\n \"fullName\": \"Rayyan\"\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:3000/api/v1/users", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "3000", + "path": [ + "api", + "v1", + "users" + ] + } + }, + "response": [] + } + ] + } + ] +} \ No newline at end of file diff --git a/prisma/migrations/20260730165554_permission/migration.sql b/prisma/migrations/20260730165554_permission/migration.sql new file mode 100644 index 0000000..23e8e28 --- /dev/null +++ b/prisma/migrations/20260730165554_permission/migration.sql @@ -0,0 +1,93 @@ +-- CreateTable +CREATE TABLE "User" ( + "id" TEXT NOT NULL, + "username" TEXT NOT NULL, + "email" TEXT NOT NULL, + "password" TEXT NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "User_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Role" ( + "id" TEXT NOT NULL, + "code" TEXT NOT NULL, + "name" TEXT NOT NULL, + "description" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Role_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Permission" ( + "id" TEXT NOT NULL, + "code" TEXT NOT NULL, + "name" TEXT NOT NULL, + "description" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Permission_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "UserRole" ( + "userId" TEXT NOT NULL, + "roleId" TEXT NOT NULL, + "assignedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "UserRole_pkey" PRIMARY KEY ("userId","roleId") +); + +-- CreateTable +CREATE TABLE "RolePermission" ( + "roleId" TEXT NOT NULL, + "permissionId" TEXT NOT NULL, + "assignedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "RolePermission_pkey" PRIMARY KEY ("roleId","permissionId") +); + +-- CreateTable +CREATE TABLE "UserPermission" ( + "userId" TEXT NOT NULL, + "permissionId" TEXT NOT NULL, + "assignedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "UserPermission_pkey" PRIMARY KEY ("userId","permissionId") +); + +-- CreateIndex +CREATE UNIQUE INDEX "User_username_key" ON "User"("username"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "Role_code_key" ON "Role"("code"); + +-- CreateIndex +CREATE UNIQUE INDEX "Permission_code_key" ON "Permission"("code"); + +-- AddForeignKey +ALTER TABLE "UserRole" ADD CONSTRAINT "UserRole_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "UserRole" ADD CONSTRAINT "UserRole_roleId_fkey" FOREIGN KEY ("roleId") REFERENCES "Role"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "RolePermission" ADD CONSTRAINT "RolePermission_roleId_fkey" FOREIGN KEY ("roleId") REFERENCES "Role"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "RolePermission" ADD CONSTRAINT "RolePermission_permissionId_fkey" FOREIGN KEY ("permissionId") REFERENCES "Permission"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "UserPermission" ADD CONSTRAINT "UserPermission_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "UserPermission" ADD CONSTRAINT "UserPermission_permissionId_fkey" FOREIGN KEY ("permissionId") REFERENCES "Permission"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20260801084138_change/migration.sql b/prisma/migrations/20260801084138_change/migration.sql new file mode 100644 index 0000000..f73805a --- /dev/null +++ b/prisma/migrations/20260801084138_change/migration.sql @@ -0,0 +1,16 @@ +/* + Warnings: + + - Added the required column `assignedBy` to the `RolePermission` table without a default value. This is not possible if the table is not empty. + - Added the required column `assignedBy` to the `UserPermission` table without a default value. This is not possible if the table is not empty. + - Added the required column `assignedBy` to the `UserRole` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "RolePermission" ADD COLUMN "assignedBy" TEXT NOT NULL; + +-- AlterTable +ALTER TABLE "UserPermission" ADD COLUMN "assignedBy" TEXT NOT NULL; + +-- AlterTable +ALTER TABLE "UserRole" ADD COLUMN "assignedBy" TEXT NOT NULL; diff --git a/prisma/migrations/20260801101438_add_role_is_default/migration.sql b/prisma/migrations/20260801101438_add_role_is_default/migration.sql new file mode 100644 index 0000000..dabc294 --- /dev/null +++ b/prisma/migrations/20260801101438_add_role_is_default/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Role" ADD COLUMN "isDefault" BOOLEAN NOT NULL DEFAULT false; diff --git a/prisma/migrations/20260801101841_add_authentik_id/migration.sql b/prisma/migrations/20260801101841_add_authentik_id/migration.sql new file mode 100644 index 0000000..aa49398 --- /dev/null +++ b/prisma/migrations/20260801101841_add_authentik_id/migration.sql @@ -0,0 +1,11 @@ +/* + Warnings: + + - A unique constraint covering the columns `[authentikId]` on the table `User` will be added. If there are existing duplicate values, this will fail. + +*/ +-- AlterTable +ALTER TABLE "User" ADD COLUMN "authentikId" TEXT; + +-- CreateIndex +CREATE UNIQUE INDEX "User_authentikId_key" ON "User"("authentikId"); diff --git a/prisma/migrations/20260801104311_add_deleted_at/migration.sql b/prisma/migrations/20260801104311_add_deleted_at/migration.sql new file mode 100644 index 0000000..a9d12c0 --- /dev/null +++ b/prisma/migrations/20260801104311_add_deleted_at/migration.sql @@ -0,0 +1,10 @@ +/* + Warnings: + + - You are about to drop the column `password` on the `User` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "User" DROP COLUMN "password", +ADD COLUMN "deletedAt" TIMESTAMP(3), +ADD COLUMN "lastSeenAt" TIMESTAMP(3); diff --git a/prisma/migrations/20260801132311_add_authentik_fields/migration.sql b/prisma/migrations/20260801132311_add_authentik_fields/migration.sql new file mode 100644 index 0000000..32ee861 --- /dev/null +++ b/prisma/migrations/20260801132311_add_authentik_fields/migration.sql @@ -0,0 +1,15 @@ +/* + Warnings: + + - A unique constraint covering the columns `[authentikUserId]` on the table `User` will be added. If there are existing duplicate values, this will fail. + - A unique constraint covering the columns `[authentikSubject]` on the table `User` will be added. If there are existing duplicate values, this will fail. + +*/ +-- AlterTable +ALTER TABLE "User" ALTER COLUMN "lastSyncedAt" SET DATA TYPE TIMESTAMP(3); + +-- CreateIndex +CREATE UNIQUE INDEX "User_authentikUserId_key" ON "User"("authentikUserId"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_authentikSubject_key" ON "User"("authentikSubject"); diff --git a/prisma/migrations/20260802_add_authentik_fields/migration.sql b/prisma/migrations/20260802_add_authentik_fields/migration.sql new file mode 100644 index 0000000..fc9ffb9 --- /dev/null +++ b/prisma/migrations/20260802_add_authentik_fields/migration.sql @@ -0,0 +1,17 @@ +-- Migration: add_authentik_fields + +ALTER TABLE "User" +ADD COLUMN IF NOT EXISTS "authentikUserId" TEXT; + +ALTER TABLE "User" +ADD COLUMN IF NOT EXISTS "authentikSubject" TEXT; + +ALTER TABLE "User" +ADD COLUMN IF NOT EXISTS "lastSyncedAt" TIMESTAMP; + +ALTER TABLE "User" +ADD COLUMN IF NOT EXISTS "syncStatus" TEXT; + +-- Optional: add unique constraints if desired +-- DO NOT add unique constraints without verifying existing data +-- ALTER TABLE "User" ADD CONSTRAINT "User_authentikUserId_key" UNIQUE ("authentikUserId"); diff --git a/prisma/migrations/20260803_add_storage/migration.sql b/prisma/migrations/20260803_add_storage/migration.sql new file mode 100644 index 0000000..d7df7a3 --- /dev/null +++ b/prisma/migrations/20260803_add_storage/migration.sql @@ -0,0 +1,7 @@ +-- Migration: add_storage + +ALTER TABLE "User" + ADD COLUMN IF NOT EXISTS "storageQuota" bigint NOT NULL DEFAULT 10737418240; + +ALTER TABLE "User" + ADD COLUMN IF NOT EXISTS "storageUsed" bigint NOT NULL DEFAULT 0; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..fbffa92 --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +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 diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 19f49c7..a6c5140 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -11,13 +11,99 @@ datasource db { } model User { - id String @id @default(uuid()) - name String - email String @unique - password String - status String @default("ACTIVE") - metadata Json? - created_at DateTime @default(now()) - updated_at DateTime @updatedAt - deleted_at DateTime? + id String @id @default(uuid()) + + authentikId String? @unique + authentikUserId String? @unique + authentikSubject String? @unique + + username String @unique + email String @unique + + + isActive Boolean @default(true) + + // storage (in bytes) + storageQuota BigInt @default(10737418240) + storageUsed BigInt @default(0) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + deletedAt DateTime? + lastSeenAt DateTime? + lastSyncedAt DateTime? + syncStatus String? + + roles UserRole[] + permissions UserPermission[] + } + +model Role { + id String @id @default(uuid()) + + code String @unique + name String + description String? + + isDefault Boolean @default(false) + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + users UserRole[] + permissions RolePermission[] +} + +model Permission { + id String @id @default(uuid()) + + code String @unique + name String + description String? + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + roles RolePermission[] + users UserPermission[] +} + +model UserRole { + userId String + roleId String + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + role Role @relation(fields: [roleId], references: [id], onDelete: Cascade) + + assignedAt DateTime @default(now()) + assignedBy String + + @@id([userId, roleId]) +} + +model RolePermission { + roleId String + permissionId String + + role Role @relation(fields: [roleId], references: [id], onDelete: Cascade) + permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade) + + assignedAt DateTime @default(now()) + assignedBy String + + @@id([roleId, permissionId]) +} + +model UserPermission { + userId String + permissionId String + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade) + + assignedAt DateTime @default(now()) + assignedBy String + + @@id([userId, permissionId]) +} \ No newline at end of file diff --git a/src/app.module.ts b/src/app.module.ts index 01cb319..e6e9b1a 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -2,6 +2,7 @@ import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { IdentityModule } from './modules/identity/identity.module'; +import { AuthModule } from './modules/auth/auth.module'; @Module({ imports: [ @@ -10,6 +11,7 @@ import { IdentityModule } from './modules/identity/identity.module'; }), IdentityModule, + AuthModule, ], }) export class AppModule {} \ No newline at end of file diff --git a/src/common/constants/permission.constants.ts b/src/common/constants/permission.constants.ts new file mode 100644 index 0000000..29c7547 --- /dev/null +++ b/src/common/constants/permission.constants.ts @@ -0,0 +1,16 @@ +export const PermissionType = { + USER_CREATE: 'USER_CREATE', + USER_READ: 'USER_READ', + USER_UPDATE: 'USER_UPDATE', + USER_DELETE: 'USER_DELETE', + + ROLE_CREATE: 'ROLE_CREATE', + ROLE_READ: 'ROLE_READ', + ROLE_UPDATE: 'ROLE_UPDATE', + ROLE_DELETE: 'ROLE_DELETE', + + PERMISSION_CREATE: 'PERMISSION_CREATE', + PERMISSION_READ: 'PERMISSION_READ', + PERMISSION_UPDATE: 'PERMISSION_UPDATE', + PERMISSION_DELETE: 'PERMISSION_DELETE', +} as const; \ No newline at end of file diff --git a/src/core/auth/guards/jwt-auth.guard.ts b/src/core/auth/guards/jwt-auth.guard.ts index d29b625..7b657bb 100644 --- a/src/core/auth/guards/jwt-auth.guard.ts +++ b/src/core/auth/guards/jwt-auth.guard.ts @@ -4,17 +4,23 @@ import { ExecutionContext, UnauthorizedException, } from '@nestjs/common'; -import { JwtService } from '@nestjs/jwt'; import { Request } from 'express'; +import { createRemoteJWKSet, jwtVerify } from 'jose'; +import { IdentityData } from '../interfaces/identity-data'; +import * as jwt from 'jsonwebtoken'; +/** + * JwtAuthGuard verifies JWTs issued by the external Identity Provider (Authentik) + * using JWKS (RS256). It also accepts internal RayLab JWTs signed with a local secret. + */ @Injectable() export class JwtAuthGuard implements CanActivate { - constructor( - private readonly jwtService: JwtService, - ) {} + private jwks: ReturnType | null = null; + + constructor() {} async canActivate(context: ExecutionContext): Promise { - const request = context.switchToHttp().getRequest(); + const request = context.switchToHttp().getRequest(); const authHeader = request.headers.authorization; @@ -28,13 +34,51 @@ export class JwtAuthGuard implements CanActivate { throw new UnauthorizedException('Invalid authorization header.'); } + const jwksUri = process.env.AUTHENTIK_JWKS_URI; + + // First try verifying with external JWKS (Authentik) + if (jwksUri) { + try { + if (!this.jwks) this.jwks = createRemoteJWKSet(new URL(jwksUri)); + + const { payload } = await jwtVerify(token, this.jwks, { + issuer: process.env.AUTHENTIK_ISSUER, + audience: process.env.AUTHENTIK_AUDIENCE, + }); + + const identity = new IdentityData( + payload.sub as string, + (payload as any).preferred_username as string | undefined, + (payload as any).email as string | undefined, + payload as Record, + ); + + request.identity = identity; + return true; + } catch (err) { + // ignore and try internal verification + } + } + + // Fallback: verify with internal symmetric secret + const secret = process.env.RAYLAB_JWT_SECRET; + if (!secret) { + throw new UnauthorizedException('Invalid or expired token.'); + } + try { - const payload = await this.jwtService.verifyAsync(token); + const payload = jwt.verify(token, secret) as any; - request['user'] = payload; + const identity = new IdentityData( + payload.sub as string, + payload.preferred_username as string | undefined, + payload.email as string | undefined, + payload as Record, + ); + request.identity = identity; return true; - } catch { + } catch (err: any) { throw new UnauthorizedException('Invalid or expired token.'); } } diff --git a/src/core/auth/interfaces/authenticated-request.interface.ts b/src/core/auth/interfaces/authenticated-request.interface.ts index 440f68b..03019a1 100644 --- a/src/core/auth/interfaces/authenticated-request.interface.ts +++ b/src/core/auth/interfaces/authenticated-request.interface.ts @@ -1,12 +1,12 @@ import { Request } from 'express'; - -export interface JwtPayload { - sub: string; - email: string; - role: string; - permissions: string[]; -} +import { UserData } from '../../../modules/identity/domain/entities/user.entity'; +import { IdentityData } from './identity-data'; export interface AuthenticatedRequest extends Request { - user: JwtPayload; + // Identity comes from the external Identity Provider (Authentik) + // JwtAuthGuard must set request.identity = payload + identity?: IdentityData; + + // After CurrentUserGuard resolves the user from repository, it must set request.currentUser = User Domain + currentUser?: UserData; } \ No newline at end of file diff --git a/src/core/auth/interfaces/identity-data.ts b/src/core/auth/interfaces/identity-data.ts new file mode 100644 index 0000000..640aca7 --- /dev/null +++ b/src/core/auth/interfaces/identity-data.ts @@ -0,0 +1,8 @@ +export class IdentityData { + constructor( + public readonly sub: string, + public readonly preferred_username?: string, + public readonly email?: string, + public readonly claims?: Record, + ) {} +} diff --git a/src/main.ts b/src/main.ts index 6449bee..f6e22bd 100644 --- a/src/main.ts +++ b/src/main.ts @@ -10,7 +10,7 @@ async function bootstrap() { const config = app.get(ConfigService); - app.setGlobalPrefix('api'); + app.setGlobalPrefix(''); app.useGlobalPipes( new ValidationPipe({ @@ -22,8 +22,7 @@ async function bootstrap() { app.enableCors(); - const swaggerEnabled = - config.get('SWAGGER_ENABLED') === 'true'; + const swaggerEnabled = config.get('SWAGGER_ENABLED') === 'true'; if (swaggerEnabled) { const swaggerConfig = new DocumentBuilder() @@ -35,7 +34,7 @@ async function bootstrap() { const document = SwaggerModule.createDocument(app, swaggerConfig); - SwaggerModule.setup('docs', app, document); + SwaggerModule.setup('ApiList', app, document); } const port = config.get('PORT') || 3000; diff --git a/src/modules/auth/auth.controller.ts b/src/modules/auth/auth.controller.ts new file mode 100644 index 0000000..5ef7553 --- /dev/null +++ b/src/modules/auth/auth.controller.ts @@ -0,0 +1,65 @@ + +import { Controller, Get, Post, Query, Res, Req, Body, HttpCode, HttpStatus } from '@nestjs/common'; +import { ApiTags, ApiOperation } from '@nestjs/swagger'; +import { AuthService } from './auth.service'; +import { Response, Request } from 'express'; + +@ApiTags('Auth') +@Controller('auth') +export class AuthController { + constructor(private readonly authService: AuthService) {} + + @Get('login') + @ApiOperation({ summary: 'Start Authorization Code + PKCE login (redirect to Identity Provider)' }) + async login(@Query('returnTo') returnTo: string | undefined, @Res() res: Response) { + const redirect = await this.authService.createAuthorizationRedirect(returnTo); + return res.redirect(302, redirect); + } + + @Get('callback') + @ApiOperation({ summary: 'OIDC callback endpoint' }) + async callback(@Query('code') code: string, @Query('state') state: string, @Res() res: Response) { + const result = await this.authService.handleCallback(code, state); + + // set cookies + const cookieOptions: any = { + httpOnly: true, + secure: process.env.NODE_ENV === 'production', + sameSite: 'lax', + path: '/', + }; + + // access token cookie (internal JWT) + res.cookie('raylab_jwt', result.accessToken, { ...cookieOptions, maxAge: result.expiresIn * 1000 }); + + // refresh token cookie + res.cookie('raylab_refresh', result.refreshToken, { ...cookieOptions, maxAge: result.refreshTtl * 1000 }); + + return res.redirect(302, result.returnTo || '/'); + } + + @Post('logout') + @HttpCode(HttpStatus.OK) + @ApiOperation({ summary: 'Logout (invalidate internal session and redirect to identity provider logout)' }) + async logout(@Req() req: Request, @Res() res: Response) { + const refreshToken = req.cookies?.raylab_refresh || req.body?.refreshToken; + const redirect = await this.authService.logout(refreshToken); + return res.redirect(302, redirect); + } + + @Post('refresh') + @ApiOperation({ summary: 'Refresh internal JWT using internal refresh token' }) + async refresh(@Req() req: Request) { + const refreshToken = req.cookies?.raylab_refresh || req.body?.refreshToken; + const result = await this.authService.refresh(refreshToken); + return { success: true, data: result }; + } + + @Get('me') + @ApiOperation({ summary: 'Get current user from internal JWT (cookie or Authorization header)' }) + async me(@Req() req: Request) { + const token = (req.cookies?.raylab_jwt) || (req.headers.authorization && (req.headers.authorization as string).replace(/^Bearer\s+/i, '')); + const user = await this.authService.me(token); + return { success: true, data: user }; + } +} diff --git a/src/modules/auth/auth.module.ts b/src/modules/auth/auth.module.ts new file mode 100644 index 0000000..820594c --- /dev/null +++ b/src/modules/auth/auth.module.ts @@ -0,0 +1,46 @@ +import { Module } from '@nestjs/common'; +import { AuthController } from './auth.controller'; +import { AuthService } from './auth.service'; +import { ConfigModule, ConfigService } from '@nestjs/config'; +import { JwtModule } from '@nestjs/jwt'; +import { PrismaService } from '../../shared/prisma.service'; +import { IUser } from '../identity/domain/repositories/user.interface'; +import { PrismaUserRepository } from '../identity/infrastructure/repositories/prisma-user.repository'; +import { SyncIdentityHandler } from '../identity/application/handlers/user/sync-identity.handler'; +import { IRole } from '../identity/domain/repositories/role.interface'; +import { PrismaRoleRepository } from '../identity/infrastructure/repositories/prisma-role.repository'; +import { IAuthConfig } from '../identity/application/config/i-auth-config'; +import { EnvAuthConfig } from '../identity/application/config/env-auth-config'; +import { RedisPkceStore } from './pkce/redis-pkce.store'; +import { InMemoryRefreshStore } from './refresh/inmemory-refresh.store'; + +@Module({ + imports: [ + ConfigModule, + JwtModule.registerAsync({ + imports: [ConfigModule], + useFactory: async (config: ConfigService) => ({ + secret: config.get('RAYLAB_JWT_SECRET') || 'raylab-secret', + signOptions: { algorithm: 'HS256' }, + }), + inject: [ConfigService], + }), + ], + controllers: [AuthController], + providers: [ + AuthService, + PrismaService, + PrismaUserRepository, + PrismaRoleRepository, + SyncIdentityHandler, + { provide: IUser, useClass: PrismaUserRepository }, + { provide: IRole, useClass: PrismaRoleRepository }, + { provide: IAuthConfig, useClass: EnvAuthConfig }, + + // In-memory PKCE and Refresh stores (Redis removed) + RedisPkceStore, + InMemoryRefreshStore, + ], + exports: [AuthService], +}) +export class AuthModule {} diff --git a/src/modules/auth/auth.service.ts b/src/modules/auth/auth.service.ts new file mode 100644 index 0000000..f488309 --- /dev/null +++ b/src/modules/auth/auth.service.ts @@ -0,0 +1,193 @@ +import { Injectable, UnauthorizedException, Inject } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { JwtService } from '@nestjs/jwt'; +import { SyncIdentityHandler } from '../identity/application/handlers/user/sync-identity.handler'; +import { IUser } from '../identity/domain/repositories/user.interface'; +import { PrismaService } from '../../shared/prisma.service'; +import { RedisPkceStore } from './pkce/redis-pkce.store'; +import { InMemoryRefreshStore } from './refresh/inmemory-refresh.store'; + +import { Issuer, generators, TokenSet } from 'openid-client'; + +@Injectable() +export class AuthService { + constructor( + private readonly config: ConfigService, + private readonly jwtService: JwtService, + private readonly prisma: PrismaService, + @Inject(IUser) private readonly userRepository: IUser, + private readonly syncIdentityHandler: SyncIdentityHandler, + private readonly pkceStore: RedisPkceStore, + private readonly refreshStore: InMemoryRefreshStore, + ) {} + + private issuer: any = null; + private client: any = null; + + private async getIssuer() { + if (this.issuer) return this.issuer; + const issuerUrl = this.config.get('AUTHENTIK_ISSUER'); + if (!issuerUrl) throw new Error('AUTHENTIK_ISSUER not configured'); + this.issuer = await Issuer.discover(issuerUrl); + return this.issuer; + } + + private async getClient() { + if (this.client) return this.client; + const issuer = await this.getIssuer(); + const clientId = this.config.get('AUTHENTIK_CLIENT_ID'); + const clientSecret = this.config.get('AUTHENTIK_CLIENT_SECRET'); + if (!clientId) throw new Error('AUTHENTIK_CLIENT_ID not configured'); + this.client = new issuer.Client({ client_id: clientId, client_secret: clientSecret }); + return this.client; + } + + async createAuthorizationRedirect(returnTo?: string) { + const client = await this.getClient(); + const redirectUri = this.config.get('AUTH_CALLBACK_URL') || `${this.config.get('APP_URL') || ''}/auth/callback`; + + const state = require('crypto').randomUUID(); + const code_verifier = generators.codeVerifier(); + const code_challenge = await generators.codeChallenge(code_verifier); + const nonce = generators.nonce(); + + await this.pkceStore.save(state, { code_verifier, nonce, returnTo }, 300); + + const url = client.authorizationUrl({ + redirect_uri: redirectUri, + scope: this.config.get('AUTHENTIK_DEFAULT_SCOPE') || 'openid email profile', + response_type: 'code', + code_challenge, + code_challenge_method: 'S256', + state, + nonce, + }); + + return url; + } + + async handleCallback(code: string, state: string) { + const client = await this.getClient(); + const pkce = await this.pkceStore.get(state); + if (!pkce) throw new UnauthorizedException('Invalid or expired state'); + + // remove one-time state + await this.pkceStore.remove(state); + + const redirectUri = this.config.get('AUTH_CALLBACK_URL') || `${this.config.get('APP_URL') || ''}/auth/callback`; + + // exchange code + const tokenSet: TokenSet = await client.callback(redirectUri, { code, state }, { code_verifier: pkce.code_verifier, nonce: pkce.nonce }); + + // verify id_token and get claims + const claims = tokenSet.claims(); + + // fetch userinfo if available + let userInfo = null; + try { + if (tokenSet.access_token && client.userinfo) { + userInfo = await client.userinfo(tokenSet.access_token); + } + } catch (e) { + // ignore + } + + const identity = { + sub: userInfo?.sub || claims.sub || null, + preferred_username: userInfo?.preferred_username || userInfo?.username || userInfo?.email || claims.preferred_username || claims.email, + email: userInfo?.email || claims.email, + raw: { tokenSet, userInfo, claims }, + } as any; + + // Sync identity to local user (create if needed) + const domainUser = await this.syncIdentityHandler.execute(identity as any); + + // ensure active/not deleted + if (!domainUser.isActive) throw new UnauthorizedException('User is not active'); + if (domainUser.deletedAt) throw new UnauthorizedException('User is deleted'); + + // create internal JWT + const jwtPayload = { + sub: domainUser.id, + preferred_username: domainUser.username, + email: domainUser.email, + } as any; + + const expiresIn = Number(this.config.get('RAYLAB_JWT_EXPIRES_IN') || 3600); + const access = this.jwtService.sign(jwtPayload, { expiresIn }); + + // create internal refresh token + const refreshToken = require('crypto').randomUUID(); + const refreshTtl = Number(this.config.get('RAYLAB_REFRESH_EXPIRES_IN') || 30 * 24 * 3600); // default 30 days + + await this.refreshStore.set(refreshToken, { userId: domainUser.id }, refreshTtl); + + return { + accessToken: access, + refreshToken, + expiresIn, + refreshTtl, + user: { + id: domainUser.id, + username: domainUser.username, + email: domainUser.email, + roles: domainUser.roles || [], + }, + returnTo: pkce.returnTo, + }; + } + + async refresh(refreshToken?: string) { + if (!refreshToken) throw new UnauthorizedException('Missing refresh token'); + const data = await this.refreshStore.get(refreshToken); + if (!data) throw new UnauthorizedException('Invalid refresh token'); + + const userId = data.userId; + // load user + const domainUser = await this.userRepository.findById(userId); + if (!domainUser) throw new UnauthorizedException('User not found'); + if (!domainUser.isActive) throw new UnauthorizedException('User is not active'); + + // rotate refresh token + await this.refreshStore.del(refreshToken); + const newRefresh = require('crypto').randomUUID(); + const refreshTtl = Number(this.config.get('RAYLAB_REFRESH_EXPIRES_IN') || 30 * 24 * 3600); + await this.refreshStore.set(newRefresh, { userId }, refreshTtl); + + const expiresIn = Number(this.config.get('RAYLAB_JWT_EXPIRES_IN') || 3600); + const access = this.jwtService.sign({ sub: domainUser.id, preferred_username: domainUser.username, email: domainUser.email }, { expiresIn }); + + return { accessToken: access, refreshToken: newRefresh, expiresIn, refreshTtl }; + } + + async logout(refreshToken?: string) { + if (refreshToken) { + await this.refreshStore.del(refreshToken); + } + + const issuer = await this.getIssuer(); + const endSession = issuer.metadata.end_session_endpoint; + const postLogout = this.config.get('APP_URL') || '/'; + + if (endSession) { + // Redirect to identity provider logout + const url = new URL(endSession); + if (postLogout) url.searchParams.set('post_logout_redirect_uri', postLogout); + return url.toString(); + } + + return postLogout; + } + + async me(token?: string) { + if (!token) throw new UnauthorizedException('Missing token'); + try { + const payload: any = this.jwtService.verify(token); + const user = await this.userRepository.findById(payload.sub); + if (!user) throw new UnauthorizedException('User not found'); + return { id: user.id, username: user.username, email: user.email, roles: user.roles || [] }; + } catch (e) { + throw new UnauthorizedException('Invalid token'); + } + } +} diff --git a/src/modules/auth/dto/login.dto.ts b/src/modules/auth/dto/login.dto.ts new file mode 100644 index 0000000..d3c2d25 --- /dev/null +++ b/src/modules/auth/dto/login.dto.ts @@ -0,0 +1,2 @@ +// Login DTO removed. Password grant has been removed in favor of Authorization Code + PKCE flow. +// Formerly contained username/password properties. diff --git a/src/modules/auth/pkce/redis-pkce.store.ts b/src/modules/auth/pkce/redis-pkce.store.ts new file mode 100644 index 0000000..2124c59 --- /dev/null +++ b/src/modules/auth/pkce/redis-pkce.store.ts @@ -0,0 +1,42 @@ +import { Injectable, OnModuleDestroy } from '@nestjs/common'; + +type PkceEntry = { code_verifier: string; nonce: string; returnTo?: string; expiresAt: number }; + +@Injectable() +export class RedisPkceStore implements OnModuleDestroy { + // In-memory PKCE store replacing Redis-backed implementation + private map = new Map(); + private cleanupInterval?: NodeJS.Timeout; + + constructor() { + // periodic cleanup + this.cleanupInterval = setInterval(() => { + const now = Date.now(); + for (const [k, v] of this.map.entries()) { + if (v.expiresAt <= now) this.map.delete(k); + } + }, 60 * 1000); + } + + private key(state: string) { return state; } + + async save(state: string, data: { code_verifier: string; nonce: string; returnTo?: string }, ttlSeconds = 300) { + const expiresAt = Date.now() + ttlSeconds * 1000; + this.map.set(this.key(state), { ...data, expiresAt }); + } + + async get(state: string) { + const v = this.map.get(this.key(state)); + if (!v) return null; + if (v.expiresAt <= Date.now()) { this.map.delete(this.key(state)); return null; } + return { code_verifier: v.code_verifier, nonce: v.nonce, returnTo: v.returnTo }; + } + + async remove(state: string) { + this.map.delete(this.key(state)); + } + + onModuleDestroy() { + if (this.cleanupInterval) clearInterval(this.cleanupInterval); + } +} diff --git a/src/modules/auth/refresh/inmemory-refresh.store.ts b/src/modules/auth/refresh/inmemory-refresh.store.ts new file mode 100644 index 0000000..5917283 --- /dev/null +++ b/src/modules/auth/refresh/inmemory-refresh.store.ts @@ -0,0 +1,38 @@ +import { Injectable, OnModuleDestroy } from '@nestjs/common'; + +type RefreshEntry = { userId: string; expiresAt: number }; + +@Injectable() +export class InMemoryRefreshStore implements OnModuleDestroy { + private map = new Map(); + private cleanupInterval?: NodeJS.Timeout; + + constructor() { + this.cleanupInterval = setInterval(() => { + const now = Date.now(); + for (const [k, v] of this.map.entries()) { + if (v.expiresAt <= now) this.map.delete(k); + } + }, 60 * 1000); + } + + async set(token: string, data: { userId: string }, ttlSeconds: number) { + const expiresAt = Date.now() + ttlSeconds * 1000; + this.map.set(token, { userId: data.userId, expiresAt }); + } + + async get(token: string) { + const v = this.map.get(token); + if (!v) return null; + if (v.expiresAt <= Date.now()) { this.map.delete(token); return null; } + return { userId: v.userId }; + } + + async del(token: string) { + this.map.delete(token); + } + + onModuleDestroy() { + if (this.cleanupInterval) clearInterval(this.cleanupInterval); + } +} diff --git a/src/modules/authorization/presentation/guards/permission.guard.ts b/src/modules/authorization/presentation/guards/permission.guard.ts index acca065..bee1027 100644 --- a/src/modules/authorization/presentation/guards/permission.guard.ts +++ b/src/modules/authorization/presentation/guards/permission.guard.ts @@ -2,6 +2,8 @@ import { Injectable, CanActivate, ExecutionContext, + UnauthorizedException, + ForbiddenException, } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; @@ -25,12 +27,20 @@ export class PermissionGuard implements CanActivate { return true; } - const request = context.switchToHttp().getRequest(); + const request = context.switchToHttp().getRequest() as any; - const user = request.user; + const user = request.currentUser; - return permissions.every(permission => - user.permissions.includes(permission), - ); + if (!user) { + throw new UnauthorizedException('Current user is missing.'); + } + + const hasAll = permissions.every((permission) => { + return user.hasPermission(permission); + }); + + if (!hasAll) throw new ForbiddenException('Insufficient permissions.'); + + return true; } } \ No newline at end of file diff --git a/src/modules/identity/application/README.md b/src/modules/identity/application/README.md index e01622b..68f05f1 100644 --- a/src/modules/identity/application/README.md +++ b/src/modules/identity/application/README.md @@ -1,12 +1 @@ -modules/identity/application/ - -Penjelasan: -Layer application berisi use-case (services/commands/queries) yang mengorkestrasi domain dan infrastruktur. - -Contoh file: -- services/get-user.service.ts -- commands/create-user.command.ts - -Aturan: -- Application service boleh memanggil repository interface, domain services, dan event publisher. -- Application menangani transaksi jika diperlukan. +ini adalah manager, semua kegiatan diarahkan dari sini, disini bukan mengakses db, menghitung, dll, dari controller akan masuk ke dalam sini dan dijalankan prosesnya, tapi tidak tau http dan databasenya. \ No newline at end of file diff --git a/src/modules/identity/application/config/env-auth-config.ts b/src/modules/identity/application/config/env-auth-config.ts new file mode 100644 index 0000000..74b24ed --- /dev/null +++ b/src/modules/identity/application/config/env-auth-config.ts @@ -0,0 +1,15 @@ +import { IAuthConfig } from './i-auth-config'; + +export class EnvAuthConfig implements IAuthConfig { + autoCreateUser(): boolean { + return (process.env.AUTH_AUTO_CREATE_USER ?? 'true') === 'true'; + } + + syncEmail(): boolean { + return (process.env.AUTH_SYNC_EMAIL ?? 'true') === 'true'; + } + + syncUsername(): boolean { + return (process.env.AUTH_SYNC_USERNAME ?? 'false') === 'true'; + } +} diff --git a/src/modules/identity/application/config/i-auth-config.ts b/src/modules/identity/application/config/i-auth-config.ts new file mode 100644 index 0000000..8e1d6a5 --- /dev/null +++ b/src/modules/identity/application/config/i-auth-config.ts @@ -0,0 +1,5 @@ +export abstract class IAuthConfig { + abstract autoCreateUser(): boolean; + abstract syncEmail(): boolean; + abstract syncUsername(): boolean; +} diff --git a/src/modules/identity/application/handlers/README.MD b/src/modules/identity/application/handlers/README.MD new file mode 100644 index 0000000..a0639ca --- /dev/null +++ b/src/modules/identity/application/handlers/README.MD @@ -0,0 +1 @@ +semua method disini didapat dari interface, itu ada di domain/repositories. \ No newline at end of file diff --git a/src/modules/identity/application/handlers/create-user.handler.ts b/src/modules/identity/application/handlers/create-user.handler.ts deleted file mode 100644 index 58a314b..0000000 --- a/src/modules/identity/application/handlers/create-user.handler.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { - Injectable, - ConflictException, -} from '@nestjs/common'; - -import { CreateUserDto } from '../../presentation/dto/create-user.dto'; -import { User } from '../../domain/entities/user.entity'; -import { UserRepository } from '../../domain/repositories/user.repository.interface'; - -@Injectable() -export class CreateUserHandler { - constructor( - private readonly userRepository: UserRepository, - ) {} - - async execute(dto: CreateUserDto): Promise { - const exists = await this.userRepository.existsByEmail(dto.email); - - if (exists) { - throw new ConflictException('Email already exists.'); - } - - const user = User.create({ - name: dto.name, - email: dto.email, - password: dto.password, - metadata: dto.metadata, - }); - - await this.userRepository.create(user); - - // TODO: - // this.eventDispatcher.publish(new UserCreatedEvent(user)); - - return user; - } -} \ No newline at end of file diff --git a/src/modules/identity/application/handlers/delete-user.handler.ts b/src/modules/identity/application/handlers/delete-user.handler.ts deleted file mode 100644 index be70def..0000000 --- a/src/modules/identity/application/handlers/delete-user.handler.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { - Injectable, - NotFoundException, -} from '@nestjs/common'; - -import { UserRepository } from '../../domain/repositories/user.repository.interface'; - -@Injectable() -export class DeleteUserHandler { - constructor( - private readonly userRepository: UserRepository, - ) {} - - async execute(id: string): Promise { - const user = await this.userRepository.findById(id); - - if (!user) { - throw new NotFoundException('User not found.'); - } - - user.delete(); - - await this.userRepository.update(user); - - // TODO: - // Publish UserDeletedEvent - } -} \ No newline at end of file diff --git a/src/modules/identity/application/handlers/find-user.handler.ts b/src/modules/identity/application/handlers/find-user.handler.ts deleted file mode 100644 index 5942fb4..0000000 --- a/src/modules/identity/application/handlers/find-user.handler.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { - Injectable, - NotFoundException, -} from '@nestjs/common'; - -import { UserRepository } from '../../domain/repositories/user.repository.interface'; -import { User } from '../../domain/entities/user.entity'; - -@Injectable() -export class FindUserHandler { - constructor( - private readonly userRepository: UserRepository, - ) {} - - async execute(id: string): Promise { - const user = await this.userRepository.findById(id); - - if (!user) { - throw new NotFoundException('User not found.'); - } - - return user; - } -} \ No newline at end of file diff --git a/src/modules/identity/application/handlers/find-users.handler.ts b/src/modules/identity/application/handlers/find-users.handler.ts deleted file mode 100644 index c7b3af1..0000000 --- a/src/modules/identity/application/handlers/find-users.handler.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -import { UserRepository } from '../../domain/repositories/user.repository.interface'; -import { User } from '../../domain/entities/user.entity'; - -@Injectable() -export class FindUsersHandler { - constructor( - private readonly userRepository: UserRepository, - ) {} - - async execute(): Promise { - return await this.userRepository.findAll(); - } -} \ No newline at end of file diff --git a/src/modules/identity/application/handlers/permission/create-permission.handler.ts b/src/modules/identity/application/handlers/permission/create-permission.handler.ts new file mode 100644 index 0000000..ebcd193 --- /dev/null +++ b/src/modules/identity/application/handlers/permission/create-permission.handler.ts @@ -0,0 +1,21 @@ +import { Injectable, ConflictException } from '@nestjs/common'; +import { IPermission } from '../../../domain/repositories/permission.interface'; +import { PermissionData } from '../../../domain/entities/permission.entity'; + +@Injectable() +export class CreatePermissionHandler { + constructor(private readonly permissionRepository: IPermission) {} + + async execute(dto: any) { + const perm = PermissionData.restore({ + id: crypto.randomUUID(), + code: dto.code || dto.name, + name: dto.name, + description: dto.description || '', + createdAt: new Date(), + updatedAt: new Date(), + } as any); + + return this.permissionRepository.create(perm); + } +} diff --git a/src/modules/identity/application/handlers/permission/delete-permission.handler.ts b/src/modules/identity/application/handlers/permission/delete-permission.handler.ts new file mode 100644 index 0000000..cde347e --- /dev/null +++ b/src/modules/identity/application/handlers/permission/delete-permission.handler.ts @@ -0,0 +1,14 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { IPermission } from '../../../domain/repositories/permission.interface'; + +@Injectable() +export class DeletePermissionHandler { + constructor(private readonly permissionRepository: IPermission) {} + + async execute(id: string) { + const p = await this.permissionRepository.getById(id); + if (!p) throw new NotFoundException('Permission not found.'); + + await this.permissionRepository.delete(id); + } +} diff --git a/src/modules/identity/application/handlers/permission/get-permission.handler.ts b/src/modules/identity/application/handlers/permission/get-permission.handler.ts new file mode 100644 index 0000000..c7a1c8c --- /dev/null +++ b/src/modules/identity/application/handlers/permission/get-permission.handler.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { IPermission } from '../../../domain/repositories/permission.interface'; + +@Injectable() +export class GetPermissionHandler { + constructor(private readonly permissionRepository: IPermission) {} + + async execute(id: string) { + return this.permissionRepository.getById(id); + } +} diff --git a/src/modules/identity/application/handlers/permission/get-permissions.handler.ts b/src/modules/identity/application/handlers/permission/get-permissions.handler.ts new file mode 100644 index 0000000..309301b --- /dev/null +++ b/src/modules/identity/application/handlers/permission/get-permissions.handler.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { IPermission } from '../../../domain/repositories/permission.interface'; + +@Injectable() +export class GetPermissionsHandler { + constructor(private readonly permissionRepository: IPermission) {} + + async execute(query: { page?: number; limit?: number; search?: string }) { + return this.permissionRepository.find({ page: query.page, limit: query.limit, search: query.search || null }); + } +} diff --git a/src/modules/identity/application/handlers/permission/update-permission.handler.ts b/src/modules/identity/application/handlers/permission/update-permission.handler.ts new file mode 100644 index 0000000..7e642cf --- /dev/null +++ b/src/modules/identity/application/handlers/permission/update-permission.handler.ts @@ -0,0 +1,18 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { IPermission } from '../../../domain/repositories/permission.interface'; + +@Injectable() +export class UpdatePermissionHandler { + constructor(private readonly permissionRepository: IPermission) {} + + async execute(id: string, dto: any) { + const perm = await this.permissionRepository.getById(id); + if (!perm) throw new NotFoundException('Permission not found.'); + + if (dto.name) perm.changeName(dto.name); + if (dto.description !== undefined) perm.changeDescription(dto.description); + if (dto.code) perm.changeCode(dto.code); + + return this.permissionRepository.update(perm); + } +} diff --git a/src/modules/identity/application/handlers/role/assign-permission.handler.ts b/src/modules/identity/application/handlers/role/assign-permission.handler.ts new file mode 100644 index 0000000..95f892f --- /dev/null +++ b/src/modules/identity/application/handlers/role/assign-permission.handler.ts @@ -0,0 +1,23 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { IRole } from '../../../domain/repositories/role.interface'; +import { IPermission } from '../../../domain/repositories/permission.interface'; + +@Injectable() +export class RoleAssignPermissionHandler { + constructor( + private readonly roleRepository: IRole, + private readonly permissionRepository: IPermission, + ) {} + + async execute(roleId: string, permissionId: string) { + const role = await this.roleRepository.findById(roleId); + if (!role) throw new NotFoundException('Role not found.'); + + const perm = await this.permissionRepository.getById(permissionId); + if (!perm) throw new NotFoundException('Permission not found.'); + + role.assignPermission(perm); + + return this.roleRepository.update(role); + } +} diff --git a/src/modules/identity/application/handlers/role/create-role.handler.ts b/src/modules/identity/application/handlers/role/create-role.handler.ts new file mode 100644 index 0000000..6cabff4 --- /dev/null +++ b/src/modules/identity/application/handlers/role/create-role.handler.ts @@ -0,0 +1,30 @@ +import { Injectable, ConflictException } from '@nestjs/common'; +import { IRole } from '../../../domain/repositories/role.interface'; +import { RoleData } from '../../../domain/entities/role.entity'; + +@Injectable() +export class CreateRoleHandler { + constructor(private readonly roleRepository: IRole) {} + + async execute(dto: any) { + // check uniqueness by code + // simple check + try { + // attempt to create; repository may enforce uniqueness + const role = RoleData.restore({ + id: crypto.randomUUID(), + code: dto.code, + name: dto.name, + description: dto.description || '', + permissions: [], + isDefault: dto.isDefault || false, + createdAt: new Date(), + updatedAt: new Date(), + } as any); + + return this.roleRepository.create(role); + } catch (e) { + throw new ConflictException('Role creation failed.'); + } + } +} diff --git a/src/modules/identity/application/handlers/role/delete-role.handler.ts b/src/modules/identity/application/handlers/role/delete-role.handler.ts new file mode 100644 index 0000000..fa694ca --- /dev/null +++ b/src/modules/identity/application/handlers/role/delete-role.handler.ts @@ -0,0 +1,14 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { IRole } from '../../../domain/repositories/role.interface'; + +@Injectable() +export class DeleteRoleHandler { + constructor(private readonly roleRepository: IRole) {} + + async execute(id: string) { + const role = await this.roleRepository.findById(id); + if (!role) throw new NotFoundException('Role not found.'); + + await this.roleRepository.delete(id); + } +} diff --git a/src/modules/identity/application/handlers/role/get-role.handler.ts b/src/modules/identity/application/handlers/role/get-role.handler.ts new file mode 100644 index 0000000..ea0df1c --- /dev/null +++ b/src/modules/identity/application/handlers/role/get-role.handler.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { IRole } from '../../../domain/repositories/role.interface'; + +@Injectable() +export class GetRoleHandler { + constructor(private readonly roleRepository: IRole) {} + + async execute(id: string) { + return this.roleRepository.findById(id); + } +} diff --git a/src/modules/identity/application/handlers/role/get-roles.handler.ts b/src/modules/identity/application/handlers/role/get-roles.handler.ts new file mode 100644 index 0000000..a931691 --- /dev/null +++ b/src/modules/identity/application/handlers/role/get-roles.handler.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { IRole } from '../../../domain/repositories/role.interface'; + +@Injectable() +export class GetRolesHandler { + constructor(private readonly roleRepository: IRole) {} + + async execute(query: { page?: number; limit?: number; search?: string }) { + return this.roleRepository.find({ page: query.page, limit: query.limit, search: query.search || null }); + } +} diff --git a/src/modules/identity/application/handlers/role/remove-permission.handler.ts b/src/modules/identity/application/handlers/role/remove-permission.handler.ts new file mode 100644 index 0000000..61a03c0 --- /dev/null +++ b/src/modules/identity/application/handlers/role/remove-permission.handler.ts @@ -0,0 +1,16 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { IRole } from '../../../domain/repositories/role.interface'; + +@Injectable() +export class RoleRemovePermissionHandler { + constructor(private readonly roleRepository: IRole) {} + + async execute(roleId: string, permissionId: string) { + const role = await this.roleRepository.findById(roleId); + if (!role) throw new NotFoundException('Role not found.'); + + role.removePermission(permissionId); + + return this.roleRepository.update(role); + } +} diff --git a/src/modules/identity/application/handlers/role/update-role.handler.ts b/src/modules/identity/application/handlers/role/update-role.handler.ts new file mode 100644 index 0000000..0b23bfc --- /dev/null +++ b/src/modules/identity/application/handlers/role/update-role.handler.ts @@ -0,0 +1,18 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { IRole } from '../../../domain/repositories/role.interface'; + +@Injectable() +export class UpdateRoleHandler { + constructor(private readonly roleRepository: IRole) {} + + async execute(id: string, dto: any) { + const role = await this.roleRepository.findById(id); + if (!role) throw new NotFoundException('Role not found.'); + + if (dto.name) role.changeName(dto.name); + if (dto.description !== undefined) role.changeDescription(dto.description); + if (dto.isDefault !== undefined) role.setDefault(!!dto.isDefault); + + return this.roleRepository.update(role); + } +} diff --git a/src/modules/identity/application/handlers/update-user.handler.ts b/src/modules/identity/application/handlers/update-user.handler.ts deleted file mode 100644 index d4e04d6..0000000 --- a/src/modules/identity/application/handlers/update-user.handler.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { - Injectable, - ConflictException, - NotFoundException, -} from '@nestjs/common'; - -import { UpdateUserDto } from '../../presentation/dto/update-user.dto'; -import { UserRepository } from '../../domain/repositories/user.repository.interface'; -import { User } from '../../domain/entities/user.entity'; - -@Injectable() -export class UpdateUserHandler { - constructor( - private readonly userRepository: UserRepository, - ) {} - - async execute( - id: string, - dto: UpdateUserDto, - ): Promise { - const user = await this.userRepository.findById(id); - - if (!user) { - throw new NotFoundException('User not found.'); - } - - if ( - dto.email && - dto.email !== user.email - ) { - const exists = - await this.userRepository.existsByEmail(dto.email); - - if (exists) { - throw new ConflictException( - 'Email already exists.', - ); - } - - user.changeEmail(dto.email); - } - - if (dto.name) { - user.changeName(dto.name); - } - - await this.userRepository.update(user); - - return user; - } -} \ No newline at end of file diff --git a/src/modules/identity/application/handlers/user/assign-permission.handler.ts b/src/modules/identity/application/handlers/user/assign-permission.handler.ts new file mode 100644 index 0000000..28b3b86 --- /dev/null +++ b/src/modules/identity/application/handlers/user/assign-permission.handler.ts @@ -0,0 +1,26 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { IUser } from '../../../domain/repositories/user.interface'; +import { PermissionData } from '../../../domain/entities/permission.entity'; + +@Injectable() +export class AssignPermissionHandler { + constructor(private readonly userRepository: IUser) {} + + async execute(userId: string, permissionId: string) { + const user = await this.userRepository.getById(userId); + if (!user) throw new NotFoundException('User not found.'); + + // Permission repository is not available; create a minimal PermissionData + const perm = PermissionData.restore({ + id: permissionId, + name: permissionId, + description: '', + createdAt: new Date(), + updatedAt: new Date(), + }); + + user.assignPermission(perm); + + return this.userRepository.update(user); + } +} diff --git a/src/modules/identity/application/handlers/user/assign-role.handler.ts b/src/modules/identity/application/handlers/user/assign-role.handler.ts new file mode 100644 index 0000000..2b07179 --- /dev/null +++ b/src/modules/identity/application/handlers/user/assign-role.handler.ts @@ -0,0 +1,23 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { IUser } from '../../../domain/repositories/user.interface'; +import { IRole } from '../../../domain/repositories/role.interface'; + +@Injectable() +export class AssignRoleHandler { + constructor( + private readonly userRepository: IUser, + private readonly roleRepository: IRole, + ) {} + + async execute(userId: string, roleId: string) { + const user = await this.userRepository.getById(userId); + if (!user) throw new NotFoundException('User not found.'); + + const role = await this.roleRepository.findById(roleId); + if (!role) throw new NotFoundException('Role not found.'); + + user.assignRole(role); + + return this.userRepository.update(user); + } +} diff --git a/src/modules/identity/application/handlers/user/create-user.handler.ts b/src/modules/identity/application/handlers/user/create-user.handler.ts new file mode 100644 index 0000000..5bee566 --- /dev/null +++ b/src/modules/identity/application/handlers/user/create-user.handler.ts @@ -0,0 +1,31 @@ +import { + Injectable, + ConflictException, + BadRequestException, +} from '@nestjs/common'; + +import { CreateUserDto } from '../../../presentation/dto/create-user.dto'; +import { IUser } from '../../../domain/repositories/user.interface'; +import { UserData } from '../../../domain/entities/user.entity'; +import { UserService } from '../../services/user.service'; + +@Injectable() +export class CreateUserHandler { + constructor( + private readonly userRepository: IUser, + private readonly userService: UserService, + ) {} + + async execute(dto: CreateUserDto): Promise { + + const exists = await this.userRepository.existByEmail(dto.email); + + if (exists) { + throw new ConflictException('Email already exists.'); + } + + // Provisioning disabled: Do not create users in external IdP from RayLab. + // Reject attempts to create users via API to enforce creation-at-Authentik policy. + throw new BadRequestException('User creation via RayLab API is disabled. Create users in Authentik and then login to sync.'); + } +} \ No newline at end of file diff --git a/src/modules/identity/application/handlers/user/delete-user.handler.ts b/src/modules/identity/application/handlers/user/delete-user.handler.ts new file mode 100644 index 0000000..17c98a4 --- /dev/null +++ b/src/modules/identity/application/handlers/user/delete-user.handler.ts @@ -0,0 +1,14 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { IUser } from '../../../domain/repositories/user.interface'; + +@Injectable() +export class DeleteUserHandler { + constructor(private readonly userRepository: IUser) {} + + async execute(id: string) { + const exists = await this.userRepository.existsById(id); + if (!exists) throw new NotFoundException('User not found.'); + + await this.userRepository.softDelete(id); + } +} diff --git a/src/modules/identity/application/handlers/user/disable-user.handler.ts b/src/modules/identity/application/handlers/user/disable-user.handler.ts new file mode 100644 index 0000000..87c627a --- /dev/null +++ b/src/modules/identity/application/handlers/user/disable-user.handler.ts @@ -0,0 +1,14 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { IUser } from '../../../domain/repositories/user.interface'; + +@Injectable() +export class DisableUserHandler { + constructor(private readonly userRepository: IUser) {} + + async execute(id: string) { + const exists = await this.userRepository.existsById(id); + if (!exists) throw new NotFoundException('User not found.'); + + return this.userRepository.disable(id); + } +} diff --git a/src/modules/identity/application/handlers/user/enable-user.handler.ts b/src/modules/identity/application/handlers/user/enable-user.handler.ts new file mode 100644 index 0000000..dd73fbd --- /dev/null +++ b/src/modules/identity/application/handlers/user/enable-user.handler.ts @@ -0,0 +1,14 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { IUser } from '../../../domain/repositories/user.interface'; + +@Injectable() +export class EnableUserHandler { + constructor(private readonly userRepository: IUser) {} + + async execute(id: string) { + const exists = await this.userRepository.existsById(id); + if (!exists) throw new NotFoundException('User not found.'); + + return this.userRepository.enable(id); + } +} diff --git a/src/modules/identity/application/handlers/user/get-current-user.handler.ts b/src/modules/identity/application/handlers/user/get-current-user.handler.ts new file mode 100644 index 0000000..a9e2184 --- /dev/null +++ b/src/modules/identity/application/handlers/user/get-current-user.handler.ts @@ -0,0 +1,10 @@ +import { Injectable } from '@nestjs/common'; +import { UserData } from '../../../domain/entities/user.entity'; + +@Injectable() +export class GetCurrentUserHandler { + async execute(currentUser: UserData) { + // currentUser is already domain user attached by CurrentUserGuard + return currentUser; + } +} diff --git a/src/modules/identity/application/handlers/user/get-user.handler.ts b/src/modules/identity/application/handlers/user/get-user.handler.ts new file mode 100644 index 0000000..d78d600 --- /dev/null +++ b/src/modules/identity/application/handlers/user/get-user.handler.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { IUser } from '../../../domain/repositories/user.interface'; + +@Injectable() +export class GetUserHandler { + constructor(private readonly userRepository: IUser) {} + + async execute(id: string) { + return this.userRepository.getById(id); + } +} diff --git a/src/modules/identity/application/handlers/user/get-users.handler.ts b/src/modules/identity/application/handlers/user/get-users.handler.ts new file mode 100644 index 0000000..fe3af46 --- /dev/null +++ b/src/modules/identity/application/handlers/user/get-users.handler.ts @@ -0,0 +1,27 @@ +import { Injectable } from '@nestjs/common'; +import { IUser } from '../../../domain/repositories/user.interface'; + +@Injectable() +export class GetUsersHandler { + constructor(private readonly userRepository: IUser) {} + + async execute(query: { + page?: number; + limit?: number; + search?: string; + isActive?: boolean; + deleted?: boolean; + roleId?: string; + }) { + const res = await this.userRepository.find({ + page: query.page, + limit: query.limit, + search: query.search || null, + isActive: query.isActive !== undefined ? query.isActive : null, + deleted: query.deleted !== undefined ? query.deleted : null, + roleId: query.roleId || null, + }); + + return res; + } +} diff --git a/src/modules/identity/application/handlers/user/remove-permission.handler.ts b/src/modules/identity/application/handlers/user/remove-permission.handler.ts new file mode 100644 index 0000000..c8cb40d --- /dev/null +++ b/src/modules/identity/application/handlers/user/remove-permission.handler.ts @@ -0,0 +1,16 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { IUser } from '../../../domain/repositories/user.interface'; + +@Injectable() +export class RemovePermissionHandler { + constructor(private readonly userRepository: IUser) {} + + async execute(userId: string, permissionId: string) { + const user = await this.userRepository.getById(userId); + if (!user) throw new NotFoundException('User not found.'); + + user.removePermission(permissionId); + + return this.userRepository.update(user); + } +} diff --git a/src/modules/identity/application/handlers/user/remove-role.handler.ts b/src/modules/identity/application/handlers/user/remove-role.handler.ts new file mode 100644 index 0000000..b6c855a --- /dev/null +++ b/src/modules/identity/application/handlers/user/remove-role.handler.ts @@ -0,0 +1,16 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { IUser } from '../../../domain/repositories/user.interface'; + +@Injectable() +export class RemoveRoleHandler { + constructor(private readonly userRepository: IUser) {} + + async execute(userId: string, roleId: string) { + const user = await this.userRepository.getById(userId); + if (!user) throw new NotFoundException('User not found.'); + + user.removeRole(roleId); + + return this.userRepository.update(user); + } +} diff --git a/src/modules/identity/application/handlers/user/restore-user.handler.ts b/src/modules/identity/application/handlers/user/restore-user.handler.ts new file mode 100644 index 0000000..657ee47 --- /dev/null +++ b/src/modules/identity/application/handlers/user/restore-user.handler.ts @@ -0,0 +1,14 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { IUser } from '../../../domain/repositories/user.interface'; + +@Injectable() +export class RestoreUserHandler { + constructor(private readonly userRepository: IUser) {} + + async execute(id: string) { + const exists = await this.userRepository.existsById(id); + if (!exists) throw new NotFoundException('User not found.'); + + return this.userRepository.restore(id); + } +} diff --git a/src/modules/identity/application/handlers/user/sync-identity.handler.ts b/src/modules/identity/application/handlers/user/sync-identity.handler.ts new file mode 100644 index 0000000..aeb114b --- /dev/null +++ b/src/modules/identity/application/handlers/user/sync-identity.handler.ts @@ -0,0 +1,86 @@ +import { Injectable, UnauthorizedException, ForbiddenException, Inject } from '@nestjs/common'; +import { IUser } from '../../../domain/repositories/user.interface'; +import { IRole } from '../../../domain/repositories/role.interface'; +import { IAuthConfig } from '../../config/i-auth-config'; +import { UserData } from '../../../domain/entities/user.entity'; +import { IdentityData } from '../../../../../core/auth/interfaces/identity-data'; + +@Injectable() +export class SyncIdentityHandler { + constructor( + private readonly userRepository: IUser, + private readonly roleRepository: IRole, + private readonly authConfig: IAuthConfig, + ) {} + + async execute(identity: IdentityData): Promise { + const { sub, preferred_username, email } = identity as any; + + if (!sub) throw new UnauthorizedException('Invalid identity payload.'); + + // Try find by authentikId + let user = await this.userRepository.findByAuthentikId(sub); + + const syncEmail = this.authConfig.syncEmail(); + const syncUsername = this.authConfig.syncUsername(); + + if (!user) { + // User does not exist locally: create minimal local record per new architecture + const username = preferred_username || email || sub; + const userEntity = UserData.create({ username, email: email || '', authentikId: sub }); + + // assign default role if available + try { + const defaultRole = await this.roleRepository.getDefaultRole(); + if (defaultRole) { + userEntity.assignRole(defaultRole); + } + } catch (e) { + // ignore if role repo not available or no default role + } + + // persist local user + user = await this.userRepository.create(userEntity); + + // return freshly created user + return user; + } else { + let changed = false; + + if (syncEmail && email && user.email !== email) { + user.changeEmail(email); + changed = true; + + // prepare event class instance if needed (no dispatch) + } + + if (syncUsername && preferred_username && user.username !== preferred_username) { + user.changeUsername(preferred_username); + changed = true; + + // prepare event class instance if needed (no dispatch) + } + + // update last seen + user.touchLastSeen(); + changed = true; + + if (changed) { + user = await this.userRepository.update(user); + } + } + + // Validations + if (!user.isActive) { + // Authentication succeeded but user is disabled + throw new ForbiddenException('User is not active.'); + } + + if (user.deletedAt) { + throw new ForbiddenException('User is deleted.'); + } + + // Ensure roles/permissions loaded (repo should return includes) + return user; + } +} diff --git a/src/modules/identity/application/services/README.md b/src/modules/identity/application/services/README.md deleted file mode 100644 index 3ac5650..0000000 --- a/src/modules/identity/application/services/README.md +++ /dev/null @@ -1,12 +0,0 @@ -services/ - -Penjelasan: -Application services (use-cases) untuk module identity. - -Contoh file: -- get-user.service.ts -- create-user.service.ts - -Aturan: -- Application service mengorkestrasi domain services dan repository. -- Menangani transaction boundary jika perlu. diff --git a/src/modules/identity/application/services/user.service.ts b/src/modules/identity/application/services/user.service.ts new file mode 100644 index 0000000..bd921df --- /dev/null +++ b/src/modules/identity/application/services/user.service.ts @@ -0,0 +1,20 @@ +import { Injectable, BadRequestException, Logger } from '@nestjs/common'; +import { PrismaService } from '../../../../shared/prisma.service'; +import { IUser } from '../../domain/repositories/user.interface'; +import { UserData } from '../../domain/entities/user.entity'; + +@Injectable() +export class UserService { + private readonly logger = new Logger(UserService.name); + + constructor( + private readonly prisma: PrismaService, + private readonly userRepository: IUser, + ) {} + + async createUser(input: { username: string; email: string; roles?: string[]; isActive?: boolean }) { + // Provisioning to external Identity Provider (Authentik) has been disabled. + // All users must be created in Authentik first. RayLab will create local record on first successful login. + throw new BadRequestException('Provisioning disabled: create users in Authentik and login to sync to RayLab'); + } +} diff --git a/src/modules/identity/domain/entities/README.md b/src/modules/identity/domain/entities/README.md index bf9110b..b394cb0 100644 --- a/src/modules/identity/domain/entities/README.md +++ b/src/modules/identity/domain/entities/README.md @@ -1,11 +1 @@ -entities/ - -Penjelasan: -Entity domain untuk identity, mis. User, Profile. - -Contoh file: -- user.entity.ts -- profile.entity.ts - -Aturan: -- Entity berisi atribut dan mungkin method domain kecil (invariants), bukan orchestration. +ini adalah tempat class objek dibuat, objek user, role, dll. disini juga ada method dan harus diingat yang boleh mengubah objek ini hanya objek ini sendiri. \ No newline at end of file diff --git a/src/modules/identity/domain/entities/permission.entity.ts b/src/modules/identity/domain/entities/permission.entity.ts new file mode 100644 index 0000000..f27dce1 --- /dev/null +++ b/src/modules/identity/domain/entities/permission.entity.ts @@ -0,0 +1,40 @@ +export class PermissionData { + private constructor( + public readonly id: string, + public code: string, + public name: string, + public description: string, + public createdAt: Date, + public updatedAt: Date, + ) {} + + changeName(name: string) { + this.name = name; + } + + changeDescription(description: string) { + this.description = description; + } + + changeCode(code: string) { + this.code = code; + } + + static restore(props: { + id: string; + code?: string; + name: string; + description: string; + createdAt: Date; + updatedAt: Date; + }) { + return new PermissionData( + props.id, + props.code || props.name, + props.name, + props.description, + props.createdAt, + props.updatedAt, + ); + } +} \ No newline at end of file diff --git a/src/modules/identity/domain/entities/role.entity.ts b/src/modules/identity/domain/entities/role.entity.ts new file mode 100644 index 0000000..96a0d0f --- /dev/null +++ b/src/modules/identity/domain/entities/role.entity.ts @@ -0,0 +1,64 @@ +import { PermissionData } from "./permission.entity"; + +export class RoleData { + private constructor( + public readonly id: string, + public code: string, + public name: string, + public description: string, + public permissions: PermissionData[], + public isDefault: boolean, + public createdAt: Date, + public updatedAt: Date, + ) {} + + hasPermissions(permissionId: string): boolean { + return this.permissions.some(x => x.id.toLowerCase() === permissionId.toLowerCase()); + } + + assignPermission(permissionData: PermissionData): void { + if (this.hasPermissions(permissionData.id)) throw new Error("Permission sudah dimiliki."); + + this.permissions.push(permissionData); + } + + removePermission(permissionId: string): void { + const idx = this.permissions.findIndex(p => p.id.toLowerCase() === permissionId.toLowerCase()); + if (idx === -1) throw new Error('Permission tidak ditemukan pada role.'); + this.permissions.splice(idx, 1); + } + + changeName(name: string) { + this.name = name; + } + + changeDescription(description: string) { + this.description = description; + } + + setDefault(isDefault: boolean) { + this.isDefault = isDefault; + } + + static restore(props: { + id: string; + code: string; + name: string; + description: string; + permissions?: PermissionData[]; + isDefault?: boolean; + createdAt: Date; + updatedAt: Date; + }) { + return new RoleData( + props.id, + props.code, + props.name, + props.description, + props.permissions || [], + props.isDefault ?? false, + props.createdAt, + props.updatedAt, + ); + } +} \ No newline at end of file diff --git a/src/modules/identity/domain/entities/user.entity.ts b/src/modules/identity/domain/entities/user.entity.ts index e1a4538..335462e 100644 --- a/src/modules/identity/domain/entities/user.entity.ts +++ b/src/modules/identity/domain/entities/user.entity.ts @@ -1,52 +1,196 @@ -export class User { - private constructor( +import { RoleData } from "./role.entity"; +import { PermissionData } from "./permission.entity"; + +export class UserData { + private constructor( public readonly id: string, - public name: string, + public authentikId: string | null, + public username: string, public email: string, - public password: string, - public metadata?: Record, + public password: string | null, + public roles: RoleData[], + public permissions: PermissionData[], + public isActive: boolean, + public deletedAt: Date | null, + public lastSeenAt: Date | null, + public storageQuota: number, + public storageUsed: number, ) {} - static create(data: { - name: string; + //#region Create + + static create(data: { + username: string; email: string; - password: string; - metadata?: Record; - }): User { - return new User( + password?: string | null; + authentikId?: string | null; + storageQuota?: number; + storageUsed?: number; + }): UserData { + const quota = data.storageQuota !== undefined ? data.storageQuota : 10737418240; // 10 GB + const used = data.storageUsed !== undefined ? data.storageUsed : 0; + return new UserData( crypto.randomUUID(), - data.name, + data.authentikId || null, + data.username, data.email, - data.password, - data.metadata, + data.password ?? null, + [], + [], + true, + null, + null, + quota, + used, ); } - delete() { - // Business Rule + //#endregion + + //#region Read + + hasRole(roleId: string) : boolean { + return this.roles.some(x => x.id.toLowerCase() === roleId.toLowerCase()) } - changeEmail(email: string) { + assignRole(roleData : RoleData) : void { + if (this.hasRole(roleData.id)) + throw new Error("Role Sudah dimiliki."); + + this.roles.push(roleData); + } + + hasPermissions(permissionId : string) : boolean { + return this.permissions.some(x => x.id.toLowerCase() === permissionId.toLowerCase()) + } + + hasPermission(permission: string) : boolean { + const byPerm = this.permissions.some(x => x.id.toLowerCase() === permission.toLowerCase() || x.name.toLowerCase() === permission.toLowerCase()); + if (byPerm) return true; + + // check roles + return this.roles.some(r => r.permissions.some(p => p.id.toLowerCase() === permission.toLowerCase() || p.name.toLowerCase() === permission.toLowerCase())); + } + + assignPermission(permissionData : PermissionData) : void { + if (this.hasPermissions(permissionData.id)) + throw new Error("Permission sudah dimiliki.") + + this.permissions.push(permissionData); + } + + //#endregion + + //#region Update + changeEmail(email: string) { this.email = email; } - changeName(name: string) { - this.name = name; + changeUsername(username: string) { + this.username = username; } - static restore(data: { - id: string; - name: string; - email: string; - password: string; - metadata?: Record; - }): User { - return new User( - data.id, - data.name, - data.email, - data.password, - data.metadata, - ); + touchLastSeen() { + this.lastSeenAt = new Date(); + } + + enable() { + this.isActive = true; + } + + disable() { + this.isActive = false; + } + //#endregion + + //#region Delete + softDelete() { + this.deletedAt = new Date(); + this.isActive = false; + } + + restoreInstance() { + this.deletedAt = null; + } + //#endregion + + public static restore(props: { + id: string; + authentikId?: string | null; + username: string; + email: string; + password: string | null; + roles?: RoleData[]; + permissions?: PermissionData[]; + isActive?: boolean; + deletedAt?: Date | null; + lastSeenAt?: Date | null; + storageQuota?: number | null; + storageUsed?: number | null; + }): UserData { + + return new UserData( + props.id, + props.authentikId || null, + props.username, + props.email, + props.password, + props.roles || [], + props.permissions || [], + props.isActive !== undefined ? props.isActive : true, + props.deletedAt || null, + props.lastSeenAt || null, + props.storageQuota !== undefined && props.storageQuota !== null ? props.storageQuota : 10737418240, + props.storageUsed !== undefined && props.storageUsed !== null ? props.storageUsed : 0, + ); + } + + removeRole(roleId: string) { + const idx = this.roles.findIndex(r => r.id.toLowerCase() === roleId.toLowerCase()); + if (idx === -1) throw new Error('Role tidak ditemukan pada user.'); + this.roles.splice(idx, 1); + } + + removePermission(permissionId: string) { + const idx = this.permissions.findIndex(p => p.id.toLowerCase() === permissionId.toLowerCase()); + if (idx === -1) throw new Error('Permission tidak ditemukan pada user.'); + this.permissions.splice(idx, 1); + } + + // Storage helpers + setStorageQuota(bytes: number) { + if (bytes < 0) throw new Error('storageQuota must be >= 0'); + if (this.storageUsed > bytes) throw new Error('storageQuota cannot be less than storageUsed'); + this.storageQuota = bytes; + } + + setStorageUsed(bytes: number) { + if (bytes < 0) throw new Error('storageUsed must be >= 0'); + if (bytes > this.storageQuota) throw new Error('storageUsed cannot exceed storageQuota'); + this.storageUsed = bytes; + } + + // Response helper for API + toResponse() { + const remaining = this.storageQuota - this.storageUsed; + const usagePercentage = this.storageQuota > 0 ? Math.round((this.storageUsed / this.storageQuota) * 100) : 0; + + return { + id: this.id, + authentikId: this.authentikId, + username: this.username, + email: this.email, + roles: this.roles, + permissions: this.permissions, + isActive: this.isActive, + deletedAt: this.deletedAt, + lastSeenAt: this.lastSeenAt, + storage: { + quota: this.storageQuota, + used: this.storageUsed, + remaining, + usagePercentage, + }, + }; } } \ No newline at end of file diff --git a/src/modules/identity/domain/events/user-created.event.ts b/src/modules/identity/domain/events/user-created.event.ts index 07fea7e..997431e 100644 --- a/src/modules/identity/domain/events/user-created.event.ts +++ b/src/modules/identity/domain/events/user-created.event.ts @@ -2,5 +2,6 @@ import { DomainEvent } from '../../../../core/events/event.interface'; export class UserCreatedEvent implements DomainEvent { readonly name = 'UserCreated'; - constructor(public readonly payload: any, public readonly occurredAt: Date = new Date()) {} + readonly occurredAt: Date = new Date(); + constructor(public readonly payload: { userId: string; authentikId: string; email: string; username: string }) {} } diff --git a/src/modules/identity/domain/events/user-deleted.event.ts b/src/modules/identity/domain/events/user-deleted.event.ts deleted file mode 100644 index 07cc1d4..0000000 --- a/src/modules/identity/domain/events/user-deleted.event.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { DomainEvent } from '../../../../core/events/event.interface'; - -export class UserDeletedEvent implements DomainEvent { - readonly name = 'UserDeleted'; - constructor(public readonly payload: any, public readonly occurredAt: Date = new Date()) {} -} diff --git a/src/modules/identity/domain/events/user-disabled.event.ts b/src/modules/identity/domain/events/user-disabled.event.ts new file mode 100644 index 0000000..2f243fc --- /dev/null +++ b/src/modules/identity/domain/events/user-disabled.event.ts @@ -0,0 +1,7 @@ +import { DomainEvent } from '../../../../core/events/event.interface'; + +export class UserDisabledEvent implements DomainEvent { + readonly name = 'UserDisabled'; + readonly occurredAt: Date = new Date(); + constructor(public readonly payload: { userId: string }) {} +} diff --git a/src/modules/identity/domain/events/user-email-changed.event.ts b/src/modules/identity/domain/events/user-email-changed.event.ts new file mode 100644 index 0000000..db50cbc --- /dev/null +++ b/src/modules/identity/domain/events/user-email-changed.event.ts @@ -0,0 +1,7 @@ +import { DomainEvent } from '../../../../core/events/event.interface'; + +export class UserEmailChangedEvent implements DomainEvent { + readonly name = 'UserEmailChanged'; + readonly occurredAt: Date = new Date(); + constructor(public readonly payload: { userId: string; oldEmail: string; newEmail: string }) {} +} diff --git a/src/modules/identity/domain/events/user-enabled.event.ts b/src/modules/identity/domain/events/user-enabled.event.ts new file mode 100644 index 0000000..9ed1c60 --- /dev/null +++ b/src/modules/identity/domain/events/user-enabled.event.ts @@ -0,0 +1,7 @@ +import { DomainEvent } from '../../../../core/events/event.interface'; + +export class UserEnabledEvent implements DomainEvent { + readonly name = 'UserEnabled'; + readonly occurredAt: Date = new Date(); + constructor(public readonly payload: { userId: string }) {} +} diff --git a/src/modules/identity/domain/events/user-username-changed.event.ts b/src/modules/identity/domain/events/user-username-changed.event.ts new file mode 100644 index 0000000..7023331 --- /dev/null +++ b/src/modules/identity/domain/events/user-username-changed.event.ts @@ -0,0 +1,7 @@ +import { DomainEvent } from '../../../../core/events/event.interface'; + +export class UserUsernameChangedEvent implements DomainEvent { + readonly name = 'UserUsernameChanged'; + readonly occurredAt: Date = new Date(); + constructor(public readonly payload: { userId: string; oldUsername: string; newUsername: string }) {} +} diff --git a/src/modules/identity/domain/repositories/README.MD b/src/modules/identity/domain/repositories/README.MD new file mode 100644 index 0000000..1d0ee81 --- /dev/null +++ b/src/modules/identity/domain/repositories/README.MD @@ -0,0 +1 @@ +ini adalah interface, semua yang akan dibuat oleh application/handler harus dibuat disini dulu. \ No newline at end of file diff --git a/src/modules/identity/domain/repositories/permission.interface.ts b/src/modules/identity/domain/repositories/permission.interface.ts new file mode 100644 index 0000000..a603ee2 --- /dev/null +++ b/src/modules/identity/domain/repositories/permission.interface.ts @@ -0,0 +1,9 @@ +import { PermissionData } from '../entities/permission.entity'; + +export abstract class IPermission { + abstract find(params: { page?: number; limit?: number; search?: string | null }): Promise<{ data: PermissionData[]; total: number }>; + abstract getById(id: string): Promise; + abstract create(permission: PermissionData): Promise; + abstract update(permission: PermissionData): Promise; + abstract delete(id: string): Promise; +} diff --git a/src/modules/identity/domain/repositories/role.interface.ts b/src/modules/identity/domain/repositories/role.interface.ts new file mode 100644 index 0000000..0405e8b --- /dev/null +++ b/src/modules/identity/domain/repositories/role.interface.ts @@ -0,0 +1,12 @@ +import { RoleData } from '../entities/role.entity'; + +export abstract class IRole { + abstract getDefaultRole(): Promise; + abstract findById(roleId: string): Promise; + + abstract find(params: { page?: number; limit?: number; search?: string | null }): Promise<{ data: RoleData[]; total: number }>; + + abstract create(role: RoleData): Promise; + abstract update(role: RoleData): Promise; + abstract delete(roleId: string): Promise; +} diff --git a/src/modules/identity/domain/repositories/user.interface.ts b/src/modules/identity/domain/repositories/user.interface.ts new file mode 100644 index 0000000..7a34862 --- /dev/null +++ b/src/modules/identity/domain/repositories/user.interface.ts @@ -0,0 +1,29 @@ +import { UserData } from '../entities/user.entity'; + +export abstract class IUser { + abstract create(user: UserData): Promise; + + abstract existsById(userId: string): Promise; + abstract existByEmail(userEmail: string): Promise; + abstract getById(userId: string): Promise; + abstract getByEmail(userEmail: string): Promise; + + abstract findByAuthentikId(authentikId: string): Promise; + + abstract update(user: UserData): Promise; + + abstract find(params: { + page?: number; + limit?: number; + search?: string | null; + isActive?: boolean | null; + deleted?: boolean | null; + roleId?: string | null; + }): Promise<{ data: UserData[]; total: number }>; + + abstract softDelete(userId: string): Promise; + abstract restore(userId: string): Promise; + + abstract enable(userId: string): Promise; + abstract disable(userId: string): Promise; +} \ No newline at end of file diff --git a/src/modules/identity/domain/repositories/user.repository.interface.ts b/src/modules/identity/domain/repositories/user.repository.interface.ts deleted file mode 100644 index f76c4a8..0000000 --- a/src/modules/identity/domain/repositories/user.repository.interface.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { User } from '../entities/user.entity'; - -export abstract class UserRepository { - abstract create(user: User): Promise; - - abstract update(user: User): Promise; - - abstract findById( - id: string, - ): Promise; - - abstract findAll(): Promise; - - abstract existsByEmail( - email: string, - ): Promise; -} \ No newline at end of file diff --git a/src/modules/identity/identity.module.ts b/src/modules/identity/identity.module.ts index 9074380..91ccfe3 100644 --- a/src/modules/identity/identity.module.ts +++ b/src/modules/identity/identity.module.ts @@ -1,52 +1,115 @@ import { Module } from '@nestjs/common'; import { UsersController } from './presentation/controllers/users.controller'; +import { RolesController } from './presentation/controllers/roles.controller'; +import { PermissionsController } from './presentation/controllers/permissions.controller'; import { PrismaService } from '../../shared/prisma.service'; +import { UserService } from './application/services/user.service'; import { PrismaUserRepository } from './infrastructure/repositories/prisma-user.repository'; -import { UserRepository } from './domain/repositories/user.repository.interface'; -import { EventDispatcher } from '../../core/events/event-dispatcher'; +import { IUser } from './domain/repositories/user.interface'; + + import { JwtAuthGuard } from '../../core/auth/guards/jwt-auth.guard'; -import { JwtModule } from '@nestjs/jwt'; -import { CreateUserHandler } from './application/handlers/create-user.handler'; -import { FindUserHandler } from './application/handlers/find-user.handler'; -import { DeleteUserHandler } from './application/handlers/delete-user.handler'; -import { FindUsersHandler } from './application/handlers/find-users.handler'; -import { UpdateUserHandler } from './application/handlers/update-user.handler'; +import { CreateUserHandler } from './application/handlers/user/create-user.handler'; import { PermissionGuard } from '../authorization/presentation/guards/permission.guard'; import { Reflector } from '@nestjs/core'; +import { SyncIdentityHandler } from './application/handlers/user/sync-identity.handler'; +import { CurrentUserGuard } from './presentation/guards/current-user.guard'; +import { PrismaRoleRepository } from './infrastructure/repositories/prisma-role.repository'; +import { PrismaPermissionRepository } from './infrastructure/repositories/prisma-permission.repository'; +import { IRole } from './domain/repositories/role.interface'; +import { IPermission } from './domain/repositories/permission.interface'; +import { IAuthConfig } from './application/config/i-auth-config'; +import { EnvAuthConfig } from './application/config/env-auth-config'; +import { GetUsersHandler } from './application/handlers/user/get-users.handler'; +import { GetUserHandler } from './application/handlers/user/get-user.handler'; +import { GetCurrentUserHandler } from './application/handlers/user/get-current-user.handler'; +import { EnableUserHandler } from './application/handlers/user/enable-user.handler'; +import { DisableUserHandler } from './application/handlers/user/disable-user.handler'; +import { DeleteUserHandler } from './application/handlers/user/delete-user.handler'; +import { RestoreUserHandler } from './application/handlers/user/restore-user.handler'; +import { AssignRoleHandler } from './application/handlers/user/assign-role.handler'; +import { RemoveRoleHandler } from './application/handlers/user/remove-role.handler'; +import { AssignPermissionHandler } from './application/handlers/user/assign-permission.handler'; +import { RemovePermissionHandler } from './application/handlers/user/remove-permission.handler'; + +import { GetRolesHandler } from './application/handlers/role/get-roles.handler'; +import { GetRoleHandler } from './application/handlers/role/get-role.handler'; +import { CreateRoleHandler } from './application/handlers/role/create-role.handler'; +import { UpdateRoleHandler } from './application/handlers/role/update-role.handler'; +import { DeleteRoleHandler } from './application/handlers/role/delete-role.handler'; +import { RoleAssignPermissionHandler } from './application/handlers/role/assign-permission.handler'; +import { RoleRemovePermissionHandler } from './application/handlers/role/remove-permission.handler'; + +import { GetPermissionsHandler } from './application/handlers/permission/get-permissions.handler'; +import { GetPermissionHandler } from './application/handlers/permission/get-permission.handler'; +import { CreatePermissionHandler } from './application/handlers/permission/create-permission.handler'; +import { UpdatePermissionHandler } from './application/handlers/permission/update-permission.handler'; +import { DeletePermissionHandler } from './application/handlers/permission/delete-permission.handler'; @Module({ - imports: [ - JwtModule.register({ - secret: process.env.JWT_SECRET, - signOptions: { - expiresIn: '1d', - }, - }), - ], - controllers: [UsersController], providers: [ - //#region User - CreateUserHandler, - FindUserHandler, - FindUsersHandler, - UpdateUserHandler, + //#region User + // CreateUserHandler has been removed: provisioning disabled; users must be created in Authentik. + SyncIdentityHandler, + GetUsersHandler, + + GetUserHandler, + GetCurrentUserHandler, + EnableUserHandler, + DisableUserHandler, DeleteUserHandler, + RestoreUserHandler, + AssignRoleHandler, + RemoveRoleHandler, + AssignPermissionHandler, + RemovePermissionHandler, //#endregion + // role & permission handlers + GetRolesHandler, + GetRoleHandler, + CreateRoleHandler, + UpdateRoleHandler, + DeleteRoleHandler, + RoleAssignPermissionHandler, + RoleRemovePermissionHandler, + + GetPermissionsHandler, + GetPermissionHandler, + CreatePermissionHandler, + UpdatePermissionHandler, + DeletePermissionHandler, + JwtAuthGuard, + CurrentUserGuard, PermissionGuard, Reflector, - PrismaService, + PrismaService, PrismaUserRepository, + PrismaRoleRepository, + PrismaPermissionRepository, + UserService, { - provide: UserRepository, + provide: IUser, useClass: PrismaUserRepository, }, - { - provide: 'EVENT_DISPATCHER', - useValue: new EventDispatcher(), + { + provide: IRole, + useClass: PrismaRoleRepository, }, - ], + { + provide: IPermission, + useClass: PrismaPermissionRepository, + }, + { + provide: IAuthConfig, + useClass: EnvAuthConfig, + }, + ], + imports: [], + controllers: [UsersController, RolesController, PermissionsController], }) export class IdentityModule {} + + diff --git a/src/modules/identity/infrastructure/README.md b/src/modules/identity/infrastructure/README.md index 06bd408..006593d 100644 --- a/src/modules/identity/infrastructure/README.md +++ b/src/modules/identity/infrastructure/README.md @@ -1,12 +1 @@ -modules/identity/infrastructure/ - -Penjelasan: -Implementasi teknis untuk module identity, seperti Prisma repository, adapter implementations, dan data mappers. - -Contoh file: -- prisma/user.repository.ts (mengimplementasikan domain repository interface) -- adapter/identity-adapter.ts - -Aturan: -- Infrastruktur hanya mengimplementasikan interface domain; jangan memuat business rules. -- Import dari infrastructure ke domain harus satu arah: infrastructure -> domain (implementasi). +infrastrucute adalah tempat yang langsung berhubungan dengan dunia luar, misal db, server lain, JWT, dsb. \ No newline at end of file diff --git a/src/modules/identity/infrastructure/mappers/README.MD b/src/modules/identity/infrastructure/mappers/README.MD new file mode 100644 index 0000000..7a42625 --- /dev/null +++ b/src/modules/identity/infrastructure/mappers/README.MD @@ -0,0 +1 @@ +disini emngubah dari domain/entity menjadi format di database dan sebaliknya. \ No newline at end of file diff --git a/src/modules/identity/infrastructure/mappers/prisma-permission.mapper.ts b/src/modules/identity/infrastructure/mappers/prisma-permission.mapper.ts new file mode 100644 index 0000000..05abad0 --- /dev/null +++ b/src/modules/identity/infrastructure/mappers/prisma-permission.mapper.ts @@ -0,0 +1,23 @@ +import { PermissionData } from '../../domain/entities/permission.entity'; + +export class PrismaPermissionMapper { + static toDomain(model: any): PermissionData { + return PermissionData.restore({ + id: model.id, + code: model.code || model.name, + name: model.name, + description: model.description, + createdAt: model.createdAt, + updatedAt: model.updatedAt, + }); + } + + static toPersistence(permission: PermissionData) { + return { + id: permission.id, + code: permission.code, + name: permission.name, + description: permission.description, + }; + } +} diff --git a/src/modules/identity/infrastructure/mappers/prisma-role.mapper.ts b/src/modules/identity/infrastructure/mappers/prisma-role.mapper.ts new file mode 100644 index 0000000..133431d --- /dev/null +++ b/src/modules/identity/infrastructure/mappers/prisma-role.mapper.ts @@ -0,0 +1,27 @@ +import { RoleData } from '../../domain/entities/role.entity'; +import { PermissionData } from '../../domain/entities/permission.entity'; + +export class PrismaRoleMapper { + static toDomain(model: any): RoleData { + const permissions: PermissionData[] = (model.permissions || []).map((p: any) => + PermissionData.restore({ + id: p.id, + name: p.name, + description: p.description, + createdAt: p.createdAt, + updatedAt: p.updatedAt, + }), + ); + + return RoleData.restore({ + id: model.id, + code: model.code, + name: model.name, + description: model.description, + permissions, + isDefault: model.isDefault ?? false, + createdAt: model.createdAt, + updatedAt: model.updatedAt, + }); + } +} \ No newline at end of file diff --git a/src/modules/identity/infrastructure/mappers/prisma-user.mapper.ts b/src/modules/identity/infrastructure/mappers/prisma-user.mapper.ts index 1ce360d..2a8dcad 100644 --- a/src/modules/identity/infrastructure/mappers/prisma-user.mapper.ts +++ b/src/modules/identity/infrastructure/mappers/prisma-user.mapper.ts @@ -1,27 +1,73 @@ -import { User } from '../../domain/entities/user.entity'; +import { UserData } from '../../domain/entities/user.entity'; +import { RoleData } from '../../domain/entities/role.entity'; +import { PermissionData } from '../../domain/entities/permission.entity'; export class PrismaUserMapper { - static toDomain(model: any): User | null { - if (!model) { - return null; - } + static toDomain(model: any): UserData { + const roles: RoleData[] = (model.roles || []).map((ur: any) => { + const r = ur.role; + const permissions: PermissionData[] = (r?.permissions || []).map((rp: any) => + PermissionData.restore({ + id: rp.permission.id, + name: rp.permission.name, + description: rp.permission.description, + createdAt: rp.permission.createdAt, + updatedAt: rp.permission.updatedAt, + }), + ); - return User.restore({ + return RoleData.restore({ + id: r.id, + code: r.code, + name: r.name, + description: r.description, + permissions, + createdAt: r.createdAt, + updatedAt: r.updatedAt, + }); + }); + + const permissions: PermissionData[] = (model.permissions || []).map((up: any) => + PermissionData.restore({ + id: up.permission.id, + name: up.permission.name, + description: up.permission.description, + createdAt: up.permission.createdAt, + updatedAt: up.permission.updatedAt, + }), + ); + + return UserData.restore({ id: model.id, - name: model.name, + authentikId: model.authentikUserId || model.authentikId || null, + username: model.username || model.name || model.username, email: model.email, - password: model.password, - metadata: model.metadata, + password: model.password ?? null, + roles, + permissions, + isActive: model.isActive ?? true, + deletedAt: model.deletedAt || null, + lastSeenAt: model.lastSeenAt || null, + storageQuota: model.storageQuota !== undefined && model.storageQuota !== null ? Number(model.storageQuota) : undefined, + storageUsed: model.storageUsed !== undefined && model.storageUsed !== null ? Number(model.storageUsed) : undefined, }); } - static toPersistence(user: User) { - return { - id: user.id, - name: user.name, - email: user.email, - password: user.password, - metadata: user.metadata ?? {}, - }; + static toPersistence(userData: UserData) { + return { + id: userData.id, + authentikUserId: (userData as any).authentikUserId || userData.authentikId, + authentikId: userData.authentikId, + username: userData.username, + email: userData.email, + password: userData.password ?? null, + isActive: userData.isActive, + deletedAt: userData.deletedAt, + lastSeenAt: userData.lastSeenAt, + lastSyncedAt: (userData as any).lastSyncedAt, + syncStatus: (userData as any).syncStatus, + storageQuota: (userData as any).storageQuota, + storageUsed: (userData as any).storageUsed, + }; } } \ No newline at end of file diff --git a/src/modules/identity/infrastructure/persistence/README.md b/src/modules/identity/infrastructure/persistence/README.md new file mode 100644 index 0000000..07d7361 --- /dev/null +++ b/src/modules/identity/infrastructure/persistence/README.md @@ -0,0 +1 @@ +ini adalah tempat konfigurasi database. \ No newline at end of file diff --git a/src/modules/identity/infrastructure/repositories/README.md b/src/modules/identity/infrastructure/repositories/README.md index b7e780b..455ca20 100644 --- a/src/modules/identity/infrastructure/repositories/README.md +++ b/src/modules/identity/infrastructure/repositories/README.md @@ -1,11 +1 @@ -repositories/ - -Penjelasan: -Implementasi repository di layer infrastructure. Biasanya berisi Prisma queries dan mapping antara DB model dan domain entity. - -Contoh file: -- prisma/user.repository.ts - -Aturan: -- Repository mengimplementasikan interface di domain layer. -- Hindari business logic di repository. +disini yang menjalankan logika bisnisnya. \ No newline at end of file diff --git a/src/modules/identity/infrastructure/repositories/prisma-permission.repository.ts b/src/modules/identity/infrastructure/repositories/prisma-permission.repository.ts new file mode 100644 index 0000000..9459cff --- /dev/null +++ b/src/modules/identity/infrastructure/repositories/prisma-permission.repository.ts @@ -0,0 +1,53 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../../../../shared/prisma.service'; +import { IPermission } from '../../domain/repositories/permission.interface'; +import { PrismaPermissionMapper } from '../mappers/prisma-permission.mapper'; +import { PermissionData } from '../../domain/entities/permission.entity'; + +@Injectable() +export class PrismaPermissionRepository implements IPermission { + constructor(private readonly prisma: PrismaService) {} + + async find(params: { page?: number; limit?: number; search?: string | null }) { + const page = params.page && params.page > 0 ? params.page : 1; + const limit = params.limit && params.limit > 0 ? params.limit : 10; + + const where: any = {}; + if (params.search) { + where.OR = [ + { name: { contains: params.search, mode: 'insensitive' } }, + { code: { contains: params.search, mode: 'insensitive' } }, + { description: { contains: params.search, mode: 'insensitive' } }, + ]; + } + + const [total, items] = await Promise.all([ + this.prisma.permission.count({ where }), + this.prisma.permission.findMany({ where, skip: (page - 1) * limit, take: limit, orderBy: { createdAt: 'desc' } }), + ]); + + return { data: items.map(i => PrismaPermissionMapper.toDomain(i)!), total }; + } + + async getById(id: string) { + const p = await this.prisma.permission.findUnique({ where: { id } }); + if (!p) throw new Error('Permission not found.'); + return PrismaPermissionMapper.toDomain(p); + } + + async create(permission: PermissionData) { + const base = PrismaPermissionMapper.toPersistence(permission); + const created = await this.prisma.permission.create({ data: base }); + return PrismaPermissionMapper.toDomain(created)!; + } + + async update(permission: PermissionData) { + const base = PrismaPermissionMapper.toPersistence(permission); + const updated = await this.prisma.permission.update({ where: { id: permission.id }, data: base }); + return PrismaPermissionMapper.toDomain(updated)!; + } + + async delete(id: string) { + await this.prisma.permission.delete({ where: { id } }); + } +} diff --git a/src/modules/identity/infrastructure/repositories/prisma-role.repository.ts b/src/modules/identity/infrastructure/repositories/prisma-role.repository.ts new file mode 100644 index 0000000..e2bbbee --- /dev/null +++ b/src/modules/identity/infrastructure/repositories/prisma-role.repository.ts @@ -0,0 +1,109 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from '../../../../shared/prisma.service'; +import { IRole } from '../../domain/repositories/role.interface'; +import { PrismaRoleMapper } from '../mappers/prisma-role.mapper'; +import { RoleData } from '../../domain/entities/role.entity'; + +@Injectable() +export class PrismaRoleRepository implements IRole { + constructor(private readonly prisma: PrismaService) {} + + async getDefaultRole() { + const role = await this.prisma.role.findFirst({ + where: { isDefault: true }, + include: { permissions: true }, + }); + + if (!role) return null; + + return PrismaRoleMapper.toDomain(role); + } + + async findById(roleId: string) { + const role = await this.prisma.role.findUnique({ + where: { id: roleId }, + include: { permissions: true }, + }); + + if (!role) throw new Error('Role not found.'); + + return PrismaRoleMapper.toDomain(role); + } + + async find(params: { page?: number; limit?: number; search?: string | null }) { + const page = params.page && params.page > 0 ? params.page : 1; + const limit = params.limit && params.limit > 0 ? params.limit : 10; + + const where: any = {}; + if (params.search) { + where.OR = [ + { name: { contains: params.search, mode: 'insensitive' } }, + { code: { contains: params.search, mode: 'insensitive' } }, + { description: { contains: params.search, mode: 'insensitive' } }, + ]; + } + + const [total, items] = await Promise.all([ + this.prisma.role.count({ where }), + this.prisma.role.findMany({ where, skip: (page - 1) * limit, take: limit, orderBy: { createdAt: 'desc' }, include: { permissions: true } }), + ]); + + return { data: items.map(i => PrismaRoleMapper.toDomain(i)!), total }; + } + + async create(role: RoleData) { + const base: any = { + id: role.id, + code: role.code, + name: role.name, + description: role.description, + isDefault: role.isDefault, + }; + + if (role.permissions && role.permissions.length > 0) { + base.permissions = { + create: role.permissions.map(p => ({ permission: { connect: { id: p.id } }, assignedBy: 'system' })), + }; + } + + const created = await this.prisma.role.create({ data: base, include: { permissions: true } }); + return PrismaRoleMapper.toDomain(created)!; + } + + async update(role: RoleData) { + const base: any = { + code: role.code, + name: role.name, + description: role.description, + isDefault: role.isDefault, + }; + + // sync permissions via transaction + const permIds = role.permissions ? role.permissions.map(p => p.id) : []; + + await this.prisma.$transaction(async (prisma) => { + const currentPerms = await prisma.rolePermission.findMany({ where: { roleId: role.id } }); + const currentIds = currentPerms.map(p => p.permissionId); + + const toAdd = permIds.filter(id => !currentIds.includes(id)); + const toRemove = currentIds.filter(id => !permIds.includes(id)); + + if (toRemove.length > 0) { + await prisma.rolePermission.deleteMany({ where: { roleId: role.id, permissionId: { in: toRemove } } }); + } + + if (toAdd.length > 0) { + await prisma.rolePermission.createMany({ data: toAdd.map(pid => ({ roleId: role.id, permissionId: pid, assignedBy: 'system' })) as any, skipDuplicates: true }); + } + + await prisma.role.update({ where: { id: role.id }, data: base }); + }); + + const updated = await this.prisma.role.findUnique({ where: { id: role.id }, include: { permissions: true } }); + return PrismaRoleMapper.toDomain(updated)!; + } + + async delete(roleId: string) { + await this.prisma.role.delete({ where: { id: roleId } }); + } +} diff --git a/src/modules/identity/infrastructure/repositories/prisma-user.repository.ts b/src/modules/identity/infrastructure/repositories/prisma-user.repository.ts index 74bc603..e575bc2 100644 --- a/src/modules/identity/infrastructure/repositories/prisma-user.repository.ts +++ b/src/modules/identity/infrastructure/repositories/prisma-user.repository.ts @@ -1,64 +1,257 @@ import { Injectable } from '@nestjs/common'; import { PrismaService } from '../../../../shared/prisma.service'; -import { UserRepository } from '../../domain/repositories/user.repository.interface'; -import { User } from '../../domain/entities/user.entity'; +import { IUser } from '../../domain/repositories/user.interface'; +import { UserData } from '../../domain/entities/user.entity'; import { PrismaUserMapper } from '../mappers/prisma-user.mapper'; @Injectable() -export class PrismaUserRepository implements UserRepository { +export class PrismaUserRepository implements IUser { constructor(private readonly prisma: PrismaService) {} + + //#region Create - async findById(id: string) { - const user = await this.prisma.user.findUnique({ - where: { id }, - }); + async create(userData: UserData): Promise { + const base = PrismaUserMapper.toPersistence(userData); - return PrismaUserMapper.toDomain(user); - } + const data: any = { ...base }; - async findAll(): Promise { - const users = await this.prisma.user.findMany({ - where: { deleted_at: null }, - orderBy: { created_at: 'desc' }, - }); + if (userData.roles && userData.roles.length > 0) { + data.roles = { + create: userData.roles.map(r => ({ role: { connect: { id: r.id } }, assignedBy: 'system' })), + }; + } - return users.map(PrismaUserMapper.toDomain); - } - - async create(user: User): Promise { const created = await this.prisma.user.create({ - data: PrismaUserMapper.toPersistence(user), + data, + include: { + roles: { include: { role: { include: { permissions: { include: { permission: true } } } } } }, + permissions: { include: { permission: true } }, + }, }); return PrismaUserMapper.toDomain(created)!; } - async update(user: User): Promise { + //#endregion + + //#region Read + + async existsById(userId: string): Promise { + return ( + (await this.prisma.user.findUnique({ + where: { id: userId }, + select: { id: true }, + })) !== null + ); + } + + async existByEmail(userEmail: string): Promise { + return ( + (await this.prisma.user.findUnique({ + where: { email: userEmail }, + select: { email: true }, + })) !== null + ); + } + + async getById(userId: string): Promise { + const userData = await this.prisma.user.findUnique({ + where: { id: userId }, + include: { + roles: { include: { role: { include: { permissions: { include: { permission: true } } } } } }, + permissions: { include: { permission: true } }, + }, + }); + + if (userData === null) throw new Error('User tidak ditemukan.'); + + return PrismaUserMapper.toDomain(userData); + } + + async getByEmail(userEmail: string): Promise { + const userData = await this.prisma.user.findUnique({ + where: { email: userEmail }, + include: { + roles: { include: { role: { include: { permissions: { include: { permission: true } } } } } }, + permissions: { include: { permission: true } }, + }, + }); + + if (userData === null) throw new Error('User tidak ditemukan.'); + + return PrismaUserMapper.toDomain(userData); + } + + async findByAuthentikId(authentikId: string): Promise { + const userData = await this.prisma.user.findUnique({ + where: { authentikId }, + include: { + roles: { include: { role: { include: { permissions: { include: { permission: true } } } } } }, + permissions: { include: { permission: true } }, + }, + }); + + if (!userData) return null; + + return PrismaUserMapper.toDomain(userData); + } + + async find(params: { + page?: number; + limit?: number; + search?: string | null; + isActive?: boolean | null; + deleted?: boolean | null; + roleId?: string | null; + }): Promise<{ data: UserData[]; total: number }> { + const page = params.page && params.page > 0 ? params.page : 1; + const limit = params.limit && params.limit > 0 ? params.limit : 10; + + const where: any = {}; + + if (params.search) { + where.OR = [ + { username: { contains: params.search, mode: 'insensitive' } }, + { email: { contains: params.search, mode: 'insensitive' } }, + ]; + } + + if (params.isActive !== undefined && params.isActive !== null) { + where.isActive = params.isActive; + } + + if (params.deleted !== undefined && params.deleted !== null) { + if (params.deleted) where.deletedAt = { not: null }; + else where.deletedAt = null; + } + + if (params.roleId) { + where.roles = { some: { roleId: params.roleId } }; + } + + const [total, items] = await Promise.all([ + this.prisma.user.count({ where }), + this.prisma.user.findMany({ + where, + include: { + roles: { include: { role: { include: { permissions: { include: { permission: true } } } } } }, + permissions: { include: { permission: true } }, + }, + skip: (page - 1) * limit, + take: limit, + orderBy: { createdAt: 'desc' }, + }), + ]); + + return { data: items.map(i => PrismaUserMapper.toDomain(i)!), total }; + } + + async softDelete(userId: string): Promise { + await this.prisma.user.update({ where: { id: userId }, data: { deletedAt: new Date(), isActive: false } }); + } + + async restore(userId: string): Promise { const updated = await this.prisma.user.update({ - where: { - id: user.id, + where: { id: userId }, + data: { deletedAt: null }, + include: { + roles: { include: { role: { include: { permissions: { include: { permission: true } } } } } }, + permissions: { include: { permission: true } }, }, - data: PrismaUserMapper.toPersistence(user), }); return PrismaUserMapper.toDomain(updated)!; } - async delete(id: string) { - const user = await this.prisma.user.update({ - where: { id }, - data: { deleted_at: new Date() }, + async enable(userId: string): Promise { + const updated = await this.prisma.user.update({ + where: { id: userId }, + data: { isActive: true }, + include: { + roles: { include: { role: { include: { permissions: { include: { permission: true } } } } } }, + permissions: { include: { permission: true } }, + }, }); - return PrismaUserMapper.toDomain(user); + + return PrismaUserMapper.toDomain(updated)!; } - async existsByEmail(email: string, excludeId?: string | null) { - const where: any = { email }; - if (excludeId) { - where.id = { not: excludeId }; - } + async disable(userId: string): Promise { + const updated = await this.prisma.user.update({ + where: { id: userId }, + data: { isActive: false }, + include: { + roles: { include: { role: { include: { permissions: { include: { permission: true } } } } } }, + permissions: { include: { permission: true } }, + }, + }); - const user = await this.prisma.user.findFirst({ where }); - return !!user; + return PrismaUserMapper.toDomain(updated)!; } + + async update(userData: UserData): Promise { + const base = PrismaUserMapper.toPersistence(userData); + + const data: any = { ...base }; + + // sync roles and permissions using transaction + const roleIds = userData.roles ? userData.roles.map(r => r.id) : []; + const permissionIds = userData.permissions ? userData.permissions.map(p => p.id) : []; + + // perform transaction: delete removed relations, create missing ones, update user + await this.prisma.$transaction(async (prisma) => { + // current roles + const currentRoles = await prisma.userRole.findMany({ where: { userId: userData.id } }); + const currentRoleIds = currentRoles.map(r => r.roleId); + + const toAddRoles = roleIds.filter(id => !currentRoleIds.includes(id)); + const toRemoveRoles = currentRoleIds.filter(id => !roleIds.includes(id)); + + if (toRemoveRoles.length > 0) { + await prisma.userRole.deleteMany({ where: { userId: userData.id, roleId: { in: toRemoveRoles } } }); + } + + if (toAddRoles.length > 0) { + await prisma.userRole.createMany({ + data: toAddRoles.map(rid => ({ userId: userData.id, roleId: rid, assignedBy: 'system' })) as any, + skipDuplicates: true, + }); + } + + // permissions + const currentPerms = await prisma.userPermission.findMany({ where: { userId: userData.id } }); + const currentPermIds = currentPerms.map(p => p.permissionId); + + const toAddPerms = permissionIds.filter(id => !currentPermIds.includes(id)); + const toRemovePerms = currentPermIds.filter(id => !permissionIds.includes(id)); + + if (toRemovePerms.length > 0) { + await prisma.userPermission.deleteMany({ where: { userId: userData.id, permissionId: { in: toRemovePerms } } }); + } + + if (toAddPerms.length > 0) { + await prisma.userPermission.createMany({ + data: toAddPerms.map(pid => ({ userId: userData.id, permissionId: pid, assignedBy: 'system' })) as any, + skipDuplicates: true, + }); + } + + // update base user fields + await prisma.user.update({ where: { id: userData.id }, data }); + }); + + const updated = await this.prisma.user.findUnique({ + where: { id: userData.id }, + include: { + roles: { include: { role: { include: { permissions: { include: { permission: true } } } } } }, + permissions: { include: { permission: true } }, + }, + }); + + return PrismaUserMapper.toDomain(updated)!; + } + + //#endregion } + + diff --git a/src/modules/identity/presentation/controllers/permissions.controller.ts b/src/modules/identity/presentation/controllers/permissions.controller.ts new file mode 100644 index 0000000..73e3fe9 --- /dev/null +++ b/src/modules/identity/presentation/controllers/permissions.controller.ts @@ -0,0 +1,67 @@ +import { Controller, Get, Post, Patch, Delete, Param, UseGuards, Body, Query } from '@nestjs/common'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; + +import { JwtAuthGuard } from '../../../../core/auth/guards/jwt-auth.guard'; +import { PermissionGuard } from '../../../authorization/presentation/guards/permission.guard'; +import { CurrentUserGuard } from '../guards/current-user.guard'; +import { Permissions } from '../../../authorization/presentation/decorators/permission.decorator'; +import { PermissionType } from '../../../../common/constants/permission.constants'; + +import { GetPermissionsHandler } from '../../application/handlers/permission/get-permissions.handler'; +import { GetPermissionHandler } from '../../application/handlers/permission/get-permission.handler'; +import { CreatePermissionHandler } from '../../application/handlers/permission/create-permission.handler'; +import { UpdatePermissionHandler } from '../../application/handlers/permission/update-permission.handler'; +import { DeletePermissionHandler } from '../../application/handlers/permission/delete-permission.handler'; + +@ApiTags('Permissions') +@Controller('permissions') +@UseGuards(JwtAuthGuard, CurrentUserGuard, PermissionGuard) +export class PermissionsController { + constructor( + private readonly getPermissionsHandler: GetPermissionsHandler, + private readonly getPermissionHandler: GetPermissionHandler, + private readonly createPermissionHandler: CreatePermissionHandler, + private readonly updatePermissionHandler: UpdatePermissionHandler, + private readonly deletePermissionHandler: DeletePermissionHandler, + ) {} + + @Get() + @Permissions(PermissionType.PERMISSION_READ) + @ApiOperation({ summary: 'List permissions' }) + async findAll(@Query() query: any) { + const res = await this.getPermissionsHandler.execute(query); + return { success: true, data: res.data, meta: { total: res.total } }; + } + + @Get(':id') + @Permissions(PermissionType.PERMISSION_READ) + @ApiOperation({ summary: 'Get permission' }) + async findOne(@Param('id') id: string) { + const p = await this.getPermissionHandler.execute(id); + return { success: true, data: p, meta: {} }; + } + + @Post() + @Permissions(PermissionType.PERMISSION_CREATE) + @ApiOperation({ summary: 'Create permission' }) + async create(@Body() body: any) { + const created = await this.createPermissionHandler.execute(body); + return { success: true, data: created, meta: {} }; + } + + @Patch(':id') + @Permissions(PermissionType.PERMISSION_UPDATE) + @ApiOperation({ summary: 'Update permission' }) + async update(@Param('id') id: string, @Body() body: any) { + const updated = await this.updatePermissionHandler.execute(id, body); + return { success: true, data: updated, meta: {} }; + } + + @Delete(':id') + @Permissions(PermissionType.PERMISSION_DELETE) + @ApiOperation({ summary: 'Delete permission' }) + async remove(@Param('id') id: string) { + await this.deletePermissionHandler.execute(id); + return { success: true, data: null, meta: {} }; + } +} diff --git a/src/modules/identity/presentation/controllers/roles.controller.ts b/src/modules/identity/presentation/controllers/roles.controller.ts new file mode 100644 index 0000000..6a8d23e --- /dev/null +++ b/src/modules/identity/presentation/controllers/roles.controller.ts @@ -0,0 +1,88 @@ +import { Controller, Get, Post, Patch, Delete, Param, UseGuards, Body, Query } from '@nestjs/common'; +import { ApiOperation, ApiTags } from '@nestjs/swagger'; + +import { JwtAuthGuard } from '../../../../core/auth/guards/jwt-auth.guard'; +import { PermissionGuard } from '../../../authorization/presentation/guards/permission.guard'; +import { CurrentUserGuard } from '../guards/current-user.guard'; +import { Permissions } from '../../../authorization/presentation/decorators/permission.decorator'; +import { PermissionType } from '../../../../common/constants/permission.constants'; + +import { GetRolesHandler } from '../../application/handlers/role/get-roles.handler'; +import { GetRoleHandler } from '../../application/handlers/role/get-role.handler'; +import { CreateRoleHandler } from '../../application/handlers/role/create-role.handler'; +import { UpdateRoleHandler } from '../../application/handlers/role/update-role.handler'; +import { DeleteRoleHandler } from '../../application/handlers/role/delete-role.handler'; +import { RoleAssignPermissionHandler } from '../../application/handlers/role/assign-permission.handler'; +import { RoleRemovePermissionHandler } from '../../application/handlers/role/remove-permission.handler'; + +@ApiTags('Roles') +@Controller('roles') +@UseGuards(JwtAuthGuard, CurrentUserGuard, PermissionGuard) +export class RolesController { + constructor( + private readonly getRolesHandler: GetRolesHandler, + private readonly getRoleHandler: GetRoleHandler, + private readonly createRoleHandler: CreateRoleHandler, + private readonly updateRoleHandler: UpdateRoleHandler, + private readonly deleteRoleHandler: DeleteRoleHandler, + private readonly roleAssignPermissionHandler: RoleAssignPermissionHandler, + private readonly roleRemovePermissionHandler: RoleRemovePermissionHandler, + ) {} + + @Get() + @Permissions(PermissionType.ROLE_READ) + @ApiOperation({ summary: 'List roles' }) + async findAll(@Query() query: any) { + const res = await this.getRolesHandler.execute(query); + return { success: true, data: res.data, meta: { total: res.total } }; + } + + @Get(':id') + @Permissions(PermissionType.ROLE_READ) + @ApiOperation({ summary: 'Get role' }) + async findOne(@Param('id') id: string) { + const role = await this.getRoleHandler.execute(id); + return { success: true, data: role, meta: {} }; + } + + @Post() + @Permissions(PermissionType.ROLE_CREATE) + @ApiOperation({ summary: 'Create role' }) + async create(@Body() body: any) { + const created = await this.createRoleHandler.execute(body); + return { success: true, data: created, meta: {} }; + } + + @Patch(':id') + @Permissions(PermissionType.ROLE_UPDATE) + @ApiOperation({ summary: 'Update role' }) + async update(@Param('id') id: string, @Body() body: any) { + const updated = await this.updateRoleHandler.execute(id, body); + return { success: true, data: updated, meta: {} }; + } + + @Delete(':id') + @Permissions(PermissionType.ROLE_DELETE) + @ApiOperation({ summary: 'Delete role' }) + async remove(@Param('id') id: string) { + await this.deleteRoleHandler.execute(id); + return { success: true, data: null, meta: {} }; + } + + @Post(':id/permissions') + @Permissions(PermissionType.ROLE_UPDATE) + @ApiOperation({ summary: 'Assign permission to role' }) + async assignPermission(@Param('id') id: string, @Body() body: any) { + const permissionId = body.permissionId; + const updated = await this.roleAssignPermissionHandler.execute(id, permissionId); + return { success: true, data: updated, meta: {} }; + } + + @Delete(':id/permissions/:permissionId') + @Permissions(PermissionType.ROLE_UPDATE) + @ApiOperation({ summary: 'Remove permission from role' }) + async removePermission(@Param('id') id: string, @Param('permissionId') permissionId: string) { + const updated = await this.roleRemovePermissionHandler.execute(id, permissionId); + return { success: true, data: updated, meta: {} }; + } +} diff --git a/src/modules/identity/presentation/controllers/users.controller.ts b/src/modules/identity/presentation/controllers/users.controller.ts index edd1057..73e766f 100644 --- a/src/modules/identity/presentation/controllers/users.controller.ts +++ b/src/modules/identity/presentation/controllers/users.controller.ts @@ -1,101 +1,134 @@ -import { - Controller, - Get, - Post, - Delete, - Param, - UseGuards, - Body, - Patch -} from '@nestjs/common'; +import { Controller, Get, Param, UseGuards, Query, Patch, Delete, Post, Body, Req } from '@nestjs/common'; import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { JwtAuthGuard } from '../../../../core/auth/guards/jwt-auth.guard'; import { PermissionGuard } from '../../../authorization/presentation/guards/permission.guard'; +import { CurrentUserGuard } from '../guards/current-user.guard'; import { Permissions } from '../../../authorization/presentation/decorators/permission.decorator'; +import { PermissionType } from '../../../../common/constants/permission.constants'; -import { FindUserHandler } from '../../application/handlers/find-user.handler'; -import { FindUsersHandler } from '../../application/handlers/find-users.handler'; -import { CreateUserHandler } from '../../application/handlers/create-user.handler'; -import { UpdateUserHandler } from '../../application/handlers/update-user.handler'; -import { DeleteUserHandler } from '../../application/handlers/delete-user.handler'; -import { CreateUserDto } from '../dto/create-user.dto'; -import { UpdateUserDto } from '../dto/update-user.dto'; +import { GetUsersHandler } from '../../application/handlers/user/get-users.handler'; +import { GetUserHandler } from '../../application/handlers/user/get-user.handler'; +import { GetCurrentUserHandler } from '../../application/handlers/user/get-current-user.handler'; +import { EnableUserHandler } from '../../application/handlers/user/enable-user.handler'; +import { DisableUserHandler } from '../../application/handlers/user/disable-user.handler'; +import { DeleteUserHandler } from '../../application/handlers/user/delete-user.handler'; +import { RestoreUserHandler } from '../../application/handlers/user/restore-user.handler'; +import { AssignRoleHandler } from '../../application/handlers/user/assign-role.handler'; +import { RemoveRoleHandler } from '../../application/handlers/user/remove-role.handler'; +import { AssignPermissionHandler } from '../../application/handlers/user/assign-permission.handler'; +import { RemovePermissionHandler } from '../../application/handlers/user/remove-permission.handler'; @ApiTags('Users') -@Controller('api/v1/users') -@UseGuards(JwtAuthGuard, PermissionGuard) +@Controller('users') +@UseGuards(JwtAuthGuard, CurrentUserGuard, PermissionGuard) export class UsersController { constructor( - private readonly createUserHandler: CreateUserHandler, - private readonly findUserHandler: FindUserHandler, - private readonly findUsersHandler: FindUsersHandler, - private readonly updateUserHandler: UpdateUserHandler, + private readonly getUsersHandler: GetUsersHandler, + private readonly getUserHandler: GetUserHandler, + private readonly getCurrentUserHandler: GetCurrentUserHandler, + private readonly enableUserHandler: EnableUserHandler, + private readonly disableUserHandler: DisableUserHandler, private readonly deleteUserHandler: DeleteUserHandler, + private readonly restoreUserHandler: RestoreUserHandler, + private readonly assignRoleHandler: AssignRoleHandler, + private readonly removeRoleHandler: RemoveRoleHandler, + private readonly assignPermissionHandler: AssignPermissionHandler, + private readonly removePermissionHandler: RemovePermissionHandler, ) {} - @Post() - @Permissions('USER_CREATE') - @ApiOperation({ summary: 'Create user' }) - async create(@Body() dto: CreateUserDto) { - const data = await this.createUserHandler.execute(dto); + @Get() + @Permissions(PermissionType.USER_READ) + @ApiOperation({ summary: 'List users' }) + async findAll(@Query() query: any) { + const res = await this.getUsersHandler.execute(query); return { success: true, - data, - meta: {}, - } + data: res.data.map(u => (u as any).toResponse ? (u as any).toResponse() : u), + meta: { total: res.total }, + }; + } + + @Get('me') + @ApiOperation({ summary: 'Get current user' }) + async me(@Req() req: any) { + const user = await this.getCurrentUserHandler.execute(req.currentUser); + + return { success: true, data: (user as any).toResponse ? (user as any).toResponse() : user, meta: {} }; } @Get(':id') - @Permissions('USER_READ') + @Permissions(PermissionType.USER_READ) @ApiOperation({ summary: 'Get user by id' }) - async getById(@Param('id') id: string) { - const data = await this.findUserHandler.execute(id); - - return { - success: true, - data, - meta: {}, - }; + async findOne(@Param('id') id: string) { + const user = await this.getUserHandler.execute(id); + return { success: true, data: (user as any).toResponse ? (user as any).toResponse() : user, meta: {} }; } - @Get() - @Permissions('USER_READ_ADMIN') - @ApiOperation({ summary: 'Get All User' }) - async getAll() { - const data = await this.findUsersHandler.execute(); - - return { - success: true, - data, - meta: {}, - }; + @Patch(':id/enable') + @Permissions(PermissionType.USER_UPDATE) + @ApiOperation({ summary: 'Enable user' }) + async enable(@Param('id') id: string) { + const updated = await this.enableUserHandler.execute(id); + return { success: true, data: (updated as any).toResponse ? (updated as any).toResponse() : updated, meta: {} }; } - @Patch(':id') - @Permissions('USER_UPDATE') - @ApiOperation({ summary: 'Update User' }) - async update(@Param('id') id:string, @Body() dto:UpdateUserDto) { - const data = await this.updateUserHandler.execute(id, dto); - - return { - success: true, - data, - meta: {}, - } + @Patch(':id/disable') + @Permissions(PermissionType.USER_UPDATE) + @ApiOperation({ summary: 'Disable user' }) + async disable(@Param('id') id: string) { + const updated = await this.disableUserHandler.execute(id); + return { success: true, data: (updated as any).toResponse ? (updated as any).toResponse() : updated, meta: {} }; } @Delete(':id') - @Permissions('USER_DELETE') - @ApiOperation({ summary: 'Delete user by id' }) - async delete(@Param('id') id: string) { + @Permissions(PermissionType.USER_DELETE) + @ApiOperation({ summary: 'Soft delete user' }) + async remove(@Param('id') id: string) { await this.deleteUserHandler.execute(id); - - return { - success: true, - data: null, - meta: {}, - }; + return { success: true, data: null, meta: {} }; } -} \ No newline at end of file + + @Post(':id/restore') + @Permissions(PermissionType.USER_UPDATE) + @ApiOperation({ summary: 'Restore user' }) + async restore(@Param('id') id: string) { + const restored = await this.restoreUserHandler.execute(id); + return { success: true, data: (restored as any).toResponse ? (restored as any).toResponse() : restored, meta: {} }; + } + + @Post(':id/roles') + @Permissions(PermissionType.USER_UPDATE) + @ApiOperation({ summary: 'Assign role to user' }) + async assignRole(@Param('id') id: string, @Body() body: any) { + const roleId = body.roleId; + const updated = await this.assignRoleHandler.execute(id, roleId); + return { success: true, data: (updated as any).toResponse ? (updated as any).toResponse() : updated, meta: {} }; + } + + @Delete(':id/roles/:roleId') + @Permissions(PermissionType.USER_UPDATE) + @ApiOperation({ summary: 'Remove role from user' }) + async removeRole(@Param('id') id: string, @Param('roleId') roleId: string) { + const updated = await this.removeRoleHandler.execute(id, roleId); + return { success: true, data: (updated as any).toResponse ? (updated as any).toResponse() : updated, meta: {} }; + } + + @Post(':id/permissions') + @Permissions(PermissionType.USER_UPDATE) + @ApiOperation({ summary: 'Assign permission to user' }) + async assignPermission(@Param('id') id: string, @Body() body: any) { + const permissionId = body.permissionId; + const updated = await this.assignPermissionHandler.execute(id, permissionId); + return { success: true, data: (updated as any).toResponse ? (updated as any).toResponse() : updated, meta: {} }; + } + + @Delete(':id/permissions/:permissionId') + @Permissions(PermissionType.USER_UPDATE) + @ApiOperation({ summary: 'Remove permission from user' }) + async removePermission(@Param('id') id: string, @Param('permissionId') permissionId: string) { + const updated = await this.removePermissionHandler.execute(id, permissionId); + return { success: true, data: (updated as any).toResponse ? (updated as any).toResponse() : updated, meta: {} }; + } +} diff --git a/src/modules/identity/presentation/dto/create-permission.dto.ts b/src/modules/identity/presentation/dto/create-permission.dto.ts new file mode 100644 index 0000000..c030a48 --- /dev/null +++ b/src/modules/identity/presentation/dto/create-permission.dto.ts @@ -0,0 +1,19 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsString, IsNotEmpty, IsOptional } from 'class-validator'; + +export class CreatePermissionDto { + @ApiProperty() + @IsString() + @IsNotEmpty() + code!: string; + + @ApiProperty() + @IsString() + @IsNotEmpty() + name!: string; + + @ApiProperty({ required: false }) + @IsOptional() + @IsString() + description?: string; +} diff --git a/src/modules/identity/presentation/dto/create-role.dto.ts b/src/modules/identity/presentation/dto/create-role.dto.ts new file mode 100644 index 0000000..6104e72 --- /dev/null +++ b/src/modules/identity/presentation/dto/create-role.dto.ts @@ -0,0 +1,23 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsString, IsNotEmpty, IsOptional } from 'class-validator'; + +export class CreateRoleDto { + @ApiProperty() + @IsString() + @IsNotEmpty() + code!: string; + + @ApiProperty() + @IsString() + @IsNotEmpty() + name!: string; + + @ApiProperty({ required: false }) + @IsOptional() + @IsString() + description?: string; + + @ApiProperty({ required: false }) + @IsOptional() + isDefault?: boolean; +} diff --git a/src/modules/identity/presentation/dto/create-user.dto.ts b/src/modules/identity/presentation/dto/create-user.dto.ts index adcfdea..ee203a6 100644 --- a/src/modules/identity/presentation/dto/create-user.dto.ts +++ b/src/modules/identity/presentation/dto/create-user.dto.ts @@ -1,11 +1,11 @@ -import { IsEmail, IsNotEmpty, IsString, Length } from 'class-validator'; -import { ApiProperty } from '@nestjs/swagger'; +import { IsEmail, IsNotEmpty, IsString, Length, IsOptional, IsInt, Min } from 'class-validator'; +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; export class CreateUserDto { @ApiProperty({ example: 'John Doe' }) @IsString() @IsNotEmpty() - name!: string; + username!: string; @ApiProperty({ example: 'user@example.com' }) @IsEmail() @@ -16,6 +16,15 @@ export class CreateUserDto { @Length(8, 128) password!: string; - @ApiProperty({ required: false }) - metadata?: Record; + @ApiPropertyOptional({ example: 10737418240 }) + @IsOptional() + @IsInt() + @Min(0) + storageQuota?: number; + + @ApiPropertyOptional({ example: 0 }) + @IsOptional() + @IsInt() + @Min(0) + storageUsed?: number; } \ No newline at end of file diff --git a/src/modules/identity/presentation/dto/update-permission.dto.ts b/src/modules/identity/presentation/dto/update-permission.dto.ts new file mode 100644 index 0000000..a942d25 --- /dev/null +++ b/src/modules/identity/presentation/dto/update-permission.dto.ts @@ -0,0 +1,21 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreatePermissionDto } from './create-permission.dto'; +import { ApiPropertyOptional } from '@nestjs/swagger'; +import { IsOptional, IsString } from 'class-validator'; + +export class UpdatePermissionDto extends PartialType(CreatePermissionDto) { + @ApiPropertyOptional() + @IsOptional() + @IsString() + name?: string; + + @ApiPropertyOptional() + @IsOptional() + @IsString() + description?: string; + + @ApiPropertyOptional() + @IsOptional() + @IsString() + code?: string; +} diff --git a/src/modules/identity/presentation/dto/update-role.dto.ts b/src/modules/identity/presentation/dto/update-role.dto.ts new file mode 100644 index 0000000..2a72472 --- /dev/null +++ b/src/modules/identity/presentation/dto/update-role.dto.ts @@ -0,0 +1,20 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreateRoleDto } from './create-role.dto'; +import { ApiPropertyOptional } from '@nestjs/swagger'; +import { IsOptional, IsString } from 'class-validator'; + +export class UpdateRoleDto extends PartialType(CreateRoleDto) { + @ApiPropertyOptional() + @IsOptional() + @IsString() + name?: string; + + @ApiPropertyOptional() + @IsOptional() + @IsString() + description?: string; + + @ApiPropertyOptional() + @IsOptional() + isDefault?: boolean; +} diff --git a/src/modules/identity/presentation/dto/update-user.dto.ts b/src/modules/identity/presentation/dto/update-user.dto.ts index 1dbe93f..968d85a 100644 --- a/src/modules/identity/presentation/dto/update-user.dto.ts +++ b/src/modules/identity/presentation/dto/update-user.dto.ts @@ -1,7 +1,7 @@ import { PartialType } from '@nestjs/mapped-types'; import { CreateUserDto } from './create-user.dto'; import { ApiPropertyOptional } from '@nestjs/swagger'; -import { IsOptional, IsString, IsEmail, Length } from 'class-validator'; +import { IsOptional, IsString, IsEmail, Length, IsInt, Min } from 'class-validator'; export class UpdateUserDto extends PartialType(CreateUserDto) { @ApiPropertyOptional() @@ -22,4 +22,16 @@ export class UpdateUserDto extends PartialType(CreateUserDto) { @ApiPropertyOptional() @IsOptional() metadata?: Record; + + @ApiPropertyOptional({ example: 10737418240 }) + @IsOptional() + @IsInt() + @Min(0) + storageQuota?: number; + + @ApiPropertyOptional({ example: 0 }) + @IsOptional() + @IsInt() + @Min(0) + storageUsed?: number; } diff --git a/src/modules/identity/presentation/guards/current-user.guard.ts b/src/modules/identity/presentation/guards/current-user.guard.ts new file mode 100644 index 0000000..f26fcd6 --- /dev/null +++ b/src/modules/identity/presentation/guards/current-user.guard.ts @@ -0,0 +1,27 @@ +import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common'; +import { SyncIdentityHandler } from '../../application/handlers/user/sync-identity.handler'; +import { IdentityData } from '../../../../core/auth/interfaces/identity-data'; + +@Injectable() +export class CurrentUserGuard implements CanActivate { + constructor( + private readonly syncIdentityHandler: SyncIdentityHandler, + ) {} + + async canActivate(context: ExecutionContext): Promise { + const request = context.switchToHttp().getRequest() as any; + + const identity = request.identity as IdentityData | undefined; + + if (!identity) { + throw new UnauthorizedException('Identity is missing.'); + } + + const user = await this.syncIdentityHandler.execute(identity); + + // attach domain user as currentUser + request.currentUser = user; + + return true; + } +} diff --git a/test-results/.last-run.json b/test-results/.last-run.json new file mode 100644 index 0000000..d8b6315 --- /dev/null +++ b/test-results/.last-run.json @@ -0,0 +1,7 @@ +{ + "status": "failed", + "failedTests": [ + "c6e079ee66bcf8f961dc-c23b04c7b0e0ed54fd6c", + "c6e079ee66bcf8f961dc-eb7b68d84e422e1710d8" + ] +} \ No newline at end of file diff --git a/test-results/user.integration-Integrati-096a0-ser-and-issues-internal-JWT/error-context.md b/test-results/user.integration-Integrati-096a0-ser-and-issues-internal-JWT/error-context.md new file mode 100644 index 0000000..9978184 --- /dev/null +++ b/test-results/user.integration-Integrati-096a0-ser-and-issues-internal-JWT/error-context.md @@ -0,0 +1,193 @@ +# Instructions + +- Following Playwright test failed. +- Explain why, be concise, respect Playwright best practices. +- Provide a snippet of code with the fix, if possible. + +# Test info + +- Name: user.integration.spec.ts >> Integration - User lifecycle >> login via Authentik creates local user and issues internal JWT +- Location: tests\integration\user.integration.spec.ts:82:7 + +# Error details + +``` +Error: No jwt cookie set after login. Saved screenshot/cookies/page to tests/test-artifacts +``` + +# Test source + +```ts + 19 | // increase default timeout for slow integration flows + 20 | test.setTimeout(60000); + 21 | + 22 | async function adminLogin() { + 23 | const adminUser = process.env.ADMIN_USERNAME; + 24 | const adminPass = process.env.ADMIN_PASSWORD; + 25 | if (!adminUser || !adminPass) throw new Error('ADMIN_USERNAME/ADMIN_PASSWORD must be set in env for integration tests'); + 26 | + 27 | const browser = await chromium.launch({ headless: true }); + 28 | const context = await browser.newContext(); + 29 | const page = await context.newPage(); + 30 | await page.goto(BASE_URL, { waitUntil: 'networkidle' }); + 31 | + 32 | try { + 33 | await page.waitForSelector('input[type="text"], input[type="email"], input[name="username"]', { timeout: 10000 }); + 34 | const usernameInput = await page.$('input[name="username"]') || await page.$('input[type="email"]') || await page.$('input[type="text"]'); + 35 | if (usernameInput) await usernameInput.fill(adminUser); + 36 | const passwordInput = await page.$('input[type="password"], input[name="password"]'); + 37 | if (passwordInput) await passwordInput.fill(adminPass); + 38 | const submitButton = await page.$('button[type="submit"], input[type="submit"]'); + 39 | if (submitButton) { + 40 | await Promise.all([page.waitForNavigation({ waitUntil: 'networkidle', timeout: 20000 }), submitButton.click()]); + 41 | } + 42 | } catch (e) { + 43 | // ignore if login form not present + 44 | } + 45 | + 46 | await page.waitForTimeout(1000); + 47 | const cookies = await context.cookies(); + 48 | const jwtCookie = cookies.find(c => c.name === 'raylab_jwt'); + 49 | await context.close(); + 50 | await browser.close(); + 51 | + 52 | if (!jwtCookie) throw new Error('Admin login failed: no session cookie'); + 53 | return jwtCookie.value; + 54 | } + 55 | + 56 | async function apiRequest(path, token, opts = {}) { + 57 | const headers = Object.assign({ 'Content-Type': 'application/json', Authorization: `Bearer ${token}` }, opts.headers || {}); + 58 | const method = opts.method || 'GET'; + 59 | const body = opts.body ? JSON.stringify(opts.body) : undefined; + 60 | let url; + 61 | try { + 62 | url = new URL(path, BASE_URL).toString(); + 63 | } catch (e) { + 64 | throw new Error(`Invalid BASE_URL for integration tests: ${BASE_URL}`); + 65 | } + 66 | const res = await fetch(url, { method, headers, body }); + 67 | let json = null; + 68 | try { json = await res.json(); } catch (e) { json = null; } + 69 | return { status: res.status, body: json }; + 70 | } + 71 | + 72 | + 73 | test.describe('Integration - User lifecycle', () => { + 74 | let adminToken; + 75 | let createdUser = null; + 76 | + 77 | test.beforeAll(async () => { + 78 | // Integration tests assume test users are created in Authentik prior to running. + 79 | // RayLab will create local user record upon first successful login via Authentik. + 80 | }); + 81 | + 82 | test('login via Authentik creates local user and issues internal JWT', async () => { + 83 | // use browser flow to login as the test user + 84 | const browser = await chromium.launch({ headless: true }); + 85 | const context = await browser.newContext(); + 86 | const page = await context.newPage(); + 87 | await page.goto(BASE_URL, { waitUntil: 'networkidle' }); + 88 | + 89 | try { + 90 | await page.waitForSelector('input[type="text"], input[type="email"], input[name="username"]', { timeout: 10000 }); + 91 | const usernameInput = await page.$('input[name="username"]') || await page.$('input[type="email"]') || await page.$('input[type="text"]'); + 92 | if (usernameInput) await usernameInput.fill(TEST_USER_USERNAME); + 93 | const passwordInput = await page.$('input[type="password"], input[name="password"]'); + 94 | if (passwordInput) await passwordInput.fill(TEST_USER_PASSWORD); + 95 | const submitButton = await page.$('button[type="submit"], input[type="submit"]'); + 96 | if (submitButton) { + 97 | await Promise.all([page.waitForNavigation({ waitUntil: 'networkidle', timeout: 20000 }), submitButton.click()]); + 98 | } + 99 | } catch (e) { + 100 | // ignore if login form not present + 101 | } + 102 | + 103 | await page.waitForTimeout(1000); + 104 | const cookies = await context.cookies(); + 105 | const jwtCookie = cookies.find(c => c.name === 'raylab_jwt'); + 106 | const refreshCookie = cookies.find(c => c.name === 'raylab_refresh'); + 107 | + 108 | if (!jwtCookie) { + 109 | const fs = require('fs'); + 110 | const dir = 'tests/test-artifacts'; + 111 | if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); + 112 | const ts = Date.now(); + 113 | await page.screenshot({ path: `${dir}/failed-login-${ts}.png`, fullPage: true }); + 114 | fs.writeFileSync(`${dir}/failed-login-${ts}-cookies.json`, JSON.stringify(cookies, null, 2), 'utf-8'); + 115 | const content = await page.content(); + 116 | fs.writeFileSync(`${dir}/failed-login-${ts}-page.html`, content, 'utf-8'); + 117 | await context.close(); + 118 | await browser.close(); +> 119 | throw new Error(`No jwt cookie set after login. Saved screenshot/cookies/page to ${dir}`); + | ^ Error: No jwt cookie set after login. Saved screenshot/cookies/page to tests/test-artifacts + 120 | } + 121 | + 122 | // ensure we have an internal jwt cookie + 123 | expect(jwtCookie).toBeDefined(); + 124 | expect(jwtCookie.value).toBeTruthy(); + 125 | + 126 | // validate /auth/me using the internal jwt + 127 | const token = jwtCookie.value; + 128 | const meUrl = new URL('/auth/me', BASE_URL).toString(); + 129 | const meResp = await fetch(meUrl, { headers: { Authorization: `Bearer ${token}` } }); + 130 | const meJson = await meResp.json(); + 131 | expect(meResp.status).toBeLessThan(300); + 132 | expect(meJson.success).toBe(true); + 133 | expect(meJson.data).toBeDefined(); + 134 | expect(meJson.data.email).toBe(TEST_USER_EMAIL); + 135 | + 136 | await context.close(); + 137 | await browser.close(); + 138 | }); + 139 | + 140 | test('login via Authentik (created user) issues internal JWT', async () => { + 141 | // use browser flow to login as the created user + 142 | const browser = await chromium.launch({ headless: true }); + 143 | const context = await browser.newContext(); + 144 | const page = await context.newPage(); + 145 | await page.goto(BASE_URL, { waitUntil: 'networkidle' }); + 146 | + 147 | try { + 148 | await page.waitForSelector('input[type="text"], input[type="email"], input[name="username"]', { timeout: 10000 }); + 149 | const usernameInput = await page.$('input[name="username"]') || await page.$('input[type="email"]') || await page.$('input[type="text"]'); + 150 | if (usernameInput) await usernameInput.fill(TEST_USER_USERNAME); + 151 | const passwordInput = await page.$('input[type="password"], input[name="password"]'); + 152 | if (passwordInput) await passwordInput.fill(TEST_USER_PASSWORD); + 153 | const submitButton = await page.$('button[type="submit"], input[type="submit"]'); + 154 | if (submitButton) { + 155 | await Promise.all([page.waitForNavigation({ waitUntil: 'networkidle', timeout: 20000 }), submitButton.click()]); + 156 | } + 157 | } catch (e) { + 158 | // ignore if login form not present + 159 | } + 160 | + 161 | await page.waitForTimeout(1000); + 162 | const cookies = await context.cookies(); + 163 | const jwtCookie = cookies.find(c => c.name === 'raylab_jwt'); + 164 | + 165 | if (!jwtCookie) { + 166 | const fs = require('fs'); + 167 | const dir = 'tests/test-artifacts'; + 168 | if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); + 169 | const ts = Date.now(); + 170 | await page.screenshot({ path: `${dir}/failed-login-2-${ts}.png`, fullPage: true }); + 171 | fs.writeFileSync(`${dir}/failed-login-2-${ts}-cookies.json`, JSON.stringify(cookies, null, 2), 'utf-8'); + 172 | const content = await page.content(); + 173 | fs.writeFileSync(`${dir}/failed-login-2-${ts}-page.html`, content, 'utf-8'); + 174 | await context.close(); + 175 | await browser.close(); + 176 | throw new Error(`No jwt cookie set after login (second test). Saved screenshot/cookies/page to ${dir}`); + 177 | } + 178 | + 179 | await context.close(); + 180 | await browser.close(); + 181 | + 182 | expect(jwtCookie).toBeDefined(); + 183 | expect(jwtCookie.value).toBeTruthy(); + 184 | }); + 185 | + 186 | // Cleanup via API provisioning has been removed. If test environment requires cleanup, perform manually in Authentik. + 187 | + 188 | }); + 189 | +``` \ No newline at end of file diff --git a/test-results/user.integration-Integrati-8202b-ed-user-issues-internal-JWT/error-context.md b/test-results/user.integration-Integrati-8202b-ed-user-issues-internal-JWT/error-context.md new file mode 100644 index 0000000..18988bc --- /dev/null +++ b/test-results/user.integration-Integrati-8202b-ed-user-issues-internal-JWT/error-context.md @@ -0,0 +1,136 @@ +# Instructions + +- Following Playwright test failed. +- Explain why, be concise, respect Playwright best practices. +- Provide a snippet of code with the fix, if possible. + +# Test info + +- Name: user.integration.spec.ts >> Integration - User lifecycle >> login via Authentik (created user) issues internal JWT +- Location: tests\integration\user.integration.spec.ts:140:7 + +# Error details + +``` +Error: No jwt cookie set after login (second test). Saved screenshot/cookies/page to tests/test-artifacts +``` + +# Test source + +```ts + 76 | + 77 | test.beforeAll(async () => { + 78 | // Integration tests assume test users are created in Authentik prior to running. + 79 | // RayLab will create local user record upon first successful login via Authentik. + 80 | }); + 81 | + 82 | test('login via Authentik creates local user and issues internal JWT', async () => { + 83 | // use browser flow to login as the test user + 84 | const browser = await chromium.launch({ headless: true }); + 85 | const context = await browser.newContext(); + 86 | const page = await context.newPage(); + 87 | await page.goto(BASE_URL, { waitUntil: 'networkidle' }); + 88 | + 89 | try { + 90 | await page.waitForSelector('input[type="text"], input[type="email"], input[name="username"]', { timeout: 10000 }); + 91 | const usernameInput = await page.$('input[name="username"]') || await page.$('input[type="email"]') || await page.$('input[type="text"]'); + 92 | if (usernameInput) await usernameInput.fill(TEST_USER_USERNAME); + 93 | const passwordInput = await page.$('input[type="password"], input[name="password"]'); + 94 | if (passwordInput) await passwordInput.fill(TEST_USER_PASSWORD); + 95 | const submitButton = await page.$('button[type="submit"], input[type="submit"]'); + 96 | if (submitButton) { + 97 | await Promise.all([page.waitForNavigation({ waitUntil: 'networkidle', timeout: 20000 }), submitButton.click()]); + 98 | } + 99 | } catch (e) { + 100 | // ignore if login form not present + 101 | } + 102 | + 103 | await page.waitForTimeout(1000); + 104 | const cookies = await context.cookies(); + 105 | const jwtCookie = cookies.find(c => c.name === 'raylab_jwt'); + 106 | const refreshCookie = cookies.find(c => c.name === 'raylab_refresh'); + 107 | + 108 | if (!jwtCookie) { + 109 | const fs = require('fs'); + 110 | const dir = 'tests/test-artifacts'; + 111 | if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); + 112 | const ts = Date.now(); + 113 | await page.screenshot({ path: `${dir}/failed-login-${ts}.png`, fullPage: true }); + 114 | fs.writeFileSync(`${dir}/failed-login-${ts}-cookies.json`, JSON.stringify(cookies, null, 2), 'utf-8'); + 115 | const content = await page.content(); + 116 | fs.writeFileSync(`${dir}/failed-login-${ts}-page.html`, content, 'utf-8'); + 117 | await context.close(); + 118 | await browser.close(); + 119 | throw new Error(`No jwt cookie set after login. Saved screenshot/cookies/page to ${dir}`); + 120 | } + 121 | + 122 | // ensure we have an internal jwt cookie + 123 | expect(jwtCookie).toBeDefined(); + 124 | expect(jwtCookie.value).toBeTruthy(); + 125 | + 126 | // validate /auth/me using the internal jwt + 127 | const token = jwtCookie.value; + 128 | const meUrl = new URL('/auth/me', BASE_URL).toString(); + 129 | const meResp = await fetch(meUrl, { headers: { Authorization: `Bearer ${token}` } }); + 130 | const meJson = await meResp.json(); + 131 | expect(meResp.status).toBeLessThan(300); + 132 | expect(meJson.success).toBe(true); + 133 | expect(meJson.data).toBeDefined(); + 134 | expect(meJson.data.email).toBe(TEST_USER_EMAIL); + 135 | + 136 | await context.close(); + 137 | await browser.close(); + 138 | }); + 139 | + 140 | test('login via Authentik (created user) issues internal JWT', async () => { + 141 | // use browser flow to login as the created user + 142 | const browser = await chromium.launch({ headless: true }); + 143 | const context = await browser.newContext(); + 144 | const page = await context.newPage(); + 145 | await page.goto(BASE_URL, { waitUntil: 'networkidle' }); + 146 | + 147 | try { + 148 | await page.waitForSelector('input[type="text"], input[type="email"], input[name="username"]', { timeout: 10000 }); + 149 | const usernameInput = await page.$('input[name="username"]') || await page.$('input[type="email"]') || await page.$('input[type="text"]'); + 150 | if (usernameInput) await usernameInput.fill(TEST_USER_USERNAME); + 151 | const passwordInput = await page.$('input[type="password"], input[name="password"]'); + 152 | if (passwordInput) await passwordInput.fill(TEST_USER_PASSWORD); + 153 | const submitButton = await page.$('button[type="submit"], input[type="submit"]'); + 154 | if (submitButton) { + 155 | await Promise.all([page.waitForNavigation({ waitUntil: 'networkidle', timeout: 20000 }), submitButton.click()]); + 156 | } + 157 | } catch (e) { + 158 | // ignore if login form not present + 159 | } + 160 | + 161 | await page.waitForTimeout(1000); + 162 | const cookies = await context.cookies(); + 163 | const jwtCookie = cookies.find(c => c.name === 'raylab_jwt'); + 164 | + 165 | if (!jwtCookie) { + 166 | const fs = require('fs'); + 167 | const dir = 'tests/test-artifacts'; + 168 | if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); + 169 | const ts = Date.now(); + 170 | await page.screenshot({ path: `${dir}/failed-login-2-${ts}.png`, fullPage: true }); + 171 | fs.writeFileSync(`${dir}/failed-login-2-${ts}-cookies.json`, JSON.stringify(cookies, null, 2), 'utf-8'); + 172 | const content = await page.content(); + 173 | fs.writeFileSync(`${dir}/failed-login-2-${ts}-page.html`, content, 'utf-8'); + 174 | await context.close(); + 175 | await browser.close(); +> 176 | throw new Error(`No jwt cookie set after login (second test). Saved screenshot/cookies/page to ${dir}`); + | ^ Error: No jwt cookie set after login (second test). Saved screenshot/cookies/page to tests/test-artifacts + 177 | } + 178 | + 179 | await context.close(); + 180 | await browser.close(); + 181 | + 182 | expect(jwtCookie).toBeDefined(); + 183 | expect(jwtCookie.value).toBeTruthy(); + 184 | }); + 185 | + 186 | // Cleanup via API provisioning has been removed. If test environment requires cleanup, perform manually in Authentik. + 187 | + 188 | }); + 189 | +``` \ No newline at end of file diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..8f482be --- /dev/null +++ b/tests/README.md @@ -0,0 +1,12 @@ +Playwright API Testing for RayLab Core + +Structure: +- helpers: auth/request helpers +- fixtures: reusable data helpers +- api: per-controller tests +- reporter: custom reporter writing tests/output/latest-result.txt + +Run: + npx playwright test + +Ensure .env is configured with BASE_URL and identity provider (Authentik or compatible) details. diff --git a/src/modules/identity/domain/.gitkeep b/tests/api/permissions/.gitkeep similarity index 100% rename from src/modules/identity/domain/.gitkeep rename to tests/api/permissions/.gitkeep diff --git a/src/modules/identity/events/.gitkeep b/tests/api/roles/.gitkeep similarity index 100% rename from src/modules/identity/events/.gitkeep rename to tests/api/roles/.gitkeep diff --git a/tests/api/users/enable-user.spec.ts b/tests/api/users/enable-user.spec.ts new file mode 100644 index 0000000..623dc56 --- /dev/null +++ b/tests/api/users/enable-user.spec.ts @@ -0,0 +1,11 @@ +import test from '@playwright/test'; +import { requestPatch } from '../../helpers/request'; + +const { expect } = test; + +test.describe('Users - PATCH /users/:id/enable', () => { + test('should return 404 for non-existing user', async () => { + const res = await requestPatch('/users/non-existing-id/enable'); + expect([404, 400, 500]).toContain(res.status); + }); +}); diff --git a/tests/api/users/get-current-user.spec.ts b/tests/api/users/get-current-user.spec.ts new file mode 100644 index 0000000..e562eba --- /dev/null +++ b/tests/api/users/get-current-user.spec.ts @@ -0,0 +1,20 @@ +import test from '@playwright/test'; +import { requestGet } from '../../helpers/request'; + +const { expect } = test; + +test.describe('Users - GET /users/me', () => { + test('should return current user when token provided', async () => { + const res = await requestGet('/users/me'); + expect(res.status).toBeGreaterThanOrEqual(200); + expect(res.status).toBeLessThan(300); + expect(res.body.success).toBe(true); + expect(res.body.data).toBeDefined(); + expect(res.body.data.email).toBeTruthy(); + }); + + test('should be unauthorized without token', async () => { + const res = await requestGet('/users/me', null); + expect(res.status).toBe(401); + }); +}); diff --git a/tests/api/users/get-user.spec.ts b/tests/api/users/get-user.spec.ts new file mode 100644 index 0000000..8333624 --- /dev/null +++ b/tests/api/users/get-user.spec.ts @@ -0,0 +1,11 @@ +import test from '@playwright/test'; +import { requestGet } from '../../helpers/request'; + +const { expect } = test; + +test.describe('Users - GET /users/:id', () => { + test('should return 404 for non-existing user', async () => { + const res = await requestGet('/users/non-existing-id'); + expect([404, 400, 500]).toContain(res.status); + }); +}); diff --git a/tests/api/users/get-users.spec.ts b/tests/api/users/get-users.spec.ts new file mode 100644 index 0000000..4855d82 --- /dev/null +++ b/tests/api/users/get-users.spec.ts @@ -0,0 +1,23 @@ +import test from '@playwright/test'; +import { requestGet } from '../../helpers/request'; + + +const { expect } = test; + +test.describe('Users - GET /users', () => { + test('should return list of users (authorized)', async () => { + const res = await requestGet('/users'); + + expect(res.status).toBeGreaterThanOrEqual(200); + expect(res.status).toBeLessThan(300); + expect(res.body).toBeTruthy(); + expect(res.body.success).toBe(true); + expect(res.body.data).toBeInstanceOf(Array); + expect(res.body.meta).toBeDefined(); + }); + + test('should return unauthorized when missing token', async () => { + const res = await requestGet('/users', null); + expect(res.status).toBe(401); + }); +}); diff --git a/tests/fixtures/user.fixture.ts b/tests/fixtures/user.fixture.ts new file mode 100644 index 0000000..74d47ae --- /dev/null +++ b/tests/fixtures/user.fixture.ts @@ -0,0 +1,11 @@ +import { requestPost, requestDelete } from '../helpers/request'; + +export async function createDummyUser(payload: any) { + const res = await requestPost('/user', 'admin', payload); + return res; +} + +export async function deleteDummyUser(userId: string) { + // soft delete + await requestDelete(`/users/${userId}`, 'admin'); +} diff --git a/tests/helpers/auth.ts b/tests/helpers/auth.ts new file mode 100644 index 0000000..d9590eb --- /dev/null +++ b/tests/helpers/auth.ts @@ -0,0 +1,91 @@ +import { chromium } from 'playwright'; +import { env } from './env'; + +const store: Map = new Map(); + +function setToken(key: string, token: string, expiresIn?: number) { + const expiresAt = expiresIn ? Date.now() + expiresIn * 1000 - 5000 : undefined; + store.set(key, { token, expiresAt }); +} + +function getTokenFromStore(key: string) { + const entry = store.get(key); + if (!entry) return null; + if (entry.expiresAt && Date.now() > entry.expiresAt) { + store.delete(key); + return null; + } + return entry.token; +} + +async function loginViaRaylab(username: string, password: string) { + const base = env.BASE_URL || 'http://localhost:3000'; + const browser = await chromium.launch({ headless: Boolean(process.env.PW_HEADLESS || '1') }); + const context = await browser.newContext(); + const page = await context.newPage(); + + // Navigate to RayLab - expects redirect to identity provider + await page.goto(base, { waitUntil: 'networkidle' }); + + // Wait for a login form to appear on identity provider + try { + await page.waitForSelector('input[type="text"], input[type="email"], input[name="username"]', { timeout: 10000 }); + // fill username + const usernameInput = await page.$('input[name="username"]') || await page.$('input[type="email"]') || await page.$('input[type="text"]'); + if (usernameInput) await usernameInput.fill(username); + + // fill password + const passwordInput = await page.$('input[type="password"], input[name="password"]'); + if (passwordInput) await passwordInput.fill(password); + + // try to submit + const submitButton = await page.$('button[type="submit"], input[type="submit"]'); + if (submitButton) { + await Promise.all([page.waitForNavigation({ waitUntil: 'networkidle', timeout: 20000 }), submitButton.click()]); + } + } catch (e) { + // If no login form found, we may already be at callback + } + + // Wait for callback to be done and cookie to be set + await page.waitForTimeout(1000); + const cookies = await context.cookies(); + const jwtCookie = cookies.find(c => c.name === 'raylab_jwt'); + const refreshCookie = cookies.find(c => c.name === 'raylab_refresh'); + + const result: any = {}; + if (jwtCookie) result.accessToken = jwtCookie.value; + if (refreshCookie) result.refreshToken = refreshCookie.value; + + await context.close(); + await browser.close(); + + if (!result.accessToken) throw new Error('Login failed: no session cookie set'); + + return result; +} + +export async function getToken(role: 'owner' | 'admin' | 'employee' = 'admin') { + const cacheKey = `role:${role}`; + const cached = getTokenFromStore(cacheKey); + if (cached) return cached; + + const username = role === 'owner' ? env.OWNER_USERNAME : role === 'admin' ? env.ADMIN_USERNAME : env.EMPLOYEE_USERNAME; + const password = role === 'owner' ? env.OWNER_PASSWORD : role === 'admin' ? env.ADMIN_PASSWORD : env.EMPLOYEE_PASSWORD; + + if (!username || !password) throw new Error('Missing credentials in .env for role: ' + role); + + const data = await loginViaRaylab(username, password); + const token = data.accessToken; + // expiresIn not available from cookie - default to 1 hour + const expiresIn = Number(process.env.TEST_TOKEN_EXPIRES_IN || 3600); + setToken(cacheKey, token, expiresIn); + return token; +} + +export async function getRawToken(username: string, password: string) { + const data = await loginViaRaylab(username, password); + return data.accessToken; +} + +export default { getToken, getRawToken }; diff --git a/tests/helpers/env.ts b/tests/helpers/env.ts new file mode 100644 index 0000000..eab59dd --- /dev/null +++ b/tests/helpers/env.ts @@ -0,0 +1,7 @@ +import dotenv from 'dotenv'; +import path from 'path'; + +const envPath = path.resolve(process.cwd(), '.env'); +dotenv.config({ path: envPath }); + +export const env = process.env; diff --git a/tests/helpers/index.ts b/tests/helpers/index.ts new file mode 100644 index 0000000..63ad0e0 --- /dev/null +++ b/tests/helpers/index.ts @@ -0,0 +1,3 @@ +export * from './auth'; +export * from './request'; +export * from './env'; diff --git a/tests/helpers/request.ts b/tests/helpers/request.ts new file mode 100644 index 0000000..eb92b0d --- /dev/null +++ b/tests/helpers/request.ts @@ -0,0 +1,73 @@ +import { request } from '@playwright/test'; +import { env } from './env'; +import { getToken } from './auth'; + +async function buildContext(token?: string) { + const headers: any = { 'Content-Type': 'application/json' }; + if (token) headers['Authorization'] = `Bearer ${token}`; + + const api = await request.newContext({ baseURL: env.BASE_URL || 'http://localhost:3000', extraHTTPHeaders: headers }); + return api; +} + +export async function requestGet(path: string, role: 'owner' | 'admin' | 'employee' | null = 'admin', opts: any = {}) { + const token = role ? await getToken(role) : undefined; + const api = await buildContext(token); + try { + const res = await api.get(path, opts); + const body = await parseResponseSafe(res); + return { status: res.status(), body, headers: res.headers() }; + } finally { + await api.dispose(); + } +} + +export async function requestPost(path: string, role: 'owner' | 'admin' | 'employee' | null = 'admin', data?: any, opts: any = {}) { + const token = role ? await getToken(role) : undefined; + const api = await buildContext(token); + try { + const res = await api.post(path, { data, ...opts }); + const body = await parseResponseSafe(res); + return { status: res.status(), body, headers: res.headers() }; + } finally { + await api.dispose(); + } +} + +export async function requestPatch(path: string, role: 'owner' | 'admin' | 'employee' | null = 'admin', data?: any, opts: any = {}) { + const token = role ? await getToken(role) : undefined; + const api = await buildContext(token); + try { + const res = await api.patch(path, { data, ...opts }); + const body = await parseResponseSafe(res); + return { status: res.status(), body, headers: res.headers() }; + } finally { + await api.dispose(); + } +} + +export async function requestDelete(path: string, role: 'owner' | 'admin' | 'employee' | null = 'admin', opts: any = {}) { + const token = role ? await getToken(role) : undefined; + const api = await buildContext(token); + try { + const res = await api.delete(path, opts); + const body = await parseResponseSafe(res); + return { status: res.status(), body, headers: res.headers() }; + } finally { + await api.dispose(); + } +} + +async function parseResponseSafe(res: any) { + const ct = res.headers()['content-type'] || ''; + try { + if (ct.includes('application/json')) return await res.json(); + return await res.text(); + } catch (e) { + try { + return await res.text(); + } catch (e2) { + return null; + } + } +} diff --git a/tests/integration/user.integration.spec.ts b/tests/integration/user.integration.spec.ts new file mode 100644 index 0000000..62bf886 --- /dev/null +++ b/tests/integration/user.integration.spec.ts @@ -0,0 +1,188 @@ +import dotenv from 'dotenv'; +import fetch from 'node-fetch'; +import { test, expect } from '@playwright/test'; +import { chromium } from 'playwright'; + +dotenv.config(); + +const TEST_USER_EMAIL = process.env.TEST_USER_EMAIL || 'test-integration@example.com'; +const TEST_USER_USERNAME = process.env.TEST_USER_USERNAME || 'test-integration'; +const TEST_USER_PASSWORD = process.env.TEST_USER_PASSWORD || 'StrongP@ssw0rd!'; + +let BASE_URL = (process.env.BASE_URL || 'http://localhost:3000').trim(); +// sometimes env can contain accidental concatenated vars; take first token +BASE_URL = BASE_URL.split(/\s+/)[0]; +if (!BASE_URL.startsWith('http://') && !BASE_URL.startsWith('https://')) { + BASE_URL = 'http://' + BASE_URL; +} + +// increase default timeout for slow integration flows +test.setTimeout(60000); + +async function adminLogin() { + const adminUser = process.env.ADMIN_USERNAME; + const adminPass = process.env.ADMIN_PASSWORD; + if (!adminUser || !adminPass) throw new Error('ADMIN_USERNAME/ADMIN_PASSWORD must be set in env for integration tests'); + + const browser = await chromium.launch({ headless: true }); + const context = await browser.newContext(); + const page = await context.newPage(); + await page.goto(BASE_URL, { waitUntil: 'networkidle' }); + + try { + await page.waitForSelector('input[type="text"], input[type="email"], input[name="username"]', { timeout: 10000 }); + const usernameInput = await page.$('input[name="username"]') || await page.$('input[type="email"]') || await page.$('input[type="text"]'); + if (usernameInput) await usernameInput.fill(adminUser); + const passwordInput = await page.$('input[type="password"], input[name="password"]'); + if (passwordInput) await passwordInput.fill(adminPass); + const submitButton = await page.$('button[type="submit"], input[type="submit"]'); + if (submitButton) { + await Promise.all([page.waitForNavigation({ waitUntil: 'networkidle', timeout: 20000 }), submitButton.click()]); + } + } catch (e) { + // ignore if login form not present + } + + await page.waitForTimeout(1000); + const cookies = await context.cookies(); + const jwtCookie = cookies.find(c => c.name === 'raylab_jwt'); + await context.close(); + await browser.close(); + + if (!jwtCookie) throw new Error('Admin login failed: no session cookie'); + return jwtCookie.value; +} + +async function apiRequest(path, token, opts = {}) { + const headers = Object.assign({ 'Content-Type': 'application/json', Authorization: `Bearer ${token}` }, opts.headers || {}); + const method = opts.method || 'GET'; + const body = opts.body ? JSON.stringify(opts.body) : undefined; + let url; + try { + url = new URL(path, BASE_URL).toString(); + } catch (e) { + throw new Error(`Invalid BASE_URL for integration tests: ${BASE_URL}`); + } + const res = await fetch(url, { method, headers, body }); + let json = null; + try { json = await res.json(); } catch (e) { json = null; } + return { status: res.status, body: json }; +} + + +test.describe('Integration - User lifecycle', () => { + let adminToken; + let createdUser = null; + + test.beforeAll(async () => { + // Integration tests assume test users are created in Authentik prior to running. + // RayLab will create local user record upon first successful login via Authentik. + }); + + test('login via Authentik creates local user and issues internal JWT', async () => { + // use browser flow to login as the test user + const browser = await chromium.launch({ headless: true }); + const context = await browser.newContext(); + const page = await context.newPage(); + await page.goto(BASE_URL, { waitUntil: 'networkidle' }); + + try { + await page.waitForSelector('input[type="text"], input[type="email"], input[name="username"]', { timeout: 10000 }); + const usernameInput = await page.$('input[name="username"]') || await page.$('input[type="email"]') || await page.$('input[type="text"]'); + if (usernameInput) await usernameInput.fill(TEST_USER_USERNAME); + const passwordInput = await page.$('input[type="password"], input[name="password"]'); + if (passwordInput) await passwordInput.fill(TEST_USER_PASSWORD); + const submitButton = await page.$('button[type="submit"], input[type="submit"]'); + if (submitButton) { + await Promise.all([page.waitForNavigation({ waitUntil: 'networkidle', timeout: 20000 }), submitButton.click()]); + } + } catch (e) { + // ignore if login form not present + } + + await page.waitForTimeout(1000); + const cookies = await context.cookies(); + const jwtCookie = cookies.find(c => c.name === 'raylab_jwt'); + const refreshCookie = cookies.find(c => c.name === 'raylab_refresh'); + + if (!jwtCookie) { + const fs = require('fs'); + const dir = 'tests/test-artifacts'; + if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); + const ts = Date.now(); + await page.screenshot({ path: `${dir}/failed-login-${ts}.png`, fullPage: true }); + fs.writeFileSync(`${dir}/failed-login-${ts}-cookies.json`, JSON.stringify(cookies, null, 2), 'utf-8'); + const content = await page.content(); + fs.writeFileSync(`${dir}/failed-login-${ts}-page.html`, content, 'utf-8'); + await context.close(); + await browser.close(); + throw new Error(`No jwt cookie set after login. Saved screenshot/cookies/page to ${dir}`); + } + + // ensure we have an internal jwt cookie + expect(jwtCookie).toBeDefined(); + expect(jwtCookie.value).toBeTruthy(); + + // validate /auth/me using the internal jwt + const token = jwtCookie.value; + const meUrl = new URL('/auth/me', BASE_URL).toString(); + const meResp = await fetch(meUrl, { headers: { Authorization: `Bearer ${token}` } }); + const meJson = await meResp.json(); + expect(meResp.status).toBeLessThan(300); + expect(meJson.success).toBe(true); + expect(meJson.data).toBeDefined(); + expect(meJson.data.email).toBe(TEST_USER_EMAIL); + + await context.close(); + await browser.close(); + }); + + test('login via Authentik (created user) issues internal JWT', async () => { + // use browser flow to login as the created user + const browser = await chromium.launch({ headless: true }); + const context = await browser.newContext(); + const page = await context.newPage(); + await page.goto(BASE_URL, { waitUntil: 'networkidle' }); + + try { + await page.waitForSelector('input[type="text"], input[type="email"], input[name="username"]', { timeout: 10000 }); + const usernameInput = await page.$('input[name="username"]') || await page.$('input[type="email"]') || await page.$('input[type="text"]'); + if (usernameInput) await usernameInput.fill(TEST_USER_USERNAME); + const passwordInput = await page.$('input[type="password"], input[name="password"]'); + if (passwordInput) await passwordInput.fill(TEST_USER_PASSWORD); + const submitButton = await page.$('button[type="submit"], input[type="submit"]'); + if (submitButton) { + await Promise.all([page.waitForNavigation({ waitUntil: 'networkidle', timeout: 20000 }), submitButton.click()]); + } + } catch (e) { + // ignore if login form not present + } + + await page.waitForTimeout(1000); + const cookies = await context.cookies(); + const jwtCookie = cookies.find(c => c.name === 'raylab_jwt'); + + if (!jwtCookie) { + const fs = require('fs'); + const dir = 'tests/test-artifacts'; + if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true }); + const ts = Date.now(); + await page.screenshot({ path: `${dir}/failed-login-2-${ts}.png`, fullPage: true }); + fs.writeFileSync(`${dir}/failed-login-2-${ts}-cookies.json`, JSON.stringify(cookies, null, 2), 'utf-8'); + const content = await page.content(); + fs.writeFileSync(`${dir}/failed-login-2-${ts}-page.html`, content, 'utf-8'); + await context.close(); + await browser.close(); + throw new Error(`No jwt cookie set after login (second test). Saved screenshot/cookies/page to ${dir}`); + } + + await context.close(); + await browser.close(); + + expect(jwtCookie).toBeDefined(); + expect(jwtCookie.value).toBeTruthy(); + }); + + // Cleanup via API provisioning has been removed. If test environment requires cleanup, perform manually in Authentik. + +}); diff --git a/src/modules/identity/infrastructure/mappers/.gitkeep b/tests/output/.gitkeep similarity index 100% rename from src/modules/identity/infrastructure/mappers/.gitkeep rename to tests/output/.gitkeep diff --git a/tests/output/latest-result.txt b/tests/output/latest-result.txt new file mode 100644 index 0000000..32528bb --- /dev/null +++ b/tests/output/latest-result.txt @@ -0,0 +1 @@ +TEST RUN FAILED OR ABORTED \ No newline at end of file diff --git a/tests/reporter/custom-reporter.js b/tests/reporter/custom-reporter.js new file mode 100644 index 0000000..3e3569d --- /dev/null +++ b/tests/reporter/custom-reporter.js @@ -0,0 +1,72 @@ +const fs = require('fs'); + +class CustomReporter { + onEnd(config, result) { + const outputPath = 'tests/output/latest-result.txt'; + + if (!result) { + // test run aborted or failed to initialize + if (!fs.existsSync('tests/output')) fs.mkdirSync('tests/output', { recursive: true }); + fs.writeFileSync(outputPath, 'TEST RUN FAILED OR ABORTED', 'utf-8'); + return; + } + + const failed = result.status === 'failed' || result.numFailedTests > 0; + + const date = new Date().toISOString(); + const duration = (result.duration || 0) + 'ms'; + + if (!fs.existsSync('tests/output')) fs.mkdirSync('tests/output', { recursive: true }); + + if (!failed) { + const content = [ + '==================================', + 'TEST RESULT', + 'PASSED', + `Date: ${date}`, + `Total Test: ${result.total || 0}`, + `Passed: ${result.passed || 0}`, + `Failed: ${result.failed || 0}`, + `Duration: ${duration}`, + '==================================', + ].join('\n'); + + fs.writeFileSync(outputPath, content, 'utf-8'); + return; + } + + const lines = []; + lines.push('=================================='); + lines.push('FAILED'); + lines.push(`Date: ${date}`); + lines.push(`Duration: ${duration}`); + lines.push('=================================='); + + const buildFailureDetails = (suites) => { + for (const s of suites) { + if (s.suites && s.suites.length) buildFailureDetails(s.suites); + if (s.tests && s.tests.length) { + for (const t of s.tests) { + if (t.status === 'failed') { + lines.push('Test Name: ' + (t.title || t.titleText || '')); + for (const r of t.results || []) { + if (r.status === 'failed') { + const error = r.error || {}; + lines.push('Error Message: ' + (error.message || '')); + if (error.stack) lines.push('Stack Trace: ' + error.stack); + } + } + lines.push('----------------------------------'); + } + } + } + } + }; + + if (result.suites) buildFailureDetails(result.suites); + + fs.writeFileSync(outputPath, lines.join('\n'), 'utf-8'); + } +} + +module.exports = CustomReporter; diff --git a/tests/reporter/custom-reporter.ts b/tests/reporter/custom-reporter.ts new file mode 100644 index 0000000..fff0d6a --- /dev/null +++ b/tests/reporter/custom-reporter.ts @@ -0,0 +1,78 @@ +import fs from 'fs'; +import { FullConfig, Reporter, Suite, TestCase, TestError } from '@playwright/test/reporter'; + +class CustomReporter implements Reporter { + onEnd(config: FullConfig, result: any) { + const outputPath = 'tests/output/latest-result.txt'; + + const allTests = result.suites || []; + + const failed = result.status === 'failed' || result.numFailedTests > 0; + + const date = new Date().toISOString(); + const duration = (result.duration || 0) + 'ms'; + + if (!fs.existsSync('tests/output')) fs.mkdirSync('tests/output', { recursive: true }); + + if (!failed) { + const content = [ + '==================================', + 'TEST RESULT', + 'PASSED', + `Date: ${date}`, + `Total Test: ${result.total || 0}`, + `Passed: ${result.passed || 0}`, + `Failed: ${result.failed || 0}`, + `Duration: ${duration}`, + '==================================', + ].join('\n'); + + fs.writeFileSync(outputPath, content, 'utf-8'); + return; + } + + // Failed: build detailed report + const lines: string[] = []; + lines.push('=================================='); + lines.push('FAILED'); + lines.push(`Date: ${date}`); + lines.push(`Duration: ${duration}`); + lines.push('=================================='); + + for (const res of result.report || []) { + // older Playwright may not provide report; fallback to result.annotations + } + + // Walk tests + const buildFailureDetails = (suites: any[]) => { + for (const s of suites) { + if (s.suites && s.suites.length) buildFailureDetails(s.suites); + if (s.tests && s.tests.length) { + for (const t of s.tests) { + if (t.status === 'failed') { + lines.push('Test Name: ' + t.title.join(' > ')); + // try extract location + const location = t.location ? `${t.location.file}:${t.location.line}` : ''; + if (location) lines.push('Location: ' + location); + for (const r of t.results || []) { + if (r.status === 'failed') { + const error = r.error as TestError | undefined; + lines.push('Error Message: ' + (error?.message || '')); + if (r.stdout && r.stdout.length) lines.push('Stdout: ' + r.stdout.join('\n')); + if (error?.stack) lines.push('Stack Trace: ' + error.stack); + } + } + lines.push('----------------------------------'); + } + } + } + } + }; + + if (result.suites) buildFailureDetails(result.suites); + + fs.writeFileSync(outputPath, lines.join('\n'), 'utf-8'); + } +} + +export default CustomReporter; diff --git a/tests/test-artifacts/failed-login-1785604157244-cookies.json b/tests/test-artifacts/failed-login-1785604157244-cookies.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/tests/test-artifacts/failed-login-1785604157244-cookies.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/tests/test-artifacts/failed-login-1785604157244-page.html b/tests/test-artifacts/failed-login-1785604157244-page.html new file mode 100644 index 0000000..fd764ba --- /dev/null +++ b/tests/test-artifacts/failed-login-1785604157244-page.html @@ -0,0 +1 @@ +

{"message":"Cannot GET /","error":"Not Found","statusCode":404}
\ No newline at end of file diff --git a/tests/test-artifacts/failed-login-1785604157244.png b/tests/test-artifacts/failed-login-1785604157244.png new file mode 100644 index 0000000000000000000000000000000000000000..2a575385ef70d9bf701f0792fa510d524ec5fbbf GIT binary patch literal 6969 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 literal 0 HcmV?d00001 diff --git a/tests/test-artifacts/failed-login-2-1785604169592-cookies.json b/tests/test-artifacts/failed-login-2-1785604169592-cookies.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/tests/test-artifacts/failed-login-2-1785604169592-cookies.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/tests/test-artifacts/failed-login-2-1785604169592-page.html b/tests/test-artifacts/failed-login-2-1785604169592-page.html new file mode 100644 index 0000000..fd764ba --- /dev/null +++ b/tests/test-artifacts/failed-login-2-1785604169592-page.html @@ -0,0 +1 @@ +
{"message":"Cannot GET /","error":"Not Found","statusCode":404}
\ No newline at end of file diff --git a/tests/test-artifacts/failed-login-2-1785604169592.png b/tests/test-artifacts/failed-login-2-1785604169592.png new file mode 100644 index 0000000000000000000000000000000000000000..2a575385ef70d9bf701f0792fa510d524ec5fbbf GIT binary patch literal 6969 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 literal 0 HcmV?d00001 diff --git a/tests/unit/user.service.spec.ts b/tests/unit/user.service.spec.ts new file mode 100644 index 0000000..d8ad0a1 --- /dev/null +++ b/tests/unit/user.service.spec.ts @@ -0,0 +1,41 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { UserService } from '../../src/modules/identity/application/services/user.service'; +import { PrismaService } from '../../src/shared/prisma.service'; +import { IUser } from '../../src/modules/identity/domain/repositories/user.interface'; + +describe('UserService', () => { + let service: UserService; + let prisma: Partial; + let userRepo: Partial; + + beforeEach(async () => { + prisma = { + user: { + update: jest.fn().mockResolvedValue(null), + findMany: jest.fn().mockResolvedValue([]), + }, + } as any; + + userRepo = { + create: jest.fn().mockImplementation(async (user) => { + return { ...user, id: 'user-1' }; + }), + getById: jest.fn().mockResolvedValue({ id: 'user-1', username: 'u', email: 'e' }), + existByEmail: jest.fn().mockResolvedValue(false), + } as any; + + const module: TestingModule = await Test.createTestingModule({ + providers: [ + UserService, + { provide: PrismaService, useValue: prisma }, + { provide: IUser, useValue: userRepo }, + ], + }).compile(); + + service = module.get(UserService); + }); + + it('createUser - provisioning disabled', async () => { + await expect(service.createUser({ username: 'u', email: 'e' })).rejects.toThrow(); + }); +});