From 785623fcbbc08cbdfaea1fd22184e2e1d9895e46 Mon Sep 17 00:00:00 2001 From: Abubeker Yasin Date: Wed, 3 Jun 2026 10:12:08 +0300 Subject: [PATCH] refactor: ( passenger-api.auth ) remove the existing auth module --- apps/edr-passenger-api/package.json | 4 +- apps/edr-passenger-api/src/app.module.ts | 31 ++-- .../edr-passenger-api/src/common/jwt.guard.ts | 9 +- .../modules/verifayda/optional-jwt.guard.ts | 37 +++-- .../modules/verifayda/verifayda.controller.ts | 17 +-- .../src/modules/verifayda/verifayda.module.ts | 5 +- .../verifayda/verifayda.service.spec.ts | 61 +++----- .../modules/verifayda/verifayda.service.ts | 19 +-- pnpm-lock.yaml | 141 ++++++++++++++++-- 9 files changed, 209 insertions(+), 115 deletions(-) diff --git a/apps/edr-passenger-api/package.json b/apps/edr-passenger-api/package.json index 4102fc619..531a64bfd 100644 --- a/apps/edr-passenger-api/package.json +++ b/apps/edr-passenger-api/package.json @@ -36,8 +36,8 @@ "@nestjs/swagger": "^7.4.0", "@nestjs/typeorm": "^11.0.1", "@sendgrid/mail": "^8.1.0", - "@tria-plc/api-common": "^0.1.4", - "@tria-plc/iamapi-common": "^0.1.6", + "@tria-plc/api-common": "1.2.3", + "@tria-plc/iamapi-common": "^0.4.1", "amqp-connection-manager": "^5.0.0", "amqplib": "^2.0.1", "axios": "^1.7.7", diff --git a/apps/edr-passenger-api/src/app.module.ts b/apps/edr-passenger-api/src/app.module.ts index 6e76d0e84..aa476f1c8 100644 --- a/apps/edr-passenger-api/src/app.module.ts +++ b/apps/edr-passenger-api/src/app.module.ts @@ -1,4 +1,9 @@ -import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common'; +import { + MiddlewareConsumer, + Module, + NestModule, + OnApplicationBootstrap, +} from '@nestjs/common'; import { ConfigModule, ConfigService } from '@nestjs/config'; import { ScheduleModule } from '@nestjs/schedule'; import { EventEmitterModule } from '@nestjs/event-emitter'; @@ -6,6 +11,7 @@ import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm'; // Subpath import: the @tria-plc/iamapi-common barrel does not resolve under moduleResolution:"Node". // Aliased to avoid clashing with the app's existing custom ./common/iam.module (remote IamGuard). import { IamModule as TriaIamModule } from '@tria-plc/iamapi-common/iam.module'; +import { DataSeeder } from '@tria-plc/iamapi-common/db/seed/seeder'; import { PrismaModule } from './common/prisma.module'; import { I18nModule } from './common/i18n/i18n.module'; import { LocaleMiddleware } from './common/i18n/locale.middleware'; @@ -18,7 +24,6 @@ import ebirrConfig from './config/ebirr.config'; import cardConfig from './config/card.config'; import waafiConfig from './config/waafi.config'; import faydaConfig from './config/fayda.config'; -import { AuthModule } from './modules/auth/auth.module'; import { StationsModule } from './modules/stations/stations.module'; import { FleetModule } from './modules/fleet/fleet.module'; import { SchedulesModule } from './modules/schedules/schedules.module'; @@ -61,22 +66,14 @@ import { VerifaydaModule } from './modules/verifayda/verifayda.module'; }), ScheduleModule.forRoot(), EventEmitterModule.forRoot(), - // TypeORM root DataSource for the shared `iam` schema (coexists with Prisma's `passenger` - // schema). Required so @tria-plc/api-common's JwtGuard can read `iam.sessions`, and so - // IamModule's forFeature repositories resolve. Options come from the `database` config - // namespace (see config/database.config.ts → iam-typeorm.config.ts). TypeOrmModule.forRootAsync({ inject: [ConfigService], useFactory: (config: ConfigService): TypeOrmModuleOptions => config.get('iamDatabase')!, }), - // Mount the @tria-plc IAM module (auth/user/org-structure). Registers the IAM REST API under - // /v1/* (URI versioning). NOTE: SharedAuthModule (global JwtGuard) is intentionally added later - // in the route-protection phase, so public passenger routes are not 401'd before then. TriaIamModule.forRoot(), PrismaModule, I18nModule, - // AuthModule, StationsModule, FleetModule, SchedulesModule, @@ -102,8 +99,16 @@ import { VerifaydaModule } from './modules/verifayda/verifayda.module'; VerifaydaModule, ], }) -export class AppModule implements NestModule { - configure(consumer: MiddlewareConsumer) { - consumer.apply(LocaleMiddleware).forRoutes('*'); +export class AppModule implements OnApplicationBootstrap { + constructor( + private readonly seeder: DataSeeder, + // private readonly edrOrgSeeder: EdrOrgSeeder, + // private readonly demoUsersSeeder: DemoUsersSeeder, + ) { } + + async onApplicationBootstrap() { + await this.seeder.run(); + // await this.edrOrgSeeder.run(); + // await this.demoUsersSeeder.run(); } } diff --git a/apps/edr-passenger-api/src/common/jwt.guard.ts b/apps/edr-passenger-api/src/common/jwt.guard.ts index f65f8455d..dfdeed190 100644 --- a/apps/edr-passenger-api/src/common/jwt.guard.ts +++ b/apps/edr-passenger-api/src/common/jwt.guard.ts @@ -1,5 +1,4 @@ -import { Injectable } from '@nestjs/common'; -import { AuthGuard } from '@nestjs/passport'; - -@Injectable() -export class JwtGuard extends AuthGuard('jwt') {} +// Compatibility alias while passenger auth moves to @tria-plc IAM. +// Existing controllers can keep importing `../../common/jwt.guard`, but the +// guard now validates IAM-issued session tokens from `iam.sessions`. +export { JwtGuard } from '@tria-plc/api-common/modules/auth/services/jwt.guard'; diff --git a/apps/edr-passenger-api/src/modules/verifayda/optional-jwt.guard.ts b/apps/edr-passenger-api/src/modules/verifayda/optional-jwt.guard.ts index 5f5fac19b..8673aa60e 100644 --- a/apps/edr-passenger-api/src/modules/verifayda/optional-jwt.guard.ts +++ b/apps/edr-passenger-api/src/modules/verifayda/optional-jwt.guard.ts @@ -1,21 +1,30 @@ -import { Injectable } from '@nestjs/common'; -import { AuthGuard } from '@nestjs/passport'; +import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; +import { Reflector } from '@nestjs/core'; +import { InjectDataSource } from '@nestjs/typeorm'; +import { JwtGuard as IamJwtGuard } from '@tria-plc/api-common/modules/auth/services/jwt.guard'; +import { DataSource } from 'typeorm'; /** - * Like {@link JwtGuard}, but never rejects the request. + * Like the IAM JwtGuard, but never rejects the request. * - * When a valid `Authorization: Bearer ` is present, `request.user` is - * populated from the JWT strategy (`{ userId, ... }`). When the token is - * missing or invalid, the request still proceeds with `request.user` - * undefined — the handler decides what to do. - * - * Used on `POST /fayda/verification/start`, which must work for both - * logged-in users (who can opt to save the verification to their account) - * and guests (anchored to a booking only). + * When a valid IAM bearer token is present, `request.user` is populated with + * the package `TCurrentUser`. Missing or invalid tokens continue as guests. */ @Injectable() -export class OptionalJwtGuard extends AuthGuard('jwt') { - handleRequest(_err: unknown, user: TUser): TUser { - return (user ?? null) as TUser; +export class OptionalJwtGuard extends IamJwtGuard implements CanActivate { + constructor( + reflector: Reflector, + @InjectDataSource() dataSource: DataSource, + ) { + super(reflector, dataSource); + } + + async canActivate(context: ExecutionContext): Promise { + try { + await super.canActivate(context); + } catch { + context.switchToHttp().getRequest().user = undefined; + } + return true; } } diff --git a/apps/edr-passenger-api/src/modules/verifayda/verifayda.controller.ts b/apps/edr-passenger-api/src/modules/verifayda/verifayda.controller.ts index f1eb25e8e..4c63736df 100644 --- a/apps/edr-passenger-api/src/modules/verifayda/verifayda.controller.ts +++ b/apps/edr-passenger-api/src/modules/verifayda/verifayda.controller.ts @@ -15,6 +15,7 @@ import { ApiOperation, ApiTags, } from '@nestjs/swagger'; +import type { TCurrentUser } from '@tria-plc/api-common/modules/auth/types/current-user.type'; import { JwtGuard } from '../../common/jwt.guard'; import { OptionalJwtGuard } from './optional-jwt.guard'; import { @@ -25,21 +26,13 @@ import { } from './verifayda.dto'; import { VerifaydaService } from './verifayda.service'; -/** Shape the JWT strategy puts on `request.user` (see common/jwt.strategy.ts). */ -interface AuthedUser { - userId: string; - email?: string; - role?: string; - passengerId?: string; -} - /** Minimal slices of the Express req we touch (avoids a hard dependency on * `@types/express`, which isn't resolved in this package). */ interface RequestWithOptionalUser { - user?: AuthedUser; + user?: TCurrentUser; } interface RequestWithUser { - user: AuthedUser; + user: TCurrentUser; } @ApiTags('Fayda Verification') @@ -75,7 +68,7 @@ export class VerifaydaController { const authorizationUrl = await this.service.startVerification({ purpose: dto.purpose ?? 'PURCHASE', platform: dto.platform ?? 'WEB', - userId: req.user?.userId, + userId: req.user?.id, bookingId: dto.bookingId, saveToAccount: dto.saveToAccount, }); @@ -106,6 +99,6 @@ export class VerifaydaController { async status( @Req() req: RequestWithUser, ): Promise { - return this.service.getVerificationStatus(req.user.userId); + return this.service.getVerificationStatus(req.user.id); } } diff --git a/apps/edr-passenger-api/src/modules/verifayda/verifayda.module.ts b/apps/edr-passenger-api/src/modules/verifayda/verifayda.module.ts index d850b1dbf..e54b94726 100644 --- a/apps/edr-passenger-api/src/modules/verifayda/verifayda.module.ts +++ b/apps/edr-passenger-api/src/modules/verifayda/verifayda.module.ts @@ -2,12 +2,9 @@ import { Module } from '@nestjs/common'; import { VerifaydaController } from './verifayda.controller'; import { VerifaydaService } from './verifayda.service'; import { PrismaModule } from '../../common/prisma.module'; -import { AuthModule } from '../auth/auth.module'; @Module({ - // AuthModule re-exports JwtModule, giving us JwtService (same secret/expiry - // config as /auth/login) to mint tokens for the LOGIN flow. - imports: [PrismaModule, AuthModule], + imports: [PrismaModule], controllers: [VerifaydaController], providers: [VerifaydaService], exports: [VerifaydaService], diff --git a/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.spec.ts b/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.spec.ts index e4b8cb790..4d4695c61 100644 --- a/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.spec.ts +++ b/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.spec.ts @@ -1,5 +1,4 @@ import { ConfigService } from '@nestjs/config'; -import { JwtService } from '@nestjs/jwt'; import { exportJWK, generateKeyPair, type JWK } from 'jose'; import { PrismaService } from '../../common/prisma.service'; import { FaydaConfig } from '../../config/fayda.config'; @@ -30,12 +29,6 @@ function buildPrismaMock() { }; } -function buildJwtMock(): jest.Mocked { - return { - sign: jest.fn(() => 'signed.jwt.token'), - } as unknown as jest.Mocked; -} - function buildConfig(overrides?: Partial): FaydaConfig { return { enabled: true, @@ -65,7 +58,6 @@ function buildConfigService(faydaConfig: FaydaConfig): jest.Mocked { let prisma: ReturnType; - let jwt: jest.Mocked; let service: VerifaydaService; let realPrivateJwk: JWK; @@ -77,12 +69,10 @@ describe('VerifaydaService (OIDC, client-callback)', () => { beforeEach(() => { prisma = buildPrismaMock(); - jwt = buildJwtMock(); const cfg = buildConfig({ privateJwk: realPrivateJwk as FaydaConfig['privateJwk'] }); service = new VerifaydaService( buildConfigService(cfg), prisma as unknown as PrismaService, - jwt, ); (global as any).fetch = jest.fn(); }); @@ -136,7 +126,6 @@ describe('VerifaydaService (OIDC, client-callback)', () => { const disabledService = new VerifaydaService( buildConfigService(buildConfig({ enabled: false })), prisma as unknown as PrismaService, - jwt, ); await expect( disabledService.startVerification({ purpose: 'PURCHASE' }), @@ -433,7 +422,7 @@ describe('VerifaydaService (OIDC, client-callback)', () => { prisma.faydaVerificationSession.findUnique.mockResolvedValue(loginSession()); }); - it('creates a new user when no match and returns { token, user }', async () => { + it('creates a new user but rejects legacy local token issuance', async () => { const fullUser = { id: 'new-user', email: 'new@example.com', @@ -452,17 +441,12 @@ describe('VerifaydaService (OIDC, client-callback)', () => { mockLoginFetch({ sub: 'login-sub-1', name: 'New Person', email: 'new@example.com' }); - const result = await service.completeVerification({ - code: 'c', - state: 'state-login', - }); - - expect(result).toMatchObject({ - purpose: 'LOGIN', - verified: true, - token: 'signed.jwt.token', - user: { id: 'new-user', passengerId: 'p-new' }, - }); + await expect( + service.completeVerification({ + code: 'c', + state: 'state-login', + }), + ).rejects.toMatchObject({ status: 401 }); expect(prisma.user.create).toHaveBeenCalledWith( expect.objectContaining({ data: expect.objectContaining({ @@ -473,12 +457,9 @@ describe('VerifaydaService (OIDC, client-callback)', () => { }), ); expect(prisma.passenger.create).toHaveBeenCalled(); - expect(jwt.sign).toHaveBeenCalledWith( - expect.objectContaining({ sub: 'new-user', passengerId: 'p-new' }), - ); }); - it('logs in an existing user already linked by faydaSub', async () => { + it('resolves an existing linked user but rejects legacy local token issuance', async () => { const fullUser = { id: 'known-user', email: 'k@example.com', @@ -491,16 +472,16 @@ describe('VerifaydaService (OIDC, client-callback)', () => { mockLoginFetch({ sub: 'login-sub-2', name: 'Known' }); - const result = await service.completeVerification({ - code: 'c', - state: 'state-login', - }); - - expect(result.user?.id).toBe('known-user'); + await expect( + service.completeVerification({ + code: 'c', + state: 'state-login', + }), + ).rejects.toMatchObject({ status: 401 }); expect(prisma.user.create).not.toHaveBeenCalled(); }); - it('links Fayda to an existing account matched by email', async () => { + it('links Fayda to an existing account matched by email but rejects legacy local token issuance', async () => { const fullUser = { id: 'acc-1', email: 'match@example.com', @@ -515,12 +496,12 @@ describe('VerifaydaService (OIDC, client-callback)', () => { mockLoginFetch({ sub: 'login-sub-3', email: 'match@example.com' }); - const result = await service.completeVerification({ - code: 'c', - state: 'state-login', - }); - - expect(result.user?.id).toBe('acc-1'); + await expect( + service.completeVerification({ + code: 'c', + state: 'state-login', + }), + ).rejects.toMatchObject({ status: 401 }); expect(prisma.user.update).toHaveBeenCalledWith( expect.objectContaining({ where: { id: 'acc-1' }, diff --git a/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.ts b/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.ts index f7b3e77fb..1adb20fea 100644 --- a/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.ts +++ b/apps/edr-passenger-api/src/modules/verifayda/verifayda.service.ts @@ -6,7 +6,6 @@ import { UnauthorizedException, } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; -import { JwtService } from '@nestjs/jwt'; import axios, { AxiosInstance } from 'axios'; import * as bcrypt from 'bcrypt'; import { randomBytes } from 'crypto'; @@ -88,7 +87,6 @@ export class VerifaydaService { constructor( private readonly config: ConfigService, private readonly prisma: PrismaService, - private readonly jwt: JwtService, ) { const fayda = this.config.get('fayda'); if (!fayda) { @@ -274,16 +272,15 @@ export class VerifaydaService { passengerId: user.passenger?.id, agentId: user.agent?.id, }; - const token = this.jwt.sign({ - sub: summary.id, - email: summary.email, - role: summary.role, - passengerId: summary.passengerId, - agentId: summary.agentId, - }); - this.logger.log(`Fayda login issued token for user ${user.id}`); - return { token, user: summary }; + this.logger.warn( + `Legacy passenger Fayda login reached for user ${user.id}; use IAM /v1/auth Fayda login to issue tokens.`, + ); + throw new UnauthorizedException({ + code: 'FAYDA_LOGIN_MIGRATED_TO_IAM', + message: 'Fayda login tokens are issued by the IAM package auth endpoints.', + user: summary, + }); } async getVerificationStatus(userId: string): Promise { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 81135f520..a99424102 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -69,11 +69,11 @@ importers: specifier: ^8.1.0 version: 8.1.6 '@tria-plc/api-common': - specifier: ^0.1.4 - version: 0.1.4(296a75716ddf658d3d4f5879ef7db3cb) + specifier: 1.2.3 + version: 1.2.3(82de1fa22df14d2f8c974e73e7d5a000) '@tria-plc/iamapi-common': - specifier: ^0.1.6 - version: 0.1.6(efb6e02fa9b4108b3ff4c3ae477b6dad) + specifier: ^0.4.1 + version: 0.4.1(c31a38bece4d321b4fae6a2e7e5e96b1) amqp-connection-manager: specifier: ^5.0.0 version: 5.0.0(amqplib@2.0.1) @@ -1397,8 +1397,8 @@ packages: '@tokenizer/token@0.3.0': resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} - '@tria-plc/api-common@0.1.4': - resolution: {integrity: sha512-lm9esp5PDxUyggqxYXbx2CQhZKwtcAaAcGFuuUURw3u5DlzGUNwMOFkQkDLM/fbgN+33+s1RKC7UynnG9NZFww==, tarball: https://npm.pkg.github.com/download/@tria-plc/api-common/0.1.4/de160e4bb61a882efd9c877b4614028f1ffd7cb8} + '@tria-plc/api-common@1.2.3': + resolution: {integrity: sha512-J30YmV/IAZjoQAB8o0yvisUwhclOWDdkqmLfVpvRc142Cv4nFnpynms+rO6IXSWwqI8bXRJg4qa+XauUrwzu5A==, tarball: https://npm.pkg.github.com/download/@tria-plc/api-common/1.2.3/7910a45187963d4a40ac0f7a6ab802fc974b708e} peerDependencies: '@nestjs/common': ^11.0.0 '@nestjs/core': ^11.0.0 @@ -1408,13 +1408,13 @@ packages: '@nestjs/swagger': ^11.0.0 '@nestjs/throttler': ^6.0.0 '@nestjs/typeorm': ^11.0.0 - '@tria-plc/iamapi-common': '*' + '@tria-plc/iamapi-common': ^0.1.0 reflect-metadata: ^0.2.0 rxjs: ^7.8.0 typeorm: ^0.3.0 - '@tria-plc/iamapi-common@0.1.6': - resolution: {integrity: sha512-qaCLZ1TgbcQ5XciRuA/aZjRCM/GmGYgcmsyDDIlhiMNw3FL3DCiR/QiFuQpERvV4FqgQNBJg66+S/jXO3I2jbw==, tarball: https://npm.pkg.github.com/download/@tria-plc/iamapi-common/0.1.6/e2a8f3357b650bb9477facae4aaa7044382acebf} + '@tria-plc/iamapi-common@0.4.1': + resolution: {integrity: sha512-DnO9bCBGpo6wRt39zXzWuJG99qZ9yCy1x1DQOAs48G5Z9wwv/EYILXpb5dkoq/oV+c4If0UYSlKMnWQCv9RhVA==, tarball: https://npm.pkg.github.com/download/@tria-plc/iamapi-common/0.4.1/78c88f7322f9cb84a38941d94d1494b5ce6e2ddf} engines: {node: '>=20'} peerDependencies: '@nestjs/axios': ^4.0.0 @@ -1426,7 +1426,7 @@ packages: '@nestjs/swagger': ^11.0.0 '@nestjs/throttler': ^6.0.0 '@nestjs/typeorm': ^11.0.0 - '@tria-plc/api-common': ^0.1.0 + '@tria-plc/api-common': '*' axios: ^1.9.0 class-transformer: ^0.5.1 class-validator: ^0.14.1 @@ -2128,6 +2128,9 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + api-common@1.2.2: + resolution: {integrity: sha512-2A3NpFNlOOvPY8Vq+g8Pokj6PdMk8fJpg58JpI/QuSXeB9JrS4YbRgzdexPBnJIUCNDHnjr+7S1vOsRRctHzyw==} + app-root-path@3.1.0: resolution: {integrity: sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==} engines: {node: '>= 6.0.0'} @@ -2247,6 +2250,9 @@ packages: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} + async@2.6.4: + resolution: {integrity: sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==} + async@3.2.6: resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} @@ -2601,6 +2607,10 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + colors@1.0.3: + resolution: {integrity: sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==} + engines: {node: '>=0.1.90'} + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -2763,6 +2773,10 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + cycle@1.0.3: + resolution: {integrity: sha512-TVF6svNzeQCOpjCqsy0/CSy8VgObG3wXusJ73xW2GbG5rGx7lC8zxDSURicsXI2UsGdi2L0QNRCi745/wUDvsA==} + engines: {node: '>=0.4.0'} + d3-array@3.2.4: resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} engines: {node: '>=12'} @@ -3080,6 +3094,12 @@ packages: resolution: {integrity: sha512-VyjaKxUmeDX/m2lxm/aknsJ1GWDWUO2Ze2Ad8S1Pb9dykAm9TjSKp5CjrNyltYqZ5W/PO6TInAmO2/BfwMyT1g==} engines: {node: '>=0.10.0'} + error-tojson@0.0.1: + resolution: {integrity: sha512-zhtlVKgW0CgzltibgAlgi6oljh7L8k7jo61NuATFXodGMI2aiqAusW5FaiAtMcT8OLzdPkfhqh34I2XjxPI+Aw==} + + errors@0.3.0: + resolution: {integrity: sha512-/4VTzspBdKkY8DE7VnjGYdHaSZdnQqQyOwYv3o2lwaKLhTvQmVATmoUCvFIFLVrn5kJqDHZl5ZltOu1Bit8rvg==} + es-abstract@1.24.2: resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==} engines: {node: '>= 0.4'} @@ -3336,6 +3356,10 @@ packages: resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==} engines: {node: '>=0.10.0'} + eyes@0.1.8: + resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} + engines: {node: '> 0.1.90'} + falsey@0.3.2: resolution: {integrity: sha512-lxEuefF5MBIVDmE6XeqCdM4BWk1+vYmGZtkbKZ/VFcg6uBBw6fXNEbWmxCjDdQlFc9hy450nkiWwM3VAW6G1qg==} engines: {node: '>=0.10.0'} @@ -4072,6 +4096,9 @@ packages: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} + isstream@0.1.2: + resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} + istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} @@ -4347,6 +4374,9 @@ packages: jws@4.0.1: resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} + jwt-decode@2.2.0: + resolution: {integrity: sha512-86GgN2vzfUu7m9Wcj63iUkuDzFNYFVmjeDm2GzWpUk+opB0pEpMsw6ePCMrhYkumz2C1ihqtZzOMAg7FiXcNoQ==} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -4703,6 +4733,9 @@ packages: resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} + minimist@0.0.8: + resolution: {integrity: sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q==} + minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -4730,6 +4763,11 @@ packages: resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==} engines: {node: '>=0.10.0'} + mkdirp@0.5.1: + resolution: {integrity: sha512-SknJC52obPfGQPnjIkXbmA6+5H15E+fR+E4iR2oQ3zzCLbd7/ONua69R/Gw7AgkTLsRG+r5fzksYwWe1AgTyWA==} + deprecated: Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.) + hasBin: true + mkdirp@0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true @@ -5137,6 +5175,10 @@ packages: pkg-types@2.3.1: resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} + pkginfo@0.4.1: + resolution: {integrity: sha512-8xCNE/aT/EXKenuMDZ+xTVwkT8gsoHN2z/Q29l80u0ppGEXVvsKRzNMbtKhg8LS8k1tJLAHHylf6p4VFmP6XUQ==} + engines: {node: '>= 0.4.0'} + pluralize@8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} @@ -5601,6 +5643,9 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + short-id-gen@1.1.2: + resolution: {integrity: sha512-rIxGIHcAhbf8jCgB6LYTeFC8jXffu4m0g+SXTljxGLkNhlMAq4jgQYPxvURtIX+tyqAx8YXuuh7j1qDVxJSZIA==} + side-channel-list@1.0.1: resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} engines: {node: '>= 0.4'} @@ -5711,6 +5756,9 @@ packages: stable-hash@0.0.5: resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} + stack-trace@0.0.10: + resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} + stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} @@ -6397,6 +6445,15 @@ packages: wide-align@1.1.5: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + winston-daily-rotate-file@1.7.2: + resolution: {integrity: sha512-bUkpSyWuDZVD2L7Ci/JrH09sIeqpwhQvmDrIAJ9PhUaewIbv9FTDTCvFnE2AFIIfDcTm7+AKiEKK4EP5lRL3fg==} + peerDependencies: + winston: 2.x + + winston@2.4.7: + resolution: {integrity: sha512-vLB4BqzCKDnnZH9PHGoS2ycawueX4HLqENXQitvFHczhgW2vFpSOn31LZtVr1KU8YTw7DS4tM+cqyovxo8taVg==} + engines: {node: '>= 0.10.0'} + wmf@1.0.2: resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==} engines: {node: '>=0.8'} @@ -7690,7 +7747,7 @@ snapshots: '@tokenizer/token@0.3.0': {} - '@tria-plc/api-common@0.1.4(296a75716ddf658d3d4f5879ef7db3cb)': + '@tria-plc/api-common@1.2.3(82de1fa22df14d2f8c974e73e7d5a000)': dependencies: '@nestjs/axios': 4.0.1(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.16.1)(rxjs@7.8.2) '@nestjs/common': 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -7701,7 +7758,7 @@ snapshots: '@nestjs/swagger': 7.4.2(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) '@nestjs/throttler': 6.5.0(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(reflect-metadata@0.2.2) '@nestjs/typeorm': 11.0.1(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.30(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))) - '@tria-plc/iamapi-common': 0.1.6(efb6e02fa9b4108b3ff4c3ae477b6dad) + '@tria-plc/iamapi-common': 0.4.1(c31a38bece4d321b4fae6a2e7e5e96b1) argon2: 0.43.1 axios: 1.16.1 change-case: 5.4.4 @@ -7734,7 +7791,7 @@ snapshots: - debug - supports-color - '@tria-plc/iamapi-common@0.1.6(efb6e02fa9b4108b3ff4c3ae477b6dad)': + '@tria-plc/iamapi-common@0.4.1(c31a38bece4d321b4fae6a2e7e5e96b1)': dependencies: '@nestjs/axios': 4.0.1(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.16.1)(rxjs@7.8.2) '@nestjs/common': 11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -7745,7 +7802,8 @@ snapshots: '@nestjs/swagger': 7.4.2(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) '@nestjs/throttler': 6.5.0(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(reflect-metadata@0.2.2) '@nestjs/typeorm': 11.0.1(@nestjs/common@11.1.23(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.23)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.30(pg@8.21.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))) - '@tria-plc/api-common': 0.1.4(296a75716ddf658d3d4f5879ef7db3cb) + '@tria-plc/api-common': 1.2.3(82de1fa22df14d2f8c974e73e7d5a000) + api-common: 1.2.2 argon2: 0.43.1 axios: 1.16.1 class-transformer: 0.5.1 @@ -8495,6 +8553,17 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.2 + api-common@1.2.2: + dependencies: + error-tojson: 0.0.1 + errors: 0.3.0 + jwt-decode: 2.2.0 + moment: 2.30.1 + pkginfo: 0.4.1 + short-id-gen: 1.1.2 + winston: 2.4.7 + winston-daily-rotate-file: 1.7.2(winston@2.4.7) + app-root-path@3.1.0: {} append-field@1.0.0: {} @@ -8653,6 +8722,10 @@ snapshots: async-function@1.0.0: {} + async@2.6.4: + dependencies: + lodash: 4.18.1 + async@3.2.6: {} asynckit@0.4.0: {} @@ -9071,6 +9144,8 @@ snapshots: colorette@2.0.20: {} + colors@1.0.3: {} + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -9228,6 +9303,8 @@ snapshots: csstype@3.2.3: {} + cycle@1.0.3: {} + d3-array@3.2.4: dependencies: internmap: 2.0.3 @@ -9490,6 +9567,10 @@ snapshots: error-symbol@0.1.0: {} + error-tojson@0.0.1: {} + + errors@0.3.0: {} + es-abstract@1.24.2: dependencies: array-buffer-byte-length: 1.0.2 @@ -9949,6 +10030,8 @@ snapshots: transitivePeerDependencies: - supports-color + eyes@0.1.8: {} + falsey@0.3.2: dependencies: kind-of: 5.1.0 @@ -10719,6 +10802,8 @@ snapshots: isobject@3.0.1: {} + isstream@0.1.2: {} + istanbul-lib-coverage@3.2.2: {} istanbul-lib-instrument@5.2.1: @@ -11215,6 +11300,8 @@ snapshots: jwa: 2.0.1 safe-buffer: 5.2.1 + jwt-decode@2.2.0: {} + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -11545,6 +11632,8 @@ snapshots: dependencies: brace-expansion: 2.1.0 + minimist@0.0.8: {} + minimist@1.2.8: {} minio@7.1.3: @@ -11582,6 +11671,10 @@ snapshots: for-in: 1.0.2 is-extendable: 1.0.1 + mkdirp@0.5.1: + dependencies: + minimist: 0.0.8 + mkdirp@0.5.6: dependencies: minimist: 1.2.8 @@ -11990,6 +12083,8 @@ snapshots: exsolve: 1.0.8 pathe: 2.0.3 + pkginfo@0.4.1: {} + pluralize@8.0.0: {} pngjs@5.0.0: {} @@ -12481,6 +12576,8 @@ snapshots: shebang-regex@3.0.0: {} + short-id-gen@1.1.2: {} + side-channel-list@1.0.1: dependencies: es-errors: 1.3.0 @@ -12598,6 +12695,8 @@ snapshots: stable-hash@0.0.5: {} + stack-trace@0.0.10: {} + stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 @@ -13376,6 +13475,20 @@ snapshots: dependencies: string-width: 4.2.3 + winston-daily-rotate-file@1.7.2(winston@2.4.7): + dependencies: + mkdirp: 0.5.1 + winston: 2.4.7 + + winston@2.4.7: + dependencies: + async: 2.6.4 + colors: 1.0.3 + cycle: 1.0.3 + eyes: 0.1.8 + isstream: 0.1.2 + stack-trace: 0.0.10 + wmf@1.0.2: {} word-wrap@1.2.5: {}