@vritti/api-sdk 0.2.5 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/auth/auth-config.module.ts","../src/request/request.module.ts","../src/request/services/request.service.ts","../src/exceptions/bad-gateway.exception.ts","../src/exceptions/base-field.exception.ts","../src/exceptions/bad-request.exception.ts","../src/exceptions/conflict.exception.ts","../src/exceptions/forbidden.exception.ts","../src/exceptions/gone.exception.ts","../src/exceptions/internal-server-error.exception.ts","../src/exceptions/method-not-allowed.exception.ts","../src/exceptions/not-acceptable.exception.ts","../src/exceptions/not-found.exception.ts","../src/exceptions/not-implemented.exception.ts","../src/exceptions/payload-too-large.exception.ts","../src/exceptions/request-timeout.exception.ts","../src/exceptions/service-unavailable.exception.ts","../src/exceptions/too-many-requests.exception.ts","../src/exceptions/unauthorized.exception.ts","../src/exceptions/unprocessable-entity.exception.ts","../src/exceptions/unsupported-media-type.exception.ts","../src/exceptions/validation.exception.ts","../src/config/index.ts","../src/auth/guards/vritti-auth.guard.ts","../src/auth/decorators/require-session.decorator.ts","../src/auth/decorators/skip-csrf.decorator.ts","../src/auth/utils/token-hash.util.ts","../src/auth/services/jwt-auth.service.ts","../src/utils/time.utils.ts","../src/auth/jwt.config.ts","../src/auth/decorators/access-token.decorator.ts","../src/auth/decorators/cookie-domain.decorator.ts","../src/auth/decorators/public.decorator.ts","../src/auth/decorators/refresh-cookie-options.decorator.ts","../src/auth/decorators/refresh-token-cookie.decorator.ts","../src/auth/decorators/subdomain.decorator.ts","../src/auth/decorators/session-data.decorator.ts","../src/auth/decorators/user-id.decorator.ts","../src/cache/cache.module.ts","../src/cache/cache.service.ts","../src/cache/constants.ts","../src/cache/providers/redis.provider.ts","../src/database/database.module.ts","../src/database/constants.ts","../src/database/services/primary-database.service.ts","../src/decorators/uploaded-file.decorator.ts","../src/database/dto/create-response.dto.ts","../src/database/dto/import-response.dto.ts","../src/database/dto/select-options-query.dto.ts","../src/database/dto/success-response.dto.ts","../src/database/dto/table-response.dto.ts","../src/database/filter/filter.processor.ts","../src/database/repositories/primary-base.repository.ts","../src/email/email.module.ts","../src/email/email.service.ts","../src/filters/http-exception.filter.ts","../src/logger/interceptors/http-logger.interceptor.ts","../src/logger/services/logger.service.ts","../src/logger/utils/index.ts","../src/logger/logger.module.ts","../src/logger/middleware/correlation-id.middleware.ts","../src/root/root.module.ts","../src/root/controllers/app.controller.ts","../src/root/docs/app.docs.ts","../src/root/services/app.service.ts","../src/root/controllers/csrf.controller.ts","../src/root/docs/csrf.docs.ts","../src/utils/phone.utils.ts","../src/data-table/data-table.module.ts","../src/data-table/data-table.constants.ts","../src/data-table/state/controllers/data-table-state.controller.ts","../src/data-table/state/docs/data-table-state.docs.ts","../src/data-table/state/dto/request/upsert-data-table-state.dto.ts","../src/data-table/state/services/data-table-state.service.ts","../src/data-table/views/controllers/data-table-views.controller.ts","../src/data-table/views/docs/data-table-views.docs.ts","../src/data-table/views/dto/entity/data-table-view.dto.ts","../src/data-table/views/dto/request/create-data-table-view.dto.ts","../src/data-table/views/dto/request/rename-data-table-view.dto.ts","../src/data-table/views/dto/request/toggle-share-data-table-view.dto.ts","../src/data-table/views/dto/request/update-data-table-view.dto.ts","../src/data-table/views/services/data-table-views.service.ts","../src/data-table/views/repositories/data-table-views.repository.ts","../src/drizzle-pg-core.ts","../src/data-table/schema/data-table-views.table.ts"],"sourcesContent":["import { type DynamicModule, Global, Module } from '@nestjs/common';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\nimport { APP_GUARD, Reflector } from '@nestjs/core';\nimport { JwtModule } from '@nestjs/jwt';\nimport { RequestModule } from '../request/request.module';\nimport { VrittiAuthGuard } from './guards/vritti-auth.guard';\nimport { JwtAuthService } from './services/jwt-auth.service';\n\n@Global()\n@Module({})\nexport class AuthConfigModule {\n // Registers JWT and global VrittiAuthGuard with async config\n static forRootAsync(): DynamicModule {\n return {\n module: AuthConfigModule,\n imports: [\n ConfigModule,\n RequestModule,\n JwtModule.registerAsync({\n imports: [ConfigModule],\n inject: [ConfigService],\n useFactory: (config: ConfigService) => ({\n secret: config.get<string>('JWT_SECRET'),\n signOptions: {\n algorithm: 'HS256',\n },\n }),\n }),\n ],\n providers: [\n // Required for external packages - NestJS global Reflector not available\n {\n provide: Reflector,\n useClass: Reflector,\n },\n {\n provide: APP_GUARD,\n useClass: VrittiAuthGuard,\n },\n JwtAuthService,\n ],\n exports: [\n JwtModule, // Export for use in other modules (e.g., generating tokens)\n JwtAuthService,\n ],\n };\n }\n}\n","import { Global, Module } from '@nestjs/common';\nimport { RequestService } from './services/request.service';\n\n@Global()\n@Module({\n providers: [RequestService],\n exports: [RequestService],\n})\nexport class RequestModule {}\n","import { Inject, Injectable, Scope } from '@nestjs/common';\nimport { REQUEST } from '@nestjs/core';\nimport type { FastifyRequest } from 'fastify';\nimport { getConfig } from '../../config';\n\n@Injectable({ scope: Scope.REQUEST })\nexport class RequestService {\n constructor(@Inject(REQUEST) private readonly request: FastifyRequest) {}\n\n // Extracts tenant identifier from x-tenant-id or x-subdomain request header\n getTenantIdentifier(): string | null {\n const getHeader = (key: string) => {\n const value = this.request.headers?.[key];\n return Array.isArray(value) ? value[0] : value;\n };\n\n return getHeader('x-tenant-id') || getHeader('x-subdomain') || null;\n }\n\n // Extracts the bearer access token from the Authorization header\n getAccessToken(): string | null {\n const authHeader = this.request.headers?.authorization;\n if (!authHeader) {\n return null;\n }\n const [type, token] = authHeader.split(' ') ?? [];\n return type === 'Bearer' && token ? token : null;\n }\n\n // Extracts the refresh token from the configured httpOnly cookie\n getRefreshToken(): string | null {\n try {\n const cookies = (this.request as unknown as { cookies?: Record<string, string> }).cookies;\n if (cookies && typeof cookies === 'object') {\n const config = getConfig();\n const refreshToken = cookies[config.cookie.refreshCookieName];\n if (refreshToken) {\n return refreshToken;\n }\n }\n return null;\n } catch (_error: unknown) {\n return null;\n }\n }\n\n // Returns the value of a specific request header by key\n getHeader(key: string): string | string[] | undefined {\n return this.request.headers?.[key];\n }\n\n // Returns all request headers\n getAllHeaders(): FastifyRequest['headers'] {\n return this.request.headers || {};\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class BadGatewayException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Bad Gateway', HttpStatus.BAD_GATEWAY);\n }\n}\n","import { HttpException, HttpStatus } from '@nestjs/common';\nimport type { FieldError } from '../types/error-response.types';\n\n// Re-export FieldError for backwards compatibility\nexport type { FieldError } from '../types/error-response.types';\n\nexport interface ProblemOptions {\n type?: string;\n label?: string;\n detail?: string;\n errors?: FieldError[];\n}\n\nexport abstract class HttpProblemException extends HttpException {\n constructor(detailOrOptions: string | ProblemOptions, httpStatus: HttpStatus) {\n const options = typeof detailOrOptions === 'string' ? { detail: detailOrOptions } : detailOrOptions;\n\n super(\n {\n type: options.type ?? 'about:blank',\n label: options.label,\n detail: options.detail,\n errors: options.errors ?? [],\n },\n httpStatus,\n );\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class BadRequestException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Bad Request', HttpStatus.BAD_REQUEST);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class ConflictException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Conflict', HttpStatus.CONFLICT);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class ForbiddenException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Forbidden', HttpStatus.FORBIDDEN);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class GoneException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Gone', HttpStatus.GONE);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class InternalServerErrorException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Internal Server Error', HttpStatus.INTERNAL_SERVER_ERROR);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class MethodNotAllowedException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Method Not Allowed', HttpStatus.METHOD_NOT_ALLOWED);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class NotAcceptableException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Not Acceptable', HttpStatus.NOT_ACCEPTABLE);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class NotFoundException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Not Found', HttpStatus.NOT_FOUND);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class NotImplementedException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Not Implemented', HttpStatus.NOT_IMPLEMENTED);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class PayloadTooLargeException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Payload Too Large', HttpStatus.PAYLOAD_TOO_LARGE);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class RequestTimeoutException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Request Timeout', HttpStatus.REQUEST_TIMEOUT);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class ServiceUnavailableException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Service Unavailable', HttpStatus.SERVICE_UNAVAILABLE);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class TooManyRequestsException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Too Many Requests', HttpStatus.TOO_MANY_REQUESTS);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class UnauthorizedException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Unauthorized', HttpStatus.UNAUTHORIZED);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class UnprocessableEntityException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Unprocessable Entity', HttpStatus.UNPROCESSABLE_ENTITY);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class UnsupportedMediaTypeException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Unsupported Media Type', HttpStatus.UNSUPPORTED_MEDIA_TYPE);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class ValidationException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Validation Failed', HttpStatus.BAD_REQUEST);\n }\n}\n","import { UnauthorizedException } from '../exceptions';\n\nexport interface CookieConfig {\n refreshCookieName: string;\n refreshCookieMaxAge: number;\n refreshCookiePath: string;\n refreshCookieSecure: boolean;\n refreshCookieSameSite: 'strict' | 'lax' | 'none';\n refreshCookieDomain?: string;\n}\n\nexport interface CookieSerializeOptions {\n httpOnly: boolean;\n secure: boolean;\n sameSite: 'strict' | 'lax' | 'none';\n path: string;\n maxAge: number;\n domain: string;\n}\n\nexport interface JwtConfig {\n accessTokenExpiry: string;\n refreshTokenExpiry: string;\n onboardingTokenExpiry: string;\n\n}\n\nexport interface GuardConfig {\n tenantHeaderName: string;\n authHeaderName: string;\n tokenPrefix: string;\n defaultSessionTypes: string[];\n}\n\nexport interface ApiSdkConfig {\n cookie?: Partial<CookieConfig>;\n jwt?: Partial<JwtConfig>;\n guard?: Partial<GuardConfig>;\n}\n\nexport interface FullConfig {\n cookie: CookieConfig;\n jwt: JwtConfig;\n guard: GuardConfig;\n}\n\nconst defaultConfig: FullConfig = {\n cookie: {\n refreshCookieName: 'vritti_refresh',\n refreshCookieMaxAge: 30 * 24 * 60 * 60 * 1000, // 30 days\n refreshCookiePath: '/',\n refreshCookieSecure: process.env.NODE_ENV === 'production',\n refreshCookieSameSite: 'strict',\n refreshCookieDomain: 'localhost',\n },\n jwt: {\n accessTokenExpiry: '15m',\n refreshTokenExpiry: '30d',\n onboardingTokenExpiry: '24h',\n },\n guard: {\n tenantHeaderName: 'x-tenant-id',\n authHeaderName: 'authorization',\n tokenPrefix: 'Bearer',\n defaultSessionTypes: ['CLOUD'],\n },\n};\n\nlet currentConfig: FullConfig = { ...defaultConfig };\n\n// Helper to define configuration with type safety (similar to Tailwind's defineConfig)\nexport function defineConfig(config: ApiSdkConfig): ApiSdkConfig {\n return config;\n}\n\n// Configures api-sdk with user settings — call once in application bootstrap\nexport function configureApiSdk(userConfig: ApiSdkConfig): void {\n currentConfig = {\n cookie: {\n ...defaultConfig.cookie,\n ...(userConfig.cookie || {}),\n },\n jwt: {\n ...defaultConfig.jwt,\n ...(userConfig.jwt || {}),\n },\n guard: {\n ...defaultConfig.guard,\n ...(userConfig.guard || {}),\n },\n };\n}\n\n// Returns the current active configuration\nexport function getConfig(): FullConfig {\n return currentConfig;\n}\n\n// Resets configuration to defaults (for testing)\nexport function resetConfig(): void {\n currentConfig = { ...defaultConfig };\n}\n\n// Returns refresh cookie options built from the current configuration\nexport function getRefreshCookieOptions(): Omit<CookieSerializeOptions, 'domain'> & { domain?: string } {\n return {\n httpOnly: true,\n secure: currentConfig.cookie.refreshCookieSecure,\n sameSite: currentConfig.cookie.refreshCookieSameSite,\n path: currentConfig.cookie.refreshCookiePath,\n maxAge: currentConfig.cookie.refreshCookieMaxAge,\n ...(currentConfig.cookie.refreshCookieDomain && { domain: currentConfig.cookie.refreshCookieDomain }),\n };\n}\n\n// Returns refresh cookie options with domain set to the request hostname, validated against the configured base domain\nexport function getRefreshCookieOptionsForHost(hostname: string): CookieSerializeOptions {\n const baseDomain = currentConfig.cookie.refreshCookieDomain;\n\n if (!baseDomain) {\n throw new Error('refreshCookieDomain must be configured before using getRefreshCookieOptionsForHost');\n }\n\n if (!hostname.endsWith(`.${baseDomain}`)) {\n throw new UnauthorizedException('Invalid request host.');\n }\n\n return {\n httpOnly: true,\n secure: currentConfig.cookie.refreshCookieSecure,\n sameSite: currentConfig.cookie.refreshCookieSameSite,\n path: currentConfig.cookie.refreshCookiePath,\n maxAge: currentConfig.cookie.refreshCookieMaxAge,\n domain: hostname,\n };\n}\n\n// Returns JWT expiry settings for access, refresh, and onboarding tokens\nexport function getJwtExpiry() {\n return {\n access: currentConfig.jwt.accessTokenExpiry,\n refresh: currentConfig.jwt.refreshTokenExpiry,\n onboarding: currentConfig.jwt.onboardingTokenExpiry,\n };\n}\n","import {\n type CanActivate,\n type ExecutionContext,\n ForbiddenException,\n Injectable,\n Logger,\n Scope,\n UnauthorizedException,\n} from '@nestjs/common';\nimport { SSE_METADATA } from '@nestjs/common/constants';\nimport { ConfigService } from '@nestjs/config';\nimport { Reflector } from '@nestjs/core';\nimport { JwtService } from '@nestjs/jwt';\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport { getConfig } from '../../config';\nimport '../../types/fastify-augmentation';\nimport { RequestService } from '../../request/services/request.service';\nimport { REQUIRE_SESSION_KEY } from '../decorators/require-session.decorator';\nimport { SKIP_CSRF_KEY } from '../decorators/skip-csrf.decorator';\nimport { verifyTokenHash } from '../utils/token-hash.util';\n\ninterface DecodedToken {\n userId: string;\n sessionId: string;\n sessionType: string;\n tokenType: string;\n refreshTokenHash?: string;\n exp?: number;\n iat?: number;\n}\n\n@Injectable({ scope: Scope.REQUEST })\nexport class VrittiAuthGuard implements CanActivate {\n private readonly logger = new Logger(VrittiAuthGuard.name);\n\n constructor(\n private readonly reflector: Reflector,\n readonly _configService: ConfigService,\n private readonly jwtService: JwtService,\n private readonly requestService: RequestService,\n ) {}\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const request = context.switchToHttp().getRequest<FastifyRequest>();\n const reply = context.switchToHttp().getResponse<FastifyReply>();\n\n // Validate CSRF for state-changing methods (unless @SkipCsrf)\n const skipCsrf = this.reflector.getAllAndOverride<boolean>(SKIP_CSRF_KEY, [\n context.getHandler(),\n context.getClass(),\n ]);\n if (!skipCsrf) {\n await this.validateCsrf(request, reply);\n }\n\n // @Public() endpoints skip all auth\n const isPublic = this.reflector.getAllAndOverride<boolean>('isPublic', [context.getHandler(), context.getClass()]);\n if (isPublic) {\n return true;\n }\n\n // @RequireSession() restricts access to specific session types\n const requiredSessionTypes = this.reflector.getAllAndOverride<string[]>(REQUIRE_SESSION_KEY, [\n context.getHandler(),\n context.getClass(),\n ]);\n\n // SSE endpoints authenticate via refresh token cookie (EventSource cannot send Authorization headers)\n const isSseEndpoint = this.reflector.get<boolean>(SSE_METADATA, context.getHandler());\n if (isSseEndpoint) {\n return this.handleSseAuth(request, requiredSessionTypes);\n }\n\n try {\n const accessToken = this.requestService.getAccessToken();\n if (!accessToken) {\n throw new UnauthorizedException('Access token not found');\n }\n\n // Validate JWT signature and expiry\n const decodedAccessToken = this.validateAccessToken(accessToken);\n\n // Must be an ACCESS token, not REFRESH\n if (decodedAccessToken.tokenType !== 'access') {\n throw new UnauthorizedException('Invalid token type');\n }\n\n // Validate refresh token binding (hash check on every request)\n this.validateRefreshTokenBinding(decodedAccessToken);\n\n // Validate session type access\n const sessionType = decodedAccessToken.sessionType;\n const allowed = requiredSessionTypes ?? getConfig().guard.defaultSessionTypes;\n\n if (!allowed.includes(sessionType)) {\n throw new UnauthorizedException(`${sessionType} sessions cannot access this endpoint`);\n }\n\n // Attach session info to request\n request.sessionInfo = {\n userId: decodedAccessToken.userId,\n sessionId: decodedAccessToken.sessionId,\n sessionType: decodedAccessToken.sessionType,\n };\n\n return true;\n } catch (error) {\n if (error instanceof UnauthorizedException) {\n throw error;\n }\n this.logger.error('Unexpected error in auth guard', error);\n throw new UnauthorizedException('Authentication failed');\n }\n }\n\n // Validates JWT signature, expiry, and not-before claims\n private validateAccessToken(token: string): DecodedToken {\n try {\n return this.jwtService.verify<DecodedToken>(token);\n } catch (error: unknown) {\n if (error instanceof UnauthorizedException) throw error;\n\n const jwtError = error as { name?: string; message?: string };\n if (jwtError?.name === 'TokenExpiredError') {\n throw new UnauthorizedException('Access token has expired');\n }\n if (jwtError?.name === 'JsonWebTokenError') {\n throw new UnauthorizedException('Invalid access token');\n }\n if (jwtError?.name === 'NotBeforeError') {\n throw new UnauthorizedException('Access token not yet valid');\n }\n\n throw new UnauthorizedException('Access token validation failed');\n }\n }\n\n // Validates that the access token is bound to the refresh token in the cookie\n private validateRefreshTokenBinding(decodedAccessToken: DecodedToken): void {\n if (!decodedAccessToken.refreshTokenHash) {\n throw new UnauthorizedException('Token missing refresh token binding');\n }\n\n const refreshToken = this.requestService.getRefreshToken();\n\n if (!refreshToken) {\n throw new UnauthorizedException('Session validation failed');\n }\n\n if (!verifyTokenHash(refreshToken, decodedAccessToken.refreshTokenHash)) {\n throw new UnauthorizedException('Session validation failed');\n }\n }\n\n // Authenticates SSE connections using the refresh token httpOnly cookie\n private handleSseAuth(request: FastifyRequest, requiredSessionTypes?: string[]): boolean {\n const refreshToken = this.requestService.getRefreshToken();\n if (!refreshToken) {\n throw new UnauthorizedException('Authentication required');\n }\n\n let decoded: { userId: string; sessionId: string; sessionType: string; tokenType: string };\n try {\n decoded = this.jwtService.verify<{ userId: string; sessionId: string; sessionType: string; tokenType: string }>(refreshToken);\n } catch {\n throw new UnauthorizedException('Invalid or expired session');\n }\n\n if (decoded.tokenType !== 'refresh') {\n throw new UnauthorizedException('Invalid token type');\n }\n\n const allowed = requiredSessionTypes ?? getConfig().guard.defaultSessionTypes;\n if (!allowed.includes(decoded.sessionType)) {\n throw new UnauthorizedException(`${decoded.sessionType} sessions cannot access this endpoint`);\n }\n\n request.sessionInfo = {\n userId: decoded.userId,\n sessionId: decoded.sessionId,\n sessionType: decoded.sessionType,\n };\n\n return true;\n }\n\n // Validates CSRF token for state-changing requests\n private async validateCsrf(request: FastifyRequest, reply: FastifyReply): Promise<void> {\n const safeMethods = ['GET', 'HEAD', 'OPTIONS'];\n if (safeMethods.includes(request.method)) return;\n\n interface FastifyInstanceWithCsrf {\n csrfProtection?: (req: FastifyRequest, reply: FastifyReply, next: (err?: Error) => void) => void;\n }\n type PatchableReply = { send: (...args: unknown[]) => unknown };\n\n try {\n const fastifyInstance = request.server as unknown as FastifyInstanceWithCsrf;\n const csrfProtection = fastifyInstance.csrfProtection;\n if (!csrfProtection) {\n throw new ForbiddenException('CSRF protection not configured');\n }\n\n await new Promise<void>((resolve, reject) => {\n // Intercept reply.send to prevent the plugin from bypassing NestJS error handling\n const originalSend = reply.send.bind(reply);\n (reply as PatchableReply).send = () => {\n (reply as PatchableReply).send = originalSend as PatchableReply['send'];\n reject(new Error('CSRF validation failed'));\n return reply;\n };\n\n csrfProtection(request, reply, (err?: Error) => {\n (reply as PatchableReply).send = originalSend as PatchableReply['send'];\n if (err) reject(err);\n else resolve();\n });\n });\n } catch (error) {\n throw new ForbiddenException({\n errors: [{ field: 'csrf', message: 'Invalid or missing CSRF token' }],\n message: 'CSRF validation failed',\n });\n }\n }\n}\n","import { SetMetadata } from '@nestjs/common';\n\n// Restricts endpoint access to specific session types\nexport const REQUIRE_SESSION_KEY = 'requiredSessionTypes';\nexport const RequireSession = (...types: string[]) => SetMetadata(REQUIRE_SESSION_KEY, types);\n","import { SetMetadata } from '@nestjs/common';\n\nexport const SKIP_CSRF_KEY = 'skipCsrf';\n\nexport const SkipCsrf = () => SetMetadata(SKIP_CSRF_KEY, true);\n","import * as crypto from 'node:crypto';\n\n// Hashes a token using SHA-256\nexport function hashToken(token: string): string {\n return crypto.createHash('sha256').update(token).digest('hex');\n}\n\n// Verifies a token against its stored hash\nexport function verifyTokenHash(token: string, expectedHash: string): boolean {\n const computedHash = hashToken(token);\n if (computedHash.length !== expectedHash.length) return false;\n return crypto.timingSafeEqual(Buffer.from(computedHash, 'hex'), Buffer.from(expectedHash, 'hex'));\n}\n","import { Injectable, Logger } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { type JwtSignOptions, JwtService as NestJwtService } from '@nestjs/jwt';\nimport { parseExpiryToMs } from '../../utils/time.utils';\nimport { getTokenExpiry, type TokenExpiry, TokenType } from '../jwt.config';\nimport { hashToken } from '../utils/token-hash.util';\n\n@Injectable()\nexport class JwtAuthService {\n private readonly logger = new Logger(JwtAuthService.name);\n private readonly tokenExpiry: TokenExpiry;\n\n constructor(\n private readonly jwtService: NestJwtService,\n readonly configService: ConfigService,\n ) {\n this.tokenExpiry = getTokenExpiry(configService);\n }\n\n // Generates an access token bound to the given refresh token\n generateAccessToken(userId: string, sessionId: string, sessionType: string, refreshToken: string): string {\n return this.jwtService.sign(\n { sessionType, tokenType: TokenType.ACCESS, userId, sessionId, refreshTokenHash: hashToken(refreshToken) },\n { expiresIn: this.tokenExpiry.access },\n );\n }\n\n // Generates a refresh token for session persistence\n generateRefreshToken(userId: string, sessionId: string, sessionType: string): string {\n return this.jwtService.sign(\n { sessionType, tokenType: TokenType.REFRESH, userId, sessionId },\n { expiresIn: this.tokenExpiry.refresh },\n );\n }\n\n // Signs an arbitrary payload with optional JWT options\n sign(payload: object, options?: JwtSignOptions): string {\n return this.jwtService.sign(payload, options);\n }\n\n // Verifies a token and ensures it matches the expected token type\n verify(\n token: string,\n expectedType: TokenType,\n ): { userId: string; sessionId: string; sessionType: string; tokenType: TokenType } {\n try {\n const payload = this.jwtService.verify(token);\n\n if (payload.tokenType !== expectedType) {\n throw new Error(`Expected ${expectedType} token, got ${payload.tokenType}`);\n }\n\n return payload;\n } catch (error) {\n this.logger.error(`Failed to verify ${expectedType} token`, error);\n throw error;\n }\n }\n\n // Returns the expiry as a Date for the given token type\n getExpiryTime(type: TokenType): Date {\n return new Date(Date.now() + parseExpiryToMs(this.tokenExpiry[type]));\n }\n\n // Returns the token lifetime in seconds for the given type\n getExpiryInSeconds(type: TokenType): number {\n return Math.floor(parseExpiryToMs(this.tokenExpiry[type]) / 1000);\n }\n}\n","// Parses a duration string (e.g. '10m', '1h', '30s', '7d') to milliseconds\nexport function parseExpiryToMs(expiry: string): number {\n const match = expiry.match(/^(\\d+)([smhdwy])$/);\n if (!match) throw new Error(`Invalid expiry format: ${expiry}`);\n\n const value = Number.parseInt(match[1]!, 10);\n const multipliers: Record<string, number> = {\n s: 1000,\n m: 60_000,\n h: 3_600_000,\n d: 86_400_000,\n w: 604_800_000,\n y: 31_536_000_000,\n };\n\n return value * multipliers[match[2]!]!;\n}\n","import type { ConfigService } from '@nestjs/config';\nimport type { JwtModuleOptions } from '@nestjs/jwt';\n\nexport const jwtConfigFactory = (configService: ConfigService): JwtModuleOptions => ({\n secret: configService.getOrThrow<string>('JWT_SECRET'),\n signOptions: {\n issuer: 'vritti-api',\n },\n});\n\ntype TokenExpiryString = `${number}${'s' | 'm' | 'h' | 'd' | 'w' | 'y'}`;\n\nexport interface TokenExpiry {\n access: TokenExpiryString;\n refresh: TokenExpiryString;\n}\n\nexport const getTokenExpiry = (configService: ConfigService): TokenExpiry => ({\n access: configService.getOrThrow<string>('ACCESS_TOKEN_EXPIRY') as TokenExpiryString,\n refresh: configService.getOrThrow<string>('REFRESH_TOKEN_EXPIRY') as TokenExpiryString,\n});\n\nexport enum TokenType {\n ACCESS = 'access',\n REFRESH = 'refresh',\n}\n\n// sessionType typed as string — each server's enum is a valid subtype\nexport interface AccessTokenPayload {\n sessionType: string;\n tokenType: TokenType.ACCESS;\n userId: string;\n sessionId: string;\n refreshTokenHash: string;\n}\n\nexport interface RefreshTokenPayload {\n sessionType: string;\n tokenType: TokenType.REFRESH;\n userId: string;\n sessionId: string;\n}\n","import { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport type { FastifyRequest } from 'fastify';\n\n// Extracts the bearer token from the Authorization header\nexport const AccessToken = createParamDecorator(\n (_data: unknown, ctx: ExecutionContext): string => {\n const request = ctx.switchToHttp().getRequest<FastifyRequest>();\n const authHeader = request.headers.authorization;\n return authHeader?.replace('Bearer ', '') || '';\n },\n);\n","import { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport type { FastifyRequest } from 'fastify';\nimport { getConfig } from '../../config';\n\n// Extracts the cookie domain from x-forwarded-host (injected by proxy), validated against baseDomain, falls back to baseDomain if invalid\nexport const CookieDomain = createParamDecorator(\n (_data: unknown, ctx: ExecutionContext): string => {\n const request = ctx.switchToHttp().getRequest<FastifyRequest>();\n const forwarded = request.headers['x-forwarded-host'];\n const raw = Array.isArray(forwarded) ? forwarded[0] : forwarded;\n const hostStr = raw ?? request.hostname;\n const domain = hostStr.split(':')[0] ?? hostStr;\n const baseDomain = getConfig().cookie.refreshCookieDomain ?? '';\n return domain.endsWith(`.${baseDomain}`) ? domain : baseDomain;\n },\n);\n","import { SetMetadata } from '@nestjs/common';\n\nexport const Public = () => SetMetadata('isPublic', true);\n","import { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport type { FastifyRequest } from 'fastify';\nimport { type CookieSerializeOptions, getRefreshCookieOptionsForHost } from '../../config';\n\n// Returns refresh cookie options with domain scoped to the request subdomain (reads x-forwarded-host injected by proxy)\nexport const RefreshCookieOptions = createParamDecorator(\n (_data: unknown, ctx: ExecutionContext): CookieSerializeOptions => {\n const request = ctx.switchToHttp().getRequest<FastifyRequest>();\n const forwarded = request.headers['x-forwarded-host'];\n const raw = Array.isArray(forwarded) ? forwarded[0] : forwarded;\n const hostStr = raw ?? request.hostname;\n const domain = hostStr.split(':')[0] ?? hostStr;\n return getRefreshCookieOptionsForHost(domain);\n },\n);\n","import { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport type { FastifyRequest } from 'fastify';\nimport { getConfig } from '../../config';\n\nexport const RefreshTokenCookie = createParamDecorator(\n (_data: unknown, ctx: ExecutionContext): string | undefined => {\n const request = ctx.switchToHttp().getRequest<FastifyRequest>();\n const cookies = request.cookies ?? {};\n const config = getConfig();\n return cookies[config.cookie.refreshCookieName] as string | undefined;\n },\n);\n","import { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport type { FastifyRequest } from 'fastify';\n\n// Extracts the subdomain from the request's origin or x-forwarded-host header\nexport const Subdomain = createParamDecorator((_data: unknown, ctx: ExecutionContext): string | undefined => {\n const request = ctx.switchToHttp().getRequest<FastifyRequest>();\n\n // Try origin header first (browser always sends this on cross-origin requests)\n const origin = request.headers.origin;\n if (origin) {\n try {\n const url = new URL(origin);\n return url.hostname.split('.')[0];\n } catch {\n // Invalid origin, fall through\n }\n }\n\n // Fallback to x-forwarded-host (set by rsbuild proxy and production reverse proxies)\n const forwarded = request.headers['x-forwarded-host'];\n const host = Array.isArray(forwarded) ? forwarded[0] : forwarded;\n if (host) return host.split('.')[0];\n\n return undefined;\n});\n","import { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport type { FastifyRequest } from 'fastify';\nimport '../../types/fastify-augmentation';\n\nexport interface SessionInfo {\n userId: string;\n sessionId: string;\n sessionType: string;\n}\n\n// Returns full decoded session info from request.sessionInfo (set by VrittiAuthGuard)\nexport const SessionData = createParamDecorator(\n (_data: unknown, ctx: ExecutionContext): SessionInfo => {\n const request = ctx.switchToHttp().getRequest<FastifyRequest>();\n const sessionInfo = request.sessionInfo;\n\n if (!sessionInfo?.sessionId) {\n throw new Error('Session info not found on request. Ensure route is protected by auth guard.');\n }\n\n return {\n userId: sessionInfo.userId,\n sessionId: sessionInfo.sessionId,\n sessionType: sessionInfo.sessionType,\n };\n },\n);\n","import { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport type { FastifyRequest } from 'fastify';\nimport '../../types/fastify-augmentation';\n\n// Extracts userId from request.sessionInfo (set by VrittiAuthGuard)\nexport const UserId = createParamDecorator(\n (_data: unknown, ctx: ExecutionContext): string => {\n const request = ctx.switchToHttp().getRequest<FastifyRequest>();\n const sessionInfo = request.sessionInfo;\n\n if (!sessionInfo?.userId) {\n throw new Error('User ID not found on request. Ensure route is protected by auth guard.');\n }\n\n return sessionInfo.userId;\n },\n);\n","import { Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';\nimport { CacheService } from './cache.service';\nimport { CACHE_PROVIDER } from './constants';\nimport { RedisCacheProvider } from './providers/redis.provider';\n\n// To add a new provider in the future:\n// 1. Create providers/memcached.provider.ts implementing ICacheProvider\n// 2. Replace RedisCacheProvider with the new class in useExisting below\n\n@Module({\n imports: [ConfigModule],\n providers: [\n RedisCacheProvider,\n {\n provide: CACHE_PROVIDER,\n useExisting: RedisCacheProvider,\n },\n CacheService,\n ],\n exports: [RedisCacheProvider, CACHE_PROVIDER, CacheService],\n})\nexport class CacheModule {}\n","import { Inject, Injectable, Logger } from '@nestjs/common';\nimport { CACHE_PROVIDER } from './constants';\nimport type { ICacheProvider } from './interfaces/cache-provider.interface';\n\n@Injectable()\nexport class CacheService {\n private readonly logger = new Logger(CacheService.name);\n\n constructor(@Inject(CACHE_PROVIDER) private readonly provider: ICacheProvider) {}\n\n // Stores a value with mandatory TTL — errors are logged and swallowed so DB writes still succeed\n async set<T>(key: string, value: T, ttlSeconds: number): Promise<void> {\n try {\n await this.provider.set(key, value, ttlSeconds);\n } catch (err) {\n this.logger.error(`Cache set failed for key \"${key}\"`, err);\n }\n }\n\n // Returns cached value or null on miss or any Redis error — callers fall back to DB\n async get<T>(key: string): Promise<T | null> {\n try {\n return await this.provider.get<T>(key);\n } catch (err) {\n this.logger.error(`Cache get failed for key \"${key}\"`, err);\n return null;\n }\n }\n\n // Deletes one or more keys — errors are logged and swallowed\n async del(...keys: string[]): Promise<void> {\n try {\n await this.provider.del(...keys);\n } catch (err) {\n this.logger.error(`Cache del failed for keys \"${keys.join(', ')}\"`, err);\n }\n }\n\n // Returns all keys matching a glob pattern — returns empty array on error\n async scanKeys(pattern: string): Promise<string[]> {\n try {\n return await this.provider.scanKeys(pattern);\n } catch (err) {\n this.logger.error(`Cache scanKeys failed for pattern \"${pattern}\"`, err);\n return [];\n }\n }\n\n // Returns raw memory info from the provider — returns empty string on error\n async getMemoryInfo(): Promise<string> {\n try {\n return await this.provider.getMemoryInfo();\n } catch (err) {\n this.logger.error('Cache getMemoryInfo failed', err);\n return '';\n }\n }\n}\n","// Injection token for the active cache provider — use this to inject ICacheProvider\nexport const CACHE_PROVIDER = Symbol('CACHE_PROVIDER');\n","import { Injectable, Logger, OnModuleDestroy, OnModuleInit } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport Redis from 'ioredis';\nimport type { ICacheProvider } from '../interfaces/cache-provider.interface';\n\n@Injectable()\nexport class RedisCacheProvider implements ICacheProvider, OnModuleInit, OnModuleDestroy {\n private readonly logger = new Logger(RedisCacheProvider.name);\n private client!: Redis;\n\n constructor(private readonly configService: ConfigService) {}\n\n // Creates the ioredis client and attaches connection/error listeners\n onModuleInit(): void {\n const url = this.configService.getOrThrow<string>('REDIS_URL');\n this.client = new Redis(url, {\n lazyConnect: true,\n maxRetriesPerRequest: 3,\n });\n this.client.on('connect', () => this.logger.log('Redis connected'));\n this.client.on('error', (err) => this.logger.error('Redis error', err));\n }\n\n // Gracefully closes the ioredis connection on app shutdown\n async onModuleDestroy(): Promise<void> {\n await this.client.quit();\n this.logger.log('Redis disconnected');\n }\n\n // Serializes value to JSON and stores with a mandatory TTL\n async set<T>(key: string, value: T, ttlSeconds: number): Promise<void> {\n const json = JSON.stringify(value);\n await this.client.setex(key, ttlSeconds, json);\n }\n\n // Reads the stored JSON string and parses back to the original type\n async get<T>(key: string): Promise<T | null> {\n const json = await this.client.get(key);\n if (!json) return null;\n return JSON.parse(json) as T;\n }\n\n // Deletes one or more keys in a single command\n async del(...keys: string[]): Promise<void> {\n if (keys.length > 0) {\n await this.client.del(...keys);\n }\n }\n\n // Cursor-iterates all keys matching a glob pattern — never uses KEYS command\n async scanKeys(pattern: string): Promise<string[]> {\n const keys: string[] = [];\n let cursor = '0';\n do {\n const [nextCursor, batch] = await this.client.scan(cursor, 'MATCH', pattern, 'COUNT', 100);\n cursor = nextCursor;\n keys.push(...batch);\n } while (cursor !== '0');\n return keys;\n }\n\n // Returns raw INFO memory output for memory monitoring\n async getMemoryInfo(): Promise<string> {\n return this.client.info('memory');\n }\n}\n","import { type DynamicModule, Global, type InjectionToken, Module, type Provider } from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { RequestModule } from '../request/request.module';\nimport { DATABASE_MODULE_OPTIONS } from './constants';\nimport type { DatabaseModuleOptions } from './interfaces';\nimport { PrimaryDatabaseService } from './services/primary-database.service';\n\n@Global()\n@Module({})\nexport class DatabaseModule {\n // Configures the database module with a single primary connection\n static forServer(options: {\n useFactory: (...args: unknown[]) => Promise<DatabaseModuleOptions> | DatabaseModuleOptions;\n inject?: InjectionToken[];\n }): DynamicModule {\n const asyncProvider: Provider = {\n provide: DATABASE_MODULE_OPTIONS,\n useFactory: options.useFactory,\n inject: options.inject || [],\n };\n\n return {\n module: DatabaseModule,\n imports: [RequestModule],\n providers: [\n { provide: Reflector, useClass: Reflector },\n asyncProvider,\n PrimaryDatabaseService,\n ],\n exports: [PrimaryDatabaseService, asyncProvider],\n };\n }\n}\n","export const DATABASE_MODULE_OPTIONS = Symbol('DATABASE_MODULE_OPTIONS');\n","import {\n Inject,\n Injectable,\n InternalServerErrorException,\n Logger,\n type OnModuleDestroy,\n type OnModuleInit,\n} from '@nestjs/common';\nimport { drizzle } from 'drizzle-orm/node-postgres';\nimport { Pool } from 'pg';\nimport { DATABASE_MODULE_OPTIONS } from '../constants';\nimport type { DatabaseModuleOptions } from '../interfaces';\nimport type { TypedDrizzleClient } from '../schema.registry';\n\n@Injectable()\nexport class PrimaryDatabaseService implements OnModuleInit, OnModuleDestroy {\n private readonly logger = new Logger(PrimaryDatabaseService.name);\n\n private pool: Pool | null = null;\n private db: TypedDrizzleClient | null = null;\n\n constructor(\n @Inject(DATABASE_MODULE_OPTIONS)\n private readonly options: DatabaseModuleOptions,\n ) {}\n\n async onModuleInit() {\n if (this.options.primaryDb) {\n await this.initializeDrizzleClient();\n }\n }\n\n // Initializes connection to primary database using Drizzle\n private async initializeDrizzleClient(): Promise<void> {\n try {\n const { host, port = 5432, username, password, database, schema, sslMode = 'require' } = this.options.primaryDb;\n\n this.pool = new Pool({\n host,\n port,\n user: username,\n password,\n database,\n max: this.options.maxConnections || 10,\n ssl: sslMode === 'disable' ? false : { rejectUnauthorized: sslMode !== 'no-verify' },\n ...(schema && { options: `-csearch_path=${schema}` }),\n });\n\n this.logger.debug(`Schema keys passed to drizzle: [${Object.keys(this.options.drizzleSchema || {}).join(', ')}]`);\n this.logger.debug(\n `Relations keys passed to drizzle: [${Object.keys(this.options.drizzleRelations || {}).join(', ')}]`,\n );\n this.db = drizzle({\n client: this.pool,\n schema: this.options.drizzleSchema,\n relations: this.options.drizzleRelations,\n }) as TypedDrizzleClient;\n this.logger.debug(`Drizzle query keys after init: [${Object.keys(this.db.query || {}).join(', ')}]`);\n\n await this.pool.query('SELECT 1');\n this.logger.log(`Connected to primary database (schema: ${schema ?? 'public'})`);\n } catch (error) {\n this.logger.error('Failed to connect to primary database', error);\n throw new InternalServerErrorException('Failed to initialize database connection');\n }\n }\n\n // Returns the initialized Drizzle client\n get drizzleClient(): TypedDrizzleClient {\n if (!this.db) {\n throw new Error('Primary database client not initialized');\n }\n return this.db;\n }\n\n // Returns the Drizzle schema passed in module options\n get schema(): typeof this.options.drizzleSchema {\n return this.options.drizzleSchema;\n }\n\n async onModuleDestroy() {\n if (this.pool) {\n await this.pool.end();\n this.logger.log('Disconnected from primary database');\n }\n }\n}\n","import { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport type { FastifyRequest } from 'fastify';\nimport { BadRequestException } from '../exceptions';\n\nexport interface UploadedFileResult {\n buffer: Buffer;\n filename: string;\n mimetype: string;\n}\n\n/**\n * Extracts a single uploaded file from a Fastify multipart request.\n *\n * Requires `@fastify/multipart` to be registered on the Fastify instance.\n * Throws `BadRequestException` if no file is present in the request.\n *\n * @example\n * ```typescript\n * @Post('upload')\n * @ApiConsumes('multipart/form-data')\n * async upload(@UploadedFile() file: UploadedFileResult) {\n * // file.buffer, file.filename, file.mimetype\n * }\n * ```\n */\nexport const UploadedFile = createParamDecorator(\n async (_data: unknown, ctx: ExecutionContext): Promise<UploadedFileResult> => {\n const request = ctx.switchToHttp().getRequest<FastifyRequest>();\n\n // request.file() is provided by @fastify/multipart\n const file = await (request as FastifyRequest & { file: () => Promise<any> }).file();\n\n if (!file) {\n throw new BadRequestException({\n label: 'File Required',\n detail: 'Please attach a file to your request.',\n });\n }\n\n const buffer = await file.toBuffer();\n return { buffer, filename: file.filename, mimetype: file.mimetype };\n },\n);\n","import { ApiProperty } from '@nestjs/swagger';\n\n// Generic wrapper for create/assign responses — includes success metadata alongside entity data\nexport class CreateResponseDto<T> {\n @ApiProperty({ example: true })\n success!: boolean;\n\n @ApiProperty({ example: 'Resource created successfully' })\n message!: string;\n\n @ApiProperty()\n data!: T;\n}\n","import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';\n\nexport class ValidatedRowDto {\n @ApiProperty({ example: 1 })\n index!: number;\n\n @ApiProperty({ example: { code: 'products', name: 'Products' } })\n data!: Record<string, string>;\n\n @ApiProperty({ example: true })\n valid!: boolean;\n\n @ApiProperty({ example: ['Code already exists'] })\n errors!: string[];\n}\n\nexport class ImportSummaryDto {\n @ApiProperty({ example: 10 })\n total!: number;\n\n @ApiProperty({ example: 8 })\n valid!: number;\n\n @ApiProperty({ example: 2 })\n invalid!: number;\n}\n\nexport class ImportResponseDto {\n @ApiProperty({ example: true })\n success!: boolean;\n\n @ApiProperty({ example: 'Import complete.' })\n message!: string;\n\n @ApiPropertyOptional({ example: 3 })\n created?: number;\n\n @ApiPropertyOptional({ example: 2 })\n updated?: number;\n\n @ApiPropertyOptional({ example: 1 })\n skipped?: number;\n\n @ApiPropertyOptional({ type: [ValidatedRowDto] })\n rows?: ValidatedRowDto[];\n\n @ApiPropertyOptional({ type: ImportSummaryDto })\n summary?: ImportSummaryDto;\n}\n","import { ApiPropertyOptional } from '@nestjs/swagger';\nimport { Type } from 'class-transformer';\nimport { IsInt, IsOptional, IsString, Min } from 'class-validator';\n\n// Standardized query params for select dropdown option endpoints\nexport class SelectOptionsQueryDto {\n @ApiPropertyOptional({ description: 'Search term to filter by label', example: 'united' })\n @IsOptional()\n @IsString()\n search?: string;\n\n @ApiPropertyOptional({ description: 'Maximum number of results', example: 20, default: 20 })\n @IsOptional()\n @Type(() => Number)\n @IsInt()\n @Min(1)\n limit?: number;\n\n @ApiPropertyOptional({ description: 'Number of results to skip', example: 0, default: 0 })\n @IsOptional()\n @Type(() => Number)\n @IsInt()\n @Min(0)\n offset?: number;\n\n @ApiPropertyOptional({ description: 'Comma-separated values to fetch specific options', example: '1,2,3' })\n @IsOptional()\n @IsString()\n values?: string;\n\n @ApiPropertyOptional({ description: 'Comma-separated IDs to exclude from results (already selected)', example: '5,10' })\n @IsOptional()\n @IsString()\n excludeIds?: string;\n\n @ApiPropertyOptional({ description: 'Column name for option value', example: 'id', default: 'id' })\n @IsOptional()\n @IsString()\n valueKey?: string;\n\n @ApiPropertyOptional({ description: 'Column name for option label', example: 'name', default: 'name' })\n @IsOptional()\n @IsString()\n labelKey?: string;\n\n @ApiPropertyOptional({ description: 'Column name for option description', example: 'description' })\n @IsOptional()\n @IsString()\n descriptionKey?: string;\n\n @ApiPropertyOptional({ description: 'Column name for group ID', example: 'regionId' })\n @IsOptional()\n @IsString()\n groupIdKey?: string;\n}\n","import { ApiProperty } from '@nestjs/swagger';\nimport { IsBoolean, IsNotEmpty, IsString } from 'class-validator';\n\nexport class SuccessResponseDto {\n @ApiProperty({ example: true })\n @IsNotEmpty()\n @IsBoolean()\n success!: boolean;\n\n @ApiProperty({ example: 'Operation completed successfully' })\n @IsNotEmpty()\n @IsString()\n message!: string;\n}\n","import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';\nimport type { TableViewState } from '../filter/filter.types';\n\nexport class TableResponseDto<T> {\n @ApiProperty()\n result!: T[];\n\n @ApiProperty()\n count!: number;\n\n @ApiProperty()\n state!: TableViewState;\n\n @ApiPropertyOptional({ nullable: true })\n activeViewId!: string | null;\n}\n","import {\n and,\n asc,\n type Column,\n desc,\n eq,\n gt,\n gte,\n ilike,\n lt,\n lte,\n ne,\n notIlike,\n or,\n type SQL,\n} from 'drizzle-orm';\nimport type { FilterCondition, SearchState, SortCondition } from './filter.types';\n\nexport type FieldDefinition =\n | { column: Column; type: 'string' | 'number' | 'boolean' }\n | { expression: (value: string | number) => SQL; type: 'string' | 'number' | 'boolean' };\nexport type FieldMap = Record<string, FieldDefinition>;\n\nexport class FilterProcessor {\n // Returns undefined if no conditions (Drizzle accepts undefined as \"no WHERE\")\n static buildWhere(filters: FilterCondition[] = [], fieldMap: FieldMap): SQL | undefined {\n const conditions = filters.flatMap((f) => {\n const def = fieldMap[f.field];\n if (!def) return []; // unknown field — skip (security whitelist)\n // Expression field — delegate SQL generation to the caller-supplied factory\n if ('expression' in def) return [def.expression(f.value)];\n const { column: col } = def;\n const val = f.value;\n switch (f.operator) {\n case 'equals':\n if (def.type === 'boolean') return [eq(col, val === 'true' || val === 1)];\n return [eq(col, val)];\n case 'notEquals':\n if (def.type === 'boolean') return [ne(col, val === 'true' || val === 1)];\n return [ne(col, val)];\n case 'contains':\n return [ilike(col, `%${val}%`)];\n case 'notContains':\n return [notIlike(col, `%${val}%`)];\n case 'gt':\n return [gt(col, val)];\n case 'gte':\n return [gte(col, val)];\n case 'lt':\n return [lt(col, val)];\n case 'lte':\n return [lte(col, val)];\n default:\n return [];\n }\n });\n return conditions.length ? and(...conditions) : undefined;\n }\n\n // Builds a search WHERE — OR across all string fields when columnId is 'all', otherwise a single ilike\n static buildSearch(search: SearchState | null | undefined, fieldMap: FieldMap): SQL | undefined {\n if (!search?.value) return undefined;\n\n if (search.columnId === 'all') {\n const conditions = Object.values(fieldMap)\n .filter((def): def is { column: Column; type: 'string' | 'number' | 'boolean' } => 'column' in def && def.type === 'string')\n .map((def) => ilike(def.column, `%${search.value}%`));\n return conditions.length ? or(...conditions) : undefined;\n }\n\n const def = fieldMap[search.columnId];\n if (!def || !('column' in def)) return undefined;\n return ilike(def.column, `%${search.value}%`);\n }\n\n // Maps each SortCondition to an asc/desc SQL expression\n static buildOrderBy(sort: SortCondition[] = [], fieldMap: FieldMap): SQL[] {\n return sort.flatMap((s) => {\n const def = fieldMap[s.field];\n if (!def || !('column' in def)) return [];\n return [s.direction === 'asc' ? asc(def.column) : desc(def.column)];\n });\n }\n}\n","import { Logger } from '@nestjs/common';\nimport {\n and,\n asc,\n type Column,\n eq,\n getTableName,\n type InferInsertModel,\n type InferSelectModel,\n ilike,\n inArray,\n notInArray,\n type SQL,\n sql,\n} from 'drizzle-orm';\nimport type { PgSelect, PgTable } from 'drizzle-orm/pg-core';\nimport type { TypedDrizzleClient } from '../schema.registry';\nimport { PrimaryDatabaseService } from '../services/primary-database.service';\nimport type { FindForSelectConfig, SelectQueryResult } from '../types';\n\n// Converts snake_case string to camelCase\nfunction snakeToCamel(str: string): string {\n return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());\n}\n\ntype RelationsWhereFilter = Record<string, unknown>;\n\ninterface TypedRelationalQueryBuilder<TSelect> {\n findFirst(config?: {\n where?: RelationsWhereFilter;\n with?: Record<string, unknown>;\n columns?: Record<string, boolean>;\n }): Promise<TSelect | undefined>;\n\n findMany(config?: {\n where?: RelationsWhereFilter;\n orderBy?: Record<string, 'asc' | 'desc'>;\n limit?: number;\n offset?: number;\n with?: Record<string, unknown>;\n columns?: Record<string, boolean>;\n }): Promise<TSelect[]>;\n}\n\nexport abstract class PrimaryBaseRepository<\n TTable extends PgTable,\n TInsert = InferInsertModel<TTable>,\n TSelect = InferSelectModel<TTable>,\n> {\n protected readonly logger: Logger;\n\n private readonly tableName: string;\n\n protected get db(): TypedDrizzleClient {\n return this.database.drizzleClient;\n }\n\n protected get model(): TypedRelationalQueryBuilder<TSelect> {\n const query = this.database.drizzleClient.query;\n const queryKeys = Object.keys(query || {});\n this.logger.debug(`Looking for '${this.tableName}' in query keys: [${queryKeys.join(', ')}]`);\n\n const model = query[this.tableName as keyof TypedDrizzleClient['query']];\n if (!model) {\n this.logger.error(`Table '${this.tableName}' not found in query object. Available: [${queryKeys.join(', ')}]`);\n }\n\n return model as unknown as TypedRelationalQueryBuilder<TSelect>;\n }\n\n constructor(\n protected readonly database: PrimaryDatabaseService,\n protected readonly table: TTable,\n ) {\n // Convert snake_case table name to camelCase to match Drizzle query object keys\n // Example: 'email_verifications' -> 'emailVerifications'\n const dbTableName = getTableName(table);\n this.tableName = snakeToCamel(dbTableName);\n this.logger = new Logger(this.constructor.name);\n this.logger.debug(`Initialized ${this.constructor.name}`);\n this.logger.debug(`Table name: '${dbTableName}' -> query key: '${this.tableName}'`);\n }\n\n // Creates a new record and returns it\n async create(data: TInsert, tx?: TypedDrizzleClient): Promise<TSelect> {\n this.logger.log('Creating record');\n const db = tx ?? this.db;\n const results = (await db\n .insert(this.table as PgTable)\n .values(data as Record<string, unknown>)\n .returning()) as TSelect[];\n const record = results[0];\n if (!record) throw new Error(`${this.tableName}: database operation returned no record`);\n return record;\n }\n\n // Finds a single record by primary key ID\n async findById(id: string): Promise<TSelect | undefined> {\n this.logger.debug(`Finding record by ID: ${id}`);\n return this.model.findFirst({\n where: { id },\n });\n }\n\n // Finds a single record matching the given where filter\n async findOne(where: RelationsWhereFilter): Promise<TSelect | undefined> {\n this.logger.debug('Finding record with custom query');\n return this.model.findFirst({ where });\n }\n\n // Finds multiple records with optional filtering, ordering, and pagination\n async findMany(options?: {\n where?: RelationsWhereFilter;\n orderBy?: Record<string, 'asc' | 'desc'>;\n limit?: number;\n offset?: number;\n }): Promise<TSelect[]> {\n this.logger.debug('Finding multiple records');\n return this.model.findMany(options);\n }\n\n // Builds a select query with optional custom fields, joins, filter, grouping, ordering, and pagination\n private buildSelectQuery(options?: {\n select?: Record<string, unknown>;\n where?: SQL;\n orderBy?: SQL[];\n limit?: number;\n offset?: number;\n leftJoin?: { table: PgTable; on: SQL | undefined };\n leftJoins?: { table: PgTable; on: SQL | undefined }[];\n groupBy?: (Column | SQL)[];\n }) {\n let query: PgSelect = (options?.select\n ? this.db.select(options.select as Record<string, Column | SQL>).from(this.table as PgTable)\n : this.db.select().from(this.table as PgTable)\n ).$dynamic();\n\n if (options?.leftJoin) {\n query = query.leftJoin(options.leftJoin.table, options.leftJoin.on);\n }\n if (options?.leftJoins) {\n for (const join of options.leftJoins) {\n query = query.leftJoin(join.table, join.on);\n }\n }\n if (options?.where) {\n query = query.where(options.where);\n }\n if (options?.groupBy?.length) {\n query = query.groupBy(...options.groupBy);\n }\n if (options?.orderBy?.length) {\n query = query.orderBy(...options.orderBy);\n }\n if (options?.limit) {\n query = query.limit(options.limit);\n }\n if (options?.offset) {\n query = query.offset(options.offset);\n }\n return query;\n }\n\n // Returns paginated result and total count, with optional custom select, LEFT JOINs, GROUP BY, and ordering\n async findAllAndCount<TResult = TSelect>(options?: {\n select?: Record<string, unknown>;\n where?: SQL;\n orderBy?: SQL[];\n limit?: number;\n offset?: number;\n leftJoin?: { table: PgTable; on: SQL | undefined };\n leftJoins?: { table: PgTable; on: SQL | undefined }[];\n groupBy?: (Column | SQL)[];\n }): Promise<{ result: TResult[]; count: number }> {\n const [count, result] = await Promise.all([\n this.count(options?.where),\n this.buildSelectQuery(options) as Promise<TResult[]>,\n ]);\n return { result, count };\n }\n\n // Updates a record by ID and returns the updated record\n async update(id: string, data: Partial<TInsert>, tx?: TypedDrizzleClient): Promise<TSelect> {\n this.logger.log(`Updating record with ID: ${id}`);\n const db = tx ?? this.db;\n const idColumn = (this.table as unknown as Record<string, Column>).id;\n if (!idColumn) throw new Error(`Table '${this.tableName}' has no 'id' column`);\n const results = (await db\n .update(this.table as PgTable)\n .set(data as Record<string, unknown>)\n .where(eq(idColumn, id))\n .returning()) as TSelect[];\n const record = results[0];\n if (!record) throw new Error(`${this.tableName}: database operation returned no record`);\n return record;\n }\n\n // Updates all records matching the SQL condition and returns the affected count\n async updateMany(where: SQL, data: Partial<TInsert>, tx?: TypedDrizzleClient): Promise<{ count: number }> {\n this.logger.log('Updating multiple records');\n const db = tx ?? this.db;\n const result = await db\n .update(this.table as PgTable)\n .set(data as Record<string, unknown>)\n .where(where);\n return { count: result.rowCount ?? 0 };\n }\n\n // Deletes a record by ID and returns the deleted record\n async delete(id: string, tx?: TypedDrizzleClient): Promise<TSelect> {\n this.logger.log(`Deleting record with ID: ${id}`);\n const db = tx ?? this.db;\n const idColumn = (this.table as unknown as Record<string, Column>).id;\n if (!idColumn) throw new Error(`Table '${this.tableName}' has no 'id' column`);\n const results = (await db\n .delete(this.table as PgTable)\n .where(eq(idColumn, id))\n .returning()) as TSelect[];\n const record = results[0];\n if (!record) throw new Error(`${this.tableName}: database operation returned no record`);\n return record;\n }\n\n // Deletes all records matching the SQL condition and returns the affected count\n async deleteMany(where: SQL, tx?: TypedDrizzleClient): Promise<{ count: number }> {\n this.logger.log('Deleting multiple records');\n const db = tx ?? this.db;\n const result = await db.delete(this.table as PgTable).where(where);\n return { count: result.rowCount ?? 0 };\n }\n\n // Counts records matching the optional SQL condition\n async count(where?: SQL): Promise<number> {\n this.logger.debug('Counting records');\n\n let query = this.db\n .select({ count: sql<number>`count(*)::int` })\n .from(this.table as PgTable)\n .$dynamic();\n\n if (where) {\n query = query.where(where);\n }\n\n const results = await query;\n return (results[0] as { count: number }).count;\n }\n\n // Returns true if at least one record matches the SQL condition\n async exists(where: SQL): Promise<boolean> {\n const count = await this.count(where);\n return count > 0;\n }\n\n // Executes the callback within a database transaction\n async transaction<T>(callback: (tx: TypedDrizzleClient) => Promise<T>): Promise<T> {\n return this.db.transaction(callback as Parameters<TypedDrizzleClient['transaction']>[0]) as Promise<T>;\n }\n\n // Finds records formatted as select dropdown options with optional search, pagination, and grouping\n async findForSelect(config: FindForSelectConfig): Promise<SelectQueryResult> {\n this.logger.debug('Finding records for select dropdown');\n\n // Use selectDistinct when deduplication is needed (e.g., distinct app codes across versions)\n const selectFn = config.distinct ? this.db.selectDistinct.bind(this.db) : this.db.select.bind(this.db);\n\n interface SelectRow {\n value: string | number | boolean;\n label: string;\n description?: string;\n groupId?: string | number;\n }\n interface SelectRowWithCount extends SelectRow {\n totalCount: number;\n }\n\n // Parse values from CSV string or use array as-is\n const parsedValues =\n typeof config.values === 'string'\n ? config.values\n .split(',')\n .map((v) => v.trim())\n .filter(Boolean)\n : config.values;\n\n // Parse excludeIds from CSV string or use array as-is\n const parsedExcludeIds =\n typeof config.excludeIds === 'string'\n ? config.excludeIds\n .split(',')\n .map((v) => v.trim())\n .filter(Boolean)\n : (config.excludeIds ?? []);\n\n const tableColumns = this.table as unknown as Record<string, Column>;\n const valueCol = tableColumns[config.value];\n if (!valueCol) throw new Error(`Column '${config.value}' not found in table '${this.tableName}'`);\n const labelCol = tableColumns[config.label];\n if (!labelCol) throw new Error(`Column '${config.label}' not found in table '${this.tableName}'`);\n\n // Resolve optional description column (checks main table first, then joined tables)\n let descriptionCol = config.description ? tableColumns[config.description] : undefined;\n if (!descriptionCol && config.description && config.joins) {\n for (const join of config.joins) {\n const joinCols = join.table as unknown as Record<string, Column>;\n if (joinCols[config.description]) {\n descriptionCol = joinCols[config.description];\n break;\n }\n }\n }\n\n // When values are provided, fetch those specific options by value (skip search/pagination)\n if (parsedValues && parsedValues.length > 0) {\n const selectCols: Record<string, Column | SQL> = { value: valueCol, label: labelCol };\n if (descriptionCol) selectCols.description = descriptionCol;\n if (config.groupId) {\n const groupIdCol = tableColumns[config.groupId];\n if (groupIdCol) selectCols.groupId = groupIdCol;\n }\n\n let valuesQuery = selectFn(selectCols)\n .from(this.table as PgTable)\n .$dynamic();\n\n if (config.joins) {\n for (const join of config.joins) {\n if (join.type === 'inner') {\n valuesQuery = valuesQuery.innerJoin(join.table, join.on);\n } else {\n valuesQuery = valuesQuery.leftJoin(join.table, join.on);\n }\n }\n }\n\n const rows = await valuesQuery.where(inArray(valueCol, parsedValues));\n\n return {\n options: (rows as unknown as SelectRow[]).map((row) => ({\n value: row.value,\n label: String(row.label),\n ...(descriptionCol && row.description != null ? { description: row.description } : {}),\n ...(config.groupId && row.groupId != null ? { groupId: row.groupId } : {}),\n })),\n hasMore: false,\n ...(config.groups ? { groups: config.groups } : {}),\n };\n }\n\n // Use SQL builder for count(*) over() window function support\n const selectFields: Record<string, Column | SQL> = {\n value: valueCol,\n label: labelCol,\n totalCount: sql<number>`count(*) over()`.mapWith(Number),\n };\n if (descriptionCol) selectFields.description = descriptionCol;\n if (config.groupId) {\n const groupIdCol = tableColumns[config.groupId];\n if (groupIdCol) selectFields.groupId = groupIdCol;\n }\n\n const conditions: SQL[] = [];\n if (config.search) {\n conditions.push(ilike(labelCol, `%${config.search}%`));\n }\n if (parsedExcludeIds.length > 0) {\n conditions.push(notInArray(valueCol, parsedExcludeIds));\n }\n if (config.where) {\n for (const [field, val] of Object.entries(config.where)) {\n const column = tableColumns[field];\n if (column) {\n conditions.push(eq(column, val));\n }\n }\n }\n // Append raw SQL conditions (e.g. for joined table columns)\n if (config.conditions) {\n conditions.push(...config.conditions);\n }\n\n const orderByKey = config.orderBy ? Object.keys(config.orderBy)[0] : undefined;\n const orderByCol = orderByKey ? (tableColumns[orderByKey] ?? labelCol) : labelCol;\n const limit = Number(config.limit) || 20;\n const offset = Number(config.offset) || 0;\n\n let query = selectFn(selectFields)\n .from(this.table as PgTable)\n .$dynamic();\n\n // Apply optional JOINs\n if (config.joins) {\n for (const join of config.joins) {\n if (join.type === 'inner') {\n query = query.innerJoin(join.table, join.on);\n } else {\n query = query.leftJoin(join.table, join.on);\n }\n }\n }\n\n if (conditions.length > 0) {\n query = query.where(conditions.length === 1 ? conditions[0] : (and(...conditions) as SQL));\n }\n\n const orderClauses: SQL[] = [];\n if (config.groupId) {\n const groupIdCol = tableColumns[config.groupId];\n if (groupIdCol) orderClauses.push(asc(groupIdCol));\n }\n orderClauses.push(asc(orderByCol));\n\n query = query\n .orderBy(...orderClauses)\n .limit(limit)\n .offset(offset);\n\n const rows = await query;\n\n const totalCount = rows.length > 0 ? (rows[0] as unknown as SelectRowWithCount).totalCount : 0;\n\n const options = (rows as unknown as SelectRow[]).map((row) => ({\n value: row.value,\n label: String(row.label),\n ...(descriptionCol && row.description != null ? { description: row.description } : {}),\n ...(config.groupId && row.groupId != null ? { groupId: row.groupId } : {}),\n }));\n\n // Auto-resolve groups from groupTable when provided\n let resolvedGroups = config.groups;\n\n if (config.groupTable && config.groupId) {\n const groupTableColumns = config.groupTable as unknown as Record<string, Column>;\n const groupIdKey = config.groupIdKey ?? 'id';\n const groupNameKey = config.groupLabelKey ?? 'name';\n const groupIdCol = groupTableColumns[groupIdKey];\n if (!groupIdCol) throw new Error(`Column '${groupIdKey}' not found in group table`);\n const groupNameCol = groupTableColumns[groupNameKey];\n if (!groupNameCol) throw new Error(`Column '${groupNameKey}' not found in group table`);\n\n const groupRows = await this.db\n .select({ id: groupIdCol, name: groupNameCol })\n .from(config.groupTable)\n .orderBy(asc(groupNameCol));\n\n resolvedGroups = (groupRows as unknown as Array<{ id: string | number; name: string }>).map((r) => ({\n id: r.id,\n name: String(r.name),\n }));\n }\n\n return {\n options,\n hasMore: offset + limit < totalCount,\n totalCount,\n ...(resolvedGroups ? { groups: resolvedGroups } : {}),\n };\n }\n}\n","import { Global, Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';\nimport { EmailService } from './email.service';\n\n@Global()\n@Module({\n imports: [ConfigModule],\n providers: [EmailService],\n exports: [EmailService],\n})\nexport class EmailModule {}\n","import { BrevoClient, BrevoError, BrevoTimeoutError } from '@getbrevo/brevo';\nimport { Injectable, Logger } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class EmailService {\n private readonly logger = new Logger(EmailService.name);\n private readonly brevoClient: BrevoClient;\n private readonly senderEmail: string;\n private readonly senderName: string;\n\n constructor(private readonly configService: ConfigService) {\n const apiKey = this.configService.get<string>('BREVO_API_KEY');\n\n if (!apiKey) {\n this.logger.error('BREVO_API_KEY is not configured. Email sending will fail.');\n throw new Error('Email service configuration error: Missing BREVO_API_KEY');\n }\n\n // Initialize Brevo client with built-in retry support\n this.brevoClient = new BrevoClient({ apiKey, maxRetries: 3 });\n\n // Get sender configuration\n const senderEmail = this.configService.get<string>('SENDER_EMAIL');\n const senderName = this.configService.get<string>('SENDER_NAME');\n\n if (!senderEmail || !senderName) {\n this.logger.error('Sender email or name is not configured.');\n throw new Error('Email service configuration error: Missing SENDER_EMAIL or SENDER_NAME');\n }\n\n this.senderEmail = senderEmail;\n this.senderName = senderName;\n\n this.logger.log('Brevo email service initialized successfully');\n }\n\n // Sends an email verification OTP to the given recipient\n async sendVerificationEmail(email: string, otp: string, expiresAt: Date, displayName?: string): Promise<void> {\n const name = displayName || 'there';\n const expiryMinutes = Math.ceil((expiresAt.getTime() - Date.now()) / 60_000);\n const subject = 'Verify Your Email - Vritti AI Cloud';\n\n const htmlContent = `\n <!DOCTYPE html>\n <html>\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n </head>\n <body style=\"margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background-color: #f5f5f5;\">\n <table role=\"presentation\" style=\"width: 100%; border-collapse: collapse;\">\n <tr>\n <td style=\"padding: 40px 20px;\">\n <table role=\"presentation\" style=\"max-width: 600px; margin: 0 auto; background-color: #ffffff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);\">\n <!-- Header -->\n <tr>\n <td style=\"padding: 40px 40px 20px; text-align: center; border-bottom: 1px solid #e0e0e0;\">\n <h1 style=\"margin: 0; color: #1a1a1a; font-size: 24px; font-weight: 600;\">Email Verification</h1>\n </td>\n </tr>\n\n <!-- Content -->\n <tr>\n <td style=\"padding: 40px;\">\n <p style=\"margin: 0 0 20px; color: #333333; font-size: 16px; line-height: 1.6;\">\n Hello <strong>${name}</strong>,\n </p>\n <p style=\"margin: 0 0 30px; color: #333333; font-size: 16px; line-height: 1.6;\">\n Thank you for signing up with Vritti AI Cloud. Please use the following verification code to complete your registration:\n </p>\n\n <!-- OTP Box -->\n <div style=\"background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 30px; border-radius: 8px; text-align: center; margin: 30px 0;\">\n <div style=\"color: #ffffff; font-size: 36px; font-weight: bold; letter-spacing: 10px; font-family: 'Courier New', monospace;\">\n ${otp}\n </div>\n </div>\n\n <p style=\"margin: 30px 0 20px; color: #666666; font-size: 14px; line-height: 1.6;\">\n <strong>Important:</strong> This code will expire in <strong>${expiryMinutes} minute${expiryMinutes === 1 ? '' : 's'}</strong>.\n </p>\n <p style=\"margin: 0; color: #666666; font-size: 14px; line-height: 1.6;\">\n If you didn't request this verification, please ignore this email.\n </p>\n </td>\n </tr>\n\n <!-- Footer -->\n <tr>\n <td style=\"padding: 30px 40px; border-top: 1px solid #e0e0e0; text-align: center;\">\n <p style=\"margin: 0; color: #999999; font-size: 12px; line-height: 1.5;\">\n Vritti AI Cloud - Cloud Management Platform\n </p>\n <p style=\"margin: 8px 0 0; color: #999999; font-size: 12px; line-height: 1.5;\">\n This is an automated message, please do not reply.\n </p>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n </body>\n </html>\n `;\n\n const textContent = `\nHello ${name},\n\nThank you for signing up with Vritti AI Cloud. Please use the following verification code to complete your registration:\n\nVerification Code: ${otp}\n\nThis code will expire in ${expiryMinutes} minute${expiryMinutes === 1 ? '' : 's'}.\n\nIf you didn't request this verification, please ignore this email.\n\n---\nVritti AI Cloud - Cloud Management Platform\nThis is an automated message, please do not reply.\n `.trim();\n\n await this.sendEmail({\n to: [{ email, name }],\n subject,\n htmlContent,\n textContent,\n });\n\n this.logger.log(`Verification email sent to ${email}`);\n }\n\n // Sends a password reset OTP to the given recipient\n async sendPasswordResetEmail(email: string, otp: string, expiresAt: Date, displayName?: string): Promise<void> {\n const name = displayName || 'there';\n const expiryMinutes = Math.ceil((expiresAt.getTime() - Date.now()) / 60_000);\n const subject = 'Reset Your Password - Vritti AI Cloud';\n\n const htmlContent = `\n <!DOCTYPE html>\n <html>\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n </head>\n <body style=\"margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background-color: #f5f5f5;\">\n <table role=\"presentation\" style=\"width: 100%; border-collapse: collapse;\">\n <tr>\n <td style=\"padding: 40px 20px;\">\n <table role=\"presentation\" style=\"max-width: 600px; margin: 0 auto; background-color: #ffffff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);\">\n <!-- Header -->\n <tr>\n <td style=\"padding: 40px 40px 20px; text-align: center; border-bottom: 1px solid #e0e0e0;\">\n <h1 style=\"margin: 0; color: #1a1a1a; font-size: 24px; font-weight: 600;\">Password Reset</h1>\n </td>\n </tr>\n\n <!-- Content -->\n <tr>\n <td style=\"padding: 40px;\">\n <p style=\"margin: 0 0 20px; color: #333333; font-size: 16px; line-height: 1.6;\">\n Hello <strong>${name}</strong>,\n </p>\n <p style=\"margin: 0 0 30px; color: #333333; font-size: 16px; line-height: 1.6;\">\n We received a request to reset your password. Use the following code to complete the process:\n </p>\n\n <!-- OTP Box -->\n <div style=\"background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); padding: 30px; border-radius: 8px; text-align: center; margin: 30px 0;\">\n <div style=\"color: #ffffff; font-size: 36px; font-weight: bold; letter-spacing: 10px; font-family: 'Courier New', monospace;\">\n ${otp}\n </div>\n </div>\n\n <p style=\"margin: 30px 0 20px; color: #666666; font-size: 14px; line-height: 1.6;\">\n <strong>Important:</strong> This code will expire in <strong>${expiryMinutes} minute${expiryMinutes === 1 ? '' : 's'}</strong>.\n </p>\n <p style=\"margin: 0 0 20px; color: #666666; font-size: 14px; line-height: 1.6;\">\n If you didn't request a password reset, please ignore this email and your password will remain unchanged.\n </p>\n <div style=\"background-color: #fff3cd; border-left: 4px solid #ffc107; padding: 15px; margin-top: 20px; border-radius: 4px;\">\n <p style=\"margin: 0; color: #856404; font-size: 13px; line-height: 1.5;\">\n <strong>Security Tip:</strong> Never share this code with anyone. Vritti will never ask for your verification code.\n </p>\n </div>\n </td>\n </tr>\n\n <!-- Footer -->\n <tr>\n <td style=\"padding: 30px 40px; border-top: 1px solid #e0e0e0; text-align: center;\">\n <p style=\"margin: 0; color: #999999; font-size: 12px; line-height: 1.5;\">\n Vritti AI Cloud - Cloud Management Platform\n </p>\n <p style=\"margin: 8px 0 0; color: #999999; font-size: 12px; line-height: 1.5;\">\n This is an automated message, please do not reply.\n </p>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n </body>\n </html>\n `;\n\n const textContent = `\nHello ${name},\n\nWe received a request to reset your password. Use the following code to complete the process:\n\nReset Code: ${otp}\n\nThis code will expire in ${expiryMinutes} minute${expiryMinutes === 1 ? '' : 's'}.\n\nIf you didn't request a password reset, please ignore this email and your password will remain unchanged.\n\nSECURITY TIP: Never share this code with anyone. Vritti will never ask for your verification code.\n\n---\nVritti AI Cloud - Cloud Management Platform\nThis is an automated message, please do not reply.\n `.trim();\n\n await this.sendEmail({\n to: [{ email, name }],\n subject,\n htmlContent,\n textContent,\n });\n\n this.logger.log(`Password reset email sent to ${email}`);\n }\n\n // Sends an email change notification to the old address with a revert link\n async sendEmailChangeNotification(\n oldEmail: string,\n newEmail: string,\n revertToken: string,\n revertExpiresAt: Date,\n displayName?: string,\n ): Promise<void> {\n const name = displayName || 'there';\n const subject = 'Your Email Address Has Been Changed - Vritti AI Cloud';\n\n // Calculate hours until expiry\n const hoursUntilExpiry = Math.floor((revertExpiresAt.getTime() - Date.now()) / (1000 * 60 * 60));\n\n // TODO: Replace with actual frontend URL from config\n const revertLink = `https://local.vrittiai.com:3012/settings/profile/revert-email?token=${revertToken}`;\n\n const htmlContent = `\n <!DOCTYPE html>\n <html>\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n </head>\n <body style=\"margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background-color: #f5f5f5;\">\n <table role=\"presentation\" style=\"width: 100%; border-collapse: collapse;\">\n <tr>\n <td style=\"padding: 40px 20px;\">\n <table role=\"presentation\" style=\"max-width: 600px; margin: 0 auto; background-color: #ffffff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);\">\n <!-- Header -->\n <tr>\n <td style=\"padding: 40px 40px 20px; text-align: center; border-bottom: 1px solid #e0e0e0;\">\n <h1 style=\"margin: 0; color: #1a1a1a; font-size: 24px; font-weight: 600;\">Email Address Changed</h1>\n </td>\n </tr>\n\n <!-- Content -->\n <tr>\n <td style=\"padding: 40px;\">\n <p style=\"margin: 0 0 20px; color: #333333; font-size: 16px; line-height: 1.6;\">\n Hello <strong>${name}</strong>,\n </p>\n <p style=\"margin: 0 0 30px; color: #333333; font-size: 16px; line-height: 1.6;\">\n We're writing to inform you that your Vritti AI Cloud email address has been successfully changed.\n </p>\n\n <div style=\"background-color: #f8f9fa; padding: 20px; border-radius: 8px; margin: 30px 0;\">\n <p style=\"margin: 0 0 10px; color: #666666; font-size: 14px;\">\n <strong>Previous Email:</strong>\n </p>\n <p style=\"margin: 0 0 20px; color: #333333; font-size: 16px; font-family: monospace;\">\n ${oldEmail}\n </p>\n <p style=\"margin: 0 0 10px; color: #666666; font-size: 14px;\">\n <strong>New Email:</strong>\n </p>\n <p style=\"margin: 0; color: #333333; font-size: 16px; font-family: monospace;\">\n ${newEmail}\n </p>\n </div>\n\n <div style=\"background-color: #fff3cd; border-left: 4px solid #ffc107; padding: 20px; margin: 30px 0; border-radius: 4px;\">\n <p style=\"margin: 0 0 15px; color: #856404; font-size: 14px; line-height: 1.6;\">\n <strong>Didn't make this change?</strong>\n </p>\n <p style=\"margin: 0 0 20px; color: #856404; font-size: 14px; line-height: 1.6;\">\n If you did not authorize this change, you can revert it within the next <strong>${hoursUntilExpiry} hours</strong> by clicking the button below:\n </p>\n <div style=\"text-align: center;\">\n <a href=\"${revertLink}\" style=\"display: inline-block; padding: 12px 30px; background-color: #dc3545; color: #ffffff; text-decoration: none; border-radius: 6px; font-weight: 600; font-size: 14px;\">\n Revert Email Change\n </a>\n </div>\n </div>\n\n <p style=\"margin: 30px 0 0; color: #666666; font-size: 14px; line-height: 1.6;\">\n If you made this change, you can safely ignore this email.\n </p>\n </td>\n </tr>\n\n <!-- Footer -->\n <tr>\n <td style=\"padding: 30px 40px; border-top: 1px solid #e0e0e0; text-align: center;\">\n <p style=\"margin: 0; color: #999999; font-size: 12px; line-height: 1.5;\">\n Vritti AI Cloud - Cloud Management Platform\n </p>\n <p style=\"margin: 8px 0 0; color: #999999; font-size: 12px; line-height: 1.5;\">\n This is an automated message, please do not reply.\n </p>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n </body>\n </html>\n `;\n\n const textContent = `\nHello ${name},\n\nWe're writing to inform you that your Vritti AI Cloud email address has been successfully changed.\n\nPrevious Email: ${oldEmail}\nNew Email: ${newEmail}\n\nDIDN'T MAKE THIS CHANGE?\n\nIf you did not authorize this change, you can revert it within the next ${hoursUntilExpiry} hours by visiting:\n${revertLink}\n\nIf you made this change, you can safely ignore this email.\n\n---\nVritti AI Cloud - Cloud Management Platform\nThis is an automated message, please do not reply.\n `.trim();\n\n await this.sendEmail({\n to: [{ email: oldEmail, name }],\n subject,\n htmlContent,\n textContent,\n });\n\n this.logger.log(`Email change notification sent to ${oldEmail}`);\n }\n\n // Sends a confirmation to the restored email address after a revert\n async sendEmailRevertConfirmation(email: string, displayName?: string): Promise<void> {\n const name = displayName || 'there';\n const subject = 'Email Address Change Reverted - Vritti AI Cloud';\n\n const htmlContent = `\n <!DOCTYPE html>\n <html>\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n </head>\n <body style=\"margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background-color: #f5f5f5;\">\n <table role=\"presentation\" style=\"width: 100%; border-collapse: collapse;\">\n <tr>\n <td style=\"padding: 40px 20px;\">\n <table role=\"presentation\" style=\"max-width: 600px; margin: 0 auto; background-color: #ffffff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);\">\n <!-- Header -->\n <tr>\n <td style=\"padding: 40px 40px 20px; text-align: center; border-bottom: 1px solid #e0e0e0;\">\n <h1 style=\"margin: 0; color: #1a1a1a; font-size: 24px; font-weight: 600;\">Email Change Reverted</h1>\n </td>\n </tr>\n\n <!-- Content -->\n <tr>\n <td style=\"padding: 40px;\">\n <p style=\"margin: 0 0 20px; color: #333333; font-size: 16px; line-height: 1.6;\">\n Hello <strong>${name}</strong>,\n </p>\n <p style=\"margin: 0 0 30px; color: #333333; font-size: 16px; line-height: 1.6;\">\n Your recent email address change has been successfully reverted. Your email is now:\n </p>\n\n <div style=\"background-color: #d4edda; padding: 20px; border-radius: 8px; margin: 30px 0; text-align: center;\">\n <p style=\"margin: 0; color: #155724; font-size: 18px; font-weight: 600; font-family: monospace;\">\n ${email}\n </p>\n </div>\n\n <p style=\"margin: 30px 0 20px; color: #666666; font-size: 14px; line-height: 1.6;\">\n If you did not request this revert, please contact our support team immediately.\n </p>\n </td>\n </tr>\n\n <!-- Footer -->\n <tr>\n <td style=\"padding: 30px 40px; border-top: 1px solid #e0e0e0; text-align: center;\">\n <p style=\"margin: 0; color: #999999; font-size: 12px; line-height: 1.5;\">\n Vritti AI Cloud - Cloud Management Platform\n </p>\n <p style=\"margin: 8px 0 0; color: #999999; font-size: 12px; line-height: 1.5;\">\n This is an automated message, please do not reply.\n </p>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n </body>\n </html>\n `;\n\n const textContent = `\nHello ${name},\n\nYour recent email address change has been successfully reverted. Your email is now:\n\n${email}\n\nIf you did not request this revert, please contact our support team immediately.\n\n---\nVritti AI Cloud - Cloud Management Platform\nThis is an automated message, please do not reply.\n `.trim();\n\n await this.sendEmail({\n to: [{ email, name }],\n subject,\n htmlContent,\n textContent,\n });\n\n this.logger.log(`Email revert confirmation sent to ${email}`);\n }\n\n // Sends an invite email to a new portal user with their set-password link\n async sendInviteEmail(params: { to: string; name: string; inviteUrl: string }): Promise<void> {\n const { to, name, inviteUrl } = params;\n const subject = 'You have been invited to Vritti AI';\n\n const htmlContent = `\n <!DOCTYPE html>\n <html>\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n </head>\n <body style=\"margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background-color: #f5f5f5;\">\n <table role=\"presentation\" style=\"width: 100%; border-collapse: collapse;\">\n <tr>\n <td style=\"padding: 40px 20px;\">\n <table role=\"presentation\" style=\"max-width: 600px; margin: 0 auto; background-color: #ffffff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);\">\n <!-- Header -->\n <tr>\n <td style=\"padding: 40px 40px 20px; text-align: center; border-bottom: 1px solid #e0e0e0;\">\n <h1 style=\"margin: 0; color: #1a1a1a; font-size: 24px; font-weight: 600;\">You're Invited</h1>\n </td>\n </tr>\n\n <!-- Content -->\n <tr>\n <td style=\"padding: 40px;\">\n <p style=\"margin: 0 0 20px; color: #333333; font-size: 16px; line-height: 1.6;\">\n Hello <strong>${name}</strong>,\n </p>\n <p style=\"margin: 0 0 30px; color: #333333; font-size: 16px; line-height: 1.6;\">\n You have been invited to join Vritti AI. Click the button below to set your password and get started.\n </p>\n\n <div style=\"text-align: center; margin: 30px 0;\">\n <a href=\"${inviteUrl}\" style=\"display: inline-block; padding: 14px 32px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: #ffffff; text-decoration: none; border-radius: 6px; font-weight: 600; font-size: 16px;\">\n Set Your Password\n </a>\n </div>\n\n <p style=\"margin: 30px 0 0; color: #666666; font-size: 14px; line-height: 1.6;\">\n If you did not expect this invitation, you can safely ignore this email.\n </p>\n </td>\n </tr>\n\n <!-- Footer -->\n <tr>\n <td style=\"padding: 30px 40px; border-top: 1px solid #e0e0e0; text-align: center;\">\n <p style=\"margin: 0; color: #999999; font-size: 12px; line-height: 1.5;\">\n Vritti AI Cloud - Cloud Management Platform\n </p>\n <p style=\"margin: 8px 0 0; color: #999999; font-size: 12px; line-height: 1.5;\">\n This is an automated message, please do not reply.\n </p>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n </body>\n </html>\n `;\n\n const textContent = `\nHello ${name},\n\nYou have been invited to join Vritti AI. Visit the link below to set your password and get started:\n\n${inviteUrl}\n\nIf you did not expect this invitation, you can safely ignore this email.\n\n---\nVritti AI Cloud - Cloud Management Platform\nThis is an automated message, please do not reply.\n `.trim();\n\n await this.sendEmail({\n to: [{ email: to, name }],\n subject,\n htmlContent,\n textContent,\n });\n\n this.logger.log(`Invite email sent to ${to}`);\n }\n\n // Verifies Brevo API connectivity — a 400 response means the API is reachable\n async verifyConnection(): Promise<boolean> {\n try {\n await this.brevoClient.transactionalEmails.sendTransacEmail({\n sender: { email: this.senderEmail, name: this.senderName },\n to: [{ email: this.senderEmail }],\n subject: 'Connection Test',\n htmlContent: '<p>Test</p>',\n });\n return true;\n } catch (err) {\n // A 400 error means the API is reachable but params are incomplete — still a successful connection test\n if (err instanceof BrevoError && err.statusCode === 400) {\n return true;\n }\n this.logger.error('Brevo connection verification failed:', err);\n return false;\n }\n }\n\n // Sends a transactional email via Brevo — retries handled internally by BrevoClient\n private async sendEmail(emailData: {\n to: Array<{ email: string; name?: string }>;\n subject: string;\n htmlContent: string;\n textContent: string;\n }): Promise<void> {\n try {\n const result = await this.brevoClient.transactionalEmails.sendTransacEmail({\n sender: { email: this.senderEmail, name: this.senderName },\n to: emailData.to,\n subject: emailData.subject,\n htmlContent: emailData.htmlContent,\n textContent: emailData.textContent,\n });\n this.logger.debug(`Email sent successfully. Message ID: ${result.messageId}`);\n } catch (err) {\n if (err instanceof BrevoTimeoutError) {\n this.logger.error('Brevo request timed out after retries.');\n throw new Error('Email sending failed: timeout');\n }\n if (err instanceof BrevoError) {\n if (err.statusCode === 429) {\n this.logger.error('Brevo rate limit exceeded after retries.');\n throw new Error('Email sending failed: rate limit exceeded');\n }\n if (err.statusCode === 401) {\n this.logger.error('Brevo authentication failed. Check your API key.');\n throw new Error('Email service authentication failed');\n }\n if (err.statusCode === 400) {\n this.logger.error('Bad request to Brevo API:', err.message);\n throw new Error(`Invalid email parameters: ${err.message}`);\n }\n this.logger.error(`Brevo API error ${err.statusCode}:`, err.message);\n throw new Error(`Email sending failed: ${err.message}`);\n }\n throw err;\n }\n }\n}\n","import { type ArgumentsHost, Catch, type ExceptionFilter, type HttpException, HttpStatus, Logger } from '@nestjs/common';\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport type { ApiErrorResponse, FieldError } from '../types/error-response.types';\n\ninterface ProblemExceptionResponse {\n type?: string;\n label?: string;\n detail?: string;\n errors?: FieldError[];\n}\n\ninterface ValidationExceptionResponse {\n message: Array<string | { property: string; constraints: Record<string, string> }>;\n error?: string;\n}\n\ninterface StandardExceptionResponse {\n message: string | string[];\n error?: string;\n}\n\ntype ExceptionResponseObject = ProblemExceptionResponse | ValidationExceptionResponse | StandardExceptionResponse;\n\n// Converts an HTTP status code to its title string (e.g., 400 → \"Bad Request\")\nexport function getHttpStatusTitle(status: number): string {\n // Find the enum key for the given status code\n const enumKey = Object.entries(HttpStatus).find(([key, value]) => value === status && Number.isNaN(Number(key)))?.[0];\n\n if (!enumKey) {\n return 'Error';\n }\n\n // Convert enum key to title case (e.g., BAD_REQUEST -> Bad Request)\n return enumKey\n .split('_')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(' ');\n}\n\n@Catch()\nexport class HttpExceptionFilter implements ExceptionFilter {\n private readonly logger = new Logger(HttpExceptionFilter.name);\n\n catch(exception: unknown, host: ArgumentsHost) {\n const ctx = host.switchToHttp();\n const response = ctx.getResponse<FastifyReply>();\n const request = ctx.getRequest<FastifyRequest>();\n\n let status = HttpStatus.INTERNAL_SERVER_ERROR;\n let type = 'about:blank';\n let label: string | undefined;\n let detail = 'Internal server error';\n let errors: FieldError[] = [];\n\n if (this.isHttpException(exception)) {\n status = exception.getStatus();\n const exceptionResponse = exception.getResponse();\n\n if (typeof exceptionResponse === 'object' && exceptionResponse !== null) {\n const responseObj = exceptionResponse as ExceptionResponseObject;\n\n // Handle custom HttpProblemException from @vritti/api-sdk\n if ('type' in responseObj || 'label' in responseObj || 'errors' in responseObj) {\n const problemResponse = responseObj as ProblemExceptionResponse;\n type = problemResponse.type ?? 'about:blank';\n label = problemResponse.label;\n detail = problemResponse.detail ?? exception.message ?? getHttpStatusTitle(status);\n errors = problemResponse.errors ?? [];\n }\n // Handle class-validator DTO validation errors\n else if ('message' in responseObj && Array.isArray(responseObj.message)) {\n errors = responseObj.message\n .map((msg) => {\n if (typeof msg === 'object' && 'property' in msg && 'constraints' in msg) {\n const constraintValues = Object.values(msg.constraints);\n return {\n field: msg.property,\n message: constraintValues[0] ?? 'Validation failed',\n };\n }\n // Non-field-specific validation messages are ignored\n // They should be handled as detail at the response level\n return null;\n })\n .filter((error): error is FieldError => error !== null);\n detail = 'Validation failed';\n }\n // Handle standard NestJS exceptions\n else if ('message' in responseObj) {\n const message = responseObj.message;\n detail = Array.isArray(message) ? message.join(', ') : message;\n }\n } else if (typeof exceptionResponse === 'string') {\n detail = exceptionResponse;\n }\n } else if (this.isAxiosError(exception)) {\n // Outgoing HTTP call failures (e.g., service-to-service calls)\n const axiosStatus = exception.response?.status;\n const axiosDetail = exception.response?.data?.message || exception.response?.data?.detail || exception.message;\n const url = exception.config?.url;\n status = HttpStatus.BAD_GATEWAY;\n detail = `Upstream service error${axiosStatus ? ` (${axiosStatus})` : ''}: ${axiosDetail}`;\n this.logger.error(`Upstream API error [${axiosStatus}]: ${axiosDetail} — URL: ${url}`, exception.stack);\n } else {\n // Unknown errors — logged by HttpLoggerInterceptor, no need to log again here\n detail = 'An unexpected error occurred';\n }\n\n const problemDetails: ApiErrorResponse = {\n type,\n title: getHttpStatusTitle(status),\n status,\n ...(label && { label }),\n detail,\n instance: request.url,\n errors,\n };\n\n response.header('Content-Type', 'application/problem+json').status(status).send(problemDetails);\n }\n\n // Duck-type check for HttpException — avoids instanceof failing across pnpm package instances\n private isHttpException(error: unknown): error is HttpException {\n return (\n error instanceof Error &&\n typeof (error as { getStatus?: unknown }).getStatus === 'function' &&\n typeof (error as { getResponse?: unknown }).getResponse === 'function'\n );\n }\n\n // Duck-type check for AxiosError without importing axios\n private isAxiosError(error: unknown): error is Error & {\n isAxiosError: true;\n response?: { status?: number; data?: Record<string, unknown> };\n config?: { url?: string };\n } {\n return error instanceof Error && (error as { isAxiosError?: boolean }).isAxiosError === true;\n }\n}\n","import { type CallHandler, type ExecutionContext, Injectable, type NestInterceptor, Optional } from '@nestjs/common';\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport type { Observable } from 'rxjs';\nimport { catchError, tap } from 'rxjs/operators';\nimport { LoggerService } from '../services/logger.service';\nimport type { HttpLoggerOptions, LogMetadata } from '../types';\nimport { getCorrelationContext } from '../utils';\n\n@Injectable()\nexport class HttpLoggerInterceptor implements NestInterceptor {\n private readonly enableRequestLog: boolean;\n private readonly enableResponseLog: boolean;\n private readonly slowRequestThreshold: number;\n\n constructor(\n private readonly logger: LoggerService,\n @Optional() options?: HttpLoggerOptions,\n ) {\n this.enableRequestLog = options?.enableRequestLog ?? true;\n this.enableResponseLog = options?.enableResponseLog ?? true;\n this.slowRequestThreshold = options?.slowRequestThreshold ?? 3000; // 3 seconds\n }\n\n intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {\n if (context.getType() !== 'http') {\n return next.handle();\n }\n\n const httpContext = context.switchToHttp();\n const request = httpContext.getRequest<FastifyRequest>();\n const response = httpContext.getResponse<FastifyReply>();\n\n const startTime = Date.now();\n\n // Log incoming request\n if (this.enableRequestLog) {\n this.logRequest(request);\n }\n\n // Process request and log response/errors\n return next.handle().pipe(\n tap(() => {\n if (this.enableResponseLog) {\n const duration = Date.now() - startTime;\n this.logResponse(request, response, duration);\n }\n }),\n catchError((error) => {\n const duration = Date.now() - startTime;\n this.logError(request, response, duration, error);\n throw error;\n }),\n );\n }\n\n private logRequest(request: FastifyRequest): void {\n try {\n const correlationContext = getCorrelationContext();\n const metadata: LogMetadata = {\n type: 'http_request',\n method: request.method,\n url: request.url,\n correlationId: correlationContext?.correlationId,\n ip: request.ip,\n userAgent: request.headers['user-agent'],\n };\n\n this.logger.logWithMetadata('log', `Incoming ${request.method} ${request.url}`, metadata);\n } catch (error) {\n this.logger.error('Failed to log HTTP request', (error as Error).stack);\n }\n }\n\n private logResponse(request: FastifyRequest, response: FastifyReply, duration: number): void {\n try {\n const correlationContext = getCorrelationContext();\n const statusCode = response.statusCode;\n\n // Determine log level based on status code\n const logLevel = statusCode >= 500 ? 'error' : statusCode >= 400 ? 'warn' : 'log';\n\n const metadata: LogMetadata = {\n type: 'http_response',\n method: request.method,\n url: request.url,\n statusCode,\n duration,\n correlationId: correlationContext?.correlationId,\n };\n\n // Flag slow requests\n if (duration > this.slowRequestThreshold) {\n metadata.slowRequest = true;\n }\n\n const message = metadata.slowRequest\n ? `SLOW ${request.method} ${request.url} ${statusCode} - ${duration}ms`\n : `${request.method} ${request.url} ${statusCode} - ${duration}ms`;\n\n this.logger.logWithMetadata(logLevel, message, metadata);\n } catch (error) {\n this.logger.error('Failed to log HTTP response', (error as Error).stack);\n }\n }\n\n private logError(request: FastifyRequest, response: FastifyReply, duration: number, error: unknown): void {\n try {\n const correlationContext = getCorrelationContext();\n const statusCode = response.statusCode || 500;\n const err = error as { name?: string; message?: string; stack?: string; response?: unknown };\n\n const metadata: LogMetadata = {\n type: 'http_error',\n method: request.method,\n url: request.url,\n statusCode,\n duration,\n correlationId: correlationContext?.correlationId,\n errorName: err.name || 'Error',\n errorMessage: err.message || 'Unknown error',\n };\n\n if (err.stack) {\n metadata.trace = err.stack;\n }\n\n if (err.response) {\n metadata.errorDetails = err.response;\n }\n\n const message = `ERROR ${request.method} ${request.url} ${statusCode} - ${err.message || 'Unknown error'}`;\n this.logger.logWithMetadata('error', message, metadata);\n } catch (loggingError) {\n this.logger.error('Failed to log HTTP error', (loggingError as Error).stack);\n }\n }\n}\n","import { Injectable, type Logger, type LoggerService as NestLoggerService, Optional } from '@nestjs/common';\nimport { createLogger, format, type LoggerOptions, transports, type Logger as WinstonLogger } from 'winston';\nimport DailyRotateFile from 'winston-daily-rotate-file';\nimport type { LoggerModuleOptions, LogLevel, LogMetadata } from '../types';\nimport { getCorrelationContext } from '../utils';\n\nexport type LogMessage = string | Error | object;\n\n@Injectable()\nexport class LoggerService implements NestLoggerService {\n private readonly activeLogger: NestLoggerService | WinstonLogger;\n private readonly options: LoggerModuleOptions;\n private context?: string;\n\n constructor(\n @Optional() options: LoggerModuleOptions = {},\n @Optional() private readonly defaultLogger?: Logger,\n ) {\n this.options = options;\n const provider = options.provider ?? 'winston';\n\n if (provider === 'default') {\n if (!this.defaultLogger) {\n throw new Error('LoggerService: Default Logger not provided');\n }\n this.activeLogger = this.defaultLogger;\n } else {\n this.activeLogger = this.createWinstonLogger(options);\n }\n }\n\n // Creates a Winston logger instance with inline transports and format configuration\n private createWinstonLogger(opts: LoggerModuleOptions): WinstonLogger {\n const level = opts.level ?? 'debug';\n const logFormat = opts.format ?? 'text';\n\n // Base formatters\n // Winston automatically merges metadata into the info object, so all properties\n // (context, correlationId, etc.) are already at the top level\n const baseFormatters = [format.timestamp({ format: 'YYYY-MM-DDTHH:mm:ss.SSSZ' }), format.errors({ stack: true })];\n\n // Console transport\n const consoleTransport =\n logFormat === 'json'\n ? new transports.Console({\n level,\n format: format.combine(...baseFormatters, format.json()),\n })\n : new transports.Console({\n level,\n format: format.combine(\n ...baseFormatters,\n format.printf((info) => {\n const { timestamp, level, message, context, correlationId, trace } = info;\n const parts = [\n timestamp,\n level.toUpperCase().padEnd(7),\n correlationId ? `[${correlationId.toString().slice(-6)}]` : '',\n context ? `[${context}]` : '',\n message,\n ].filter(Boolean);\n let output = parts.join(' ');\n\n // Append stack trace on new line if present\n if (trace) {\n output += `\\n${trace}`;\n }\n\n return output;\n }),\n format.colorize({ all: true }),\n ),\n });\n\n const winstonTransports: (InstanceType<typeof transports.Console> | DailyRotateFile)[] = [consoleTransport];\n\n // File transports\n if (opts.enableFileLogger) {\n const filePath = opts.filePath ?? './logs';\n const maxFiles = opts.maxFiles ?? '14d';\n\n winstonTransports.push(\n new DailyRotateFile({\n level,\n filename: `${filePath}/%DATE%-combined.log`,\n datePattern: 'YYYY-MM-DD',\n maxSize: '20m',\n maxFiles,\n format: format.combine(format.timestamp(), format.json()),\n }),\n new DailyRotateFile({\n level: 'error',\n filename: `${filePath}/%DATE%-error.log`,\n datePattern: 'YYYY-MM-DD',\n maxSize: '20m',\n maxFiles,\n format: format.combine(format.timestamp(), format.json()),\n }),\n );\n }\n\n const config: LoggerOptions = {\n level,\n transports: winstonTransports,\n exitOnError: false,\n };\n\n if (opts.defaultMeta || opts.appName) {\n config.defaultMeta = {\n ...opts.defaultMeta,\n appName: opts.appName,\n environment: opts.environment,\n };\n }\n\n return createLogger(config);\n }\n\n // NestJS LoggerService interface methods\n log(message: LogMessage, context?: string): void {\n this._log('log', message, context);\n }\n\n error(message: LogMessage, trace?: string, context?: string): void {\n this._log('error', message, context, trace);\n }\n\n warn(message: LogMessage, context?: string): void {\n this._log('warn', message, context);\n }\n\n debug(message: LogMessage, context?: string): void {\n this._log('debug', message, context);\n }\n\n verbose(message: LogMessage, context?: string): void {\n this._log('verbose', message, context);\n }\n\n setContext(context: string): void {\n this.context = context;\n }\n\n // Dispatches a log entry to either the Winston or NestJS logger implementation\n private _log(level: LogLevel, message: LogMessage, context?: string, trace?: string): void {\n const ctx = context ?? this.context;\n\n // Check if Winston logger by duck typing\n if ('format' in this.activeLogger && 'transports' in this.activeLogger) {\n // Winston logger path\n const winstonLogger = this.activeLogger as WinstonLogger;\n const winstonLevel = level === 'log' ? 'info' : level;\n const formattedMessage = this.formatMessage(message);\n const metadata = this.enrichMetadata({}, ctx, trace);\n // Winston merges all properties into the info object when using object syntax\n winstonLogger.log({ level: winstonLevel, message: formattedMessage, ...metadata });\n } else {\n // NestJS logger path\n const nestLogger = this.activeLogger as Logger;\n if (level === 'error' && trace) {\n ctx ? nestLogger.error(message, trace, ctx) : nestLogger.error(message, trace);\n } else if (level === 'log') {\n ctx ? nestLogger.log(message, ctx) : nestLogger.log(message);\n } else if (level === 'warn') {\n ctx ? nestLogger.warn(message, ctx) : nestLogger.warn(message);\n } else if (level === 'debug' && nestLogger.debug) {\n ctx ? nestLogger.debug(message, ctx) : nestLogger.debug(message);\n } else if (level === 'verbose' && nestLogger.verbose) {\n ctx ? nestLogger.verbose(message, ctx) : nestLogger.verbose(message);\n }\n }\n }\n\n // Logs a message with custom metadata fields (Winston only)\n logWithMetadata(level: LogLevel, message: LogMessage, metadata?: LogMetadata, context?: string): void {\n const ctx = context ?? this.context;\n\n // Check if Winston logger by duck typing\n if ('format' in this.activeLogger && 'transports' in this.activeLogger) {\n const winstonLogger = this.activeLogger as WinstonLogger;\n const winstonLevel = level === 'log' ? 'info' : level;\n // const enriched = this.enrichMetadata(metadata, ctx);\n // Winston merges all properties into the info object when using object syntax\n winstonLogger.log({ level: winstonLevel, message: this.formatMessage(message), ...metadata });\n } else {\n // Fallback for default logger\n const messageWithMeta = metadata ? `${message} ${JSON.stringify(metadata)}` : message;\n this[level](messageWithMeta, ctx);\n }\n }\n\n private formatMessage(message: LogMessage): string {\n if (message instanceof Error) return message.message;\n if (typeof message === 'object' && message !== null) {\n try {\n return JSON.stringify(message);\n } catch {\n return String(message);\n }\n }\n return String(message);\n }\n\n // Enriches metadata with correlation context from AsyncLocalStorage\n private enrichMetadata(metadata: LogMetadata = {}, context?: string, trace?: string): LogMetadata {\n const enriched: LogMetadata = { ...metadata };\n\n if (context) enriched.context = context;\n\n const correlationContext = getCorrelationContext();\n if (correlationContext) {\n if (correlationContext.correlationId) enriched.correlationId = correlationContext.correlationId;\n for (const [key, value] of Object.entries(correlationContext)) {\n if (key !== 'correlationId') {\n enriched[key] = value;\n }\n }\n }\n\n if (trace) enriched.trace = trace;\n\n return enriched;\n }\n\n child(context: string): LoggerService {\n const childLogger = new LoggerService(this.options, this.defaultLogger);\n childLogger.setContext(context);\n return childLogger;\n }\n}\n","import { AsyncLocalStorage } from 'node:async_hooks';\nimport { randomUUID } from 'node:crypto';\nimport type { FastifyReply } from 'fastify';\nimport type { CorrelationContext } from '../types';\n\n// ============================================================================\n// Async Context Management (AsyncLocalStorage)\n// ============================================================================\n\nexport const correlationStorage = new AsyncLocalStorage<CorrelationContext>();\n\n// Returns the current correlation context from AsyncLocalStorage\nexport function getCorrelationContext(): CorrelationContext | undefined {\n return correlationStorage.getStore();\n}\n\n// Runs a callback within the given correlation context\nexport function runWithCorrelationContext<T>(context: CorrelationContext, callback: () => T): T {\n return correlationStorage.run(context, callback);\n}\n\n// Updates the current correlation context with new values\nexport function updateCorrelationContext(updates: Partial<CorrelationContext>): void {\n const context = correlationStorage.getStore();\n if (context) {\n Object.assign(context, updates);\n }\n}\n\n// ============================================================================\n// Correlation ID Management\n// ============================================================================\n\nexport const DEFAULT_CORRELATION_HEADER = 'x-correlation-id';\n\n// Generates a new UUID v4 correlation ID for the current request\nexport function generateCorrelationId(): string {\n return randomUUID();\n}\n\n// Adds the correlation ID to Fastify response headers\nexport function addCorrelationIdToResponse(\n reply: FastifyReply,\n correlationId: string,\n headerName: string = DEFAULT_CORRELATION_HEADER,\n): void {\n if (typeof reply.header === 'function') {\n reply.header(headerName, correlationId);\n } else if (reply.raw && typeof reply.raw.setHeader === 'function') {\n reply.raw.setHeader(headerName, correlationId);\n }\n}\n","import {\n type DynamicModule,\n Global,\n type InjectionToken,\n Logger,\n type MiddlewareConsumer,\n Module,\n type NestModule,\n type Provider,\n} from '@nestjs/common';\nimport { HttpLoggerInterceptor } from './interceptors/http-logger.interceptor';\nimport { CorrelationIdMiddleware } from './middleware/correlation-id.middleware';\nimport { LoggerService } from './services/logger.service';\nimport type { LoggerModuleAsyncOptions, LoggerModuleOptions, LoggerOptionsFactory } from './types';\n\n// ============================================================================\n// Constants (inline from constants.ts)\n// ============================================================================\n\nexport const LOGGER_MODULE_OPTIONS = Symbol('LOGGER_MODULE_OPTIONS');\n\nconst DEFAULT_LOGGER_OPTIONS = {\n provider: 'winston' as const,\n enableCorrelationId: true,\n enableHttpLogger: true,\n filePath: './logs',\n maxFiles: '14d',\n} as const;\n\n// ============================================================================\n// Environment Presets (NEW - replaces process.env auto-detection)\n// ============================================================================\n\nconst ENVIRONMENT_PRESETS: Record<string, Partial<LoggerModuleOptions>> = {\n development: {\n provider: 'winston',\n level: 'debug',\n format: 'text',\n enableFileLogger: false,\n enableCorrelationId: true,\n enableHttpLogger: true,\n httpLogger: {\n enableRequestLog: true,\n enableResponseLog: true,\n slowRequestThreshold: 1000, // 1 second - lower threshold for dev\n },\n },\n\n staging: {\n provider: 'winston',\n level: 'log',\n format: 'json',\n enableFileLogger: true,\n enableCorrelationId: true,\n enableHttpLogger: true,\n httpLogger: {\n enableRequestLog: true,\n enableResponseLog: true,\n slowRequestThreshold: 3000, // 3 seconds\n },\n },\n\n production: {\n provider: 'winston',\n level: 'warn',\n format: 'json',\n enableFileLogger: true,\n enableCorrelationId: true,\n enableHttpLogger: true,\n httpLogger: {\n enableRequestLog: false, // Reduce noise in production\n enableResponseLog: true,\n slowRequestThreshold: 5000, // 5 seconds - higher threshold for prod\n },\n },\n\n test: {\n provider: 'winston',\n level: 'error',\n format: 'json',\n enableFileLogger: false,\n enableCorrelationId: false,\n enableHttpLogger: false,\n },\n} as const;\n\n// ============================================================================\n// Configuration Merging (refactored to use presets instead of process.env)\n// ============================================================================\n\n// Merges user-provided options with default and environment preset values\nfunction mergeWithDefaults(options: LoggerModuleOptions = {}): LoggerModuleOptions {\n // Select preset based on explicit environment option (defaults to development)\n const preset = options.environment\n ? (ENVIRONMENT_PRESETS[options.environment] ?? ENVIRONMENT_PRESETS.development)\n : ENVIRONMENT_PRESETS.development;\n\n // Filter out undefined values from user options to avoid overriding preset defaults\n const filteredOptions = Object.fromEntries(Object.entries(options).filter(([_, value]) => value !== undefined));\n\n // Handle nested httpLogger object - merge with preset httpLogger if both exist\n if (filteredOptions.httpLogger && preset?.httpLogger) {\n filteredOptions.httpLogger = {\n ...preset.httpLogger,\n ...Object.fromEntries(Object.entries(filteredOptions.httpLogger).filter(([_, value]) => value !== undefined)),\n };\n }\n\n // Merge: base defaults < preset < user options (with undefined values removed)\n const merged = {\n ...DEFAULT_LOGGER_OPTIONS,\n ...preset,\n ...filteredOptions,\n };\n\n return merged;\n}\n\n// ============================================================================\n// Provider Factories (inline from logging.providers.ts)\n// ============================================================================\n\n// Creates the default NestJS Logger provider with optional log level configuration\nfunction createDefaultLoggerProvider(options: LoggerModuleOptions): Provider {\n return {\n provide: Logger,\n useFactory: () => {\n const logger = new Logger();\n\n // Set log levels if specified and method exists\n if (options.level) {\n const levels = getLevelsUpTo(options.level);\n (logger as { setLogLevels?: (levels: NestLogLevel[]) => void }).setLogLevels?.(levels);\n }\n\n return logger;\n },\n };\n}\n\n// Builds all logger providers for the module based on merged configuration\nfunction createLoggerProviders(options: LoggerModuleOptions = {}): Provider[] {\n // Merge user options with preset defaults\n const mergedOptions = mergeWithDefaults(options);\n\n // Base providers (always included)\n const providers: Provider[] = [\n // Options provider\n {\n provide: LOGGER_MODULE_OPTIONS,\n useValue: mergedOptions,\n },\n ];\n\n // Default logger provider (only if using default provider)\n if (mergedOptions.provider === 'default') {\n providers.push(createDefaultLoggerProvider(mergedOptions));\n }\n\n // Unified LoggerService facade (always included)\n providers.push({\n provide: LoggerService,\n useFactory: (opts: LoggerModuleOptions, defaultLogger?: Logger) => {\n return new LoggerService(opts, defaultLogger);\n },\n inject: [LOGGER_MODULE_OPTIONS, { token: Logger, optional: true }],\n });\n\n // Correlation ID middleware\n providers.push({\n provide: CorrelationIdMiddleware,\n useFactory: () => {\n return new CorrelationIdMiddleware({\n includeInResponse: true,\n responseHeader: 'x-correlation-id',\n });\n },\n });\n\n // HTTP logger interceptor\n providers.push({\n provide: HttpLoggerInterceptor,\n useFactory: (logger: LoggerService, opts: LoggerModuleOptions) => {\n // Use detailed httpLogger config if provided, otherwise fall back to simple enableHttpLogger\n const httpLoggerOptions = opts.httpLogger ?? {\n enableRequestLog: opts.enableHttpLogger,\n enableResponseLog: opts.enableHttpLogger,\n };\n return new HttpLoggerInterceptor(logger, httpLoggerOptions);\n },\n inject: [LoggerService, LOGGER_MODULE_OPTIONS],\n });\n\n return providers;\n}\n\ntype NestLogLevel = 'error' | 'warn' | 'log' | 'debug' | 'verbose';\n\n// Returns all NestJS log levels up to and including the specified level\nfunction getLevelsUpTo(level: string): NestLogLevel[] {\n const allLevels: NestLogLevel[] = ['error', 'warn', 'log', 'debug', 'verbose'];\n\n // Check if level is a valid NestLogLevel\n const isValidLevel = (l: string): l is NestLogLevel => allLevels.includes(l as NestLogLevel);\n\n if (!isValidLevel(level)) {\n return ['error', 'warn', 'log'];\n }\n\n const levelIndex = allLevels.indexOf(level);\n return allLevels.slice(0, levelIndex + 1);\n}\n\n// ============================================================================\n// Logger Module\n// ============================================================================\n\n@Global()\n@Module({})\nexport class LoggerModule implements NestModule {\n // Configures the logger module with static options and environment preset\n static forRoot(options: LoggerModuleOptions = {}): DynamicModule {\n const providers = createLoggerProviders(options);\n\n return {\n module: LoggerModule,\n providers,\n exports: [LoggerService, CorrelationIdMiddleware, HttpLoggerInterceptor, LOGGER_MODULE_OPTIONS],\n };\n }\n\n // Configures the logger module with async options (useFactory, useClass, useExisting)\n static forRootAsync(options: LoggerModuleAsyncOptions): DynamicModule {\n const asyncProviders = LoggerModule.createAsyncProviders(options);\n\n return {\n module: LoggerModule,\n imports: options.imports || [],\n providers: [\n ...asyncProviders,\n // Default logger provider\n {\n provide: Logger,\n useFactory: (opts: LoggerModuleOptions) => {\n if (opts.provider === 'default') {\n const logger = new Logger();\n if (opts.level) {\n const levels = getLevelsUpTo(opts.level);\n (logger as { setLogLevels?: (levels: NestLogLevel[]) => void }).setLogLevels?.(levels);\n }\n return logger;\n }\n return null;\n },\n inject: [LOGGER_MODULE_OPTIONS],\n },\n // Unified logger service\n {\n provide: LoggerService,\n useFactory: (opts: LoggerModuleOptions, defaultLogger?: Logger) => {\n return new LoggerService(opts, defaultLogger);\n },\n inject: [LOGGER_MODULE_OPTIONS, { token: Logger, optional: true }],\n },\n // Correlation ID middleware\n {\n provide: CorrelationIdMiddleware,\n useFactory: () => {\n return new CorrelationIdMiddleware({\n includeInResponse: true,\n responseHeader: 'x-correlation-id',\n });\n },\n },\n // HTTP logger interceptor\n {\n provide: HttpLoggerInterceptor,\n useFactory: (logger: LoggerService, opts: LoggerModuleOptions) => {\n // Use detailed httpLogger config if provided, otherwise fall back to simple enableHttpLogger\n const httpLoggerOptions = opts.httpLogger ?? {\n enableRequestLog: opts.enableHttpLogger,\n enableResponseLog: opts.enableHttpLogger,\n };\n return new HttpLoggerInterceptor(logger, httpLoggerOptions);\n },\n inject: [LoggerService, LOGGER_MODULE_OPTIONS],\n },\n ],\n exports: [LoggerService, CorrelationIdMiddleware, HttpLoggerInterceptor, LOGGER_MODULE_OPTIONS],\n };\n }\n\n // Middleware registration is handled globally in main.ts via Fastify hooks\n configure(_consumer: MiddlewareConsumer): void {\n // Middleware is registered globally in main.ts using Fastify's addHook('onRequest')\n // This avoids DI issues with the middleware constructor\n }\n\n // Creates async providers for dynamic module configuration\n private static createAsyncProviders(options: LoggerModuleAsyncOptions): Provider[] {\n if (options.useFactory) {\n return [LoggerModule.createAsyncOptionsProvider(options)];\n }\n\n const providers: Provider[] = [LoggerModule.createAsyncOptionsProvider(options)];\n\n if (options.useClass) {\n providers.push({\n provide: options.useClass,\n useClass: options.useClass,\n });\n }\n\n return providers;\n }\n\n // Creates the DI provider that resolves and merges async logger options\n private static createAsyncOptionsProvider(options: LoggerModuleAsyncOptions): Provider {\n if (options.useFactory) {\n return {\n provide: LOGGER_MODULE_OPTIONS,\n useFactory: async (...args: unknown[]) => {\n const userOptions = await options.useFactory?.(...args);\n return mergeWithDefaults(userOptions);\n },\n inject: (options.inject || []) as InjectionToken[],\n };\n }\n\n if (options.useClass) {\n return {\n provide: LOGGER_MODULE_OPTIONS,\n useFactory: async (optionsFactory: LoggerOptionsFactory) => {\n const userOptions = await optionsFactory.createLoggerOptions();\n return mergeWithDefaults(userOptions);\n },\n inject: [options.useClass],\n };\n }\n\n if (options.useExisting) {\n return {\n provide: LOGGER_MODULE_OPTIONS,\n useFactory: async (optionsFactory: LoggerOptionsFactory) => {\n const userOptions = await optionsFactory.createLoggerOptions();\n return mergeWithDefaults(userOptions);\n },\n inject: [options.useExisting],\n };\n }\n\n throw new Error('LoggerModule.forRootAsync() requires one of: useFactory, useClass, or useExisting');\n }\n}\n","import { Injectable, type NestMiddleware } from '@nestjs/common';\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport {\n addCorrelationIdToResponse,\n correlationStorage,\n DEFAULT_CORRELATION_HEADER,\n generateCorrelationId,\n runWithCorrelationContext,\n} from '../utils';\n\nexport interface CorrelationIdMiddlewareOptions {\n includeInResponse?: boolean;\n responseHeader?: string;\n}\n\n@Injectable()\nexport class CorrelationIdMiddleware implements NestMiddleware {\n private readonly includeInResponse: boolean;\n private readonly responseHeader: string;\n\n constructor(options: CorrelationIdMiddlewareOptions = {}) {\n this.includeInResponse = options.includeInResponse ?? true;\n this.responseHeader = options.responseHeader ?? DEFAULT_CORRELATION_HEADER;\n }\n\n // Generates and stores a correlation ID for the incoming request\n use(_req: FastifyRequest, reply: FastifyReply, next: () => void): void {\n // Generate new correlation ID for this request\n const correlationId = generateCorrelationId();\n\n // Add to response headers if enabled\n if (this.includeInResponse) {\n addCorrelationIdToResponse(reply, correlationId, this.responseHeader);\n }\n\n // Run the rest of the request in AsyncLocalStorage context\n runWithCorrelationContext({ correlationId }, () => {\n next();\n });\n }\n\n // Fastify onRequest hook that initializes correlation context in AsyncLocalStorage\n async onRequest(_req: FastifyRequest, reply: FastifyReply): Promise<void> {\n // Generate new correlation ID for this request\n const correlationId = generateCorrelationId();\n\n // Add to response headers if enabled\n if (this.includeInResponse) {\n addCorrelationIdToResponse(reply, correlationId, this.responseHeader);\n }\n\n // Store in AsyncLocalStorage for the request lifecycle\n // Note: We don't wrap in runWithCorrelationContext here because\n // Fastify's async context tracking handles it automatically\n const store = correlationStorage.getStore();\n if (!store) {\n // Initialize new store\n correlationStorage.enterWith({ correlationId });\n }\n }\n}\n","import { Module } from '@nestjs/common';\nimport { AppController } from './controllers/app.controller';\nimport { CsrfController } from './controllers/csrf.controller';\nimport { AppService } from './services/app.service';\n\n@Module({\n controllers: [AppController, CsrfController],\n providers: [AppService],\n})\nexport class RootModule {}\n","import { Controller, Get } from '@nestjs/common';\nimport { ApiTags } from '@nestjs/swagger';\nimport { Public } from '../../auth/decorators/public.decorator';\nimport { ApiHealthCheck } from '../docs/app.docs';\nimport { AppService } from '../services/app.service';\n\n@ApiTags('Health')\n@Controller()\nexport class AppController {\n constructor(private readonly appService: AppService) {}\n\n // Returns a welcome message indicating the API is running\n @Get()\n @Public()\n @ApiHealthCheck()\n getHello(): string {\n return this.appService.getHello();\n }\n}\n","import { applyDecorators } from '@nestjs/common';\nimport { ApiOperation, ApiResponse } from '@nestjs/swagger';\n\nexport function ApiHealthCheck() {\n return applyDecorators(\n ApiOperation({ summary: 'Health check endpoint' }),\n ApiResponse({\n status: 200,\n description: 'Returns a welcome message indicating the API is running',\n type: String,\n }),\n );\n}\n","import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n // Returns the API welcome message\n getHello(): string {\n return `Hello World!`;\n }\n}\n","import { Controller, Get, HttpCode, HttpStatus, Res } from '@nestjs/common';\nimport { ApiTags } from '@nestjs/swagger';\nimport type { FastifyReply } from 'fastify';\nimport { Public } from '../../auth/decorators/public.decorator';\nimport { ApiGetCsrfToken } from '../docs/csrf.docs';\n\n// Type augmentation for @fastify/csrf-protection — added by the consuming server at runtime\ntype FastifyReplyWithCsrf = FastifyReply & { generateCsrf(): string };\n\n@ApiTags('CSRF')\n@Controller('csrf')\nexport class CsrfController {\n // Generates a CSRF token via Fastify's csrf-protection plugin\n @Get('token')\n @Public()\n @HttpCode(HttpStatus.OK)\n @ApiGetCsrfToken()\n getToken(@Res({ passthrough: true }) reply: FastifyReply): { csrfToken: string } {\n const csrfToken = (reply as FastifyReplyWithCsrf).generateCsrf();\n return { csrfToken };\n }\n}\n","import { applyDecorators } from '@nestjs/common';\nimport { ApiOperation, ApiResponse } from '@nestjs/swagger';\n\nexport function ApiGetCsrfToken() {\n return applyDecorators(\n ApiOperation({\n summary: 'Get CSRF token',\n description:\n 'Generates and returns a CSRF token that must be included in all state-changing requests (POST, PUT, PATCH, DELETE). The token should be sent in the X-CSRF-Token header.',\n }),\n ApiResponse({\n status: 200,\n description: 'CSRF token generated successfully',\n schema: {\n type: 'object',\n properties: {\n csrfToken: {\n type: 'string',\n description: 'The CSRF token to use in subsequent requests',\n example: 'abc123xyz789',\n },\n },\n required: ['csrfToken'],\n },\n }),\n );\n}\n","const CALLING_CODE_TO_COUNTRY: Record<string, string> = {\n // 3-digit codes\n '355': 'AL', '213': 'DZ', '376': 'AD', '244': 'AO', '672': 'AQ',\n '374': 'AM', '297': 'AW', '994': 'AZ', '973': 'BH', '880': 'BD',\n '375': 'BY', '501': 'BZ', '229': 'BJ', '975': 'BT', '591': 'BO',\n '387': 'BA', '267': 'BW', '673': 'BN', '359': 'BG', '226': 'BF',\n '257': 'BI', '855': 'KH', '237': 'CM', '238': 'CV', '236': 'CF',\n '235': 'TD', '269': 'KM', '242': 'CG', '243': 'CD', '506': 'CR',\n '385': 'HR', '357': 'CY', '420': 'CZ', '253': 'DJ', '593': 'EC',\n '503': 'SV', '240': 'GQ', '291': 'ER', '372': 'EE', '251': 'ET',\n '679': 'FJ', '358': 'FI', '241': 'GA', '220': 'GM', '995': 'GE',\n '233': 'GH', '350': 'GI', '299': 'GL', '502': 'GT', '224': 'GN',\n '245': 'GW', '592': 'GY', '509': 'HT', '504': 'HN', '354': 'IS',\n '964': 'IQ', '353': 'IE', '972': 'IL', '225': 'CI', '962': 'JO',\n '254': 'KE', '686': 'KI', '965': 'KW', '996': 'KG', '856': 'LA',\n '371': 'LV', '961': 'LB', '266': 'LS', '231': 'LR', '218': 'LY',\n '423': 'LI', '370': 'LT', '352': 'LU', '389': 'MK', '261': 'MG',\n '265': 'MW', '960': 'MV', '223': 'ML', '356': 'MT', '692': 'MH',\n '222': 'MR', '230': 'MU', '262': 'YT', '691': 'FM', '373': 'MD',\n '377': 'MC', '976': 'MN', '382': 'ME', '258': 'MZ', '264': 'NA',\n '674': 'NR', '977': 'NP', '505': 'NI', '227': 'NE', '234': 'NG',\n '683': 'NU', '968': 'OM', '680': 'PW', '970': 'PS', '507': 'PA',\n '675': 'PG', '595': 'PY', '351': 'PT', '974': 'QA', '250': 'RW',\n '685': 'WS', '378': 'SM', '239': 'ST', '966': 'SA', '221': 'SN',\n '381': 'RS', '248': 'SC', '232': 'SL', '421': 'SK', '386': 'SI',\n '677': 'SB', '252': 'SO', '211': 'SS', '249': 'SD', '597': 'SR',\n '268': 'SZ', '963': 'SY', '992': 'TJ', '255': 'TZ', '228': 'TG',\n '676': 'TO', '216': 'TN', '993': 'TM', '688': 'TV', '256': 'UG',\n '380': 'UA', '971': 'AE', '598': 'UY', '998': 'UZ', '678': 'VU',\n '379': 'VA', '967': 'YE', '260': 'ZM', '263': 'ZW',\n\n // 2-digit codes\n '93': 'AF', '54': 'AR', '61': 'AU', '43': 'AT', '32': 'BE',\n '55': 'BR', '56': 'CL', '86': 'CN', '57': 'CO', '53': 'CU',\n '45': 'DK', '20': 'EG', '33': 'FR', '49': 'DE', '30': 'GR',\n '36': 'HU', '91': 'IN', '62': 'ID', '98': 'IR', '39': 'IT',\n '81': 'JP', '82': 'KR', '60': 'MY', '52': 'MX', '31': 'NL',\n '64': 'NZ', '47': 'NO', '92': 'PK', '51': 'PE', '63': 'PH',\n '48': 'PL', '40': 'RO', '65': 'SG', '27': 'ZA', '34': 'ES',\n '94': 'LK', '46': 'SE', '41': 'CH', '66': 'TH', '90': 'TR',\n '44': 'GB', '58': 'VE', '84': 'VN',\n\n // 1-digit codes (shared codes default to most common country)\n '1': 'US', // Also CA, but default to US\n '7': 'RU', // Also KZ, but default to RU\n};\n\n// Extracts ISO 3166-1 alpha-2 country code from an E.164 phone number\nexport function extractCountryFromPhone(phone: string): string | undefined {\n // Remove + prefix if present\n const digits = phone.startsWith('+') ? phone.slice(1) : phone;\n\n // Try matching from longest to shortest prefix (3, 2, 1 digits)\n for (const length of [3, 2, 1]) {\n const prefix = digits.slice(0, length);\n if (CALLING_CODE_TO_COUNTRY[prefix]) {\n return CALLING_CODE_TO_COUNTRY[prefix];\n }\n }\n\n return undefined;\n}\n\n// Normalizes a phone number to E.164 format by ensuring a + prefix\nexport function normalizePhoneNumber(phone: string): string {\n return phone.startsWith('+') ? phone : `+${phone}`;\n}\n","import { type DynamicModule, Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';\nimport type { PgTable } from 'drizzle-orm/pg-core';\nimport { CacheModule } from '../cache/cache.module';\nimport { DATA_TABLE_VIEWS_TABLE } from './data-table.constants';\nimport { DataTableStateController } from './state/controllers/data-table-state.controller';\nimport { DataTableStateService } from './state/services/data-table-state.service';\nimport { DataTableViewsController } from './views/controllers/data-table-views.controller';\nimport { DataTableViewsRepository } from './views/repositories/data-table-views.repository';\nimport { DataTableViewsService } from './views/services/data-table-views.service';\n\nexport { DATA_TABLE_VIEWS_TABLE };\n\nexport interface DataTableModuleOptions {\n tableViews: PgTable;\n}\n\n@Module({})\nexport class DataTableModule {\n static forRoot(options: DataTableModuleOptions): DynamicModule {\n return {\n global: true,\n module: DataTableModule,\n imports: [ConfigModule, CacheModule],\n controllers: [DataTableStateController, DataTableViewsController],\n providers: [\n {\n provide: DATA_TABLE_VIEWS_TABLE,\n useValue: options.tableViews,\n },\n DataTableViewsService,\n DataTableViewsRepository,\n DataTableStateService,\n ],\n exports: [DataTableViewsService, DataTableStateService],\n };\n }\n}\n","export const DATA_TABLE_VIEWS_TABLE = Symbol('DATA_TABLE_VIEWS_TABLE');\n","import { Body, Controller, HttpCode, HttpStatus, Logger, Post } from '@nestjs/common';\nimport { ApiBearerAuth, ApiTags } from '@nestjs/swagger';\nimport { RequireSession } from '../../../auth/decorators/require-session.decorator';\nimport { UserId } from '../../../auth/decorators/user-id.decorator';\nimport { ApiUpsertDataTableState } from '../docs/data-table-state.docs';\nimport { UpsertDataTableStateDto } from '../dto/request/upsert-data-table-state.dto';\nimport { DataTableStateService } from '../services/data-table-state.service';\n\n@ApiTags('Table States')\n@ApiBearerAuth()\n@RequireSession('CLOUD', 'ADMIN')\n@Controller('table-states')\nexport class DataTableStateController {\n private readonly logger = new Logger(DataTableStateController.name);\n\n constructor(private readonly dataTableStateService: DataTableStateService) {}\n\n // Saves live table state to Redis cache for the authenticated user's table\n @Post()\n @HttpCode(HttpStatus.OK)\n @ApiUpsertDataTableState()\n upsertCurrentState(@UserId() userId: string, @Body() dto: UpsertDataTableStateDto): Promise<void> {\n this.logger.log(`POST /table-states - User: ${userId}, table: ${dto.tableSlug}`);\n return this.dataTableStateService.upsertCurrentState(userId, dto);\n }\n}\n","import { applyDecorators } from '@nestjs/common';\nimport { ApiBody, ApiOperation, ApiResponse } from '@nestjs/swagger';\nimport { UpsertDataTableStateDto } from '../dto/request/upsert-data-table-state.dto';\n\nexport function ApiUpsertDataTableState() {\n return applyDecorators(\n ApiOperation({\n summary: 'Save live table state',\n description:\n 'Stores the current filter, sort, and column visibility state in Redis cache. Called on filter Apply and sort column click. State expires after TABLE_STATE_CACHE_TTL seconds.',\n }),\n ApiBody({ type: UpsertDataTableStateDto }),\n ApiResponse({ status: 200, description: 'Live state cached.' }),\n ApiResponse({ status: 400, description: 'Invalid request body.' }),\n ApiResponse({ status: 401, description: 'Unauthorized.' }),\n );\n}\n","import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';\nimport { IsObject, IsOptional, IsString, IsUUID, MaxLength } from 'class-validator';\nimport type { TableViewState } from '../../../../database/filter/filter.types';\n\nexport class UpsertDataTableStateDto {\n @ApiProperty({ description: 'Unique slug identifying the table', example: 'cloud-providers' })\n @IsString()\n @MaxLength(100)\n tableSlug!: string;\n\n @ApiProperty({ description: 'Full table view state including filters, sort, and column visibility' })\n @IsObject()\n state!: TableViewState;\n\n @ApiPropertyOptional()\n @IsOptional()\n @IsUUID()\n activeViewId?: string | null;\n}\n","import { Injectable, Logger } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { CacheService } from '../../../cache/cache.service';\nimport type { TableViewState } from '../../../database/filter/filter.types';\nimport type { UpsertDataTableStateDto } from '../dto/request/upsert-data-table-state.dto';\n\nconst EMPTY_TABLE_STATE: TableViewState = {\n filters: [],\n sort: [],\n columnVisibility: {},\n columnOrder: [],\n columnSizing: {},\n columnPinning: { left: [], right: [] },\n lockedColumnSizing: false,\n density: 'normal',\n filterOrder: [],\n filterVisibility: {},\n pagination: { limit: 20, offset: 0 },\n};\n\n@Injectable()\nexport class DataTableStateService {\n private readonly logger = new Logger(DataTableStateService.name);\n\n constructor(\n private readonly cacheService: CacheService,\n private readonly configService: ConfigService,\n ) {}\n\n // Returns configured TTL for live table state in seconds, defaulting to 3600 (1h)\n private get stateTtl(): number {\n return this.configService.get<number>('TABLE_STATE_CACHE_TTL') ?? 3600;\n }\n\n // Saves live table state and active view ID to Redis; DB is not written\n async upsertCurrentState(userId: string, dto: UpsertDataTableStateDto): Promise<void> {\n const key = `dt:${userId}:${dto.tableSlug}`;\n await this.cacheService.set(key, { state: dto.state, activeViewId: dto.activeViewId ?? null }, this.stateTtl);\n this.logger.log(`Cached live state for user: ${userId}, table: ${dto.tableSlug}`);\n }\n\n // Returns live table state and active view ID from Redis; returns empty state on miss — no DB query\n async getCurrentState(userId: string, tableSlug: string): Promise<{ state: TableViewState; activeViewId: string | null }> {\n const key = `dt:${userId}:${tableSlug}`;\n const cached = await this.cacheService.get<{ state: TableViewState; activeViewId: string | null }>(key);\n return cached ?? { state: EMPTY_TABLE_STATE, activeViewId: null };\n }\n}\n","import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Logger, Param, Patch, Post, Query } from '@nestjs/common';\nimport { ApiBearerAuth, ApiTags } from '@nestjs/swagger';\nimport { RequireSession } from '../../../auth/decorators/require-session.decorator';\nimport { UserId } from '../../../auth/decorators/user-id.decorator';\nimport { ApiCreateDataTableView, ApiDeleteDataTableView, ApiListDataTableViews, ApiRenameDataTableView, ApiToggleShareDataTableView, ApiUpdateDataTableView } from '../docs/data-table-views.docs';\nimport { DataTableViewDto } from '../dto/entity/data-table-view.dto';\nimport { CreateDataTableViewDto } from '../dto/request/create-data-table-view.dto';\nimport { RenameDataTableViewDto } from '../dto/request/rename-data-table-view.dto';\nimport { ToggleShareDataTableViewDto } from '../dto/request/toggle-share-data-table-view.dto';\nimport { UpdateDataTableViewDto } from '../dto/request/update-data-table-view.dto';\nimport { DataTableViewsService } from '../services/data-table-views.service';\n\n@ApiTags('Table Views')\n@ApiBearerAuth()\n@RequireSession('CLOUD', 'ADMIN')\n@Controller('table-views')\nexport class DataTableViewsController {\n private readonly logger = new Logger(DataTableViewsController.name);\n\n constructor(private readonly dataTableViewsService: DataTableViewsService) {}\n\n // Returns all named views for the given table — own plus shared\n @Get()\n @ApiListDataTableViews()\n findViews(@UserId() userId: string, @Query('tableSlug') tableSlug: string): Promise<DataTableViewDto[]> {\n this.logger.log(`GET /table-views?tableSlug=${tableSlug} - User: ${userId}`);\n return this.dataTableViewsService.findViews(userId, tableSlug);\n }\n\n // Creates a named snapshot of the current table state\n @Post()\n @HttpCode(HttpStatus.CREATED)\n @ApiCreateDataTableView()\n createView(@UserId() userId: string, @Body() dto: CreateDataTableViewDto): Promise<DataTableViewDto> {\n this.logger.log(`POST /table-views - User: ${userId}, table: ${dto.tableSlug}`);\n return this.dataTableViewsService.createView(userId, dto);\n }\n\n // Updates state of an existing named view\n @Patch(':id')\n @ApiUpdateDataTableView()\n updateView(@UserId() userId: string, @Param('id') id: string, @Body() dto: UpdateDataTableViewDto): Promise<DataTableViewDto> {\n this.logger.log(`PATCH /table-views/${id} - User: ${userId}`);\n return this.dataTableViewsService.updateView(userId, id, dto);\n }\n\n // Renames an existing named view — enforces unique name per user+table\n @Patch(':id/rename')\n @ApiRenameDataTableView()\n renameView(@UserId() userId: string, @Param('id') id: string, @Body() dto: RenameDataTableViewDto): Promise<DataTableViewDto> {\n this.logger.log(`PATCH /table-views/${id}/rename - User: ${userId}`);\n return this.dataTableViewsService.renameView(userId, id, dto.name);\n }\n\n // Toggles sharing visibility of a named view\n @Patch(':id/share')\n @ApiToggleShareDataTableView()\n toggleShareView(@UserId() userId: string, @Param('id') id: string, @Body() dto: ToggleShareDataTableViewDto): Promise<DataTableViewDto> {\n this.logger.log(`PATCH /table-views/${id}/share - User: ${userId}`);\n return this.dataTableViewsService.toggleShareView(userId, id, dto.isShared);\n }\n\n // Deletes a named view owned by the authenticated user\n @Delete(':id')\n @ApiDeleteDataTableView()\n deleteView(@UserId() userId: string, @Param('id') id: string): Promise<DataTableViewDto> {\n this.logger.log(`DELETE /table-views/${id} - User: ${userId}`);\n return this.dataTableViewsService.deleteView(userId, id);\n }\n}\n","import { applyDecorators } from '@nestjs/common';\nimport { ApiBody, ApiOperation, ApiParam, ApiQuery, ApiResponse } from '@nestjs/swagger';\nimport { DataTableViewDto } from '../dto/entity/data-table-view.dto';\nimport { CreateDataTableViewDto } from '../dto/request/create-data-table-view.dto';\nimport { RenameDataTableViewDto } from '../dto/request/rename-data-table-view.dto';\nimport { ToggleShareDataTableViewDto } from '../dto/request/toggle-share-data-table-view.dto';\nimport { UpdateDataTableViewDto } from '../dto/request/update-data-table-view.dto';\n\nexport function ApiListDataTableViews() {\n return applyDecorators(\n ApiOperation({\n summary: 'List named table views',\n description: \"Returns the authenticated user's own named views plus all shared views for the given table slug.\",\n }),\n ApiQuery({\n name: 'tableSlug',\n description: 'Slug of the table to fetch views for',\n example: 'cloud-providers',\n required: true,\n }),\n ApiResponse({ status: 200, description: 'Named views retrieved.', type: [DataTableViewDto] }),\n ApiResponse({ status: 401, description: 'Unauthorized.' }),\n );\n}\n\nexport function ApiCreateDataTableView() {\n return applyDecorators(\n ApiOperation({\n summary: 'Create named table view',\n description: 'Saves the current table state as a named view snapshot. The name must be unique per user+table.',\n }),\n ApiBody({ type: CreateDataTableViewDto }),\n ApiResponse({ status: 201, description: 'Named view created.', type: DataTableViewDto }),\n ApiResponse({ status: 400, description: 'Invalid request body.' }),\n ApiResponse({ status: 401, description: 'Unauthorized.' }),\n );\n}\n\nexport function ApiUpdateDataTableView() {\n return applyDecorators(\n ApiOperation({\n summary: 'Update named table view',\n description: 'Updates the state of an existing named view. Only the owner can update.',\n }),\n ApiParam({ name: 'id', description: 'UUID of the table view to update' }),\n ApiBody({ type: UpdateDataTableViewDto }),\n ApiResponse({ status: 200, description: 'View updated.', type: DataTableViewDto }),\n ApiResponse({ status: 400, description: 'Validation failed or not owned by caller.' }),\n ApiResponse({ status: 401, description: 'Unauthorized.' }),\n ApiResponse({ status: 404, description: 'View not found.' }),\n );\n}\n\nexport function ApiRenameDataTableView() {\n return applyDecorators(\n ApiOperation({\n summary: 'Rename a named table view',\n description: 'Updates the display name of an existing view. The new name must be unique per user+table. Only the owner can rename.',\n }),\n ApiParam({ name: 'id', description: 'UUID of the table view to rename' }),\n ApiBody({ type: RenameDataTableViewDto }),\n ApiResponse({ status: 200, description: 'View renamed.', type: DataTableViewDto }),\n ApiResponse({ status: 400, description: 'Not owned by caller.' }),\n ApiResponse({ status: 401, description: 'Unauthorized.' }),\n ApiResponse({ status: 404, description: 'View not found.' }),\n ApiResponse({ status: 409, description: 'A view with this name already exists.' }),\n );\n}\n\nexport function ApiToggleShareDataTableView() {\n return applyDecorators(\n ApiOperation({\n summary: 'Toggle view sharing',\n description: 'Makes a view visible to all users (shared) or restricts it to the owner only (private). Only the owner can toggle sharing.',\n }),\n ApiParam({ name: 'id', description: 'UUID of the table view' }),\n ApiBody({ type: ToggleShareDataTableViewDto }),\n ApiResponse({ status: 200, description: 'Sharing status updated.', type: DataTableViewDto }),\n ApiResponse({ status: 400, description: 'Not owned by caller.' }),\n ApiResponse({ status: 401, description: 'Unauthorized.' }),\n ApiResponse({ status: 404, description: 'View not found.' }),\n );\n}\n\nexport function ApiDeleteDataTableView() {\n return applyDecorators(\n ApiOperation({\n summary: 'Delete named table view',\n description: 'Permanently deletes a named view. Only the owner can delete their own views.',\n }),\n ApiParam({ name: 'id', description: 'UUID of the table view to delete' }),\n ApiResponse({ status: 200, description: 'View deleted.', type: DataTableViewDto }),\n ApiResponse({ status: 400, description: 'Not owned by caller.' }),\n ApiResponse({ status: 401, description: 'Unauthorized.' }),\n ApiResponse({ status: 404, description: 'View not found.' }),\n );\n}\n","import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';\nimport type { DataTableViewRecord } from '../../../schema/data-table-views.table';\nimport type { TableViewState } from '../../../../database/filter/filter.types';\n\nexport class DataTableViewDto {\n @ApiProperty({ description: 'View unique identifier' })\n id!: string;\n\n @ApiPropertyOptional({ description: 'Display name of the view', nullable: true })\n name!: string | null;\n\n @ApiProperty({ description: 'Slug of the table this view belongs to', example: 'cloud-providers' })\n tableSlug!: string;\n\n @ApiProperty({ description: 'Stored filter, sort, and column visibility state' })\n state!: TableViewState;\n\n @ApiProperty({ description: 'Whether the view is visible to all users', example: false })\n isShared!: boolean;\n\n @ApiProperty({ description: 'Whether the requesting user owns this view', example: true })\n isOwn!: boolean;\n\n @ApiProperty({ description: 'Creation timestamp' })\n createdAt!: Date;\n\n @ApiPropertyOptional({ description: 'Last updated timestamp', nullable: true })\n updatedAt!: Date | null;\n\n // Creates a response DTO from a DataTableView entity, computing isOwn by comparing userId\n static from(view: DataTableViewRecord, userId: string): DataTableViewDto {\n const dto = new DataTableViewDto();\n dto.id = view.id;\n dto.name = view.name ?? null;\n dto.tableSlug = view.tableSlug;\n dto.state = view.state;\n dto.isShared = view.isShared;\n dto.isOwn = view.userId === userId;\n dto.createdAt = view.createdAt;\n dto.updatedAt = view.updatedAt ?? null;\n return dto;\n }\n}\n","import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';\nimport { IsBoolean, IsObject, IsOptional, IsString, MaxLength } from 'class-validator';\nimport type { TableViewState } from '../../../../database/filter/filter.types';\n\nexport class CreateDataTableViewDto {\n @ApiProperty({ description: 'Display name for the saved view', example: 'AWS Only' })\n @IsString()\n @MaxLength(100)\n name!: string;\n\n @ApiProperty({ description: 'Unique slug identifying the table', example: 'cloud-providers' })\n @IsString()\n @MaxLength(100)\n tableSlug!: string;\n\n @ApiProperty({ description: 'Full table view state including filters, sort, and column visibility' })\n @IsObject()\n state!: TableViewState;\n\n @ApiPropertyOptional({ description: 'Whether this view is visible to all users', example: false })\n @IsBoolean()\n @IsOptional()\n isShared?: boolean;\n}\n","import { ApiProperty } from '@nestjs/swagger';\nimport { IsString, MaxLength, MinLength } from 'class-validator';\n\nexport class RenameDataTableViewDto {\n @ApiProperty({ description: 'New display name for the view', example: 'AWS Only' })\n @IsString()\n @MinLength(1)\n @MaxLength(100)\n name!: string;\n}\n","import { ApiProperty } from '@nestjs/swagger';\nimport { IsBoolean } from 'class-validator';\n\nexport class ToggleShareDataTableViewDto {\n @ApiProperty({ description: 'Whether the view should be visible to all users', example: true })\n @IsBoolean()\n isShared!: boolean;\n}\n","import { ApiProperty } from '@nestjs/swagger';\nimport { IsObject } from 'class-validator';\nimport type { TableViewState } from '../../../../database/filter/filter.types';\n\n// State-only update — name, tableSlug, and isShared are not updatable via this DTO\nexport class UpdateDataTableViewDto {\n @ApiProperty({ description: 'Updated filter, sort, and column visibility state' })\n @IsObject()\n state!: TableViewState;\n}\n","import { createHash } from 'node:crypto';\nimport { Injectable, Logger } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { CacheService } from '../../../cache/cache.service';\nimport { BadRequestException, ConflictException, NotFoundException } from '../../../exceptions';\nimport type { DataTableViewRecord } from '../../schema/data-table-views.table';\nimport { DataTableViewDto } from '../dto/entity/data-table-view.dto';\nimport type { CreateDataTableViewDto } from '../dto/request/create-data-table-view.dto';\nimport type { UpdateDataTableViewDto } from '../dto/request/update-data-table-view.dto';\nimport { DataTableViewsRepository } from '../repositories/data-table-views.repository';\n\n// Computes a deterministic SHA-256 checksum of a value for equality comparison\nfunction computeChecksum(value: unknown): string {\n return createHash('sha256').update(JSON.stringify(value)).digest('hex');\n}\n\n@Injectable()\nexport class DataTableViewsService {\n private readonly logger = new Logger(DataTableViewsService.name);\n\n constructor(\n private readonly dataTableViewsRepository: DataTableViewsRepository,\n private readonly cacheService: CacheService,\n private readonly configService: ConfigService,\n ) {}\n\n // Builds the Redis key for a user's personal (non-shared) views for a given table\n private personalViewsKey(userId: string, tableSlug: string): string {\n return `views:personal:${userId}:${tableSlug}`;\n }\n\n // Builds the Redis key for all shared views for a given table — same key for all users\n private sharedViewsKey(tableSlug: string): string {\n return `views:shared:${tableSlug}`;\n }\n\n // Returns configured TTL for named views in seconds, defaulting to 86400 (24h)\n private get viewsTtl(): number {\n return this.configService.get<number>('TABLE_VIEWS_CACHE_TTL') ?? 86400;\n }\n\n // Fetches personal views from cache; falls back to DB and warms cache on miss\n private async getOrCachePersonalViews(userId: string, tableSlug: string): Promise<DataTableViewRecord[]> {\n const key = this.personalViewsKey(userId, tableSlug);\n const cached = await this.cacheService.get<DataTableViewRecord[]>(key);\n if (cached) {\n this.logger.debug(`Cache hit for personal views: user=${userId}, table=${tableSlug}`);\n return cached;\n }\n const rows = await this.dataTableViewsRepository.findPersonalViewsBySlug(userId, tableSlug);\n await this.cacheService.set(key, rows, this.viewsTtl);\n return rows;\n }\n\n // Fetches shared views from cache; falls back to DB and warms cache on miss\n private async getOrCacheSharedViews(tableSlug: string): Promise<DataTableViewRecord[]> {\n const key = this.sharedViewsKey(tableSlug);\n const cached = await this.cacheService.get<DataTableViewRecord[]>(key);\n if (cached) {\n this.logger.debug(`Cache hit for shared views: table=${tableSlug}`);\n return cached;\n }\n const rows = await this.dataTableViewsRepository.findSharedViewsBySlug(tableSlug);\n await this.cacheService.set(key, rows, this.viewsTtl);\n return rows;\n }\n\n // Deletes personal and/or shared cache keys based on which pools the mutation affects\n private async invalidateViewsCache(\n userId: string,\n tableSlug: string,\n affectsPersonal: boolean,\n affectsShared: boolean,\n ): Promise<void> {\n const toDelete: string[] = [];\n if (affectsPersonal) toDelete.push(this.personalViewsKey(userId, tableSlug));\n if (affectsShared) toDelete.push(this.sharedViewsKey(tableSlug));\n if (toDelete.length > 0) await this.cacheService.del(...toDelete);\n }\n\n // Returns personal + shared named views — each pool fetched from cache or DB in parallel\n async findViews(userId: string, tableSlug: string): Promise<DataTableViewDto[]> {\n const [personalRows, sharedRows] = await Promise.all([\n this.getOrCachePersonalViews(userId, tableSlug),\n this.getOrCacheSharedViews(tableSlug),\n ]);\n return [...personalRows, ...sharedRows].map((row) => DataTableViewDto.from(row, userId));\n }\n\n // Creates a named snapshot and invalidates the relevant cache pool\n async createView(userId: string, dto: CreateDataTableViewDto): Promise<DataTableViewDto> {\n const view = await this.dataTableViewsRepository.create({\n userId,\n tableSlug: dto.tableSlug,\n name: dto.name,\n state: dto.state,\n isShared: dto.isShared ?? false,\n });\n this.logger.log(`Created view \"${dto.name}\" for user: ${userId}, table: ${dto.tableSlug}`);\n const isShared = dto.isShared ?? false;\n await this.invalidateViewsCache(userId, dto.tableSlug, !isShared, isShared);\n return DataTableViewDto.from(view, userId);\n }\n\n // Updates the state of a named view — skips DB write if state is unchanged\n async updateView(userId: string, id: string, dto: UpdateDataTableViewDto): Promise<DataTableViewDto> {\n const view = await this.dataTableViewsRepository.findById(id);\n if (!view) throw new NotFoundException('Table view not found.');\n if (view.userId !== userId) throw new BadRequestException('You do not have permission to update this view.');\n\n // Skip DB write if the state has not changed\n if (computeChecksum(dto.state) === computeChecksum(view.state)) {\n this.logger.log(`State unchanged for view ${id} — skipping DB write`);\n return DataTableViewDto.from(view, userId);\n }\n\n const updated = await this.dataTableViewsRepository.update(id, { state: dto.state });\n this.logger.log(`Updated state for view ${id}, user: ${userId}`);\n await this.invalidateViewsCache(userId, view.tableSlug, !view.isShared, view.isShared);\n return DataTableViewDto.from(updated, userId);\n }\n\n // Toggles the sharing status of a named view — updates both personal and shared cache\n async toggleShareView(userId: string, id: string, isShared: boolean): Promise<DataTableViewDto> {\n const view = await this.dataTableViewsRepository.findById(id);\n if (!view) throw new NotFoundException('Table view not found.');\n if (view.userId !== userId) throw new BadRequestException('You do not have permission to share this view.');\n\n const updated = await this.dataTableViewsRepository.update(id, { isShared });\n this.logger.log(`Set isShared=${isShared} for view ${id}, user: ${userId}`);\n // Invalidate both pools — the view moves from one to the other\n await this.invalidateViewsCache(userId, view.tableSlug, true, true);\n return DataTableViewDto.from(updated, userId);\n }\n\n // Renames a named view — enforces unique name per user+table, invalidates personal cache\n async renameView(userId: string, id: string, name: string): Promise<DataTableViewDto> {\n const view = await this.dataTableViewsRepository.findById(id);\n if (!view) throw new NotFoundException('Table view not found.');\n if (view.userId !== userId) throw new BadRequestException('You do not have permission to rename this view.');\n\n // Check for duplicate name within the same user+table\n const existing = await this.dataTableViewsRepository.findOne({\n userId,\n tableSlug: view.tableSlug,\n name,\n isShared: false,\n });\n if (existing && existing.id !== id) {\n throw new ConflictException({\n label: 'Name Already Taken',\n detail: 'A view with this name already exists for this table.',\n errors: [{ field: 'name', message: 'Name already taken' }],\n });\n }\n\n const updated = await this.dataTableViewsRepository.update(id, { name });\n this.logger.log(`Renamed view ${id} to \"${name}\" for user: ${userId}`);\n // Rename only affects personal views (shared views are owned by a user too, but visible to all)\n await this.invalidateViewsCache(userId, view.tableSlug, !view.isShared, view.isShared);\n return DataTableViewDto.from(updated, userId);\n }\n\n // Deletes a named view and invalidates the relevant cache pool\n async deleteView(userId: string, id: string): Promise<DataTableViewDto> {\n const view = await this.dataTableViewsRepository.findById(id);\n if (!view) throw new NotFoundException('Table view not found.');\n if (view.userId !== userId) throw new BadRequestException('You do not have permission to delete this view.');\n\n await this.dataTableViewsRepository.delete(id);\n this.logger.log(`Deleted view ${id} for user: ${userId}`);\n await this.invalidateViewsCache(userId, view.tableSlug, !view.isShared, view.isShared);\n return DataTableViewDto.from(view, userId);\n }\n}\n","import { Inject, Injectable } from '@nestjs/common';\nimport { and, eq } from 'drizzle-orm';\nimport type { PgTable } from 'drizzle-orm/pg-core';\nimport { PrimaryBaseRepository } from '../../../database/repositories/primary-base.repository';\nimport { PrimaryDatabaseService } from '../../../database/services/primary-database.service';\nimport { DATA_TABLE_VIEWS_TABLE } from '../../data-table.constants';\nimport type { DataTableViewRecord, NewDataTableViewRecord } from '../../schema/data-table-views.table';\n\nconst NAMED_VIEWS_LIMIT = 100;\n\n@Injectable()\nexport class DataTableViewsRepository extends PrimaryBaseRepository<PgTable, NewDataTableViewRecord, DataTableViewRecord> {\n constructor(\n database: PrimaryDatabaseService,\n @Inject(DATA_TABLE_VIEWS_TABLE) table: PgTable,\n ) {\n super(database, table);\n }\n\n // Returns personal (non-shared) named views owned by the user for a given table\n async findPersonalViewsBySlug(userId: string, tableSlug: string): Promise<DataTableViewRecord[]> {\n // biome-ignore lint/suspicious/noExplicitAny: table columns are typed at runtime via the injected schema-qualified table\n const t = this.table as any;\n return this.db\n .select()\n .from(this.table)\n .where(and(eq(t.tableSlug, tableSlug), eq(t.userId, userId), eq(t.isShared, false)))\n .orderBy(t.createdAt)\n .limit(NAMED_VIEWS_LIMIT) as unknown as Promise<DataTableViewRecord[]>;\n }\n\n // Returns all shared named views for a given table — visible to all users\n async findSharedViewsBySlug(tableSlug: string): Promise<DataTableViewRecord[]> {\n // biome-ignore lint/suspicious/noExplicitAny: table columns are typed at runtime via the injected schema-qualified table\n const t = this.table as any;\n return this.db\n .select()\n .from(this.table)\n .where(and(eq(t.tableSlug, tableSlug), eq(t.isShared, true)))\n .orderBy(t.createdAt)\n .limit(NAMED_VIEWS_LIMIT) as unknown as Promise<DataTableViewRecord[]>;\n }\n}\n","// Re-export all of drizzle-orm/pg-core\nexport * from 'drizzle-orm/pg-core';\n","import type { TableViewState } from '../../database/filter/filter.types';\nimport { boolean, index, jsonb, timestamp, uniqueIndex, uuid, varchar } from '../../drizzle-pg-core';\n\n// Returns a fresh set of column builder instances — call once per table declaration\nexport function dataTableViewsColumns() {\n return {\n id: uuid('id').primaryKey().defaultRandom(),\n userId: uuid('user_id').notNull(),\n tableSlug: varchar('table_slug', { length: 100 }).notNull(),\n name: varchar('name', { length: 100 }).notNull(),\n state: jsonb('state').notNull().$type<TableViewState>(),\n isShared: boolean('is_shared').notNull().default(false),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n updatedAt: timestamp('updated_at', { withTimezone: true }).$onUpdate(() => new Date()),\n };\n}\n\n// Index definitions — reusable callback, works with any table that has the same column names\n// biome-ignore lint/suspicious/noExplicitAny: receives Drizzle-bound columns, not raw builders\nexport function dataTableViewsIndexes(table: any) {\n return [\n index('table_views_user_table_idx').on(table.userId, table.tableSlug),\n index('table_views_shared_slug_idx').on(table.tableSlug, table.isShared),\n uniqueIndex('table_views_user_table_name_shared_unique').on(\n table.userId,\n table.tableSlug,\n table.name,\n table.isShared,\n ),\n ];\n}\n\n// Shape of a persisted table view record — used across service, repository, and DTO layers\nexport interface DataTableViewRecord {\n id: string;\n userId: string;\n tableSlug: string;\n name: string;\n state: TableViewState;\n isShared: boolean;\n createdAt: Date;\n updatedAt: Date | null | undefined;\n}\n\n// Shape of a new table view record for insertion — server-generated fields omitted\nexport interface NewDataTableViewRecord {\n userId: string;\n tableSlug: string;\n name: string;\n state: TableViewState;\n isShared?: boolean;\n}\n"],"mappings":"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","names":["Global","Module","ConfigModule","ConfigService","APP_GUARD","Reflector","JwtModule","Global","Module","Inject","Injectable","Scope","REQUEST","HttpStatus","HttpException","HttpProblemException","HttpException","detailOrOptions","httpStatus","options","detail","type","label","errors","BadGatewayException","HttpProblemException","detailOrOptions","HttpStatus","BAD_GATEWAY","HttpStatus","BadRequestException","HttpProblemException","detailOrOptions","HttpStatus","BAD_REQUEST","HttpStatus","ConflictException","HttpProblemException","detailOrOptions","HttpStatus","CONFLICT","HttpStatus","ForbiddenException","HttpProblemException","detailOrOptions","HttpStatus","FORBIDDEN","HttpStatus","GoneException","HttpProblemException","detailOrOptions","HttpStatus","GONE","HttpStatus","InternalServerErrorException","HttpProblemException","detailOrOptions","HttpStatus","INTERNAL_SERVER_ERROR","HttpStatus","MethodNotAllowedException","HttpProblemException","detailOrOptions","HttpStatus","METHOD_NOT_ALLOWED","HttpStatus","NotAcceptableException","HttpProblemException","detailOrOptions","HttpStatus","NOT_ACCEPTABLE","HttpStatus","NotFoundException","HttpProblemException","detailOrOptions","HttpStatus","NOT_FOUND","HttpStatus","NotImplementedException","HttpProblemException","detailOrOptions","HttpStatus","NOT_IMPLEMENTED","HttpStatus","PayloadTooLargeException","HttpProblemException","detailOrOptions","HttpStatus","PAYLOAD_TOO_LARGE","HttpStatus","RequestTimeoutException","HttpProblemException","detailOrOptions","HttpStatus","REQUEST_TIMEOUT","HttpStatus","ServiceUnavailableException","HttpProblemException","detailOrOptions","HttpStatus","SERVICE_UNAVAILABLE","HttpStatus","TooManyRequestsException","HttpProblemException","detailOrOptions","HttpStatus","TOO_MANY_REQUESTS","HttpStatus","UnauthorizedException","HttpProblemException","detailOrOptions","HttpStatus","UNAUTHORIZED","HttpStatus","UnprocessableEntityException","HttpProblemException","detailOrOptions","HttpStatus","UNPROCESSABLE_ENTITY","HttpStatus","UnsupportedMediaTypeException","HttpProblemException","detailOrOptions","HttpStatus","UNSUPPORTED_MEDIA_TYPE","HttpStatus","ValidationException","HttpProblemException","detailOrOptions","HttpStatus","BAD_REQUEST","defaultConfig","cookie","refreshCookieName","refreshCookieMaxAge","refreshCookiePath","refreshCookieSecure","process","env","NODE_ENV","refreshCookieSameSite","refreshCookieDomain","jwt","accessTokenExpiry","refreshTokenExpiry","onboardingTokenExpiry","guard","tenantHeaderName","authHeaderName","tokenPrefix","defaultSessionTypes","currentConfig","defineConfig","config","configureApiSdk","userConfig","getConfig","resetConfig","getRefreshCookieOptions","httpOnly","secure","sameSite","path","maxAge","domain","getRefreshCookieOptionsForHost","hostname","baseDomain","Error","endsWith","UnauthorizedException","getJwtExpiry","access","refresh","onboarding","RequestService","request","getTenantIdentifier","getHeader","key","value","headers","Array","isArray","getAccessToken","authHeader","authorization","type","token","split","getRefreshToken","cookies","config","getConfig","refreshToken","cookie","refreshCookieName","_error","getAllHeaders","scope","Scope","REQUEST","RequestModule","providers","RequestService","exports","ForbiddenException","Injectable","Logger","Scope","UnauthorizedException","SSE_METADATA","ConfigService","Reflector","JwtService","SetMetadata","REQUIRE_SESSION_KEY","RequireSession","types","SetMetadata","SetMetadata","SKIP_CSRF_KEY","SkipCsrf","SetMetadata","crypto","hashToken","token","createHash","update","digest","verifyTokenHash","expectedHash","computedHash","length","timingSafeEqual","Buffer","from","VrittiAuthGuard","logger","Logger","name","reflector","_configService","jwtService","requestService","canActivate","context","request","switchToHttp","getRequest","reply","getResponse","skipCsrf","getAllAndOverride","SKIP_CSRF_KEY","getHandler","getClass","validateCsrf","isPublic","requiredSessionTypes","REQUIRE_SESSION_KEY","isSseEndpoint","get","SSE_METADATA","handleSseAuth","accessToken","getAccessToken","UnauthorizedException","decodedAccessToken","validateAccessToken","tokenType","validateRefreshTokenBinding","sessionType","allowed","getConfig","guard","defaultSessionTypes","includes","sessionInfo","userId","sessionId","error","token","verify","jwtError","refreshTokenHash","refreshToken","getRefreshToken","verifyTokenHash","decoded","safeMethods","method","fastifyInstance","server","csrfProtection","ForbiddenException","Promise","resolve","reject","originalSend","send","bind","Error","err","errors","field","message","scope","Scope","REQUEST","Injectable","Logger","ConfigService","JwtService","NestJwtService","parseExpiryToMs","expiry","match","Error","value","Number","parseInt","multipliers","s","m","h","d","w","y","jwtConfigFactory","configService","secret","getOrThrow","signOptions","issuer","getTokenExpiry","access","refresh","TokenType","JwtAuthService","logger","Logger","name","tokenExpiry","jwtService","configService","getTokenExpiry","generateAccessToken","userId","sessionId","sessionType","refreshToken","sign","tokenType","TokenType","ACCESS","refreshTokenHash","hashToken","expiresIn","access","generateRefreshToken","REFRESH","refresh","payload","options","verify","token","expectedType","Error","error","getExpiryTime","type","Date","now","parseExpiryToMs","getExpiryInSeconds","Math","floor","AuthConfigModule","forRootAsync","module","imports","ConfigModule","RequestModule","JwtModule","registerAsync","inject","ConfigService","useFactory","config","secret","get","signOptions","algorithm","providers","provide","Reflector","useClass","APP_GUARD","VrittiAuthGuard","JwtAuthService","exports","createParamDecorator","AccessToken","_data","ctx","request","switchToHttp","getRequest","authHeader","headers","authorization","replace","createParamDecorator","CookieDomain","createParamDecorator","_data","ctx","request","switchToHttp","getRequest","forwarded","headers","raw","Array","isArray","hostStr","hostname","domain","split","baseDomain","getConfig","cookie","refreshCookieDomain","endsWith","SetMetadata","Public","SetMetadata","createParamDecorator","RefreshCookieOptions","createParamDecorator","_data","ctx","request","switchToHttp","getRequest","forwarded","headers","raw","Array","isArray","hostStr","hostname","domain","split","getRefreshCookieOptionsForHost","createParamDecorator","RefreshTokenCookie","createParamDecorator","_data","ctx","request","switchToHttp","getRequest","cookies","config","getConfig","cookie","refreshCookieName","createParamDecorator","Subdomain","_data","ctx","request","switchToHttp","getRequest","origin","headers","url","URL","hostname","split","forwarded","host","Array","isArray","undefined","createParamDecorator","SessionData","createParamDecorator","_data","ctx","request","switchToHttp","getRequest","sessionInfo","sessionId","Error","userId","sessionType","createParamDecorator","UserId","createParamDecorator","_data","ctx","request","switchToHttp","getRequest","sessionInfo","userId","Error","Module","ConfigModule","Inject","Injectable","Logger","CACHE_PROVIDER","Symbol","CacheService","logger","Logger","name","provider","set","key","value","ttlSeconds","err","error","get","del","keys","join","scanKeys","pattern","getMemoryInfo","Injectable","Logger","ConfigService","Redis","RedisCacheProvider","logger","Logger","name","client","configService","onModuleInit","url","getOrThrow","Redis","lazyConnect","maxRetriesPerRequest","on","log","err","error","onModuleDestroy","quit","set","key","value","ttlSeconds","json","JSON","stringify","setex","get","parse","del","keys","length","scanKeys","pattern","cursor","nextCursor","batch","scan","push","getMemoryInfo","info","CacheModule","imports","ConfigModule","providers","RedisCacheProvider","provide","CACHE_PROVIDER","useExisting","CacheService","exports","Global","Module","Reflector","DATABASE_MODULE_OPTIONS","Symbol","Inject","Injectable","InternalServerErrorException","Logger","drizzle","Pool","PrimaryDatabaseService","logger","Logger","name","pool","db","options","onModuleInit","primaryDb","initializeDrizzleClient","host","port","username","password","database","schema","sslMode","Pool","user","max","maxConnections","ssl","rejectUnauthorized","debug","Object","keys","drizzleSchema","join","drizzleRelations","drizzle","client","relations","query","log","error","InternalServerErrorException","drizzleClient","Error","onModuleDestroy","end","DatabaseModule","forServer","options","asyncProvider","provide","DATABASE_MODULE_OPTIONS","useFactory","inject","module","imports","RequestModule","providers","Reflector","useClass","PrimaryDatabaseService","exports","createParamDecorator","UploadedFile","createParamDecorator","_data","ctx","request","switchToHttp","getRequest","file","BadRequestException","label","detail","buffer","toBuffer","filename","mimetype","ApiProperty","CreateResponseDto","success","message","data","example","ApiProperty","ApiPropertyOptional","ValidatedRowDto","index","data","valid","errors","example","code","name","ImportSummaryDto","total","invalid","ImportResponseDto","success","message","created","updated","skipped","rows","summary","type","ApiPropertyOptional","Type","IsInt","IsOptional","IsString","Min","SelectOptionsQueryDto","search","limit","offset","values","excludeIds","valueKey","labelKey","descriptionKey","groupIdKey","description","example","default","Number","ApiProperty","IsBoolean","IsNotEmpty","IsString","SuccessResponseDto","success","message","example","ApiProperty","ApiPropertyOptional","TableResponseDto","result","count","state","activeViewId","nullable","and","asc","desc","eq","gt","gte","ilike","lt","lte","ne","notIlike","or","FilterProcessor","buildWhere","filters","fieldMap","conditions","flatMap","f","def","field","expression","value","column","col","val","operator","type","eq","ne","ilike","notIlike","gt","gte","lt","lte","length","and","undefined","buildSearch","search","columnId","Object","values","filter","map","or","buildOrderBy","sort","s","direction","asc","desc","Logger","and","asc","eq","getTableName","ilike","inArray","notInArray","sql","snakeToCamel","str","replace","_","letter","toUpperCase","PrimaryBaseRepository","logger","tableName","db","database","drizzleClient","model","query","queryKeys","Object","keys","debug","join","error","table","dbTableName","getTableName","Logger","name","create","data","tx","log","results","insert","values","returning","record","Error","findById","id","findFirst","where","findOne","findMany","options","buildSelectQuery","select","from","$dynamic","leftJoin","on","leftJoins","groupBy","length","orderBy","limit","offset","findAllAndCount","count","result","Promise","all","update","idColumn","set","eq","updateMany","rowCount","delete","deleteMany","sql","exists","transaction","callback","findForSelect","config","selectFn","distinct","selectDistinct","bind","parsedValues","split","map","v","trim","filter","Boolean","parsedExcludeIds","excludeIds","tableColumns","valueCol","value","labelCol","label","descriptionCol","description","undefined","joins","joinCols","selectCols","groupId","groupIdCol","valuesQuery","type","innerJoin","rows","inArray","row","String","hasMore","groups","selectFields","totalCount","mapWith","Number","conditions","search","push","ilike","notInArray","field","val","entries","column","orderByKey","orderByCol","and","orderClauses","asc","resolvedGroups","groupTable","groupTableColumns","groupIdKey","groupNameKey","groupLabelKey","groupNameCol","groupRows","r","Global","Module","ConfigModule","BrevoClient","BrevoError","BrevoTimeoutError","Injectable","Logger","ConfigService","EmailService","logger","Logger","name","brevoClient","senderEmail","senderName","configService","apiKey","get","error","Error","BrevoClient","maxRetries","log","sendVerificationEmail","email","otp","expiresAt","displayName","expiryMinutes","Math","ceil","getTime","Date","now","subject","htmlContent","textContent","trim","sendEmail","to","sendPasswordResetEmail","sendEmailChangeNotification","oldEmail","newEmail","revertToken","revertExpiresAt","hoursUntilExpiry","floor","revertLink","sendEmailRevertConfirmation","sendInviteEmail","params","inviteUrl","verifyConnection","transactionalEmails","sendTransacEmail","sender","err","BrevoError","statusCode","emailData","result","debug","messageId","BrevoTimeoutError","message","EmailModule","imports","ConfigModule","providers","EmailService","exports","Catch","HttpStatus","Logger","getHttpStatusTitle","status","enumKey","Object","entries","HttpStatus","find","key","value","Number","isNaN","split","map","word","charAt","toUpperCase","slice","toLowerCase","join","HttpExceptionFilter","logger","Logger","name","catch","exception","host","ctx","switchToHttp","response","getResponse","request","getRequest","INTERNAL_SERVER_ERROR","type","label","detail","errors","isHttpException","getStatus","exceptionResponse","responseObj","problemResponse","message","Array","isArray","msg","constraintValues","values","constraints","field","property","filter","error","isAxiosError","axiosStatus","axiosDetail","data","url","config","BAD_GATEWAY","stack","problemDetails","title","instance","header","send","Error","Injectable","Optional","catchError","tap","Injectable","Optional","createLogger","format","transports","DailyRotateFile","AsyncLocalStorage","randomUUID","correlationStorage","AsyncLocalStorage","getCorrelationContext","getStore","runWithCorrelationContext","context","callback","run","updateCorrelationContext","updates","Object","assign","DEFAULT_CORRELATION_HEADER","generateCorrelationId","randomUUID","addCorrelationIdToResponse","reply","correlationId","headerName","header","raw","setHeader","LoggerService","activeLogger","options","context","defaultLogger","provider","Error","createWinstonLogger","opts","level","logFormat","format","baseFormatters","timestamp","errors","stack","consoleTransport","transports","Console","combine","json","printf","info","message","correlationId","trace","parts","toUpperCase","padEnd","toString","slice","filter","Boolean","output","join","colorize","all","winstonTransports","enableFileLogger","filePath","maxFiles","push","DailyRotateFile","filename","datePattern","maxSize","config","exitOnError","defaultMeta","appName","environment","createLogger","log","_log","error","warn","debug","verbose","setContext","ctx","winstonLogger","winstonLevel","formattedMessage","formatMessage","metadata","enrichMetadata","nestLogger","logWithMetadata","messageWithMeta","JSON","stringify","String","enriched","correlationContext","getCorrelationContext","key","value","Object","entries","child","childLogger","HttpLoggerInterceptor","enableRequestLog","enableResponseLog","slowRequestThreshold","logger","options","intercept","context","next","getType","handle","httpContext","switchToHttp","request","getRequest","response","getResponse","startTime","Date","now","logRequest","pipe","tap","duration","logResponse","catchError","error","logError","correlationContext","getCorrelationContext","metadata","type","method","url","correlationId","ip","userAgent","headers","logWithMetadata","stack","statusCode","logLevel","slowRequest","message","err","errorName","name","errorMessage","trace","errorDetails","loggingError","Global","Logger","Module","Injectable","CorrelationIdMiddleware","includeInResponse","responseHeader","options","DEFAULT_CORRELATION_HEADER","use","_req","reply","next","correlationId","generateCorrelationId","addCorrelationIdToResponse","runWithCorrelationContext","onRequest","store","correlationStorage","getStore","enterWith","LOGGER_MODULE_OPTIONS","Symbol","DEFAULT_LOGGER_OPTIONS","provider","enableCorrelationId","enableHttpLogger","filePath","maxFiles","ENVIRONMENT_PRESETS","development","level","format","enableFileLogger","httpLogger","enableRequestLog","enableResponseLog","slowRequestThreshold","staging","production","test","mergeWithDefaults","options","preset","environment","filteredOptions","Object","fromEntries","entries","filter","_","value","undefined","merged","createDefaultLoggerProvider","provide","Logger","useFactory","logger","levels","getLevelsUpTo","setLogLevels","createLoggerProviders","mergedOptions","providers","useValue","push","LoggerService","opts","defaultLogger","inject","token","optional","CorrelationIdMiddleware","includeInResponse","responseHeader","HttpLoggerInterceptor","httpLoggerOptions","allLevels","isValidLevel","l","includes","levelIndex","indexOf","slice","LoggerModule","forRoot","module","exports","forRootAsync","asyncProviders","createAsyncProviders","imports","configure","_consumer","createAsyncOptionsProvider","useClass","args","userOptions","optionsFactory","createLoggerOptions","useExisting","Error","Module","Controller","Get","ApiTags","applyDecorators","ApiOperation","ApiResponse","ApiHealthCheck","applyDecorators","ApiOperation","summary","ApiResponse","status","description","type","String","Injectable","AppService","getHello","AppController","appService","getHello","Controller","Get","HttpCode","HttpStatus","Res","ApiTags","applyDecorators","ApiOperation","ApiResponse","ApiGetCsrfToken","applyDecorators","ApiOperation","summary","description","ApiResponse","status","schema","type","properties","csrfToken","example","required","CsrfController","getToken","reply","csrfToken","generateCsrf","OK","passthrough","RootModule","controllers","AppController","CsrfController","providers","AppService","CALLING_CODE_TO_COUNTRY","extractCountryFromPhone","phone","digits","startsWith","slice","length","prefix","undefined","normalizePhoneNumber","Module","ConfigModule","DATA_TABLE_VIEWS_TABLE","Symbol","Body","Controller","HttpCode","HttpStatus","Logger","Post","ApiBearerAuth","ApiTags","applyDecorators","ApiBody","ApiOperation","ApiResponse","ApiProperty","ApiPropertyOptional","IsObject","IsOptional","IsString","IsUUID","MaxLength","UpsertDataTableStateDto","tableSlug","state","activeViewId","description","example","ApiUpsertDataTableState","applyDecorators","ApiOperation","summary","description","ApiBody","type","UpsertDataTableStateDto","ApiResponse","status","Injectable","Logger","ConfigService","EMPTY_TABLE_STATE","filters","sort","columnVisibility","columnOrder","columnSizing","columnPinning","left","right","lockedColumnSizing","density","filterOrder","filterVisibility","pagination","limit","offset","DataTableStateService","logger","Logger","name","cacheService","configService","stateTtl","get","upsertCurrentState","userId","dto","key","tableSlug","set","state","activeViewId","log","getCurrentState","cached","DataTableStateController","logger","Logger","name","dataTableStateService","upsertCurrentState","userId","dto","log","tableSlug","OK","Body","Controller","Delete","Get","HttpCode","HttpStatus","Logger","Param","Patch","Post","Query","ApiBearerAuth","ApiTags","applyDecorators","ApiBody","ApiOperation","ApiParam","ApiQuery","ApiResponse","ApiProperty","ApiPropertyOptional","DataTableViewDto","id","name","tableSlug","state","isShared","isOwn","createdAt","updatedAt","from","view","userId","dto","description","nullable","example","ApiProperty","ApiPropertyOptional","IsBoolean","IsObject","IsOptional","IsString","MaxLength","CreateDataTableViewDto","name","tableSlug","state","isShared","description","example","ApiProperty","IsString","MaxLength","MinLength","RenameDataTableViewDto","name","description","example","ApiProperty","IsBoolean","ToggleShareDataTableViewDto","isShared","description","example","ApiProperty","IsObject","UpdateDataTableViewDto","state","description","ApiListDataTableViews","applyDecorators","ApiOperation","summary","description","ApiQuery","name","example","required","ApiResponse","status","type","DataTableViewDto","ApiCreateDataTableView","ApiBody","CreateDataTableViewDto","ApiUpdateDataTableView","ApiParam","UpdateDataTableViewDto","ApiRenameDataTableView","RenameDataTableViewDto","ApiToggleShareDataTableView","ToggleShareDataTableViewDto","ApiDeleteDataTableView","createHash","Injectable","Logger","ConfigService","Inject","Injectable","and","eq","NAMED_VIEWS_LIMIT","DataTableViewsRepository","PrimaryBaseRepository","database","table","findPersonalViewsBySlug","userId","tableSlug","t","db","select","from","where","and","eq","isShared","orderBy","createdAt","limit","findSharedViewsBySlug","computeChecksum","value","createHash","update","JSON","stringify","digest","DataTableViewsService","logger","Logger","name","dataTableViewsRepository","cacheService","configService","personalViewsKey","userId","tableSlug","sharedViewsKey","viewsTtl","get","getOrCachePersonalViews","key","cached","debug","rows","findPersonalViewsBySlug","set","getOrCacheSharedViews","findSharedViewsBySlug","invalidateViewsCache","affectsPersonal","affectsShared","toDelete","push","length","del","findViews","personalRows","sharedRows","Promise","all","map","row","DataTableViewDto","from","createView","dto","view","create","state","isShared","log","updateView","id","findById","NotFoundException","BadRequestException","updated","toggleShareView","renameView","existing","findOne","ConflictException","label","detail","errors","field","message","deleteView","delete","DataTableViewsController","logger","Logger","name","dataTableViewsService","findViews","userId","tableSlug","log","createView","dto","updateView","id","renameView","toggleShareView","isShared","deleteView","CREATED","DataTableModule","forRoot","options","global","module","imports","ConfigModule","CacheModule","controllers","DataTableStateController","DataTableViewsController","providers","provide","DATA_TABLE_VIEWS_TABLE","useValue","tableViews","DataTableViewsService","DataTableViewsRepository","DataTableStateService","exports","dataTableViewsColumns","id","uuid","primaryKey","defaultRandom","userId","notNull","tableSlug","varchar","length","name","state","jsonb","$type","isShared","boolean","default","createdAt","timestamp","withTimezone","defaultNow","updatedAt","$onUpdate","Date","dataTableViewsIndexes","table","index","on","uniqueIndex"]}
1
+ {"version":3,"sources":["../src/auth/auth.config.ts","../src/auth/auth-config.module.ts","../src/request/request.module.ts","../src/request/services/request.service.ts","../src/auth/guards/vritti-auth.guard.ts","../src/auth/decorators/require-session.decorator.ts","../src/auth/decorators/skip-csrf.decorator.ts","../src/auth/services/token.service.ts","../src/utils/time.utils.ts","../src/auth/utils/token-hash.util.ts","../src/auth/decorators/access-token.decorator.ts","../src/auth/decorators/cookie-domain.decorator.ts","../src/auth/decorators/cookie-name.decorator.ts","../src/auth/decorators/hostname.decorator.ts","../src/auth/decorators/public.decorator.ts","../src/auth/decorators/refresh-cookie-options.decorator.ts","../src/exceptions/bad-gateway.exception.ts","../src/exceptions/base-field.exception.ts","../src/exceptions/bad-request.exception.ts","../src/exceptions/conflict.exception.ts","../src/exceptions/forbidden.exception.ts","../src/exceptions/gone.exception.ts","../src/exceptions/internal-server-error.exception.ts","../src/exceptions/method-not-allowed.exception.ts","../src/exceptions/not-acceptable.exception.ts","../src/exceptions/not-found.exception.ts","../src/exceptions/not-implemented.exception.ts","../src/exceptions/payload-too-large.exception.ts","../src/exceptions/request-timeout.exception.ts","../src/exceptions/service-unavailable.exception.ts","../src/exceptions/too-many-requests.exception.ts","../src/exceptions/unauthorized.exception.ts","../src/exceptions/unprocessable-entity.exception.ts","../src/exceptions/unsupported-media-type.exception.ts","../src/exceptions/validation.exception.ts","../src/auth/decorators/refresh-token-cookie.decorator.ts","../src/auth/decorators/session-data.decorator.ts","../src/auth/decorators/subdomain.decorator.ts","../src/auth/decorators/user-id.decorator.ts","../src/cache/cache.module.ts","../src/cache/cache.service.ts","../src/cache/constants.ts","../src/cache/providers/redis.provider.ts","../src/data-table/data-table.module.ts","../src/data-table/data-table.constants.ts","../src/data-table/state/controllers/data-table-state.controller.ts","../src/data-table/state/docs/data-table-state.docs.ts","../src/data-table/state/dto/request/upsert-data-table-state.dto.ts","../src/data-table/state/services/data-table-state.service.ts","../src/data-table/views/controllers/data-table-views.controller.ts","../src/data-table/views/docs/data-table-views.docs.ts","../src/data-table/views/dto/entity/data-table-view.dto.ts","../src/data-table/views/dto/request/create-data-table-view.dto.ts","../src/data-table/views/dto/request/rename-data-table-view.dto.ts","../src/data-table/views/dto/request/toggle-share-data-table-view.dto.ts","../src/data-table/views/dto/request/update-data-table-view.dto.ts","../src/data-table/views/services/data-table-views.service.ts","../src/data-table/views/repositories/data-table-views.repository.ts","../src/database/repositories/primary-base.repository.ts","../src/database/services/primary-database.service.ts","../src/database/constants.ts","../src/database/services/rls-aware-pool.ts","../src/drizzle-pg-core.ts","../src/data-table/schema/data-table-views.table.ts","../src/database/database.module.ts","../src/database/dto/create-response.dto.ts","../src/database/dto/import-response.dto.ts","../src/database/dto/select-options-query.dto.ts","../src/database/dto/success-response.dto.ts","../src/database/dto/table-response.dto.ts","../src/database/filter/filter.processor.ts","../src/database/filter/filter.types.ts","../src/decorators/is-currency.decorator.ts","../src/money.ts","../src/decorators/is-currency-code.decorator.ts","../src/decorators/is-date-time.decorator.ts","../src/decorators/uploaded-file.decorator.ts","../src/dto/currency-amount.dto.ts","../src/email/email.module.ts","../src/email/email.service.ts","../src/filters/http-exception.filter.ts","../src/filters/pg-error.translator.ts","../src/filters/rpc-problem-exception.filter.ts","../src/logger/interceptors/http-logger.interceptor.ts","../src/logger/services/logger.service.ts","../src/logger/utils/index.ts","../src/logger/logger.module.ts","../src/logger/middleware/correlation-id.middleware.ts","../src/nats/decorators/nats-headers.decorator.ts","../src/nats/nats-context.ts","../src/nats/nats-client.module.ts","../src/nats/constants.ts","../src/nats/nats-client.service.ts","../src/nats/nats-microservice-client.service.ts","../src/root/root.module.ts","../src/root/controllers/app.controller.ts","../src/root/docs/app.docs.ts","../src/root/services/app.service.ts","../src/root/controllers/csrf.controller.ts","../src/root/docs/csrf.docs.ts","../src/utils/math.utils.ts","../src/utils/phone.utils.ts"],"sourcesContent":["import type { FastifyRequest } from 'fastify';\nimport type { RequestService } from '../request/services/request.service';\n\nexport const AUTH_CONFIG = Symbol('AUTH_CONFIG');\n\nexport type OnAuthenticatedCallback = (\n requestService: RequestService,\n sessionInfo: NonNullable<FastifyRequest['sessionInfo']>,\n) => void | Promise<void>;\n\nexport type TokenExpiryString = `${number}${'s' | 'm' | 'h' | 'd' | 'w' | 'y'}`;\n\nexport interface TokenExpiry {\n access: TokenExpiryString;\n refresh: TokenExpiryString;\n}\n\nexport interface CookieConfig {\n refreshCookieName: string;\n refreshCookieMaxAge: number;\n refreshCookiePath: string;\n refreshCookieSecure: boolean;\n refreshCookieSameSite: 'strict' | 'lax' | 'none';\n refreshCookieDomain?: string;\n}\n\nexport interface GuardConfig {\n authHeaderName: string;\n tokenPrefix: string;\n csrfExemptSessionTypes?: string[];\n refreshTokenBindingExemptSessionTypes?: string[];\n onAuthenticated?: OnAuthenticatedCallback;\n}\n\n// Complete auth configuration — token expiry, cookie, and guard settings\nexport interface AuthConfig {\n tokenExpiry: TokenExpiry;\n cookie: CookieConfig;\n guard: GuardConfig;\n}\n\n// Default values for cookie and guard config — servers only override what they need\nexport const AUTH_CONFIG_DEFAULTS = {\n cookie: {\n refreshCookieName: 'vritti_refresh',\n refreshCookieMaxAge: 30 * 24 * 60 * 60 * 1000, // 30 days\n refreshCookiePath: '/',\n refreshCookieSecure: process.env.NODE_ENV === 'production',\n refreshCookieSameSite: 'strict' as const,\n refreshCookieDomain: 'localhost',\n },\n guard: {\n authHeaderName: 'authorization',\n tokenPrefix: 'Bearer',\n csrfExemptSessionTypes: [],\n refreshTokenBindingExemptSessionTypes: [],\n },\n} satisfies Omit<AuthConfig, 'tokenExpiry'>;\n\nexport interface CookieSerializeOptions {\n httpOnly: boolean;\n secure: boolean;\n sameSite: 'strict' | 'lax' | 'none';\n path: string;\n maxAge: number;\n domain: string;\n}\n\nexport enum TokenType {\n ACCESS = 'access',\n REFRESH = 'refresh',\n}\n\n// JWT claims added automatically by the library on every signed token\ninterface JwtClaims {\n exp: number;\n iat: number;\n}\n\n// Access token — signed payload + JWT claims\nexport interface AccessTokenPayload {\n sessionType: string;\n tokenType: TokenType.ACCESS;\n userId: string;\n sessionId: string;\n refreshTokenHash: string;\n}\n\nexport type DecodedAccessToken = AccessTokenPayload & JwtClaims;\n\n// Refresh token — signed payload + JWT claims\nexport interface RefreshTokenPayload {\n sessionType: string;\n tokenType: TokenType.REFRESH;\n userId: string;\n sessionId: string;\n}\n\nexport type DecodedRefreshToken = RefreshTokenPayload & JwtClaims;\n","import { type DynamicModule, Global, type InjectionToken, Module } from '@nestjs/common';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\nimport { APP_GUARD, Reflector } from '@nestjs/core';\nimport { JwtModule } from '@nestjs/jwt';\nimport { RequestModule } from '../request/request.module';\nimport {\n AUTH_CONFIG,\n AUTH_CONFIG_DEFAULTS,\n type AuthConfig,\n type CookieConfig,\n type GuardConfig,\n type TokenExpiry,\n} from './auth.config';\nimport { VrittiAuthGuard } from './guards/vritti-auth.guard';\nimport { TokenService } from './services/token.service';\n\n// Factory return type — tokenExpiry is required, cookie and guard are partial with defaults merged\ninterface AuthConfigInput {\n tokenExpiry: TokenExpiry;\n cookie?: Partial<CookieConfig>;\n guard?: Partial<GuardConfig>;\n}\n\ninterface AuthConfigModuleOptions<T extends unknown[] = unknown[]> {\n useFactory: (...args: [...T]) => AuthConfigInput | Promise<AuthConfigInput>;\n inject?: InjectionToken[];\n}\n\n// Merges user-provided partial config with defaults to produce a complete AuthConfig\nfunction mergeWithDefaults(input: AuthConfigInput): AuthConfig {\n return {\n tokenExpiry: input.tokenExpiry,\n cookie: {\n ...AUTH_CONFIG_DEFAULTS.cookie,\n ...(input.cookie ?? {}),\n },\n guard: {\n ...AUTH_CONFIG_DEFAULTS.guard,\n ...(input.guard ?? {}),\n },\n };\n}\n\n@Global()\n@Module({})\nexport class AuthConfigModule {\n // Registers JWT, TokenService, and global VrittiAuthGuard\n static forRootAsync<T extends unknown[] = unknown[]>(options: AuthConfigModuleOptions<T>): DynamicModule {\n return {\n module: AuthConfigModule,\n imports: [\n ConfigModule,\n RequestModule,\n JwtModule.registerAsync({\n imports: [ConfigModule],\n inject: [ConfigService],\n useFactory: (config: ConfigService) => ({\n secret: config.getOrThrow<string>('JWT_SECRET'),\n signOptions: { algorithm: 'HS256' as const },\n }),\n }),\n ],\n providers: [\n {\n provide: Reflector,\n useClass: Reflector,\n },\n {\n provide: APP_GUARD,\n useClass: VrittiAuthGuard,\n },\n {\n provide: AUTH_CONFIG,\n useFactory: async (...args: unknown[]) => {\n const input = await options.useFactory(...(args as [...T]));\n return mergeWithDefaults(input);\n },\n inject: options.inject || [],\n },\n TokenService,\n ],\n exports: [JwtModule, TokenService, AUTH_CONFIG],\n };\n }\n}\n","import { Global, Module } from '@nestjs/common';\nimport { RequestService } from './services/request.service';\n\n@Global()\n@Module({\n providers: [RequestService],\n exports: [RequestService],\n})\nexport class RequestModule {}\n","import { Inject, Injectable, Scope } from '@nestjs/common';\nimport { REQUEST } from '@nestjs/core';\nimport type { FastifyRequest } from 'fastify';\nimport { AUTH_CONFIG, type AuthConfig } from '../../auth/auth.config';\n\n@Injectable({ scope: Scope.REQUEST })\nexport class RequestService {\n constructor(\n @Inject(REQUEST) private readonly request: FastifyRequest,\n @Inject(AUTH_CONFIG) private readonly config: AuthConfig,\n ) {}\n\n // Extracts the bearer access token from the Authorization header\n getAccessToken(): string | null {\n const authHeader = this.request.headers?.[this.config.guard.authHeaderName];\n if (!authHeader || typeof authHeader !== 'string') {\n return null;\n }\n const [type, token] = authHeader.split(' ') ?? [];\n return type === this.config.guard.tokenPrefix && token ? token : null;\n }\n\n // Extracts the refresh token from the configured httpOnly cookie\n getRefreshToken(): string | null {\n try {\n const cookies = (this.request as unknown as { cookies?: Record<string, string> }).cookies;\n if (cookies && typeof cookies === 'object') {\n const refreshToken = cookies[this.config.cookie.refreshCookieName];\n if (refreshToken) {\n return refreshToken;\n }\n }\n return null;\n } catch (_error: unknown) {\n return null;\n }\n }\n\n // Returns the value of a specific request header by key\n getHeader(key: string): string | string[] | undefined {\n return this.request.headers?.[key];\n }\n\n // Returns the request hostname (without port)\n getHostname(): string {\n return this.request.hostname ?? '';\n }\n\n // Returns all request headers\n getAllHeaders(): FastifyRequest['headers'] {\n return this.request.headers || {};\n }\n}\n","import {\n type CanActivate,\n type ExecutionContext,\n ForbiddenException,\n Inject,\n Injectable,\n Logger,\n Scope,\n UnauthorizedException,\n} from '@nestjs/common';\nimport { SSE_METADATA } from '@nestjs/common/constants';\nimport { Reflector } from '@nestjs/core';\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport '../../types/fastify-augmentation';\nimport { RequestService } from '../../request/services/request.service';\nimport { AUTH_CONFIG, type AuthConfig } from '../auth.config';\nimport { REQUIRE_SESSION_KEY } from '../decorators/require-session.decorator';\nimport { SKIP_CSRF_KEY } from '../decorators/skip-csrf.decorator';\nimport { TokenService } from '../services/token.service';\n\ninterface FastifyInstanceWithCsrf {\n csrfProtection?: (req: FastifyRequest, reply: FastifyReply, next: (err?: Error) => void) => void;\n}\n\ntype PatchableReply = { send: (...args: unknown[]) => unknown };\n\n@Injectable({ scope: Scope.REQUEST })\nexport class VrittiAuthGuard implements CanActivate {\n private readonly logger = new Logger(VrittiAuthGuard.name);\n\n constructor(\n private readonly reflector: Reflector,\n private readonly requestService: RequestService,\n private readonly tokenService: TokenService,\n @Inject(AUTH_CONFIG) private readonly config: AuthConfig,\n ) {}\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const request = context.switchToHttp().getRequest<FastifyRequest>();\n const reply = context.switchToHttp().getResponse<FastifyReply>();\n const route = `${request.method} ${request.url}`;\n\n // Attach auth config to request so decorators can access it without injection\n request.authConfig = this.config;\n\n const skipCsrf = this.reflector.getAllAndOverride<boolean>(SKIP_CSRF_KEY, [\n context.getHandler(),\n context.getClass(),\n ]);\n\n // @Public() endpoints skip auth, while preserving their current CSRF behavior\n const isPublic = this.reflector.getAllAndOverride<boolean>('isPublic', [context.getHandler(), context.getClass()]);\n if (isPublic) {\n if (!skipCsrf) {\n await this.validateCsrf(request, reply);\n }\n this.logger.debug(`${route} — public endpoint, skipping auth`);\n return true;\n }\n\n // @RequireSession() restricts access to specific session types\n const requiredSessionTypes = this.reflector.getAllAndOverride<string[]>(REQUIRE_SESSION_KEY, [\n context.getHandler(),\n context.getClass(),\n ]);\n\n // SSE endpoints authenticate via refresh token cookie (EventSource cannot send Authorization headers)\n const isSseEndpoint = this.reflector.get<boolean>(SSE_METADATA, context.getHandler());\n if (isSseEndpoint) {\n this.logger.debug(`${route} — SSE endpoint, authenticating via refresh cookie`);\n return this.handleSseAuth(request, requiredSessionTypes);\n }\n\n const sessionType = await this.handleHttpAuth(request, requiredSessionTypes);\n\n const csrfExemptSessionTypes = this.config.guard.csrfExemptSessionTypes ?? [];\n if (!skipCsrf && !csrfExemptSessionTypes.includes(sessionType)) {\n await this.validateCsrf(request, reply);\n }\n\n return true;\n }\n\n // Authenticates standard HTTP requests using the access token from Authorization header\n private async handleHttpAuth(request: FastifyRequest, requiredSessionTypes?: string[]): Promise<string> {\n const route = `${request.method} ${request.url}`;\n\n const accessToken = this.requestService.getAccessToken();\n if (!accessToken) {\n this.logger.warn(`${route} — no access token found`);\n throw new UnauthorizedException('Access token not found');\n }\n\n const decoded = this.tokenService.validateAccessToken(accessToken);\n\n const refreshTokenBindingExemptSessionTypes = this.config.guard.refreshTokenBindingExemptSessionTypes ?? [];\n\n if (!refreshTokenBindingExemptSessionTypes.includes(decoded.sessionType)) {\n const refreshToken = this.requestService.getRefreshToken();\n if (!refreshToken) {\n throw new UnauthorizedException('Session validation failed');\n }\n this.tokenService.validateTokenBinding(decoded, refreshToken);\n }\n\n // Validate session type access (only if @RequireSession specifies types)\n if (requiredSessionTypes?.length && !requiredSessionTypes.includes(decoded.sessionType)) {\n this.logger.warn(\n `${route} — session type ${decoded.sessionType} not in allowed: [${requiredSessionTypes.join(', ')}]`,\n );\n throw new UnauthorizedException(`${decoded.sessionType} sessions cannot access this endpoint`);\n }\n\n // Attach session info to request — spread full decoded token (includes metadata fields)\n const { tokenType: _tokenType, refreshTokenHash: _hash, exp: _exp, iat: _iat, ...sessionInfo } = decoded;\n request.sessionInfo = sessionInfo;\n\n // Call onAuthenticated callback if configured\n const onAuthenticated = this.config.guard.onAuthenticated;\n if (onAuthenticated) {\n await onAuthenticated(this.requestService, request.sessionInfo);\n }\n\n this.logger.debug(`${route} — authenticated user: ${decoded.userId} (${decoded.sessionType})`);\n return decoded.sessionType;\n }\n\n // Authenticates SSE connections using the refresh token httpOnly cookie\n private handleSseAuth(request: FastifyRequest, requiredSessionTypes?: string[]): boolean {\n const refreshToken = this.requestService.getRefreshToken();\n if (!refreshToken) {\n this.logger.warn(`SSE ${request.url} — no refresh token cookie`);\n throw new UnauthorizedException('Authentication required');\n }\n\n const decoded = this.tokenService.validateRefreshToken(refreshToken);\n\n if (requiredSessionTypes?.length && !requiredSessionTypes.includes(decoded.sessionType)) {\n this.logger.warn(`SSE ${request.url} — session type ${decoded.sessionType} not allowed`);\n throw new UnauthorizedException(`${decoded.sessionType} sessions cannot access this endpoint`);\n }\n\n const { tokenType: _tokenType, exp: _exp, iat: _iat, ...sessionInfo } = decoded;\n request.sessionInfo = sessionInfo;\n\n this.logger.debug(`SSE ${request.url} — authenticated user: ${decoded.userId} (${decoded.sessionType})`);\n return true;\n }\n\n // Validates CSRF token for state-changing requests\n private async validateCsrf(request: FastifyRequest, reply: FastifyReply): Promise<void> {\n const safeMethods = ['GET', 'HEAD', 'OPTIONS'];\n if (safeMethods.includes(request.method)) return;\n\n try {\n const fastifyInstance = request.server as unknown as FastifyInstanceWithCsrf;\n const csrfProtection = fastifyInstance.csrfProtection;\n if (!csrfProtection) {\n throw new ForbiddenException('CSRF protection not configured');\n }\n\n await new Promise<void>((resolve, reject) => {\n const originalSend = reply.send.bind(reply);\n (reply as PatchableReply).send = () => {\n (reply as PatchableReply).send = originalSend as PatchableReply['send'];\n reject(new Error('CSRF validation failed'));\n return reply;\n };\n\n csrfProtection(request, reply, (err?: Error) => {\n (reply as PatchableReply).send = originalSend as PatchableReply['send'];\n if (err) reject(err);\n else resolve();\n });\n });\n } catch (_error: unknown) {\n this.logger.warn(`${request.method} ${request.url} — CSRF validation failed`);\n throw new ForbiddenException({\n errors: [{ field: 'csrf', message: 'Invalid or missing CSRF token' }],\n message: 'CSRF validation failed',\n });\n }\n }\n}\n","import { SetMetadata } from '@nestjs/common';\n\n// Restricts endpoint access to specific session types\nexport const REQUIRE_SESSION_KEY = 'requiredSessionTypes';\nexport const RequireSession = (...types: string[]) => SetMetadata(REQUIRE_SESSION_KEY, types);\n","import { SetMetadata } from '@nestjs/common';\n\nexport const SKIP_CSRF_KEY = 'skipCsrf';\n\nexport const SkipCsrf = () => SetMetadata(SKIP_CSRF_KEY, true);\n","import { Inject, Injectable, Logger, UnauthorizedException } from '@nestjs/common';\nimport { JwtService, type JwtSignOptions } from '@nestjs/jwt';\nimport type { FastifyRequest } from 'fastify';\nimport '../../types/fastify-augmentation';\nimport { parseExpiryToMs } from '../../utils/time.utils';\nimport {\n AUTH_CONFIG,\n type AuthConfig,\n type DecodedAccessToken,\n type DecodedRefreshToken,\n TokenType,\n} from '../auth.config';\nimport { hashToken, verifyTokenHash } from '../utils/token-hash.util';\n\nexport type { DecodedAccessToken, DecodedRefreshToken };\n\n// Session info type from Fastify augmentation\ntype SessionInfo = NonNullable<FastifyRequest['sessionInfo']>;\n\ninterface TokenError extends Error {\n name: 'TokenExpiredError' | 'JsonWebTokenError' | 'NotBeforeError';\n}\n\n// Handles all token operations — generation, validation, and binding verification\n@Injectable()\nexport class TokenService {\n private readonly logger = new Logger(TokenService.name);\n\n constructor(\n private readonly jwtService: JwtService,\n @Inject(AUTH_CONFIG) private readonly config: AuthConfig,\n ) {}\n\n // ---- Generation ----\n\n // Generates an access token bound to the given refresh token\n generateAccessToken(sessionInfo: SessionInfo, refreshToken: string): string {\n const { userId, sessionId, sessionType, ...metadata } = sessionInfo;\n return this.jwtService.sign(\n {\n sessionType,\n tokenType: TokenType.ACCESS,\n userId,\n sessionId,\n refreshTokenHash: hashToken(refreshToken),\n ...metadata,\n },\n { expiresIn: this.config.tokenExpiry.access },\n );\n }\n\n // Generates a refresh token for session persistence\n generateRefreshToken(sessionInfo: SessionInfo): string {\n const { userId, sessionId, sessionType, ...metadata } = sessionInfo;\n return this.jwtService.sign(\n { sessionType, tokenType: TokenType.REFRESH, userId, sessionId, ...metadata },\n { expiresIn: this.config.tokenExpiry.refresh },\n );\n }\n\n // Signs an arbitrary payload with optional JWT options\n sign(payload: object, options?: JwtSignOptions): string {\n return this.jwtService.sign(payload, options);\n }\n\n // Verifies a token and ensures it matches the expected token type\n verify(\n token: string,\n expectedType: TokenType,\n ): { userId: string; sessionId: string; sessionType: string; tokenType: TokenType } {\n try {\n const payload = this.jwtService.verify(token);\n\n if (payload.tokenType !== expectedType) {\n throw new Error(`Expected ${expectedType} token, got ${payload.tokenType}`);\n }\n\n return payload;\n } catch (error) {\n this.logger.error(`Failed to verify ${expectedType} token`, error);\n throw error;\n }\n }\n\n // Returns the expiry as a Date for the given token type\n getExpiryTime(type: TokenType): Date {\n return new Date(Date.now() + parseExpiryToMs(this.config.tokenExpiry[type]));\n }\n\n // Returns the token lifetime in seconds for the given type\n getExpiryInSeconds(type: TokenType): number {\n return Math.floor(parseExpiryToMs(this.config.tokenExpiry[type]) / 1000);\n }\n\n // ---- Validation ----\n\n // Decodes and validates an access token JWT\n validateAccessToken(token: string): DecodedAccessToken {\n try {\n const decoded = this.jwtService.verify<DecodedAccessToken>(token);\n\n if (decoded.tokenType !== TokenType.ACCESS) {\n throw new UnauthorizedException('Invalid token type');\n }\n\n return decoded;\n } catch (error) {\n if (error instanceof UnauthorizedException) throw error;\n\n const jwtError = error as TokenError;\n switch (jwtError.name) {\n case 'TokenExpiredError':\n throw new UnauthorizedException('Access token has expired');\n case 'JsonWebTokenError':\n throw new UnauthorizedException('Invalid access token');\n case 'NotBeforeError':\n throw new UnauthorizedException('Access token not yet valid');\n default:\n throw new UnauthorizedException('Access token validation failed');\n }\n }\n }\n\n // Decodes and validates a refresh token JWT\n validateRefreshToken(token: string): DecodedRefreshToken {\n try {\n const decoded = this.jwtService.verify<DecodedRefreshToken>(token);\n\n if (decoded.tokenType !== TokenType.REFRESH) {\n throw new UnauthorizedException('Invalid token type');\n }\n\n return decoded;\n } catch (error) {\n if (error instanceof UnauthorizedException) throw error;\n throw new UnauthorizedException('Invalid or expired session');\n }\n }\n\n // Validates that the access token is bound to the refresh token\n validateTokenBinding(accessToken: DecodedAccessToken, refreshToken: string): void {\n if (!verifyTokenHash(refreshToken, accessToken.refreshTokenHash)) {\n throw new UnauthorizedException('Session validation failed');\n }\n }\n}\n","// Parses a duration string (e.g. '10m', '1h', '30s', '7d') to milliseconds\nexport function parseExpiryToMs(expiry: string): number {\n const match = expiry.match(/^(\\d+)([smhdwy])$/);\n if (!match) throw new Error(`Invalid expiry format: ${expiry}`);\n\n const value = Number.parseInt(match[1]!, 10);\n const multipliers: Record<string, number> = {\n s: 1000,\n m: 60_000,\n h: 3_600_000,\n d: 86_400_000,\n w: 604_800_000,\n y: 31_536_000_000,\n };\n\n return value * multipliers[match[2]!]!;\n}\n","import * as crypto from 'node:crypto';\n\n// Hashes a token using SHA-256\nexport function hashToken(token: string): string {\n return crypto.createHash('sha256').update(token).digest('hex');\n}\n\n// Verifies a token against its stored hash\nexport function verifyTokenHash(token: string, expectedHash: string): boolean {\n const computedHash = hashToken(token);\n if (computedHash.length !== expectedHash.length) return false;\n return crypto.timingSafeEqual(Buffer.from(computedHash, 'hex'), Buffer.from(expectedHash, 'hex'));\n}\n","import { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport type { FastifyRequest } from 'fastify';\n\n// Extracts the bearer token from the Authorization header\nexport const AccessToken = createParamDecorator((_data: unknown, ctx: ExecutionContext): string => {\n const request = ctx.switchToHttp().getRequest<FastifyRequest>();\n const authHeader = request.headers.authorization;\n return authHeader?.replace('Bearer ', '') || '';\n});\n","import { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport type { FastifyRequest } from 'fastify';\nimport { AUTH_CONFIG_DEFAULTS } from '../auth.config';\n\n// Extracts the cookie domain from x-forwarded-host (injected by proxy), validated against baseDomain, falls back to baseDomain if invalid\nexport const CookieDomain = createParamDecorator((_data: unknown, ctx: ExecutionContext): string => {\n const request = ctx.switchToHttp().getRequest<FastifyRequest>();\n const forwarded = request.headers['x-forwarded-host'];\n const raw = Array.isArray(forwarded) ? forwarded[0] : forwarded;\n const hostStr = raw ?? request.hostname;\n const domain = hostStr.split(':')[0] ?? hostStr;\n const baseDomain =\n request.authConfig?.cookie.refreshCookieDomain ?? AUTH_CONFIG_DEFAULTS.cookie.refreshCookieDomain ?? '';\n return domain.endsWith(`.${baseDomain}`) ? domain : baseDomain;\n});\n","import { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport type { FastifyRequest } from 'fastify';\nimport { AUTH_CONFIG_DEFAULTS } from '../auth.config';\n\n// Returns the configured refresh cookie name from request.authConfig\nexport const CookieName = createParamDecorator((_data: unknown, ctx: ExecutionContext): string => {\n const request = ctx.switchToHttp().getRequest<FastifyRequest>();\n return request.authConfig?.cookie.refreshCookieName ?? AUTH_CONFIG_DEFAULTS.cookie.refreshCookieName;\n});\n","import { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport type { FastifyRequest } from 'fastify';\n\n// Extracts the request hostname from x-forwarded-host (set by reverse proxies and dev proxy) with fallback to request.hostname\nexport const Hostname = createParamDecorator((_data: unknown, ctx: ExecutionContext): string => {\n const request = ctx.switchToHttp().getRequest<FastifyRequest>();\n const forwarded = request.headers['x-forwarded-host'];\n const raw = Array.isArray(forwarded) ? forwarded[0] : forwarded;\n const hostStr = raw ?? request.hostname;\n return hostStr.split(':')[0] ?? hostStr;\n});\n","import { SetMetadata } from '@nestjs/common';\n\nexport const Public = () => SetMetadata('isPublic', true);\n","import { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport type { FastifyRequest } from 'fastify';\nimport { UnauthorizedException } from '../../exceptions';\nimport { AUTH_CONFIG_DEFAULTS, type CookieConfig, type CookieSerializeOptions } from '../auth.config';\n\n// Builds cookie serialize options from the given cookie config\nfunction buildCookieOptionsForHost(cookieConfig: CookieConfig, hostname: string): CookieSerializeOptions {\n const baseDomain = cookieConfig.refreshCookieDomain;\n\n if (!baseDomain) {\n throw new Error('refreshCookieDomain must be configured before using @RefreshCookieOptions()');\n }\n\n if (!hostname.endsWith(`.${baseDomain}`)) {\n throw new UnauthorizedException('Invalid request host.');\n }\n\n return {\n httpOnly: true,\n secure: cookieConfig.refreshCookieSecure,\n sameSite: cookieConfig.refreshCookieSameSite,\n path: cookieConfig.refreshCookiePath,\n maxAge: cookieConfig.refreshCookieMaxAge,\n domain: hostname,\n };\n}\n\n// Returns refresh cookie options with domain scoped to the request subdomain (reads x-forwarded-host injected by proxy)\nexport const RefreshCookieOptions = createParamDecorator(\n (_data: unknown, ctx: ExecutionContext): CookieSerializeOptions => {\n const request = ctx.switchToHttp().getRequest<FastifyRequest>();\n const forwarded = request.headers['x-forwarded-host'];\n const raw = Array.isArray(forwarded) ? forwarded[0] : forwarded;\n const hostStr = raw ?? request.hostname;\n const domain = hostStr.split(':')[0] ?? hostStr;\n const cookieConfig: CookieConfig = request.authConfig?.cookie ?? AUTH_CONFIG_DEFAULTS.cookie;\n return buildCookieOptionsForHost(cookieConfig, domain);\n },\n);\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class BadGatewayException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Bad Gateway', HttpStatus.BAD_GATEWAY);\n }\n}\n","import { HttpException, HttpStatus } from '@nestjs/common';\nimport type { FieldError } from '../types/error-response.types';\n\n// Re-export FieldError for backwards compatibility\nexport type { FieldError } from '../types/error-response.types';\n\nexport interface ProblemOptions {\n type?: string;\n label?: string;\n detail?: string;\n errors?: FieldError[];\n}\n\nexport abstract class HttpProblemException extends HttpException {\n constructor(detailOrOptions: string | ProblemOptions, httpStatus: HttpStatus) {\n const options = typeof detailOrOptions === 'string' ? { detail: detailOrOptions } : detailOrOptions;\n\n super(\n {\n type: options.type ?? 'about:blank',\n label: options.label,\n detail: options.detail,\n errors: options.errors ?? [],\n },\n httpStatus,\n );\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class BadRequestException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Bad Request', HttpStatus.BAD_REQUEST);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class ConflictException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Conflict', HttpStatus.CONFLICT);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class ForbiddenException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Forbidden', HttpStatus.FORBIDDEN);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class GoneException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Gone', HttpStatus.GONE);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class InternalServerErrorException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Internal Server Error', HttpStatus.INTERNAL_SERVER_ERROR);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class MethodNotAllowedException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Method Not Allowed', HttpStatus.METHOD_NOT_ALLOWED);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class NotAcceptableException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Not Acceptable', HttpStatus.NOT_ACCEPTABLE);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class NotFoundException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Not Found', HttpStatus.NOT_FOUND);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class NotImplementedException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Not Implemented', HttpStatus.NOT_IMPLEMENTED);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class PayloadTooLargeException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Payload Too Large', HttpStatus.PAYLOAD_TOO_LARGE);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class RequestTimeoutException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Request Timeout', HttpStatus.REQUEST_TIMEOUT);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class ServiceUnavailableException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Service Unavailable', HttpStatus.SERVICE_UNAVAILABLE);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class TooManyRequestsException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Too Many Requests', HttpStatus.TOO_MANY_REQUESTS);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class UnauthorizedException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Unauthorized', HttpStatus.UNAUTHORIZED);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class UnprocessableEntityException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Unprocessable Entity', HttpStatus.UNPROCESSABLE_ENTITY);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class UnsupportedMediaTypeException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Unsupported Media Type', HttpStatus.UNSUPPORTED_MEDIA_TYPE);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class ValidationException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Validation Failed', HttpStatus.UNPROCESSABLE_ENTITY);\n }\n}\n","import { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport type { FastifyRequest } from 'fastify';\nimport { AUTH_CONFIG_DEFAULTS } from '../auth.config';\n\nexport const RefreshTokenCookie = createParamDecorator((_data: unknown, ctx: ExecutionContext): string | undefined => {\n const request = ctx.switchToHttp().getRequest<FastifyRequest>();\n const cookies = request.cookies ?? {};\n const cookieName = request.authConfig?.cookie.refreshCookieName ?? AUTH_CONFIG_DEFAULTS.cookie.refreshCookieName;\n return cookies[cookieName] as string | undefined;\n});\n","import { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport type { FastifyRequest } from 'fastify';\nimport '../../types/fastify-augmentation';\n\nexport interface SessionInfo {\n userId: string;\n sessionId: string;\n sessionType: string;\n}\n\n// Returns full decoded session info from request.sessionInfo (set by VrittiAuthGuard)\nexport const SessionData = createParamDecorator((_data: unknown, ctx: ExecutionContext): SessionInfo => {\n const request = ctx.switchToHttp().getRequest<FastifyRequest>();\n const sessionInfo = request.sessionInfo;\n\n if (!sessionInfo?.sessionId) {\n throw new Error('Session info not found on request. Ensure route is protected by auth guard.');\n }\n\n return {\n userId: sessionInfo.userId,\n sessionId: sessionInfo.sessionId,\n sessionType: sessionInfo.sessionType,\n };\n});\n","import { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport type { FastifyRequest } from 'fastify';\n\n// Extracts the subdomain from the request's origin or x-forwarded-host header\nexport const Subdomain = createParamDecorator((_data: unknown, ctx: ExecutionContext): string | undefined => {\n const request = ctx.switchToHttp().getRequest<FastifyRequest>();\n\n // Try origin header first (browser always sends this on cross-origin requests)\n const origin = request.headers.origin;\n if (origin) {\n try {\n const url = new URL(origin);\n return url.hostname.split('.')[0];\n } catch {\n // Invalid origin, fall through\n }\n }\n\n // Fallback to x-forwarded-host (set by rsbuild proxy and production reverse proxies)\n const forwarded = request.headers['x-forwarded-host'];\n const host = Array.isArray(forwarded) ? forwarded[0] : forwarded;\n if (host) return host.split('.')[0];\n\n return undefined;\n});\n","import { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport type { FastifyRequest } from 'fastify';\nimport '../../types/fastify-augmentation';\n\n// Extracts userId from request.sessionInfo (set by VrittiAuthGuard)\nexport const UserId = createParamDecorator((_data: unknown, ctx: ExecutionContext): string => {\n const request = ctx.switchToHttp().getRequest<FastifyRequest>();\n const sessionInfo = request.sessionInfo;\n\n if (!sessionInfo?.userId) {\n throw new Error('User ID not found on request. Ensure route is protected by auth guard.');\n }\n\n return sessionInfo.userId;\n});\n","import { Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';\nimport { CacheService } from './cache.service';\nimport { CACHE_PROVIDER } from './constants';\nimport { RedisCacheProvider } from './providers/redis.provider';\n\n// To add a new provider in the future:\n// 1. Create providers/memcached.provider.ts implementing ICacheProvider\n// 2. Replace RedisCacheProvider with the new class in useExisting below\n\n@Module({\n imports: [ConfigModule],\n providers: [\n RedisCacheProvider,\n {\n provide: CACHE_PROVIDER,\n useExisting: RedisCacheProvider,\n },\n CacheService,\n ],\n exports: [RedisCacheProvider, CACHE_PROVIDER, CacheService],\n})\nexport class CacheModule {}\n","import { Inject, Injectable, Logger } from '@nestjs/common';\nimport { CACHE_PROVIDER } from './constants';\nimport type { ICacheProvider } from './interfaces/cache-provider.interface';\n\n@Injectable()\nexport class CacheService {\n private readonly logger = new Logger(CacheService.name);\n\n constructor(@Inject(CACHE_PROVIDER) private readonly provider: ICacheProvider) {}\n\n // Stores a value with mandatory TTL — errors are logged and swallowed so DB writes still succeed\n async set<T>(key: string, value: T, ttlSeconds: number): Promise<void> {\n try {\n await this.provider.set(key, value, ttlSeconds);\n } catch (err) {\n this.logger.error(`Cache set failed for key \"${key}\"`, err);\n }\n }\n\n // Returns cached value or null on miss or any Redis error — callers fall back to DB\n async get<T>(key: string): Promise<T | null> {\n try {\n return await this.provider.get<T>(key);\n } catch (err) {\n this.logger.error(`Cache get failed for key \"${key}\"`, err);\n return null;\n }\n }\n\n // Deletes one or more keys — errors are logged and swallowed\n async del(...keys: string[]): Promise<void> {\n try {\n await this.provider.del(...keys);\n } catch (err) {\n this.logger.error(`Cache del failed for keys \"${keys.join(', ')}\"`, err);\n }\n }\n\n // Returns all keys matching a glob pattern — returns empty array on error\n async scanKeys(pattern: string): Promise<string[]> {\n try {\n return await this.provider.scanKeys(pattern);\n } catch (err) {\n this.logger.error(`Cache scanKeys failed for pattern \"${pattern}\"`, err);\n return [];\n }\n }\n\n // Returns raw memory info from the provider — returns empty string on error\n async getMemoryInfo(): Promise<string> {\n try {\n return await this.provider.getMemoryInfo();\n } catch (err) {\n this.logger.error('Cache getMemoryInfo failed', err);\n return '';\n }\n }\n}\n","// Injection token for the active cache provider — use this to inject ICacheProvider\nexport const CACHE_PROVIDER = Symbol('CACHE_PROVIDER');\n","import { Injectable, Logger, OnModuleDestroy, OnModuleInit } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport Redis from 'ioredis';\nimport type { ICacheProvider } from '../interfaces/cache-provider.interface';\n\n@Injectable()\nexport class RedisCacheProvider implements ICacheProvider, OnModuleInit, OnModuleDestroy {\n private readonly logger = new Logger(RedisCacheProvider.name);\n private client: Redis;\n\n constructor(private readonly configService: ConfigService) {}\n\n // Creates the ioredis client and attaches connection/error listeners\n onModuleInit(): void {\n const url = this.configService.getOrThrow<string>('REDIS_URL');\n this.client = new Redis(url, {\n lazyConnect: true,\n maxRetriesPerRequest: 3,\n });\n this.client.on('connect', () => this.logger.log('Redis connected'));\n this.client.on('error', (err) => this.logger.error('Redis error', err));\n }\n\n // Gracefully closes the ioredis connection on app shutdown\n async onModuleDestroy(): Promise<void> {\n await this.client.quit();\n this.logger.log('Redis disconnected');\n }\n\n // Serializes value to JSON and stores with a mandatory TTL\n async set<T>(key: string, value: T, ttlSeconds: number): Promise<void> {\n const json = JSON.stringify(value);\n await this.client.setex(key, ttlSeconds, json);\n }\n\n // Reads the stored JSON string and parses back to the original type\n async get<T>(key: string): Promise<T | null> {\n const json = await this.client.get(key);\n if (!json) return null;\n return JSON.parse(json) as T;\n }\n\n // Deletes one or more keys in a single command\n async del(...keys: string[]): Promise<void> {\n if (keys.length > 0) {\n await this.client.del(...keys);\n }\n }\n\n // Cursor-iterates all keys matching a glob pattern — never uses KEYS command\n async scanKeys(pattern: string): Promise<string[]> {\n const keys: string[] = [];\n let cursor = '0';\n do {\n const [nextCursor, batch] = await this.client.scan(cursor, 'MATCH', pattern, 'COUNT', 100);\n cursor = nextCursor;\n keys.push(...batch);\n } while (cursor !== '0');\n return keys;\n }\n\n // Returns raw INFO memory output for memory monitoring\n async getMemoryInfo(): Promise<string> {\n return this.client.info('memory');\n }\n}\n","import { type DynamicModule, Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';\nimport type { PgTable } from 'drizzle-orm/pg-core';\nimport { CacheModule } from '../cache/cache.module';\nimport { DATA_TABLE_VIEWS_TABLE } from './data-table.constants';\nimport { DataTableStateController } from './state/controllers/data-table-state.controller';\nimport { DataTableStateService } from './state/services/data-table-state.service';\nimport { DataTableViewsController } from './views/controllers/data-table-views.controller';\nimport { DataTableViewsRepository } from './views/repositories/data-table-views.repository';\nimport { DataTableViewsService } from './views/services/data-table-views.service';\n\nexport { DATA_TABLE_VIEWS_TABLE };\n\nexport interface DataTableModuleOptions {\n tableViews: PgTable;\n}\n\n@Module({})\nexport class DataTableModule {\n static forRoot(options: DataTableModuleOptions): DynamicModule {\n return {\n global: true,\n module: DataTableModule,\n imports: [ConfigModule, CacheModule],\n controllers: [DataTableStateController, DataTableViewsController],\n providers: [\n {\n provide: DATA_TABLE_VIEWS_TABLE,\n useValue: options.tableViews,\n },\n DataTableViewsService,\n DataTableViewsRepository,\n DataTableStateService,\n ],\n exports: [DataTableViewsService, DataTableStateService],\n };\n }\n}\n","export const DATA_TABLE_VIEWS_TABLE = Symbol('DATA_TABLE_VIEWS_TABLE');\n","import { Body, Controller, HttpCode, HttpStatus, Logger, Post } from '@nestjs/common';\nimport { ApiBearerAuth, ApiTags } from '@nestjs/swagger';\nimport { UserId } from '../../../auth/decorators/user-id.decorator';\nimport { ApiUpsertDataTableState } from '../docs/data-table-state.docs';\nimport { UpsertDataTableStateDto } from '../dto/request/upsert-data-table-state.dto';\nimport { DataTableStateService } from '../services/data-table-state.service';\n\n@ApiTags('Table States')\n@ApiBearerAuth()\n@Controller('table-states')\nexport class DataTableStateController {\n private readonly logger = new Logger(DataTableStateController.name);\n\n constructor(private readonly dataTableStateService: DataTableStateService) {}\n\n // Saves live table state to Redis cache for the authenticated user's table\n @Post()\n @HttpCode(HttpStatus.OK)\n @ApiUpsertDataTableState()\n upsertCurrentState(@UserId() userId: string, @Body() dto: UpsertDataTableStateDto): Promise<void> {\n this.logger.log(`POST /table-states - User: ${userId}, table: ${dto.tableSlug}`);\n return this.dataTableStateService.upsertCurrentState(userId, dto);\n }\n}\n","import { applyDecorators } from '@nestjs/common';\nimport { ApiBody, ApiOperation, ApiResponse } from '@nestjs/swagger';\nimport { UpsertDataTableStateDto } from '../dto/request/upsert-data-table-state.dto';\n\nexport function ApiUpsertDataTableState() {\n return applyDecorators(\n ApiOperation({\n summary: 'Save live table state',\n description:\n 'Stores the current filter, sort, and column visibility state in Redis cache. Called on filter Apply and sort column click. State expires after TABLE_STATE_CACHE_TTL seconds.',\n }),\n ApiBody({ type: UpsertDataTableStateDto }),\n ApiResponse({ status: 200, description: 'Live state cached.' }),\n ApiResponse({ status: 400, description: 'Invalid request body.' }),\n ApiResponse({ status: 401, description: 'Unauthorized.' }),\n );\n}\n","import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';\nimport { IsObject, IsOptional, IsString, IsUUID, MaxLength } from 'class-validator';\nimport type { TableViewState } from '../../../../database/filter/filter.types';\n\nexport class UpsertDataTableStateDto {\n @ApiProperty({ description: 'Unique slug identifying the table', example: 'cloud-providers' })\n @IsString()\n @MaxLength(200)\n tableSlug: string;\n\n @ApiProperty({ description: 'Full table view state including filters, sort, and column visibility' })\n @IsObject()\n state: TableViewState;\n\n @ApiPropertyOptional()\n @IsOptional()\n @IsUUID()\n activeViewId?: string | null;\n}\n","import { Injectable, Logger } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { CacheService } from '../../../cache/cache.service';\nimport type { TableViewState } from '../../../database/filter/filter.types';\nimport type { UpsertDataTableStateDto } from '../dto/request/upsert-data-table-state.dto';\n\nconst EMPTY_TABLE_STATE: TableViewState = {\n filters: [],\n sort: [],\n columnVisibility: {},\n columnOrder: [],\n columnSizing: {},\n columnPinning: { left: [], right: [] },\n lockedColumnSizing: false,\n density: 'normal',\n filterOrder: [],\n filterVisibility: {},\n search: null,\n pagination: { limit: 20, offset: 0 },\n};\n\n@Injectable()\nexport class DataTableStateService {\n private readonly logger = new Logger(DataTableStateService.name);\n\n constructor(\n private readonly cacheService: CacheService,\n private readonly configService: ConfigService,\n ) {}\n\n // Returns configured TTL for live table state in seconds, defaulting to 3600 (1h)\n private get stateTtl(): number {\n return this.configService.get<number>('TABLE_STATE_CACHE_TTL') ?? 3600;\n }\n\n // Saves live table state and active view ID to Redis; DB is not written\n async upsertCurrentState(userId: string, dto: UpsertDataTableStateDto): Promise<void> {\n const key = `dt:${userId}:${dto.tableSlug}`;\n await this.cacheService.set(key, { state: dto.state, activeViewId: dto.activeViewId ?? null }, this.stateTtl);\n this.logger.log(`Cached live state for user: ${userId}, table: ${dto.tableSlug}`);\n }\n\n // Returns live table state and active view ID from Redis; returns empty state on miss — no DB query\n async getCurrentState(\n userId: string,\n tableSlug: string,\n ): Promise<{ state: TableViewState; activeViewId: string | null }> {\n const key = `dt:${userId}:${tableSlug}`;\n const cached = await this.cacheService.get<{ state: TableViewState; activeViewId: string | null }>(key);\n return cached ?? { state: EMPTY_TABLE_STATE, activeViewId: null };\n }\n}\n","import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Logger, Param, Patch, Post, Query } from '@nestjs/common';\nimport { ApiBearerAuth, ApiTags } from '@nestjs/swagger';\nimport { UserId } from '../../../auth/decorators/user-id.decorator';\nimport {\n ApiCreateDataTableView,\n ApiDeleteDataTableView,\n ApiListDataTableViews,\n ApiRenameDataTableView,\n ApiToggleShareDataTableView,\n ApiUpdateDataTableView,\n} from '../docs/data-table-views.docs';\nimport { DataTableViewDto } from '../dto/entity/data-table-view.dto';\nimport { CreateDataTableViewDto } from '../dto/request/create-data-table-view.dto';\nimport { RenameDataTableViewDto } from '../dto/request/rename-data-table-view.dto';\nimport { ToggleShareDataTableViewDto } from '../dto/request/toggle-share-data-table-view.dto';\nimport { UpdateDataTableViewDto } from '../dto/request/update-data-table-view.dto';\nimport { DataTableViewsService } from '../services/data-table-views.service';\n\n@ApiTags('Table Views')\n@ApiBearerAuth()\n@Controller('table-views')\nexport class DataTableViewsController {\n private readonly logger = new Logger(DataTableViewsController.name);\n\n constructor(private readonly dataTableViewsService: DataTableViewsService) {}\n\n // Returns all named views for the given table — own plus shared\n @Get()\n @ApiListDataTableViews()\n findViews(@UserId() userId: string, @Query('tableSlug') tableSlug: string): Promise<DataTableViewDto[]> {\n this.logger.log(`GET /table-views?tableSlug=${tableSlug} - User: ${userId}`);\n return this.dataTableViewsService.findViews(userId, tableSlug);\n }\n\n // Creates a named snapshot of the current table state\n @Post()\n @HttpCode(HttpStatus.CREATED)\n @ApiCreateDataTableView()\n createView(@UserId() userId: string, @Body() dto: CreateDataTableViewDto): Promise<DataTableViewDto> {\n this.logger.log(`POST /table-views - User: ${userId}, table: ${dto.tableSlug}`);\n return this.dataTableViewsService.createView(userId, dto);\n }\n\n // Updates state of an existing named view\n @Patch(':id')\n @ApiUpdateDataTableView()\n updateView(\n @UserId() userId: string,\n @Param('id') id: string,\n @Body() dto: UpdateDataTableViewDto,\n ): Promise<DataTableViewDto> {\n this.logger.log(`PATCH /table-views/${id} - User: ${userId}`);\n return this.dataTableViewsService.updateView(userId, id, dto);\n }\n\n // Renames an existing named view — enforces unique name per user+table\n @Patch(':id/rename')\n @ApiRenameDataTableView()\n renameView(\n @UserId() userId: string,\n @Param('id') id: string,\n @Body() dto: RenameDataTableViewDto,\n ): Promise<DataTableViewDto> {\n this.logger.log(`PATCH /table-views/${id}/rename - User: ${userId}`);\n return this.dataTableViewsService.renameView(userId, id, dto.name);\n }\n\n // Toggles sharing visibility of a named view\n @Patch(':id/share')\n @ApiToggleShareDataTableView()\n toggleShareView(\n @UserId() userId: string,\n @Param('id') id: string,\n @Body() dto: ToggleShareDataTableViewDto,\n ): Promise<DataTableViewDto> {\n this.logger.log(`PATCH /table-views/${id}/share - User: ${userId}`);\n return this.dataTableViewsService.toggleShareView(userId, id, dto.isShared);\n }\n\n // Deletes a named view owned by the authenticated user\n @Delete(':id')\n @ApiDeleteDataTableView()\n deleteView(@UserId() userId: string, @Param('id') id: string): Promise<DataTableViewDto> {\n this.logger.log(`DELETE /table-views/${id} - User: ${userId}`);\n return this.dataTableViewsService.deleteView(userId, id);\n }\n}\n","import { applyDecorators } from '@nestjs/common';\nimport { ApiBody, ApiOperation, ApiParam, ApiQuery, ApiResponse } from '@nestjs/swagger';\nimport { DataTableViewDto } from '../dto/entity/data-table-view.dto';\nimport { CreateDataTableViewDto } from '../dto/request/create-data-table-view.dto';\nimport { RenameDataTableViewDto } from '../dto/request/rename-data-table-view.dto';\nimport { ToggleShareDataTableViewDto } from '../dto/request/toggle-share-data-table-view.dto';\nimport { UpdateDataTableViewDto } from '../dto/request/update-data-table-view.dto';\n\nexport function ApiListDataTableViews() {\n return applyDecorators(\n ApiOperation({\n summary: 'List named table views',\n description: \"Returns the authenticated user's own named views plus all shared views for the given table slug.\",\n }),\n ApiQuery({\n name: 'tableSlug',\n description: 'Slug of the table to fetch views for',\n example: 'cloud-providers',\n required: true,\n }),\n ApiResponse({ status: 200, description: 'Named views retrieved.', type: [DataTableViewDto] }),\n ApiResponse({ status: 401, description: 'Unauthorized.' }),\n );\n}\n\nexport function ApiCreateDataTableView() {\n return applyDecorators(\n ApiOperation({\n summary: 'Create named table view',\n description: 'Saves the current table state as a named view snapshot. The name must be unique per user+table.',\n }),\n ApiBody({ type: CreateDataTableViewDto }),\n ApiResponse({ status: 201, description: 'Named view created.', type: DataTableViewDto }),\n ApiResponse({ status: 400, description: 'Invalid request body.' }),\n ApiResponse({ status: 401, description: 'Unauthorized.' }),\n );\n}\n\nexport function ApiUpdateDataTableView() {\n return applyDecorators(\n ApiOperation({\n summary: 'Update named table view',\n description: 'Updates the state of an existing named view. Only the owner can update.',\n }),\n ApiParam({ name: 'id', description: 'UUID of the table view to update' }),\n ApiBody({ type: UpdateDataTableViewDto }),\n ApiResponse({ status: 200, description: 'View updated.', type: DataTableViewDto }),\n ApiResponse({ status: 400, description: 'Validation failed or not owned by caller.' }),\n ApiResponse({ status: 401, description: 'Unauthorized.' }),\n ApiResponse({ status: 404, description: 'View not found.' }),\n );\n}\n\nexport function ApiRenameDataTableView() {\n return applyDecorators(\n ApiOperation({\n summary: 'Rename a named table view',\n description:\n 'Updates the display name of an existing view. The new name must be unique per user+table. Only the owner can rename.',\n }),\n ApiParam({ name: 'id', description: 'UUID of the table view to rename' }),\n ApiBody({ type: RenameDataTableViewDto }),\n ApiResponse({ status: 200, description: 'View renamed.', type: DataTableViewDto }),\n ApiResponse({ status: 400, description: 'Not owned by caller.' }),\n ApiResponse({ status: 401, description: 'Unauthorized.' }),\n ApiResponse({ status: 404, description: 'View not found.' }),\n ApiResponse({ status: 409, description: 'A view with this name already exists.' }),\n );\n}\n\nexport function ApiToggleShareDataTableView() {\n return applyDecorators(\n ApiOperation({\n summary: 'Toggle view sharing',\n description:\n 'Makes a view visible to all users (shared) or restricts it to the owner only (private). Only the owner can toggle sharing.',\n }),\n ApiParam({ name: 'id', description: 'UUID of the table view' }),\n ApiBody({ type: ToggleShareDataTableViewDto }),\n ApiResponse({ status: 200, description: 'Sharing status updated.', type: DataTableViewDto }),\n ApiResponse({ status: 400, description: 'Not owned by caller.' }),\n ApiResponse({ status: 401, description: 'Unauthorized.' }),\n ApiResponse({ status: 404, description: 'View not found.' }),\n );\n}\n\nexport function ApiDeleteDataTableView() {\n return applyDecorators(\n ApiOperation({\n summary: 'Delete named table view',\n description: 'Permanently deletes a named view. Only the owner can delete their own views.',\n }),\n ApiParam({ name: 'id', description: 'UUID of the table view to delete' }),\n ApiResponse({ status: 200, description: 'View deleted.', type: DataTableViewDto }),\n ApiResponse({ status: 400, description: 'Not owned by caller.' }),\n ApiResponse({ status: 401, description: 'Unauthorized.' }),\n ApiResponse({ status: 404, description: 'View not found.' }),\n );\n}\n","import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';\nimport type { TableViewState } from '../../../../database/filter/filter.types';\nimport type { DataTableViewRecord } from '../../../schema/data-table-views.table';\n\nexport class DataTableViewDto {\n @ApiProperty({ description: 'View unique identifier' })\n id: string;\n\n @ApiPropertyOptional({ description: 'Display name of the view', nullable: true })\n name: string | null;\n\n @ApiProperty({ description: 'Slug of the table this view belongs to', example: 'cloud-providers' })\n tableSlug: string;\n\n @ApiProperty({ description: 'Stored filter, sort, and column visibility state' })\n state: TableViewState;\n\n @ApiProperty({ description: 'Whether the view is visible to all users', example: false })\n isShared: boolean;\n\n @ApiProperty({ description: 'Whether the requesting user owns this view', example: true })\n isOwn: boolean;\n\n @ApiProperty({ description: 'Creation timestamp' })\n createdAt: Date;\n\n @ApiPropertyOptional({ description: 'Last updated timestamp', nullable: true })\n updatedAt: Date | null;\n\n // Creates a response DTO from a DataTableView entity, computing isOwn by comparing userId\n static from(view: DataTableViewRecord, userId: string): DataTableViewDto {\n const dto = new DataTableViewDto();\n dto.id = view.id;\n dto.name = view.name ?? null;\n dto.tableSlug = view.tableSlug;\n dto.state = view.state;\n dto.isShared = view.isShared;\n dto.isOwn = view.userId === userId;\n dto.createdAt = view.createdAt;\n dto.updatedAt = view.updatedAt ?? null;\n return dto;\n }\n}\n","import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';\nimport { IsBoolean, IsObject, IsOptional, IsString, MaxLength } from 'class-validator';\nimport type { TableViewState } from '../../../../database/filter/filter.types';\n\nexport class CreateDataTableViewDto {\n @ApiProperty({ description: 'Display name for the saved view', example: 'AWS Only' })\n @IsString()\n @MaxLength(100)\n name: string;\n\n @ApiProperty({ description: 'Unique slug identifying the table', example: 'cloud-providers' })\n @IsString()\n @MaxLength(200)\n tableSlug: string;\n\n @ApiProperty({ description: 'Full table view state including filters, sort, and column visibility' })\n @IsObject()\n state: TableViewState;\n\n @ApiPropertyOptional({ description: 'Whether this view is visible to all users', example: false })\n @IsBoolean()\n @IsOptional()\n isShared?: boolean;\n}\n","import { ApiProperty } from '@nestjs/swagger';\nimport { IsString, MaxLength, MinLength } from 'class-validator';\n\nexport class RenameDataTableViewDto {\n @ApiProperty({ description: 'New display name for the view', example: 'AWS Only' })\n @IsString()\n @MinLength(1)\n @MaxLength(100)\n name: string;\n}\n","import { ApiProperty } from '@nestjs/swagger';\nimport { IsBoolean } from 'class-validator';\n\nexport class ToggleShareDataTableViewDto {\n @ApiProperty({ description: 'Whether the view should be visible to all users', example: true })\n @IsBoolean()\n isShared: boolean;\n}\n","import { ApiProperty } from '@nestjs/swagger';\nimport { IsObject } from 'class-validator';\nimport type { TableViewState } from '../../../../database/filter/filter.types';\n\n// State-only update — name, tableSlug, and isShared are not updatable via this DTO\nexport class UpdateDataTableViewDto {\n @ApiProperty({ description: 'Updated filter, sort, and column visibility state' })\n @IsObject()\n state: TableViewState;\n}\n","import { createHash } from 'node:crypto';\nimport { Injectable, Logger } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { CacheService } from '../../../cache/cache.service';\nimport { BadRequestException, ConflictException, NotFoundException } from '../../../exceptions';\nimport type { DataTableViewRecord } from '../../schema/data-table-views.table';\nimport { DataTableViewDto } from '../dto/entity/data-table-view.dto';\nimport type { CreateDataTableViewDto } from '../dto/request/create-data-table-view.dto';\nimport type { UpdateDataTableViewDto } from '../dto/request/update-data-table-view.dto';\nimport { DataTableViewsRepository } from '../repositories/data-table-views.repository';\n\n// Computes a deterministic SHA-256 checksum of a value for equality comparison\nfunction computeChecksum(value: unknown): string {\n return createHash('sha256').update(JSON.stringify(value)).digest('hex');\n}\n\n@Injectable()\nexport class DataTableViewsService {\n private readonly logger = new Logger(DataTableViewsService.name);\n\n constructor(\n private readonly dataTableViewsRepository: DataTableViewsRepository,\n private readonly cacheService: CacheService,\n private readonly configService: ConfigService,\n ) {}\n\n // Builds the Redis key for a user's personal (non-shared) views for a given table\n private personalViewsKey(userId: string, tableSlug: string): string {\n return `views:personal:${userId}:${tableSlug}`;\n }\n\n // Builds the Redis key for all shared views for a given table — same key for all users\n private sharedViewsKey(tableSlug: string): string {\n return `views:shared:${tableSlug}`;\n }\n\n // Returns configured TTL for named views in seconds, defaulting to 86400 (24h)\n private get viewsTtl(): number {\n return this.configService.get<number>('TABLE_VIEWS_CACHE_TTL') ?? 86400;\n }\n\n // Fetches personal views from cache; falls back to DB and warms cache on miss\n private async getOrCachePersonalViews(userId: string, tableSlug: string): Promise<DataTableViewRecord[]> {\n const key = this.personalViewsKey(userId, tableSlug);\n const cached = await this.cacheService.get<DataTableViewRecord[]>(key);\n if (cached) {\n this.logger.debug(`Cache hit for personal views: user=${userId}, table=${tableSlug}`);\n return cached;\n }\n const rows = await this.dataTableViewsRepository.findPersonalViewsBySlug(userId, tableSlug);\n await this.cacheService.set(key, rows, this.viewsTtl);\n return rows;\n }\n\n // Fetches shared views from cache; falls back to DB and warms cache on miss\n private async getOrCacheSharedViews(tableSlug: string): Promise<DataTableViewRecord[]> {\n const key = this.sharedViewsKey(tableSlug);\n const cached = await this.cacheService.get<DataTableViewRecord[]>(key);\n if (cached) {\n this.logger.debug(`Cache hit for shared views: table=${tableSlug}`);\n return cached;\n }\n const rows = await this.dataTableViewsRepository.findSharedViewsBySlug(tableSlug);\n await this.cacheService.set(key, rows, this.viewsTtl);\n return rows;\n }\n\n // Deletes personal and/or shared cache keys based on which pools the mutation affects\n private async invalidateViewsCache(\n userId: string,\n tableSlug: string,\n affectsPersonal: boolean,\n affectsShared: boolean,\n ): Promise<void> {\n const toDelete: string[] = [];\n if (affectsPersonal) toDelete.push(this.personalViewsKey(userId, tableSlug));\n if (affectsShared) toDelete.push(this.sharedViewsKey(tableSlug));\n if (toDelete.length > 0) await this.cacheService.del(...toDelete);\n }\n\n // Returns personal + shared named views — each pool fetched from cache or DB in parallel\n async findViews(userId: string, tableSlug: string): Promise<DataTableViewDto[]> {\n const [personalRows, sharedRows] = await Promise.all([\n this.getOrCachePersonalViews(userId, tableSlug),\n this.getOrCacheSharedViews(tableSlug),\n ]);\n return [...personalRows, ...sharedRows].map((row) => DataTableViewDto.from(row, userId));\n }\n\n // Creates a named snapshot and invalidates the relevant cache pool\n async createView(userId: string, dto: CreateDataTableViewDto): Promise<DataTableViewDto> {\n const view = await this.dataTableViewsRepository.create({\n userId,\n tableSlug: dto.tableSlug,\n name: dto.name,\n state: dto.state,\n isShared: dto.isShared ?? false,\n });\n this.logger.log(`Created view \"${dto.name}\" for user: ${userId}, table: ${dto.tableSlug}`);\n const isShared = dto.isShared ?? false;\n await this.invalidateViewsCache(userId, dto.tableSlug, !isShared, isShared);\n return DataTableViewDto.from(view, userId);\n }\n\n // Updates the state of a named view — skips DB write if state is unchanged\n async updateView(userId: string, id: string, dto: UpdateDataTableViewDto): Promise<DataTableViewDto> {\n const view = await this.dataTableViewsRepository.findById(id);\n if (!view) throw new NotFoundException('Table view not found.');\n if (view.userId !== userId) throw new BadRequestException('You do not have permission to update this view.');\n\n // Skip DB write if the state has not changed\n if (computeChecksum(dto.state) === computeChecksum(view.state)) {\n this.logger.log(`State unchanged for view ${id} — skipping DB write`);\n return DataTableViewDto.from(view, userId);\n }\n\n const updated = await this.dataTableViewsRepository.update(id, { state: dto.state });\n this.logger.log(`Updated state for view ${id}, user: ${userId}`);\n await this.invalidateViewsCache(userId, view.tableSlug, !view.isShared, view.isShared);\n return DataTableViewDto.from(updated, userId);\n }\n\n // Toggles the sharing status of a named view — updates both personal and shared cache\n async toggleShareView(userId: string, id: string, isShared: boolean): Promise<DataTableViewDto> {\n const view = await this.dataTableViewsRepository.findById(id);\n if (!view) throw new NotFoundException('Table view not found.');\n if (view.userId !== userId) throw new BadRequestException('You do not have permission to share this view.');\n\n const updated = await this.dataTableViewsRepository.update(id, { isShared });\n this.logger.log(`Set isShared=${isShared} for view ${id}, user: ${userId}`);\n // Invalidate both pools — the view moves from one to the other\n await this.invalidateViewsCache(userId, view.tableSlug, true, true);\n return DataTableViewDto.from(updated, userId);\n }\n\n // Renames a named view — enforces unique name per user+table, invalidates personal cache\n async renameView(userId: string, id: string, name: string): Promise<DataTableViewDto> {\n const view = await this.dataTableViewsRepository.findById(id);\n if (!view) throw new NotFoundException('Table view not found.');\n if (view.userId !== userId) throw new BadRequestException('You do not have permission to rename this view.');\n\n // Check for duplicate name within the same user+table\n const existing = await this.dataTableViewsRepository.findOne({\n userId,\n tableSlug: view.tableSlug,\n name,\n isShared: false,\n });\n if (existing && existing.id !== id) {\n throw new ConflictException({\n label: 'Name Already Taken',\n detail: 'A view with this name already exists for this table.',\n errors: [{ field: 'name', message: 'Name already taken' }],\n });\n }\n\n const updated = await this.dataTableViewsRepository.update(id, { name });\n this.logger.log(`Renamed view ${id} to \"${name}\" for user: ${userId}`);\n // Rename only affects personal views (shared views are owned by a user too, but visible to all)\n await this.invalidateViewsCache(userId, view.tableSlug, !view.isShared, view.isShared);\n return DataTableViewDto.from(updated, userId);\n }\n\n // Deletes a named view and invalidates the relevant cache pool\n async deleteView(userId: string, id: string): Promise<DataTableViewDto> {\n const view = await this.dataTableViewsRepository.findById(id);\n if (!view) throw new NotFoundException('Table view not found.');\n if (view.userId !== userId) throw new BadRequestException('You do not have permission to delete this view.');\n\n await this.dataTableViewsRepository.delete(id);\n this.logger.log(`Deleted view ${id} for user: ${userId}`);\n await this.invalidateViewsCache(userId, view.tableSlug, !view.isShared, view.isShared);\n return DataTableViewDto.from(view, userId);\n }\n}\n","import { Inject, Injectable } from '@nestjs/common';\nimport { and, eq } from 'drizzle-orm';\nimport type { PgTable } from 'drizzle-orm/pg-core';\nimport { PrimaryBaseRepository } from '../../../database/repositories/primary-base.repository';\nimport { PrimaryDatabaseService } from '../../../database/services/primary-database.service';\nimport { DATA_TABLE_VIEWS_TABLE } from '../../data-table.constants';\nimport type { DataTableViewRecord, NewDataTableViewRecord } from '../../schema/data-table-views.table';\n\nconst NAMED_VIEWS_LIMIT = 100;\n\n@Injectable()\nexport class DataTableViewsRepository extends PrimaryBaseRepository<\n PgTable,\n NewDataTableViewRecord,\n DataTableViewRecord\n> {\n constructor(database: PrimaryDatabaseService, @Inject(DATA_TABLE_VIEWS_TABLE) table: PgTable) {\n super(database, table);\n }\n\n // Returns personal (non-shared) named views owned by the user for a given table\n async findPersonalViewsBySlug(userId: string, tableSlug: string): Promise<DataTableViewRecord[]> {\n // biome-ignore lint/suspicious/noExplicitAny: table columns are typed at runtime via the injected schema-qualified table\n const t = this.table as any;\n return this.db\n .select()\n .from(this.table)\n .where(and(eq(t.tableSlug, tableSlug), eq(t.userId, userId), eq(t.isShared, false)))\n .orderBy(t.createdAt)\n .limit(NAMED_VIEWS_LIMIT) as unknown as Promise<DataTableViewRecord[]>;\n }\n\n // Returns all shared named views for a given table — visible to all users\n async findSharedViewsBySlug(tableSlug: string): Promise<DataTableViewRecord[]> {\n // biome-ignore lint/suspicious/noExplicitAny: table columns are typed at runtime via the injected schema-qualified table\n const t = this.table as any;\n return this.db\n .select()\n .from(this.table)\n .where(and(eq(t.tableSlug, tableSlug), eq(t.isShared, true)))\n .orderBy(t.createdAt)\n .limit(NAMED_VIEWS_LIMIT) as unknown as Promise<DataTableViewRecord[]>;\n }\n}\n","import { Logger } from '@nestjs/common';\nimport {\n and,\n asc,\n desc,\n eq,\n getTableName,\n type InferInsertModel,\n type InferSelectModel,\n ilike,\n inArray,\n notInArray,\n type SQL,\n sql,\n} from 'drizzle-orm';\nimport type { PgColumn, PgSequence, PgTable, SelectedFields } from 'drizzle-orm/pg-core';\nimport type { AnyPgAsyncSelect } from 'drizzle-orm/pg-core/async';\nimport type { TypedDrizzleClient } from '../schema.registry';\nimport { PrimaryDatabaseService } from '../services/primary-database.service';\nimport type { FindForSelectConfig, SelectQueryResult } from '../types';\n\n// Converts snake_case string to camelCase\nfunction snakeToCamel(str: string): string {\n return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());\n}\n\ntype RelationsWhereFilter = Record<string, unknown>;\n\ninterface TypedRelationalQueryBuilder<TSelect> {\n findFirst(config?: {\n where?: RelationsWhereFilter;\n with?: Record<string, unknown>;\n columns?: Record<string, boolean>;\n }): Promise<TSelect | undefined>;\n\n findMany(config?: {\n where?: RelationsWhereFilter;\n orderBy?: Record<string, 'asc' | 'desc'>;\n limit?: number;\n offset?: number;\n with?: Record<string, unknown>;\n columns?: Record<string, boolean>;\n }): Promise<TSelect[]>;\n}\n\nexport abstract class PrimaryBaseRepository<\n TTable extends PgTable,\n TInsert = InferInsertModel<TTable>,\n TSelect = InferSelectModel<TTable>,\n> {\n protected readonly logger: Logger;\n protected readonly sequence?: PgSequence;\n\n private readonly tableName: string;\n\n protected get db(): TypedDrizzleClient {\n return this.database.drizzleClient;\n }\n\n protected get model(): TypedRelationalQueryBuilder<TSelect> {\n const query = this.database.drizzleClient.query;\n const queryKeys = Object.keys(query || {});\n this.logger.debug(`Looking for '${this.tableName}' in query keys: [${queryKeys.join(', ')}]`);\n\n const model = query[this.tableName as keyof TypedDrizzleClient['query']];\n if (!model) {\n this.logger.error(`Table '${this.tableName}' not found in query object. Available: [${queryKeys.join(', ')}]`);\n }\n\n return model as unknown as TypedRelationalQueryBuilder<TSelect>;\n }\n\n constructor(\n protected readonly database: PrimaryDatabaseService,\n protected readonly table: TTable,\n options?: {\n sequence?: PgSequence;\n },\n ) {\n // Convert snake_case table name to camelCase to match Drizzle query object keys\n // Example: 'email_verifications' -> 'emailVerifications'\n const dbTableName = getTableName(table);\n this.tableName = snakeToCamel(dbTableName);\n this.sequence = options?.sequence;\n this.logger = new Logger(this.constructor.name);\n this.logger.debug(`Initialized ${this.constructor.name}`);\n this.logger.debug(`Table name: '${dbTableName}' -> query key: '${this.tableName}'`);\n }\n\n // Returns next value from configured sequence, or an explicitly passed sequence\n protected async nextSequenceValue(sequence?: PgSequence): Promise<number> {\n const resolvedSequence = sequence ?? this.sequence;\n if (!resolvedSequence) {\n throw new Error(`${this.constructor.name}: sequence is required for nextSequenceValue`);\n }\n\n const sequenceName = resolvedSequence.schema\n ? `${resolvedSequence.schema}.${resolvedSequence.seqName}`\n : resolvedSequence.seqName;\n\n const result = await this.db.execute<{ sequence_value: number }>(\n sql`select nextval(${sequenceName}::regclass) as sequence_value`,\n );\n const rows = (result as { rows?: Array<{ sequence_value: number | string }> }).rows ?? [];\n return Number(rows[0]?.sequence_value ?? 1);\n }\n\n // Creates a new record and returns it\n async create(data: TInsert, tx?: TypedDrizzleClient): Promise<TSelect> {\n this.logger.log('Creating record');\n const db = tx ?? this.db;\n const results = (await db\n .insert(this.table as PgTable)\n .values(data as Record<string, unknown>)\n .returning()) as TSelect[];\n const record = results[0];\n if (!record) throw new Error(`${this.tableName}: database operation returned no record`);\n return record;\n }\n\n // Finds a single record by primary key ID\n async findById(id: string): Promise<TSelect | undefined> {\n this.logger.debug(`Finding record by ID: ${id}`);\n return this.model.findFirst({\n where: { id },\n });\n }\n\n // Finds a single record matching the given where filter\n async findOne(where: RelationsWhereFilter): Promise<TSelect | undefined> {\n this.logger.debug('Finding record with custom query');\n return this.model.findFirst({ where });\n }\n\n // Finds multiple records with optional filtering, ordering, and pagination\n async findMany(options?: {\n where?: RelationsWhereFilter;\n orderBy?: Record<string, 'asc' | 'desc'>;\n limit?: number;\n offset?: number;\n }): Promise<TSelect[]> {\n this.logger.debug('Finding multiple records');\n return this.model.findMany(options);\n }\n\n // Builds a select query with optional custom fields, joins, filter, grouping, ordering, and pagination\n private buildSelectQuery(options?: {\n select?: Record<string, unknown>;\n where?: SQL;\n orderBy?: SQL[];\n limit?: number;\n offset?: number;\n leftJoin?: { table: PgTable; on: SQL | undefined };\n leftJoins?: { table: PgTable; on: SQL | undefined }[];\n groupBy?: (PgColumn | SQL)[];\n }) {\n // Drizzle's dynamic query builder methods (leftJoin, where, groupBy, etc.) return union types\n // that include Omit<...> variants, making precise type annotations impractical for mutable query\n // building. We type the variable as the concrete async select and cast each reassignment.\n let query = (\n options?.select\n ? this.db.select(options.select as SelectedFields).from(this.table as PgTable)\n : this.db.select().from(this.table as PgTable)\n ).$dynamic() as AnyPgAsyncSelect;\n\n if (options?.leftJoin) {\n query = query.leftJoin(options.leftJoin.table, options.leftJoin.on) as AnyPgAsyncSelect;\n }\n if (options?.leftJoins) {\n for (const join of options.leftJoins) {\n query = query.leftJoin(join.table, join.on) as AnyPgAsyncSelect;\n }\n }\n if (options?.where) {\n query = query.where(options.where) as AnyPgAsyncSelect;\n }\n if (options?.groupBy?.length) {\n query = query.groupBy(...options.groupBy) as AnyPgAsyncSelect;\n }\n if (options?.orderBy?.length) {\n query = query.orderBy(...options.orderBy) as AnyPgAsyncSelect;\n }\n if (options?.limit) {\n query = query.limit(options.limit) as AnyPgAsyncSelect;\n }\n if (options?.offset) {\n query = query.offset(options.offset) as AnyPgAsyncSelect;\n }\n return query;\n }\n\n // Returns paginated result and total count, with optional custom select, LEFT JOINs, GROUP BY, and ordering\n async findAllAndCount<TResult = TSelect>(options?: {\n select?: Record<string, unknown>;\n where?: SQL;\n orderBy?: SQL[];\n limit?: number;\n offset?: number;\n leftJoin?: { table: PgTable; on: SQL | undefined };\n leftJoins?: { table: PgTable; on: SQL | undefined }[];\n groupBy?: (PgColumn | SQL)[];\n }): Promise<{ result: TResult[]; count: number }> {\n let countResultPromise: Promise<{ count: number }[]>;\n\n if (options?.groupBy?.length) {\n // When groupBy is active, wrap the grouped query in a subquery so we count\n // distinct groups rather than raw join rows.\n let subq = this.db\n .select({ _: sql`1` })\n .from(this.table as PgTable)\n .$dynamic();\n if (options.leftJoin) {\n subq = subq.leftJoin(options.leftJoin.table, options.leftJoin.on) as typeof subq;\n }\n if (options.leftJoins) {\n for (const join of options.leftJoins) {\n subq = subq.leftJoin(join.table, join.on) as typeof subq;\n }\n }\n if (options.where) {\n subq = subq.where(options.where) as typeof subq;\n }\n subq = subq.groupBy(...options.groupBy) as typeof subq;\n\n const named = subq.as('_count_subq');\n countResultPromise = this.db\n .select({ count: sql<number>`count(*)::int` })\n .from(named) as unknown as Promise<{ count: number }[]>;\n } else {\n // Count query mirrors the same JOINs so WHERE clauses on joined columns are valid\n let countQuery = this.db\n .select({ count: sql<number>`count(*)::int` })\n .from(this.table as PgTable)\n .$dynamic();\n if (options?.leftJoin) {\n countQuery = countQuery.leftJoin(options.leftJoin.table, options.leftJoin.on) as typeof countQuery;\n }\n if (options?.leftJoins) {\n for (const join of options.leftJoins) {\n countQuery = countQuery.leftJoin(join.table, join.on) as typeof countQuery;\n }\n }\n if (options?.where) {\n countQuery = countQuery.where(options.where) as typeof countQuery;\n }\n countResultPromise = countQuery as unknown as Promise<{ count: number }[]>;\n }\n\n const [countResult, result] = await Promise.all([\n countResultPromise,\n this.buildSelectQuery(options) as unknown as Promise<TResult[]>,\n ]);\n return { result, count: (countResult[0] as { count: number }).count };\n }\n\n // Updates a record by ID and returns the updated record\n async update(id: string, data: Partial<TInsert>, tx?: TypedDrizzleClient): Promise<TSelect> {\n this.logger.log(`Updating record with ID: ${id}`);\n const db = tx ?? this.db;\n const idColumn = (this.table as unknown as Record<string, PgColumn>).id;\n if (!idColumn) throw new Error(`Table '${this.tableName}' has no 'id' column`);\n const results = (await db\n .update(this.table as PgTable)\n .set(data as Record<string, unknown>)\n .where(eq(idColumn, id))\n .returning()) as TSelect[];\n const record = results[0];\n if (!record) throw new Error(`${this.tableName}: database operation returned no record`);\n return record;\n }\n\n // Updates all records matching the SQL condition and returns the affected count\n async updateMany(where: SQL, data: Partial<TInsert>, tx?: TypedDrizzleClient): Promise<{ count: number }> {\n this.logger.log('Updating multiple records');\n const db = tx ?? this.db;\n const result = await db\n .update(this.table as PgTable)\n .set(data as Record<string, unknown>)\n .where(where);\n return { count: result.rowCount ?? 0 };\n }\n\n // Deletes a record by ID and returns the deleted record\n async delete(id: string, tx?: TypedDrizzleClient): Promise<TSelect> {\n this.logger.log(`Deleting record with ID: ${id}`);\n const db = tx ?? this.db;\n const idColumn = (this.table as unknown as Record<string, PgColumn>).id;\n if (!idColumn) throw new Error(`Table '${this.tableName}' has no 'id' column`);\n const results = (await db\n .delete(this.table as PgTable)\n .where(eq(idColumn, id))\n .returning()) as TSelect[];\n const record = results[0];\n if (!record) throw new Error(`${this.tableName}: database operation returned no record`);\n return record;\n }\n\n // Deletes all records matching the SQL condition and returns the affected count\n async deleteMany(where: SQL, tx?: TypedDrizzleClient): Promise<{ count: number }> {\n this.logger.log('Deleting multiple records');\n const db = tx ?? this.db;\n const result = await db.delete(this.table as PgTable).where(where);\n return { count: result.rowCount ?? 0 };\n }\n\n // Counts records matching the optional SQL condition\n async count(where?: SQL): Promise<number> {\n this.logger.debug('Counting records');\n\n let query = this.db\n .select({ count: sql<number>`count(*)::int` })\n .from(this.table as PgTable)\n .$dynamic();\n\n if (where) {\n query = query.where(where);\n }\n\n const results = await query;\n return (results[0] as { count: number }).count;\n }\n\n // Returns true if at least one record matches the SQL condition\n async exists(where: SQL): Promise<boolean> {\n const count = await this.count(where);\n return count > 0;\n }\n\n // Executes the callback within a database transaction. Routes through PrimaryDatabaseService so\n // the RLS context from AsyncLocalStorage is applied once at BEGIN and queries inside `callback`\n // (whether they use the passed tx arg or `this.db` via ALS) all participate in the same txn.\n async transaction<T>(callback: (tx: TypedDrizzleClient) => Promise<T>): Promise<T> {\n return this.database.runInTransaction(async () => callback(this.database.drizzleClient));\n }\n\n // Finds records formatted as select dropdown options with optional search, pagination, and grouping\n async findForSelect(config: FindForSelectConfig): Promise<SelectQueryResult> {\n this.logger.debug('Finding records for select dropdown');\n\n // Use selectDistinct when deduplication is needed (e.g., distinct app codes across versions)\n const selectFn = config.distinct ? this.db.selectDistinct.bind(this.db) : this.db.select.bind(this.db);\n\n interface SelectRow {\n value: string | number | boolean;\n label: string;\n description?: string;\n groupId?: string | number;\n }\n interface SelectRowWithCount extends SelectRow {\n totalCount: number;\n }\n\n // Parse values from CSV string or use array as-is\n const parsedValues =\n typeof config.values === 'string'\n ? config.values\n .split(',')\n .map((v) => v.trim())\n .filter(Boolean)\n : config.values;\n\n // Parse excludeIds from CSV string or use array as-is\n const parsedExcludeIds =\n typeof config.excludeIds === 'string'\n ? config.excludeIds\n .split(',')\n .map((v) => v.trim())\n .filter(Boolean)\n : (config.excludeIds ?? []);\n\n const tableColumns = this.table as unknown as Record<string, PgColumn>;\n\n const joinTables = config.joins?.map((join) => join.table as unknown as Record<string, PgColumn>) ?? [];\n const resolveColumn = (key: string): PgColumn | undefined => {\n if (tableColumns[key]) return tableColumns[key];\n for (const joinColumns of joinTables) {\n if (joinColumns[key]) return joinColumns[key];\n }\n return undefined;\n };\n\n const valueCol = resolveColumn(config.value);\n if (!valueCol) throw new Error(`Column '${config.value}' not found in table '${this.tableName}' or its joins`);\n\n const labelCol = resolveColumn(config.label);\n if (!labelCol) throw new Error(`Column '${config.label}' not found in table '${this.tableName}' or its joins`);\n\n const descriptionCol = config.description ? resolveColumn(config.description) : undefined;\n\n const parseKeys = (input?: string | string[]): string[] => {\n if (!input) return [];\n const values = Array.isArray(input) ? input : input.split(',');\n return values.map((v) => v.trim()).filter(Boolean);\n };\n const additionalKeys = parseKeys(config.additionalKeys);\n const additionalEntries: { key: string; expr: PgColumn | SQL }[] = [\n ...additionalKeys\n .map((key) => ({ key, expr: resolveColumn(key) as PgColumn | undefined }))\n .filter((e): e is { key: string; expr: PgColumn } => Boolean(e.expr)),\n ...Object.entries(config.additionalExpressions ?? {}).map(([key, expr]) => ({ key, expr })),\n ];\n const additionalAlias = (key: string) => `__additional_${key}`;\n\n // When values are provided, fetch those specific options by value (skip search/pagination)\n if (parsedValues && parsedValues.length > 0) {\n const selectCols: Record<string, PgColumn | SQL> = { value: valueCol, label: labelCol };\n if (descriptionCol) selectCols.description = descriptionCol;\n if (config.groupIdKey) {\n const groupIdCol = resolveColumn(config.groupIdKey);\n if (groupIdCol) selectCols.groupId = groupIdCol;\n }\n for (const entry of additionalEntries) {\n selectCols[additionalAlias(entry.key)] = entry.expr;\n }\n\n let valuesQuery = selectFn(selectCols as SelectedFields)\n .from(this.table as PgTable)\n .$dynamic();\n\n if (config.joins) {\n for (const join of config.joins) {\n if (join.type === 'inner') {\n valuesQuery = valuesQuery.innerJoin(join.table, join.on);\n } else {\n valuesQuery = valuesQuery.leftJoin(join.table, join.on);\n }\n }\n }\n\n const rows = await valuesQuery.where(inArray(valueCol, parsedValues));\n\n return {\n options: (rows as unknown as SelectRow[]).map((row) => ({\n value: row.value,\n label: String(row.label),\n ...(descriptionCol && row.description != null ? { description: String(row.description) } : {}),\n ...(config.groupIdKey && row.groupId != null ? { groupId: row.groupId } : {}),\n ...(additionalEntries.length > 0\n ? {\n additionals: additionalEntries.reduce<Record<string, string | number | boolean | null>>(\n (acc, entry) => {\n const value = (row as unknown as Record<string, unknown>)[additionalAlias(entry.key)];\n if (value !== undefined) {\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean' ||\n value === null\n ) {\n acc[entry.key] = value;\n } else {\n acc[entry.key] = String(value);\n }\n }\n return acc;\n },\n {},\n ),\n }\n : {}),\n })),\n hasMore: false,\n ...(config.groups ? { groups: config.groups } : {}),\n };\n }\n\n // Use SQL builder for count(*) over() window function support\n const selectFields: Record<string, PgColumn | SQL> = {\n value: valueCol,\n label: labelCol,\n totalCount: sql<number>`count(*) over()`.mapWith(Number),\n };\n if (descriptionCol) selectFields.description = descriptionCol;\n if (config.groupIdKey) {\n const groupIdCol = resolveColumn(config.groupIdKey);\n if (groupIdCol) selectFields.groupId = groupIdCol;\n }\n for (const entry of additionalEntries) {\n selectFields[additionalAlias(entry.key)] = entry.expr;\n }\n\n const conditions: SQL[] = [];\n if (config.search) {\n conditions.push(ilike(labelCol, `%${config.search}%`));\n }\n if (parsedExcludeIds.length > 0) {\n conditions.push(notInArray(valueCol, parsedExcludeIds));\n }\n if (config.where) {\n for (const [field, val] of Object.entries(config.where)) {\n const column = tableColumns[field];\n if (column) {\n conditions.push(eq(column, val));\n }\n }\n }\n // Append raw SQL conditions (e.g. for joined table columns)\n if (config.conditions) {\n conditions.push(...config.conditions);\n }\n\n const orderByKey = config.orderByKey || (config.orderBy ? Object.keys(config.orderBy)[0] : undefined);\n const orderDirection = config.orderDirection || (config.orderBy ? Object.values(config.orderBy)[0] : undefined);\n const orderByCol = orderByKey ? (tableColumns[orderByKey] ?? labelCol) : labelCol;\n const limit = Number(config.limit) || 20;\n const offset = Number(config.offset) || 0;\n\n let query = selectFn(selectFields as SelectedFields)\n .from(this.table as PgTable)\n .$dynamic();\n\n // Apply optional JOINs\n if (config.joins) {\n for (const join of config.joins) {\n if (join.type === 'inner') {\n query = query.innerJoin(join.table, join.on);\n } else {\n query = query.leftJoin(join.table, join.on);\n }\n }\n }\n\n if (conditions.length > 0) {\n query = query.where(conditions.length === 1 ? conditions[0] : (and(...conditions) as SQL));\n }\n\n const orderClauses: SQL[] = [];\n if (config.groupIdKey) {\n const groupIdCol = resolveColumn(config.groupIdKey);\n if (groupIdCol) orderClauses.push(asc(groupIdCol));\n }\n orderClauses.push(orderDirection === 'desc' ? desc(orderByCol) : asc(orderByCol));\n\n query = query\n .orderBy(...orderClauses)\n .limit(limit)\n .offset(offset);\n\n const rows = await query;\n\n const totalCount = rows.length > 0 ? (rows[0] as unknown as SelectRowWithCount).totalCount : 0;\n\n const options = (rows as unknown as SelectRow[]).map((row) => ({\n value: row.value,\n label: String(row.label),\n ...(descriptionCol && row.description != null ? { description: String(row.description) } : {}),\n ...(config.groupIdKey && row.groupId != null ? { groupId: row.groupId } : {}),\n ...(additionalEntries.length > 0\n ? {\n additionals: additionalEntries.reduce<Record<string, string | number | boolean | null>>((acc, entry) => {\n const value = (row as unknown as Record<string, unknown>)[additionalAlias(entry.key)];\n if (value !== undefined) {\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean' ||\n value === null\n ) {\n acc[entry.key] = value;\n } else {\n acc[entry.key] = String(value);\n }\n }\n return acc;\n }, {}),\n }\n : {}),\n }));\n\n // Auto-resolve groups from groupTable when provided\n let resolvedGroups = config.groups;\n\n if (config.groupTable && config.groupIdKey) {\n const groupTableColumns = config.groupTable as unknown as Record<string, PgColumn>;\n const groupIdKey = config.groupTableIdKey ?? 'id';\n const groupNameKey = config.groupLabelKey ?? 'name';\n const groupIdCol = groupTableColumns[groupIdKey];\n if (!groupIdCol) throw new Error(`Column '${groupIdKey}' not found in group table`);\n const groupNameCol = groupTableColumns[groupNameKey];\n if (!groupNameCol) throw new Error(`Column '${groupNameKey}' not found in group table`);\n\n const groupRows = await this.db\n .select({ id: groupIdCol, name: groupNameCol } as SelectedFields)\n .from(config.groupTable)\n .orderBy(asc(groupNameCol));\n\n resolvedGroups = (groupRows as unknown as Array<{ id: string | number; name: string }>).map((r) => ({\n id: r.id,\n name: String(r.name),\n }));\n }\n\n return {\n options,\n hasMore: offset + limit < totalCount,\n totalCount,\n ...(resolvedGroups ? { groups: resolvedGroups } : {}),\n };\n }\n}\n","import { AsyncLocalStorage } from 'node:async_hooks';\nimport {\n Inject,\n Injectable,\n InternalServerErrorException,\n Logger,\n type OnModuleDestroy,\n type OnModuleInit,\n} from '@nestjs/common';\nimport { drizzle } from 'drizzle-orm/node-postgres';\nimport type { PoolClient } from 'pg';\nimport { DATABASE_MODULE_OPTIONS } from '../constants';\nimport type { DatabaseModuleOptions } from '../interfaces';\nimport type { TypedDrizzleClient } from '../schema.registry';\nimport { RlsAwarePool } from './rls-aware-pool';\n\n@Injectable()\nexport class PrimaryDatabaseService implements OnModuleInit, OnModuleDestroy {\n private readonly logger = new Logger(PrimaryDatabaseService.name);\n\n private pool: RlsAwarePool | null = null;\n private db: TypedDrizzleClient | null = null;\n\n // Per-request RLS context values (e.g. { orgId, buId, ... }). Read by RlsAwarePool on each\n // auto-wrapped query and by runInTransaction at BEGIN to apply SET LOCAL once for the txn body.\n private readonly rlsAls = new AsyncLocalStorage<unknown>();\n\n // Active Drizzle transaction client when inside runInTransaction. Repository queries via\n // drizzleClient resolve to this so they participate in the transaction instead of getting\n // their own mini-transaction via the pool wrapper.\n private readonly txAls = new AsyncLocalStorage<TypedDrizzleClient>();\n\n constructor(\n @Inject(DATABASE_MODULE_OPTIONS)\n private readonly options: DatabaseModuleOptions,\n ) {}\n\n async onModuleInit() {\n if (this.options.primaryDb) {\n await this.initializeDrizzleClient();\n }\n }\n\n // Initializes connection to primary database using Drizzle\n private async initializeDrizzleClient(): Promise<void> {\n try {\n const { host, port = 5432, username, password, database, schema, sslMode = 'require' } = this.options.primaryDb;\n\n this.pool = new RlsAwarePool({\n host,\n port,\n user: username,\n password,\n database,\n max: this.options.maxConnections || 10,\n ssl: sslMode === 'disable' ? false : { rejectUnauthorized: sslMode !== 'no-verify' },\n ...(schema && { options: `-csearch_path=${schema}` }),\n rlsAls: this.rlsAls,\n txAls: this.txAls,\n applyRlsContext: this.options.applyRlsContext,\n });\n\n this.logger.debug(\n `Relations keys passed to drizzle: [${Object.keys(this.options.drizzleRelations || {}).join(', ')}]`,\n );\n this.db = drizzle({\n client: this.pool,\n relations: this.options.drizzleRelations,\n }) as unknown as TypedDrizzleClient;\n\n // Health check runs before any ALS scope is set → bypasses auto-wrap naturally.\n await this.pool.query('SELECT 1');\n this.logger.log(`Connected to primary database (schema: ${schema ?? 'public'})`);\n } catch (error) {\n this.logger.error('Failed to connect to primary database', error);\n throw new InternalServerErrorException('Failed to initialize database connection');\n }\n }\n\n // Returns the active Drizzle client. When inside runInTransaction, returns the pinned tx so\n // repository queries participate in the transaction. Otherwise returns the pool-backed Drizzle\n // whose individual queries auto-wrap in mini-transactions via RlsAwarePool.\n get drizzleClient(): TypedDrizzleClient {\n const pinned = this.txAls.getStore();\n if (pinned) return pinned;\n if (!this.db) {\n throw new Error('Primary database client not initialized');\n }\n return this.db;\n }\n\n // Stashes per-request RLS context (any shape) in AsyncLocalStorage. Each downstream query via\n // RlsAwarePool reads it and applies SET LOCAL on the connection inside a mini-transaction.\n // No DB connection is held by this scope itself — only during each individual query.\n runWithRlsContext<T>(rls: unknown, fn: () => Promise<T>): Promise<T> {\n return this.rlsAls.run(rls, fn);\n }\n\n // Opens a transaction and pins all queries inside `fn` to one connection. Applies the RLS\n // context once at BEGIN via SET LOCAL so it persists for the entire transaction body.\n // Nested calls reuse the pinned tx and emit a SAVEPOINT (via Drizzle's tx.transaction).\n async runInTransaction<T>(fn: () => Promise<T>): Promise<T> {\n const pinned = this.txAls.getStore();\n if (pinned) {\n return pinned.transaction(async (sp) => this.txAls.run(sp as TypedDrizzleClient, fn));\n }\n\n if (!this.db) {\n throw new Error('Primary database client not initialized');\n }\n const rls = this.rlsAls.getStore();\n const applyRls = this.options.applyRlsContext;\n\n return this.db.transaction(async (tx) => {\n if (rls !== undefined && applyRls) {\n // Drizzle's NodePgSession stores the checked-out PoolClient at session.client.\n // We need the raw client to issue SET LOCAL with parameter binding via client.query(text, params).\n // biome-ignore lint/suspicious/noExplicitAny: drizzle internal session shape, stable across recent versions\n const sessionClient = (tx as any)?.session?.client as PoolClient | undefined;\n if (sessionClient) {\n await applyRls(sessionClient, rls);\n }\n }\n return this.txAls.run(tx as TypedDrizzleClient, fn);\n });\n }\n\n // Deprecated: prefer runInTransaction. Retained so existing callers keep working until migrated.\n async runWithPinnedConnection<T>(fn: () => Promise<T>): Promise<T> {\n return this.runInTransaction(fn);\n }\n\n async onModuleDestroy() {\n if (this.pool) {\n await this.pool.end();\n this.logger.log('Disconnected from primary database');\n }\n }\n}\n","export const DATABASE_MODULE_OPTIONS = Symbol('DATABASE_MODULE_OPTIONS');\n","import type { AsyncLocalStorage } from 'node:async_hooks';\nimport { Pool, type PoolClient, type PoolConfig, type QueryResult, type QueryResultRow, type Submittable } from 'pg';\n\nexport type ApplyRlsContextFn = (client: PoolClient, ctx: unknown) => Promise<void>;\n\nexport interface RlsAwarePoolOptions extends PoolConfig {\n rlsAls: AsyncLocalStorage<unknown>;\n txAls: AsyncLocalStorage<unknown>;\n applyRlsContext?: ApplyRlsContextFn;\n}\n\n// pg.Pool subclass that auto-wraps each promise-form query in BEGIN; SET LOCAL …; <query>; COMMIT;\n// when a request-scoped RLS context is present in `rlsAls` and no explicit transaction is active in `txAls`.\n// Subclassing (not composition) is required because drizzle-orm's transaction path does\n// `this.client instanceof Pool` to decide whether to checkout a PoolClient.\nexport class RlsAwarePool extends Pool {\n private readonly rlsAls: AsyncLocalStorage<unknown>;\n private readonly txAls: AsyncLocalStorage<unknown>;\n private readonly applyRlsContext?: ApplyRlsContextFn;\n\n constructor(options: RlsAwarePoolOptions) {\n const { rlsAls, txAls, applyRlsContext, ...poolConfig } = options;\n super(poolConfig);\n this.rlsAls = rlsAls;\n this.txAls = txAls;\n this.applyRlsContext = applyRlsContext;\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: matches pg.Pool.query overload surface\n override query(textOrConfig: any, values?: any, cb?: any): any {\n // Bypass: legacy callback-only form (text is actually a callback)\n if (typeof textOrConfig === 'function') {\n return super.query(textOrConfig);\n }\n // Bypass: Submittable (pg-cursor, pg-query-stream) — must reuse one Client end-to-end\n if (textOrConfig && typeof (textOrConfig as Submittable).submit === 'function') {\n return super.query(textOrConfig, values, cb);\n }\n // Bypass: callback variants — preserve raw signature\n if (typeof values === 'function' || typeof cb === 'function') {\n return super.query(textOrConfig, values, cb);\n }\n\n const rls = this.rlsAls.getStore();\n // Bypass: no RLS context (init queries, health checks) OR already inside an explicit transaction\n if (rls === undefined || this.txAls.getStore() !== undefined || !this.applyRlsContext) {\n return super.query(textOrConfig, values);\n }\n\n return this.runWrapped(textOrConfig, values, rls);\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: dispatched from query() overload\n private async runWrapped(textOrConfig: any, values: any, rls: unknown): Promise<QueryResult<QueryResultRow>> {\n const client = await super.connect();\n try {\n await client.query('BEGIN');\n // applyRlsContext is non-null in this branch (checked in query())\n await (this.applyRlsContext as ApplyRlsContextFn)(client, rls);\n const result = await client.query(textOrConfig, values);\n await client.query('COMMIT');\n client.release();\n return result;\n } catch (err) {\n try {\n await client.query('ROLLBACK');\n } catch {\n // connection likely already dead — fall through to release with original error\n }\n // Passing an Error to release() tells pg-pool to evict the client instead of returning it to the pool.\n client.release(err as Error);\n throw err;\n }\n }\n}\n","// Re-export all of drizzle-orm/pg-core\nexport * from 'drizzle-orm/pg-core';\n","import type { TableViewState } from '../../database/filter/filter.types';\nimport { boolean, index, jsonb, timestamp, uniqueIndex, uuid, varchar } from '../../drizzle-pg-core';\n\n// Returns a fresh set of column builder instances — call once per table declaration\nexport function dataTableViewsColumns() {\n return {\n id: uuid('id').primaryKey().defaultRandom(),\n userId: uuid('user_id').notNull(),\n tableSlug: varchar('table_slug', { length: 200 }).notNull(),\n name: varchar('name', { length: 100 }).notNull(),\n state: jsonb('state').notNull().$type<TableViewState>(),\n isShared: boolean('is_shared').notNull().default(false),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n updatedAt: timestamp('updated_at', { withTimezone: true }).$onUpdate(() => new Date()),\n };\n}\n\n// Index definitions — reusable callback, works with any table that has the same column names\n// biome-ignore lint/suspicious/noExplicitAny: receives Drizzle-bound columns, not raw builders\nexport function dataTableViewsIndexes(table: any) {\n return [\n index('table_views_user_table_idx').on(table.userId, table.tableSlug),\n index('table_views_shared_slug_idx').on(table.tableSlug, table.isShared),\n uniqueIndex('table_views_user_table_name_shared_unique').on(\n table.userId,\n table.tableSlug,\n table.name,\n table.isShared,\n ),\n ];\n}\n\n// Shape of a persisted table view record — used across service, repository, and DTO layers\nexport interface DataTableViewRecord {\n id: string;\n userId: string;\n tableSlug: string;\n name: string;\n state: TableViewState;\n isShared: boolean;\n createdAt: Date;\n updatedAt: Date | null | undefined;\n}\n\n// Shape of a new table view record for insertion — server-generated fields omitted\nexport interface NewDataTableViewRecord {\n userId: string;\n tableSlug: string;\n name: string;\n state: TableViewState;\n isShared?: boolean;\n}\n","import { type DynamicModule, Global, type InjectionToken, Module, type Provider } from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { DATABASE_MODULE_OPTIONS } from './constants';\nimport type { DatabaseModuleOptions } from './interfaces';\nimport { PrimaryDatabaseService } from './services/primary-database.service';\n\n@Global()\n@Module({})\nexport class DatabaseModule {\n // Configures the database module with a single primary connection\n static forServer<T extends unknown[] = unknown[]>(options: {\n useFactory: (...args: [...T]) => Promise<DatabaseModuleOptions> | DatabaseModuleOptions;\n inject?: InjectionToken[];\n }): DynamicModule {\n const asyncProvider: Provider = {\n provide: DATABASE_MODULE_OPTIONS,\n useFactory: options.useFactory,\n inject: options.inject || [],\n };\n\n return {\n module: DatabaseModule,\n providers: [{ provide: Reflector, useClass: Reflector }, asyncProvider, PrimaryDatabaseService],\n exports: [PrimaryDatabaseService, asyncProvider],\n };\n }\n}\n","import { ApiProperty } from '@nestjs/swagger';\n\n// Generic wrapper for create/assign responses — includes success metadata alongside entity data\nexport class CreateResponseDto<T> {\n @ApiProperty({ example: true })\n success: boolean;\n\n @ApiProperty({ example: 'Resource created successfully' })\n message: string;\n\n @ApiProperty()\n data: T;\n}\n","import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';\n\nexport class ValidatedRowDto {\n @ApiProperty({ example: 1 })\n index: number;\n\n @ApiProperty({ example: { code: 'products', name: 'Products' } })\n data: Record<string, string>;\n\n @ApiProperty({ example: true })\n valid: boolean;\n\n @ApiProperty({ example: ['Code already exists'] })\n errors: string[];\n}\n\nexport class ImportSummaryDto {\n @ApiProperty({ example: 10 })\n total: number;\n\n @ApiProperty({ example: 8 })\n valid: number;\n\n @ApiProperty({ example: 2 })\n invalid: number;\n}\n\nexport class ImportResponseDto {\n @ApiProperty({ example: true })\n success: boolean;\n\n @ApiProperty({ example: 'Import complete.' })\n message: string;\n\n @ApiPropertyOptional({ example: 3 })\n created?: number;\n\n @ApiPropertyOptional({ example: 2 })\n updated?: number;\n\n @ApiPropertyOptional({ example: 1 })\n skipped?: number;\n\n @ApiPropertyOptional({ type: [ValidatedRowDto] })\n rows?: ValidatedRowDto[];\n\n @ApiPropertyOptional({ type: ImportSummaryDto })\n summary?: ImportSummaryDto;\n}\n","import { ApiPropertyOptional } from '@nestjs/swagger';\nimport { Type } from 'class-transformer';\nimport { IsIn, IsInt, IsOptional, IsString, Min } from 'class-validator';\n\n// Standardized query params for select dropdown option endpoints\nexport class SelectOptionsQueryDto {\n @ApiPropertyOptional({ description: 'Search term to filter by label', example: 'united' })\n @IsOptional()\n @IsString()\n search?: string;\n\n @ApiPropertyOptional({ description: 'Maximum number of results', example: 20, default: 20 })\n @IsOptional()\n @Type(() => Number)\n @IsInt()\n @Min(1)\n limit?: number;\n\n @ApiPropertyOptional({ description: 'Number of results to skip', example: 0, default: 0 })\n @IsOptional()\n @Type(() => Number)\n @IsInt()\n @Min(0)\n offset?: number;\n\n @ApiPropertyOptional({ description: 'Comma-separated values to fetch specific options', example: '1,2,3' })\n @IsOptional()\n @IsString()\n values?: string;\n\n @ApiPropertyOptional({\n description: 'Comma-separated IDs to exclude from results (already selected)',\n example: '5,10',\n })\n @IsOptional()\n @IsString()\n excludeIds?: string;\n\n @ApiPropertyOptional({ description: 'Column name for option value', example: 'id', default: 'id' })\n @IsOptional()\n @IsString()\n valueKey?: string;\n\n @ApiPropertyOptional({ description: 'Column name for option label', example: 'name', default: 'name' })\n @IsOptional()\n @IsString()\n labelKey?: string;\n\n @ApiPropertyOptional({ description: 'Column name for option description', example: 'description' })\n @IsOptional()\n @IsString()\n descriptionKey?: string;\n\n @ApiPropertyOptional({\n description: 'Comma-separated column names to include in option.additionals',\n example: 'locationName,availableQuantity',\n })\n @IsOptional()\n @IsString()\n additionalKeys?: string;\n\n @ApiPropertyOptional({ description: 'Column name for group ID', example: 'regionId' })\n @IsOptional()\n @IsString()\n groupIdKey?: string;\n\n @ApiPropertyOptional({ description: 'Column name to sort options by', example: 'name', default: 'name' })\n @IsOptional()\n @IsString()\n orderByKey?: string;\n\n @ApiPropertyOptional({\n description: 'Sort direction for options',\n example: 'asc',\n default: 'asc',\n enum: ['asc', 'desc'],\n })\n @IsOptional()\n @IsString()\n @IsIn(['asc', 'desc'])\n orderDirection?: 'asc' | 'desc';\n}\n","import { ApiProperty } from '@nestjs/swagger';\nimport { IsBoolean, IsNotEmpty, IsString } from 'class-validator';\n\nexport class SuccessResponseDto {\n @ApiProperty({ example: true })\n @IsNotEmpty()\n @IsBoolean()\n success: boolean;\n\n @ApiProperty({ example: 'Operation completed successfully' })\n @IsNotEmpty()\n @IsString()\n message: string;\n}\n","import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';\nimport type { TableViewState } from '../filter/filter.types';\n\nexport class TableResponseDto<T> {\n @ApiProperty()\n result: T[];\n\n @ApiProperty()\n count: number;\n\n @ApiProperty()\n state: TableViewState;\n\n @ApiPropertyOptional({ nullable: true })\n activeViewId: string | null;\n}\n","import { and, asc, type Column, desc, eq, gt, gte, ilike, inArray, lt, lte, ne, notIlike, notInArray, or, type SQL } from 'drizzle-orm';\nimport type { FilterCondition, FilterOperator, SearchState, SortCondition } from './filter.types';\n\nexport type FieldDefinition =\n | { column: Column; type: 'string' | 'number' | 'boolean' }\n | { expression: (value: string | number, operator: FilterOperator) => SQL; type: 'string' | 'number' | 'boolean' };\nexport type FieldMap = Record<string, FieldDefinition>;\n\nexport class FilterProcessor {\n // Returns undefined if no conditions (Drizzle accepts undefined as \"no WHERE\")\n static buildWhere(filters: FilterCondition[] = [], fieldMap: FieldMap): SQL | undefined {\n const conditions = filters.flatMap((f) => {\n const def = fieldMap[f.field];\n if (!def) return []; // unknown field — skip (security whitelist)\n // Expression field — delegate SQL generation to the caller-supplied factory (operator passed for custom handling)\n if ('expression' in def) return Array.isArray(f.value) ? [] : [def.expression(f.value, f.operator)];\n const { column: col } = def;\n const val = f.value;\n switch (f.operator) {\n case 'equals':\n if (def.type === 'boolean') return [eq(col, val === 'true' || val === 1)];\n return [eq(col, val)];\n case 'notEquals':\n if (def.type === 'boolean') return [ne(col, val === 'true' || val === 1)];\n return [ne(col, val)];\n case 'contains':\n return [ilike(col, `%${val}%`)];\n case 'notContains':\n return [notIlike(col, `%${val}%`)];\n case 'gt':\n return [gt(col, val)];\n case 'gte':\n return [gte(col, val)];\n case 'lt':\n return [lt(col, val)];\n case 'lte':\n return [lte(col, val)];\n case 'isAnyOf':\n return [inArray(col, Array.isArray(val) ? val : [String(val)])];\n case 'isNotAnyOf':\n return [notInArray(col, Array.isArray(val) ? val : [String(val)])];\n default:\n return [];\n }\n });\n return conditions.length ? and(...conditions) : undefined;\n }\n\n // Builds a search WHERE — OR across all string fields when columnId is 'all', otherwise a single ilike\n static buildSearch(search: SearchState | null | undefined, fieldMap: FieldMap): SQL | undefined {\n if (!search?.value) return undefined;\n\n if (search.columnId === 'all') {\n const conditions = Object.values(fieldMap)\n .filter(\n (def): def is { column: Column; type: 'string' | 'number' | 'boolean' } =>\n 'column' in def && def.type === 'string',\n )\n .map((def) => ilike(def.column, `%${search.value}%`));\n return conditions.length ? or(...conditions) : undefined;\n }\n\n const def = fieldMap[search.columnId];\n if (!def || !('column' in def)) return undefined;\n return ilike(def.column, `%${search.value}%`);\n }\n\n // Maps each SortCondition to an asc/desc SQL expression\n static buildOrderBy(sort: SortCondition[] = [], fieldMap: FieldMap): SQL[] {\n return sort.flatMap((s) => {\n const def = fieldMap[s.field];\n if (!def || !('column' in def)) return [];\n return [s.direction === 'asc' ? asc(def.column) : desc(def.column)];\n });\n }\n}\n","export type FilterOperator = 'equals' | 'notEquals' | 'contains' | 'notContains' | 'gt' | 'gte' | 'lt' | 'lte' | 'isAnyOf' | 'isNotAnyOf';\n\nexport const FilterOperators = {\n EQUALS: 'equals',\n NOT_EQUALS: 'notEquals',\n CONTAINS: 'contains',\n NOT_CONTAINS: 'notContains',\n GT: 'gt',\n GTE: 'gte',\n LT: 'lt',\n LTE: 'lte',\n IS_ANY_OF: 'isAnyOf',\n IS_NOT_ANY_OF: 'isNotAnyOf',\n} as const satisfies Record<string, FilterOperator>;\n\nexport interface FilterCondition {\n field: string;\n operator: FilterOperator;\n value: string | number | string[];\n}\n\nexport interface SortCondition {\n field: string;\n direction: 'asc' | 'desc';\n}\n\nexport type DensityType = 'compact' | 'normal' | 'comfortable';\n\nexport interface ColumnPinning {\n left: string[];\n right: string[];\n}\n\nexport interface SearchState {\n columnId: string;\n value: string;\n}\n\nexport interface TableViewState {\n filters: FilterCondition[];\n sort: SortCondition[];\n columnVisibility: Record<string, boolean>;\n columnOrder: string[];\n columnSizing: Record<string, number>;\n columnPinning: ColumnPinning;\n lockedColumnSizing: boolean;\n density: DensityType;\n filterOrder: string[];\n filterVisibility: Record<string, boolean>;\n search: SearchState | null;\n pagination: { limit: number; offset: number };\n}\n","import { registerDecorator, type ValidationArguments, type ValidationOptions } from 'class-validator';\nimport { type CurrencyCode, majorToMinor, SUPPORTED_CURRENCIES } from '../money';\n\n// Self-contained validator for `{currency, value}` payloads. Intentionally does NOT compose\n// `@ValidateNested()` + `@Type(() => CurrencyAmountDto)` — api-sdk and the consuming app each\n// load their own copy of `class-validator` (different MetadataStorage singletons), so any\n// field-level decorators registered on `CurrencyAmountDto` from inside api-sdk are invisible\n// to the consumer's validator. Doing everything here, at the consumer's call site, sidesteps\n// that and keeps the decorator usable everywhere.\n//\n// Checks performed (in order, short-circuiting):\n// 1. Value is a non-null object.\n// 2. `currency` and `value` are both strings.\n// 3. `currency` is in `SUPPORTED_CURRENCIES`.\n// 4. `majorToMinor(value, currency)` succeeds — enforces decimal precision ≤ currency exponent.\nexport function IsCurrency(validationOptions?: ValidationOptions): PropertyDecorator {\n return (target: object, propertyName: string | symbol) => {\n registerDecorator({\n name: 'isCurrency',\n target: target.constructor,\n propertyName: String(propertyName),\n options: validationOptions,\n validator: {\n validate(value: unknown): boolean {\n if (!value || typeof value !== 'object') return false;\n const { currency, value: amount } = value as Record<string, unknown>;\n if (typeof currency !== 'string' || typeof amount !== 'string') return false;\n if (!(currency in SUPPORTED_CURRENCIES)) return false;\n try {\n majorToMinor(amount, currency as CurrencyCode);\n return true;\n } catch {\n return false;\n }\n },\n defaultMessage(args: ValidationArguments): string {\n return `${args.property} must be {currency, value} where currency is a valid ISO 4217 code and value precision matches the currency exponent.`;\n },\n },\n });\n };\n}\n","import { dinero, toDecimal } from 'dinero.js/bigint';\nimport {\n AED,\n AFN,\n ALL,\n AMD,\n AOA,\n ARS,\n AUD,\n AWG,\n AZN,\n BAM,\n BBD,\n BDT,\n BGN,\n BHD,\n BIF,\n BMD,\n BND,\n BOB,\n BOV,\n BRL,\n BSD,\n BTN,\n BWP,\n BYN,\n BZD,\n CAD,\n CDF,\n CHE,\n CHF,\n CHW,\n CLF,\n CLP,\n CNY,\n COP,\n COU,\n CRC,\n CUP,\n CVE,\n CZK,\n DJF,\n DKK,\n DOP,\n DZD,\n EGP,\n ERN,\n ETB,\n EUR,\n FJD,\n FKP,\n GBP,\n GEL,\n GHS,\n GIP,\n GMD,\n GNF,\n GTQ,\n GYD,\n HKD,\n HNL,\n HTG,\n HUF,\n IDR,\n ILS,\n INR,\n IQD,\n IRR,\n ISK,\n JMD,\n JOD,\n JPY,\n KES,\n KGS,\n KHR,\n KMF,\n KPW,\n KRW,\n KWD,\n KYD,\n KZT,\n LAK,\n LBP,\n LKR,\n LRD,\n LSL,\n LYD,\n MAD,\n MDL,\n MGA,\n MKD,\n MMK,\n MNT,\n MOP,\n MRU,\n MUR,\n MVR,\n MWK,\n MXN,\n MXV,\n MYR,\n MZN,\n NAD,\n NGN,\n NIO,\n NOK,\n NPR,\n NZD,\n OMR,\n PAB,\n PEN,\n PGK,\n PHP,\n PKR,\n PLN,\n PYG,\n QAR,\n RON,\n RSD,\n RUB,\n RWF,\n SAR,\n SBD,\n SCR,\n SDG,\n SEK,\n SGD,\n SHP,\n SLE,\n SOS,\n SRD,\n SSP,\n STN,\n SVC,\n SYP,\n SZL,\n THB,\n TJS,\n TMT,\n TND,\n TOP,\n TRY,\n TTD,\n TWD,\n TZS,\n UAH,\n UGX,\n USD,\n USN,\n UYI,\n UYU,\n UYW,\n UZS,\n VED,\n VES,\n VND,\n VUV,\n WST,\n XAD,\n XAF,\n XCD,\n XCG,\n XOF,\n XPF,\n YER,\n ZAR,\n ZMW,\n ZWG,\n} from 'dinero.js/bigint/currencies';\nimport { ValidationException } from './exceptions/validation.exception';\n\nexport * from 'dinero.js/bigint';\n\nconst ANG = { code: 'ANG', base: 10n, exponent: 2n } as const;\nconst HRK = { code: 'HRK', base: 10n, exponent: 2n } as const;\nconst XAG = { code: 'XAG', base: 10n, exponent: 0n } as const;\nconst XAU = { code: 'XAU', base: 10n, exponent: 0n } as const;\nconst XDR = { code: 'XDR', base: 10n, exponent: 0n } as const;\nconst XPD = { code: 'XPD', base: 10n, exponent: 0n } as const;\nconst XPT = { code: 'XPT', base: 10n, exponent: 0n } as const;\nconst ZWL = { code: 'ZWL', base: 10n, exponent: 2n } as const;\n\nexport const SUPPORTED_CURRENCIES = {\n AED,\n AFN,\n ALL,\n AMD,\n ANG,\n AOA,\n ARS,\n AUD,\n AWG,\n AZN,\n BAM,\n BBD,\n BDT,\n BGN,\n BHD,\n BIF,\n BMD,\n BND,\n BOB,\n BOV,\n BRL,\n BSD,\n BTN,\n BWP,\n BYN,\n BZD,\n CAD,\n CDF,\n CHE,\n CHF,\n CHW,\n CLF,\n CLP,\n CNY,\n COP,\n COU,\n CRC,\n CUP,\n CVE,\n CZK,\n DJF,\n DKK,\n DOP,\n DZD,\n EGP,\n ERN,\n ETB,\n EUR,\n FJD,\n FKP,\n GBP,\n GEL,\n GHS,\n GIP,\n GMD,\n GNF,\n GTQ,\n GYD,\n HKD,\n HNL,\n HRK,\n HTG,\n HUF,\n IDR,\n ILS,\n INR,\n IQD,\n IRR,\n ISK,\n JMD,\n JOD,\n JPY,\n KES,\n KGS,\n KHR,\n KMF,\n KPW,\n KRW,\n KWD,\n KYD,\n KZT,\n LAK,\n LBP,\n LKR,\n LRD,\n LSL,\n LYD,\n MAD,\n MDL,\n MGA,\n MKD,\n MMK,\n MNT,\n MOP,\n MRU,\n MUR,\n MVR,\n MWK,\n MXN,\n MXV,\n MYR,\n MZN,\n NAD,\n NGN,\n NIO,\n NOK,\n NPR,\n NZD,\n OMR,\n PAB,\n PEN,\n PGK,\n PHP,\n PKR,\n PLN,\n PYG,\n QAR,\n RON,\n RSD,\n RUB,\n RWF,\n SAR,\n SBD,\n SCR,\n SDG,\n SEK,\n SGD,\n SHP,\n SLE,\n SOS,\n SRD,\n SSP,\n STN,\n SVC,\n SYP,\n SZL,\n THB,\n TJS,\n TMT,\n TND,\n TOP,\n TRY,\n TTD,\n TWD,\n TZS,\n UAH,\n UGX,\n USD,\n USN,\n UYI,\n UYU,\n UYW,\n UZS,\n VED,\n VES,\n VND,\n VUV,\n WST,\n XAD,\n XAF,\n XAG,\n XAU,\n XCD,\n XCG,\n XDR,\n XOF,\n XPD,\n XPF,\n XPT,\n YER,\n ZAR,\n ZMW,\n ZWG,\n ZWL,\n} as const;\n\nexport type CurrencyCode = keyof typeof SUPPORTED_CURRENCIES;\nexport type Currency = (typeof SUPPORTED_CURRENCIES)[CurrencyCode];\n\nexport type MinorToMajorTransform<TOutput> = (props: { value: string; currency: Currency }) => TOutput;\n\nexport function resolveCurrency(currencyCode: CurrencyCode): Currency {\n return SUPPORTED_CURRENCIES[currencyCode];\n}\n\nexport function minorToMajor<TOutput = string>(\n minor: bigint,\n currencyCode: CurrencyCode,\n transform?: MinorToMajorTransform<TOutput>,\n): string | TOutput {\n const currency = resolveCurrency(currencyCode);\n const amount = dinero({ amount: minor, currency });\n\n if (!transform) {\n return toDecimal(amount);\n }\n\n return toDecimal(amount, ({ value, currency: resolvedCurrency }) => transform({ value, currency: resolvedCurrency }));\n}\n\n// Throws ValidationException (HTTP 422) instead of generic Error so the\n// NestJS error filter maps it to a field-level response automatically.\n// Callers pass `field` so the validation error binds to the right form field.\nexport function majorToMinor(major: string, currencyCode: CurrencyCode, field = 'amount'): bigint {\n const { exponent } = resolveCurrency(currencyCode);\n const scale = typeof exponent === 'bigint' ? Number(exponent) : exponent;\n const trimmed = major.trim();\n\n if (!/^-?\\d+(\\.\\d+)?$/.test(trimmed)) {\n throw new ValidationException({\n detail: `Invalid amount: \"${major}\".`,\n errors: [{ field, message: 'Enter a valid number.' }],\n });\n }\n\n const isNegative = trimmed.startsWith('-');\n const unsignedValue = isNegative ? trimmed.slice(1) : trimmed;\n const [wholePart, fractionalPart = ''] = unsignedValue.split('.');\n\n if (fractionalPart.length > scale) {\n throw new ValidationException({\n detail: `Too many decimal places for ${currencyCode}. Maximum allowed is ${scale}.`,\n errors: [{ field, message: `${currencyCode} allows up to ${scale} decimal place${scale === 1 ? '' : 's'}.` }],\n });\n }\n\n const paddedFraction = fractionalPart.padEnd(scale, '0');\n const normalizedDigits = `${wholePart}${paddedFraction}`.replace(/^0+(?=\\d)/, '');\n const minor = BigInt(normalizedDigits || '0');\n\n return isNegative ? -minor : minor;\n}\n","import { registerDecorator, type ValidationArguments, type ValidationOptions } from 'class-validator';\nimport { SUPPORTED_CURRENCIES } from '../money';\n\nexport function IsCurrencyCode(validationOptions?: ValidationOptions): PropertyDecorator {\n return (target: object, propertyName: string | symbol) => {\n registerDecorator({\n name: 'isCurrencyCode',\n target: target.constructor,\n propertyName: String(propertyName),\n options: validationOptions,\n validator: {\n validate(value: unknown): boolean {\n if (typeof value !== 'string') return false;\n return value in SUPPORTED_CURRENCIES;\n },\n defaultMessage(args: ValidationArguments): string {\n return `${args.property} must be a valid ISO 4217 currency code.`;\n },\n },\n });\n };\n}\n","import { registerDecorator, type ValidationArguments, type ValidationOptions } from 'class-validator';\n\nconst UTC_ISO_DATETIME_REGEX = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{1,3})?Z$/;\n\nexport function IsDateTime(validationOptions?: ValidationOptions): PropertyDecorator {\n return (target: object, propertyName: string | symbol) => {\n registerDecorator({\n name: 'isDateTime',\n target: target.constructor,\n propertyName: String(propertyName),\n options: validationOptions,\n validator: {\n validate(value: unknown): boolean {\n if (typeof value !== 'string') return false;\n if (!UTC_ISO_DATETIME_REGEX.test(value)) return false;\n return !Number.isNaN(Date.parse(value));\n },\n defaultMessage(args: ValidationArguments): string {\n return `${args.property} must be a UTC ISO date-time string ending with Z.`;\n },\n },\n });\n };\n}\n","import type { MultipartFile } from '@fastify/multipart';\nimport { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport type { FastifyRequest } from 'fastify';\nimport { BadRequestException } from '../exceptions';\n\nexport interface UploadedFileResult {\n buffer: Buffer;\n filename: string;\n mimetype: string;\n}\n\nasync function collectFiles(\n request: FastifyRequest,\n fieldName?: string,\n): Promise<{ files: MultipartFile[]; consumed: boolean }> {\n // Single-file shortcut when no fieldName filter is needed\n if (!fieldName) {\n const file = await request.file();\n return { files: file ? [file] : [], consumed: true };\n }\n\n const matched: MultipartFile[] = [];\n for await (const file of request.files()) {\n if (file.fieldname === fieldName) {\n matched.push(file);\n }\n }\n return { files: matched, consumed: true };\n}\n\n/**\n * Extracts a single uploaded file from a Fastify multipart request.\n * Pass an optional field name to match a specific form key.\n *\n * Requires `@fastify/multipart` to be registered on the Fastify instance.\n * Throws `BadRequestException` if no file is present in the request.\n *\n * @example\n * ```typescript\n * @Post('upload')\n * @ApiConsumes('multipart/form-data')\n * async upload(\n * @UploadedFile() file: UploadedFileResult, // grabs first file\n * @UploadedFile('avatar') avatar: UploadedFileResult, // grabs file with key \"avatar\"\n * ) {}\n * ```\n */\nexport const UploadedFile = createParamDecorator(\n async (fieldName: string | undefined, ctx: ExecutionContext): Promise<UploadedFileResult> => {\n const request = ctx.switchToHttp().getRequest<FastifyRequest>();\n const { files } = await collectFiles(request, fieldName);\n const file = files[0];\n\n if (!file) {\n const field = fieldName ?? 'file';\n throw new BadRequestException({\n label: 'File Required',\n detail: `Please attach a file${fieldName ? ` under \"${fieldName}\"` : ''} to your request.`,\n errors: [{ field, message: 'File required' }],\n });\n }\n\n const buffer = await file.toBuffer();\n return { buffer, filename: file.filename, mimetype: file.mimetype };\n },\n);\n\n/**\n * Extracts multiple uploaded files from a Fastify multipart request.\n * Pass an optional field name to match only files under a specific form key.\n *\n * Requires `@fastify/multipart` to be registered on the Fastify instance.\n * Throws `BadRequestException` if no files are present in the request.\n *\n * @example\n * ```typescript\n * @Post('upload')\n * @ApiConsumes('multipart/form-data')\n * async upload(\n * @UploadedFiles() files: UploadedFileResult[], // grabs all files\n * @UploadedFiles('documents') docs: UploadedFileResult[], // grabs files with key \"documents\"\n * ) {}\n * ```\n */\nexport const UploadedFiles = createParamDecorator(\n async (fieldName: string | undefined, ctx: ExecutionContext): Promise<UploadedFileResult[]> => {\n const request = ctx.switchToHttp().getRequest<FastifyRequest>();\n const { files } = await collectFiles(request, fieldName);\n\n if (files.length === 0) {\n const field = fieldName ?? 'files';\n throw new BadRequestException({\n label: 'Files Required',\n detail: `Please attach at least one file${fieldName ? ` under \"${fieldName}\"` : ''} to your request.`,\n errors: [{ field, message: 'At least one file is required' }],\n });\n }\n\n const results: UploadedFileResult[] = [];\n for (const file of files) {\n const buffer = await file.toBuffer();\n results.push({ buffer, filename: file.filename, mimetype: file.mimetype });\n }\n return results;\n },\n);\n","import { type CurrencyCode, minorToMajor } from '../money';\n\nexport class CurrencyAmountDto {\n currency: string;\n value: string;\n\n static from(minor: bigint, currencyCode: string): CurrencyAmountDto;\n static from(minor: bigint | null | undefined, currencyCode: string): CurrencyAmountDto | null;\n static from(minor: bigint | null | undefined, currencyCode: string): CurrencyAmountDto | null {\n if (minor == null) return null;\n const dto = new CurrencyAmountDto();\n dto.currency = currencyCode;\n dto.value = minorToMajor(minor, currencyCode as CurrencyCode);\n return dto;\n }\n}\n","import { Global, Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';\nimport { EmailService } from './email.service';\n\n@Global()\n@Module({\n imports: [ConfigModule],\n providers: [EmailService],\n exports: [EmailService],\n})\nexport class EmailModule {}\n","import { BrevoClient, BrevoError, BrevoTimeoutError } from '@getbrevo/brevo';\nimport { Injectable, Logger } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\n\n@Injectable()\nexport class EmailService {\n private readonly logger = new Logger(EmailService.name);\n private readonly brevoClient: BrevoClient;\n private readonly senderEmail: string;\n private readonly senderName: string;\n\n constructor(private readonly configService: ConfigService) {\n const apiKey = this.configService.get<string>('BREVO_API_KEY');\n\n if (!apiKey) {\n this.logger.error('BREVO_API_KEY is not configured. Email sending will fail.');\n throw new Error('Email service configuration error: Missing BREVO_API_KEY');\n }\n\n // Initialize Brevo client with built-in retry support\n this.brevoClient = new BrevoClient({ apiKey, maxRetries: 3 });\n\n // Get sender configuration\n const senderEmail = this.configService.get<string>('SENDER_EMAIL');\n const senderName = this.configService.get<string>('SENDER_NAME');\n\n if (!senderEmail || !senderName) {\n this.logger.error('Sender email or name is not configured.');\n throw new Error('Email service configuration error: Missing SENDER_EMAIL or SENDER_NAME');\n }\n\n this.senderEmail = senderEmail;\n this.senderName = senderName;\n\n this.logger.log('Brevo email service initialized successfully');\n }\n\n // Sends an email verification OTP to the given recipient\n async sendVerificationEmail(email: string, otp: string, expiresAt: Date, displayName?: string): Promise<void> {\n const name = displayName || 'there';\n const expiryMinutes = Math.ceil((expiresAt.getTime() - Date.now()) / 60_000);\n const subject = 'Verify Your Email - Vritti AI Cloud';\n\n const htmlContent = `\n <!DOCTYPE html>\n <html>\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n </head>\n <body style=\"margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background-color: #f5f5f5;\">\n <table role=\"presentation\" style=\"width: 100%; border-collapse: collapse;\">\n <tr>\n <td style=\"padding: 40px 20px;\">\n <table role=\"presentation\" style=\"max-width: 600px; margin: 0 auto; background-color: #ffffff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);\">\n <!-- Header -->\n <tr>\n <td style=\"padding: 40px 40px 20px; text-align: center; border-bottom: 1px solid #e0e0e0;\">\n <h1 style=\"margin: 0; color: #1a1a1a; font-size: 24px; font-weight: 600;\">Email Verification</h1>\n </td>\n </tr>\n\n <!-- Content -->\n <tr>\n <td style=\"padding: 40px;\">\n <p style=\"margin: 0 0 20px; color: #333333; font-size: 16px; line-height: 1.6;\">\n Hello <strong>${name}</strong>,\n </p>\n <p style=\"margin: 0 0 30px; color: #333333; font-size: 16px; line-height: 1.6;\">\n Thank you for signing up with Vritti AI Cloud. Please use the following verification code to complete your registration:\n </p>\n\n <!-- OTP Box -->\n <div style=\"background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 30px; border-radius: 8px; text-align: center; margin: 30px 0;\">\n <div style=\"color: #ffffff; font-size: 36px; font-weight: bold; letter-spacing: 10px; font-family: 'Courier New', monospace;\">\n ${otp}\n </div>\n </div>\n\n <p style=\"margin: 30px 0 20px; color: #666666; font-size: 14px; line-height: 1.6;\">\n <strong>Important:</strong> This code will expire in <strong>${expiryMinutes} minute${expiryMinutes === 1 ? '' : 's'}</strong>.\n </p>\n <p style=\"margin: 0; color: #666666; font-size: 14px; line-height: 1.6;\">\n If you didn't request this verification, please ignore this email.\n </p>\n </td>\n </tr>\n\n <!-- Footer -->\n <tr>\n <td style=\"padding: 30px 40px; border-top: 1px solid #e0e0e0; text-align: center;\">\n <p style=\"margin: 0; color: #999999; font-size: 12px; line-height: 1.5;\">\n Vritti AI Cloud - Cloud Management Platform\n </p>\n <p style=\"margin: 8px 0 0; color: #999999; font-size: 12px; line-height: 1.5;\">\n This is an automated message, please do not reply.\n </p>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n </body>\n </html>\n `;\n\n const textContent = `\nHello ${name},\n\nThank you for signing up with Vritti AI Cloud. Please use the following verification code to complete your registration:\n\nVerification Code: ${otp}\n\nThis code will expire in ${expiryMinutes} minute${expiryMinutes === 1 ? '' : 's'}.\n\nIf you didn't request this verification, please ignore this email.\n\n---\nVritti AI Cloud - Cloud Management Platform\nThis is an automated message, please do not reply.\n `.trim();\n\n await this.sendEmail({\n to: [{ email, name }],\n subject,\n htmlContent,\n textContent,\n });\n\n this.logger.log(`Verification email sent to ${email}`);\n }\n\n // Sends a password reset OTP to the given recipient\n async sendPasswordResetEmail(email: string, otp: string, expiresAt: Date, displayName?: string): Promise<void> {\n const name = displayName || 'there';\n const expiryMinutes = Math.ceil((expiresAt.getTime() - Date.now()) / 60_000);\n const subject = 'Reset Your Password - Vritti AI Cloud';\n\n const htmlContent = `\n <!DOCTYPE html>\n <html>\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n </head>\n <body style=\"margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background-color: #f5f5f5;\">\n <table role=\"presentation\" style=\"width: 100%; border-collapse: collapse;\">\n <tr>\n <td style=\"padding: 40px 20px;\">\n <table role=\"presentation\" style=\"max-width: 600px; margin: 0 auto; background-color: #ffffff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);\">\n <!-- Header -->\n <tr>\n <td style=\"padding: 40px 40px 20px; text-align: center; border-bottom: 1px solid #e0e0e0;\">\n <h1 style=\"margin: 0; color: #1a1a1a; font-size: 24px; font-weight: 600;\">Password Reset</h1>\n </td>\n </tr>\n\n <!-- Content -->\n <tr>\n <td style=\"padding: 40px;\">\n <p style=\"margin: 0 0 20px; color: #333333; font-size: 16px; line-height: 1.6;\">\n Hello <strong>${name}</strong>,\n </p>\n <p style=\"margin: 0 0 30px; color: #333333; font-size: 16px; line-height: 1.6;\">\n We received a request to reset your password. Use the following code to complete the process:\n </p>\n\n <!-- OTP Box -->\n <div style=\"background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); padding: 30px; border-radius: 8px; text-align: center; margin: 30px 0;\">\n <div style=\"color: #ffffff; font-size: 36px; font-weight: bold; letter-spacing: 10px; font-family: 'Courier New', monospace;\">\n ${otp}\n </div>\n </div>\n\n <p style=\"margin: 30px 0 20px; color: #666666; font-size: 14px; line-height: 1.6;\">\n <strong>Important:</strong> This code will expire in <strong>${expiryMinutes} minute${expiryMinutes === 1 ? '' : 's'}</strong>.\n </p>\n <p style=\"margin: 0 0 20px; color: #666666; font-size: 14px; line-height: 1.6;\">\n If you didn't request a password reset, please ignore this email and your password will remain unchanged.\n </p>\n <div style=\"background-color: #fff3cd; border-left: 4px solid #ffc107; padding: 15px; margin-top: 20px; border-radius: 4px;\">\n <p style=\"margin: 0; color: #856404; font-size: 13px; line-height: 1.5;\">\n <strong>Security Tip:</strong> Never share this code with anyone. Vritti will never ask for your verification code.\n </p>\n </div>\n </td>\n </tr>\n\n <!-- Footer -->\n <tr>\n <td style=\"padding: 30px 40px; border-top: 1px solid #e0e0e0; text-align: center;\">\n <p style=\"margin: 0; color: #999999; font-size: 12px; line-height: 1.5;\">\n Vritti AI Cloud - Cloud Management Platform\n </p>\n <p style=\"margin: 8px 0 0; color: #999999; font-size: 12px; line-height: 1.5;\">\n This is an automated message, please do not reply.\n </p>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n </body>\n </html>\n `;\n\n const textContent = `\nHello ${name},\n\nWe received a request to reset your password. Use the following code to complete the process:\n\nReset Code: ${otp}\n\nThis code will expire in ${expiryMinutes} minute${expiryMinutes === 1 ? '' : 's'}.\n\nIf you didn't request a password reset, please ignore this email and your password will remain unchanged.\n\nSECURITY TIP: Never share this code with anyone. Vritti will never ask for your verification code.\n\n---\nVritti AI Cloud - Cloud Management Platform\nThis is an automated message, please do not reply.\n `.trim();\n\n await this.sendEmail({\n to: [{ email, name }],\n subject,\n htmlContent,\n textContent,\n });\n\n this.logger.log(`Password reset email sent to ${email}`);\n }\n\n // Sends an email change notification to the old address with a revert link\n async sendEmailChangeNotification(\n oldEmail: string,\n newEmail: string,\n revertToken: string,\n revertExpiresAt: Date,\n displayName?: string,\n ): Promise<void> {\n const name = displayName || 'there';\n const subject = 'Your Email Address Has Been Changed - Vritti AI Cloud';\n\n // Calculate hours until expiry\n const hoursUntilExpiry = Math.floor((revertExpiresAt.getTime() - Date.now()) / (1000 * 60 * 60));\n\n // TODO: Replace with actual frontend URL from config\n const revertLink = `https://local.vrittiai.com:3012/settings/profile/revert-email?token=${revertToken}`;\n\n const htmlContent = `\n <!DOCTYPE html>\n <html>\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n </head>\n <body style=\"margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background-color: #f5f5f5;\">\n <table role=\"presentation\" style=\"width: 100%; border-collapse: collapse;\">\n <tr>\n <td style=\"padding: 40px 20px;\">\n <table role=\"presentation\" style=\"max-width: 600px; margin: 0 auto; background-color: #ffffff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);\">\n <!-- Header -->\n <tr>\n <td style=\"padding: 40px 40px 20px; text-align: center; border-bottom: 1px solid #e0e0e0;\">\n <h1 style=\"margin: 0; color: #1a1a1a; font-size: 24px; font-weight: 600;\">Email Address Changed</h1>\n </td>\n </tr>\n\n <!-- Content -->\n <tr>\n <td style=\"padding: 40px;\">\n <p style=\"margin: 0 0 20px; color: #333333; font-size: 16px; line-height: 1.6;\">\n Hello <strong>${name}</strong>,\n </p>\n <p style=\"margin: 0 0 30px; color: #333333; font-size: 16px; line-height: 1.6;\">\n We're writing to inform you that your Vritti AI Cloud email address has been successfully changed.\n </p>\n\n <div style=\"background-color: #f8f9fa; padding: 20px; border-radius: 8px; margin: 30px 0;\">\n <p style=\"margin: 0 0 10px; color: #666666; font-size: 14px;\">\n <strong>Previous Email:</strong>\n </p>\n <p style=\"margin: 0 0 20px; color: #333333; font-size: 16px; font-family: monospace;\">\n ${oldEmail}\n </p>\n <p style=\"margin: 0 0 10px; color: #666666; font-size: 14px;\">\n <strong>New Email:</strong>\n </p>\n <p style=\"margin: 0; color: #333333; font-size: 16px; font-family: monospace;\">\n ${newEmail}\n </p>\n </div>\n\n <div style=\"background-color: #fff3cd; border-left: 4px solid #ffc107; padding: 20px; margin: 30px 0; border-radius: 4px;\">\n <p style=\"margin: 0 0 15px; color: #856404; font-size: 14px; line-height: 1.6;\">\n <strong>Didn't make this change?</strong>\n </p>\n <p style=\"margin: 0 0 20px; color: #856404; font-size: 14px; line-height: 1.6;\">\n If you did not authorize this change, you can revert it within the next <strong>${hoursUntilExpiry} hours</strong> by clicking the button below:\n </p>\n <div style=\"text-align: center;\">\n <a href=\"${revertLink}\" style=\"display: inline-block; padding: 12px 30px; background-color: #dc3545; color: #ffffff; text-decoration: none; border-radius: 6px; font-weight: 600; font-size: 14px;\">\n Revert Email Change\n </a>\n </div>\n </div>\n\n <p style=\"margin: 30px 0 0; color: #666666; font-size: 14px; line-height: 1.6;\">\n If you made this change, you can safely ignore this email.\n </p>\n </td>\n </tr>\n\n <!-- Footer -->\n <tr>\n <td style=\"padding: 30px 40px; border-top: 1px solid #e0e0e0; text-align: center;\">\n <p style=\"margin: 0; color: #999999; font-size: 12px; line-height: 1.5;\">\n Vritti AI Cloud - Cloud Management Platform\n </p>\n <p style=\"margin: 8px 0 0; color: #999999; font-size: 12px; line-height: 1.5;\">\n This is an automated message, please do not reply.\n </p>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n </body>\n </html>\n `;\n\n const textContent = `\nHello ${name},\n\nWe're writing to inform you that your Vritti AI Cloud email address has been successfully changed.\n\nPrevious Email: ${oldEmail}\nNew Email: ${newEmail}\n\nDIDN'T MAKE THIS CHANGE?\n\nIf you did not authorize this change, you can revert it within the next ${hoursUntilExpiry} hours by visiting:\n${revertLink}\n\nIf you made this change, you can safely ignore this email.\n\n---\nVritti AI Cloud - Cloud Management Platform\nThis is an automated message, please do not reply.\n `.trim();\n\n await this.sendEmail({\n to: [{ email: oldEmail, name }],\n subject,\n htmlContent,\n textContent,\n });\n\n this.logger.log(`Email change notification sent to ${oldEmail}`);\n }\n\n // Sends a confirmation to the restored email address after a revert\n async sendEmailRevertConfirmation(email: string, displayName?: string): Promise<void> {\n const name = displayName || 'there';\n const subject = 'Email Address Change Reverted - Vritti AI Cloud';\n\n const htmlContent = `\n <!DOCTYPE html>\n <html>\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n </head>\n <body style=\"margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background-color: #f5f5f5;\">\n <table role=\"presentation\" style=\"width: 100%; border-collapse: collapse;\">\n <tr>\n <td style=\"padding: 40px 20px;\">\n <table role=\"presentation\" style=\"max-width: 600px; margin: 0 auto; background-color: #ffffff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);\">\n <!-- Header -->\n <tr>\n <td style=\"padding: 40px 40px 20px; text-align: center; border-bottom: 1px solid #e0e0e0;\">\n <h1 style=\"margin: 0; color: #1a1a1a; font-size: 24px; font-weight: 600;\">Email Change Reverted</h1>\n </td>\n </tr>\n\n <!-- Content -->\n <tr>\n <td style=\"padding: 40px;\">\n <p style=\"margin: 0 0 20px; color: #333333; font-size: 16px; line-height: 1.6;\">\n Hello <strong>${name}</strong>,\n </p>\n <p style=\"margin: 0 0 30px; color: #333333; font-size: 16px; line-height: 1.6;\">\n Your recent email address change has been successfully reverted. Your email is now:\n </p>\n\n <div style=\"background-color: #d4edda; padding: 20px; border-radius: 8px; margin: 30px 0; text-align: center;\">\n <p style=\"margin: 0; color: #155724; font-size: 18px; font-weight: 600; font-family: monospace;\">\n ${email}\n </p>\n </div>\n\n <p style=\"margin: 30px 0 20px; color: #666666; font-size: 14px; line-height: 1.6;\">\n If you did not request this revert, please contact our support team immediately.\n </p>\n </td>\n </tr>\n\n <!-- Footer -->\n <tr>\n <td style=\"padding: 30px 40px; border-top: 1px solid #e0e0e0; text-align: center;\">\n <p style=\"margin: 0; color: #999999; font-size: 12px; line-height: 1.5;\">\n Vritti AI Cloud - Cloud Management Platform\n </p>\n <p style=\"margin: 8px 0 0; color: #999999; font-size: 12px; line-height: 1.5;\">\n This is an automated message, please do not reply.\n </p>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n </body>\n </html>\n `;\n\n const textContent = `\nHello ${name},\n\nYour recent email address change has been successfully reverted. Your email is now:\n\n${email}\n\nIf you did not request this revert, please contact our support team immediately.\n\n---\nVritti AI Cloud - Cloud Management Platform\nThis is an automated message, please do not reply.\n `.trim();\n\n await this.sendEmail({\n to: [{ email, name }],\n subject,\n htmlContent,\n textContent,\n });\n\n this.logger.log(`Email revert confirmation sent to ${email}`);\n }\n\n // Sends an invite email to a new portal user with their set-password link\n async sendInviteEmail(params: { to: string; name: string; inviteUrl: string }): Promise<void> {\n const { to, name, inviteUrl } = params;\n const subject = 'You have been invited to Vritti AI';\n\n const htmlContent = `\n <!DOCTYPE html>\n <html>\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n </head>\n <body style=\"margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background-color: #f5f5f5;\">\n <table role=\"presentation\" style=\"width: 100%; border-collapse: collapse;\">\n <tr>\n <td style=\"padding: 40px 20px;\">\n <table role=\"presentation\" style=\"max-width: 600px; margin: 0 auto; background-color: #ffffff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);\">\n <!-- Header -->\n <tr>\n <td style=\"padding: 40px 40px 20px; text-align: center; border-bottom: 1px solid #e0e0e0;\">\n <h1 style=\"margin: 0; color: #1a1a1a; font-size: 24px; font-weight: 600;\">You're Invited</h1>\n </td>\n </tr>\n\n <!-- Content -->\n <tr>\n <td style=\"padding: 40px;\">\n <p style=\"margin: 0 0 20px; color: #333333; font-size: 16px; line-height: 1.6;\">\n Hello <strong>${name}</strong>,\n </p>\n <p style=\"margin: 0 0 30px; color: #333333; font-size: 16px; line-height: 1.6;\">\n You have been invited to join Vritti AI. Click the button below to set your password and get started.\n </p>\n\n <div style=\"text-align: center; margin: 30px 0;\">\n <a href=\"${inviteUrl}\" style=\"display: inline-block; padding: 14px 32px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: #ffffff; text-decoration: none; border-radius: 6px; font-weight: 600; font-size: 16px;\">\n Set Your Password\n </a>\n </div>\n\n <p style=\"margin: 30px 0 0; color: #666666; font-size: 14px; line-height: 1.6;\">\n If you did not expect this invitation, you can safely ignore this email.\n </p>\n </td>\n </tr>\n\n <!-- Footer -->\n <tr>\n <td style=\"padding: 30px 40px; border-top: 1px solid #e0e0e0; text-align: center;\">\n <p style=\"margin: 0; color: #999999; font-size: 12px; line-height: 1.5;\">\n Vritti AI Cloud - Cloud Management Platform\n </p>\n <p style=\"margin: 8px 0 0; color: #999999; font-size: 12px; line-height: 1.5;\">\n This is an automated message, please do not reply.\n </p>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n </body>\n </html>\n `;\n\n const textContent = `\nHello ${name},\n\nYou have been invited to join Vritti AI. Visit the link below to set your password and get started:\n\n${inviteUrl}\n\nIf you did not expect this invitation, you can safely ignore this email.\n\n---\nVritti AI Cloud - Cloud Management Platform\nThis is an automated message, please do not reply.\n `.trim();\n\n await this.sendEmail({\n to: [{ email: to, name }],\n subject,\n htmlContent,\n textContent,\n });\n\n this.logger.log(`Invite email sent to ${to}`);\n }\n\n // Sends a transactional email with custom subject, HTML, and text content\n async sendTransactionalEmail(params: {\n to: { email: string; name?: string };\n subject: string;\n htmlContent: string;\n textContent: string;\n }): Promise<void> {\n await this.sendEmail({\n to: [params.to],\n subject: params.subject,\n htmlContent: params.htmlContent,\n textContent: params.textContent,\n });\n this.logger.log(`Transactional email sent to ${params.to.email}`);\n }\n\n // Verifies Brevo API connectivity — a 400 response means the API is reachable\n async verifyConnection(): Promise<boolean> {\n try {\n await this.brevoClient.transactionalEmails.sendTransacEmail({\n sender: { email: this.senderEmail, name: this.senderName },\n to: [{ email: this.senderEmail }],\n subject: 'Connection Test',\n htmlContent: '<p>Test</p>',\n });\n return true;\n } catch (err) {\n // A 400 error means the API is reachable but params are incomplete — still a successful connection test\n if (err instanceof BrevoError && err.statusCode === 400) {\n return true;\n }\n this.logger.error('Brevo connection verification failed:', err);\n return false;\n }\n }\n\n // Sends a transactional email via Brevo — retries handled internally by BrevoClient\n private async sendEmail(emailData: {\n to: Array<{ email: string; name?: string }>;\n subject: string;\n htmlContent: string;\n textContent: string;\n }): Promise<void> {\n try {\n const result = await this.brevoClient.transactionalEmails.sendTransacEmail({\n sender: { email: this.senderEmail, name: this.senderName },\n to: emailData.to,\n subject: emailData.subject,\n htmlContent: emailData.htmlContent,\n textContent: emailData.textContent,\n });\n this.logger.debug(`Email sent successfully. Message ID: ${result.messageId}`);\n } catch (err) {\n if (err instanceof BrevoTimeoutError) {\n this.logger.error('Brevo request timed out after retries.');\n throw new Error('Email sending failed: timeout');\n }\n if (err instanceof BrevoError) {\n if (err.statusCode === 429) {\n this.logger.error('Brevo rate limit exceeded after retries.');\n throw new Error('Email sending failed: rate limit exceeded');\n }\n if (err.statusCode === 401) {\n this.logger.error('Brevo authentication failed. Check your API key.');\n throw new Error('Email service authentication failed');\n }\n if (err.statusCode === 400) {\n this.logger.error('Bad request to Brevo API:', err.message);\n throw new Error(`Invalid email parameters: ${err.message}`);\n }\n this.logger.error(`Brevo API error ${err.statusCode}:`, err.message);\n throw new Error(`Email sending failed: ${err.message}`);\n }\n throw err;\n }\n }\n}\n","import {\n type ArgumentsHost,\n Catch,\n type ExceptionFilter,\n type HttpException,\n HttpStatus,\n Logger,\n} from '@nestjs/common';\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport type { ApiErrorResponse, FieldError } from '../types/error-response.types';\nimport { tryTranslatePgError } from './pg-error.translator';\n\ninterface ProblemExceptionResponse {\n type?: string;\n label?: string;\n detail?: string;\n errors?: FieldError[];\n}\n\ninterface ValidationExceptionResponse {\n message: Array<string | { property: string; constraints: Record<string, string> }>;\n error?: string;\n}\n\ninterface StandardExceptionResponse {\n message: string | string[];\n error?: string;\n}\n\ntype ExceptionResponseObject = ProblemExceptionResponse | ValidationExceptionResponse | StandardExceptionResponse;\n\n// Converts an HTTP status code to its title string (e.g., 400 → \"Bad Request\")\nexport function getHttpStatusTitle(status: number): string {\n // Find the enum key for the given status code\n const enumKey = Object.entries(HttpStatus).find(([key, value]) => value === status && Number.isNaN(Number(key)))?.[0];\n\n if (!enumKey) {\n return 'Error';\n }\n\n // Convert enum key to title case (e.g., BAD_REQUEST -> Bad Request)\n return enumKey\n .split('_')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(' ');\n}\n\n@Catch()\nexport class HttpExceptionFilter implements ExceptionFilter {\n private readonly logger = new Logger(HttpExceptionFilter.name);\n\n catch(exception: unknown, host: ArgumentsHost) {\n const ctx = host.switchToHttp();\n const response = ctx.getResponse<FastifyReply>();\n const request = ctx.getRequest<FastifyRequest>();\n\n // Translate raw Postgres errors (e.g. 23505 unique_violation from an unguarded INSERT)\n // into a ConflictException before the rest of the filter classifies it as 500.\n const translatedPgError = tryTranslatePgError(exception);\n if (translatedPgError) exception = translatedPgError;\n\n let status = HttpStatus.INTERNAL_SERVER_ERROR;\n let type = 'about:blank';\n let label: string | undefined;\n let detail = 'Internal server error';\n let errors: FieldError[] = [];\n\n if (this.isHttpException(exception)) {\n status = exception.getStatus();\n const exceptionResponse = exception.getResponse();\n\n if (typeof exceptionResponse === 'object' && exceptionResponse !== null) {\n const responseObj = exceptionResponse as ExceptionResponseObject;\n\n // Handle custom HttpProblemException from @vritti/api-sdk\n if ('type' in responseObj || 'label' in responseObj || 'errors' in responseObj) {\n const problemResponse = responseObj as ProblemExceptionResponse;\n type = problemResponse.type ?? 'about:blank';\n label = problemResponse.label;\n detail = problemResponse.detail ?? exception.message ?? getHttpStatusTitle(status);\n errors = problemResponse.errors ?? [];\n }\n // Handle class-validator DTO validation errors\n else if ('message' in responseObj && Array.isArray(responseObj.message)) {\n errors = responseObj.message\n .map((msg) => {\n if (typeof msg === 'object' && 'property' in msg && 'constraints' in msg) {\n const constraintValues = Object.values(msg.constraints);\n return {\n field: msg.property,\n message: constraintValues[0] ?? 'Validation failed',\n };\n }\n // Non-field-specific validation messages are ignored\n // They should be handled as detail at the response level\n return null;\n })\n .filter((error): error is FieldError => error !== null);\n detail = 'Validation failed';\n }\n // Handle standard NestJS exceptions\n else if ('message' in responseObj) {\n const message = responseObj.message;\n detail = Array.isArray(message) ? message.join(', ') : message;\n }\n } else if (typeof exceptionResponse === 'string') {\n detail = exceptionResponse;\n }\n } else if (this.isProblemLikeObject(exception)) {\n const problemObj = exception as Record<string, unknown>;\n const statusCandidate = problemObj.status ?? problemObj.statusCode;\n if (typeof statusCandidate === 'number' && statusCandidate >= 400 && statusCandidate <= 599) {\n status = statusCandidate;\n }\n type = typeof problemObj.type === 'string' ? problemObj.type : 'about:blank';\n label = typeof problemObj.label === 'string' ? problemObj.label : undefined;\n detail =\n typeof problemObj.detail === 'string'\n ? problemObj.detail\n : typeof problemObj.message === 'string'\n ? problemObj.message\n : getHttpStatusTitle(status);\n errors = Array.isArray(problemObj.errors) ? (problemObj.errors as FieldError[]) : [];\n } else if (this.isAxiosError(exception)) {\n // Outgoing HTTP call failures (e.g., service-to-service calls)\n const axiosStatus = exception.response?.status;\n const axiosDetail = exception.response?.data?.message || exception.response?.data?.detail || exception.message;\n const url = exception.config?.url;\n status = HttpStatus.BAD_GATEWAY;\n detail = `Upstream service error${axiosStatus ? ` (${axiosStatus})` : ''}: ${axiosDetail}`;\n this.logger.error(`Upstream API error [${axiosStatus}]: ${axiosDetail} — URL: ${url}`, exception.stack);\n } else {\n // Unknown errors — logged by HttpLoggerInterceptor, no need to log again here\n detail = 'An unexpected error occurred';\n }\n\n const problemDetails: ApiErrorResponse = {\n type,\n title: getHttpStatusTitle(status),\n status,\n ...(label && { label }),\n detail,\n instance: request.url,\n errors,\n };\n\n response.header('Content-Type', 'application/problem+json').status(status).send(problemDetails);\n }\n\n // Duck-type check for HttpException — avoids instanceof failing across pnpm package instances\n private isHttpException(error: unknown): error is HttpException {\n return (\n error instanceof Error &&\n typeof (error as { getStatus?: unknown }).getStatus === 'function' &&\n typeof (error as { getResponse?: unknown }).getResponse === 'function'\n );\n }\n\n // Duck-type check for AxiosError without importing axios\n private isAxiosError(error: unknown): error is Error & {\n isAxiosError: true;\n response?: { status?: number; data?: Record<string, unknown> };\n config?: { url?: string };\n } {\n return error instanceof Error && (error as { isAxiosError?: boolean }).isAxiosError === true;\n }\n\n private isProblemLikeObject(error: unknown): error is Record<string, unknown> {\n if (!error || typeof error !== 'object') return false;\n const obj = error as Record<string, unknown>;\n return (\n typeof obj.status === 'number' ||\n typeof obj.statusCode === 'number' ||\n typeof obj.detail === 'string' ||\n Array.isArray(obj.errors)\n );\n }\n}\n","import { ConflictException } from '../exceptions/conflict.exception';\n\n// Postgres SQLSTATE codes we translate before the global filters render the response.\n// Reference: https://www.postgresql.org/docs/current/errcodes-appendix.html\n//\n// Today we only handle 23505 (unique_violation) — services already pre-check the common\n// duplicate cases for friendly messages; this is the race-condition / unguarded-write backstop\n// so a raw `error: duplicate key value violates unique constraint \"...\"` never reaches the\n// client as a 500. Extend the switch below as we identify other SQLSTATEs worth surfacing\n// (e.g. 23503 foreign_key_violation → 409 with FK info).\nconst PG_UNIQUE_VIOLATION = '23505';\n\ntype PgErrorShape = {\n code?: string;\n constraint?: string;\n table?: string;\n detail?: string;\n};\n\n// Returns a ConflictException for a Postgres unique-violation error, otherwise undefined.\n// Both global filters call this at the top of their catch method so any 23505 escaping a\n// service produces the same RFC 9457 payload regardless of where it was thrown.\n//\n// Drizzle 1.0+ wraps pg driver errors in `DrizzleQueryError` with the original pg error on\n// `.cause`, so we walk a short cause chain to find the SQLSTATE.\nexport function tryTranslatePgError(error: unknown): ConflictException | undefined {\n const pgError = findPgError(error);\n if (!pgError) return undefined;\n const { code, constraint, table, detail } = pgError;\n if (code !== PG_UNIQUE_VIOLATION) return undefined;\n return new ConflictException({\n label: 'Duplicate Entry',\n detail: detail?.trim() || 'A record with these values already exists.',\n errors: [],\n ...(constraint || table ? { meta: { constraint, table } } : {}),\n });\n}\n\n// Walks up to N levels of `.cause` looking for a pg-shaped error (has SQLSTATE `code`).\n// Caps depth so a circular `cause` graph can't trap us.\nfunction findPgError(error: unknown, depth = 0): PgErrorShape | undefined {\n if (!error || typeof error !== 'object' || depth > 5) return undefined;\n const candidate = error as PgErrorShape & { cause?: unknown };\n if (typeof candidate.code === 'string') return candidate;\n return findPgError(candidate.cause, depth + 1);\n}\n","import { type ArgumentsHost, Catch, type HttpException, HttpStatus, Logger } from '@nestjs/common';\nimport { RpcException } from '@nestjs/microservices';\nimport { type Observable, throwError } from 'rxjs';\nimport { tryTranslatePgError } from './pg-error.translator';\n\ninterface FieldError {\n field: string;\n message: string;\n}\n\ninterface ProblemPayload {\n type: string;\n label?: string;\n detail: string;\n message: string;\n errors: FieldError[];\n status: number;\n statusCode: number;\n}\n\n@Catch()\nexport class RpcProblemExceptionFilter {\n private readonly logger = new Logger(RpcProblemExceptionFilter.name);\n\n catch(exception: unknown, _host: ArgumentsHost): Observable<never> {\n // Translate raw Postgres errors (e.g. 23505 unique_violation from an unguarded INSERT in\n // a NATS handler) into a ConflictException before the rest of the filter handles them.\n const translatedPgError = tryTranslatePgError(exception);\n if (translatedPgError) exception = translatedPgError;\n\n if (exception instanceof RpcException) {\n return throwError(() => exception.getError());\n }\n\n if (this.isHttpException(exception)) {\n const status = exception.getStatus();\n const response = exception.getResponse();\n return throwError(() => this.toProblemPayload(response, status));\n }\n\n if (exception instanceof Error) {\n const cause = (exception as { cause?: unknown }).cause;\n const causeMessage = cause instanceof Error ? cause.message : undefined;\n const causeStack = cause instanceof Error ? cause.stack : undefined;\n this.logger.error(causeMessage ?? exception.message, causeStack ?? exception.stack);\n if (cause && cause !== exception) {\n this.logger.error(`Wrapped by: ${exception.message}`);\n }\n return throwError(() =>\n this.toProblemPayload(\n {\n type: 'about:blank',\n detail: causeMessage ?? exception.message,\n errors: [],\n },\n HttpStatus.INTERNAL_SERVER_ERROR,\n ),\n );\n }\n\n this.logger.error(`Unhandled non-error exception: ${JSON.stringify(exception)}`);\n return throwError(() =>\n this.toProblemPayload(\n {\n type: 'about:blank',\n detail: 'An unexpected error occurred',\n errors: [],\n },\n HttpStatus.INTERNAL_SERVER_ERROR,\n ),\n );\n }\n\n private toProblemPayload(response: unknown, status: number): ProblemPayload {\n if (typeof response === 'string') {\n return {\n type: 'about:blank',\n detail: response,\n message: response,\n errors: [],\n status,\n statusCode: status,\n };\n }\n\n const obj = (response ?? {}) as Record<string, unknown>;\n const detail = typeof obj.detail === 'string' ? obj.detail : 'Request failed';\n return {\n type: typeof obj.type === 'string' ? obj.type : 'about:blank',\n label: typeof obj.label === 'string' ? obj.label : undefined,\n detail,\n message: detail,\n errors: Array.isArray(obj.errors) ? (obj.errors as FieldError[]) : [],\n status,\n statusCode: status,\n };\n }\n\n private isHttpException(error: unknown): error is HttpException {\n return (\n error instanceof Error &&\n typeof (error as { getStatus?: unknown }).getStatus === 'function' &&\n typeof (error as { getResponse?: unknown }).getResponse === 'function'\n );\n }\n}\n","import { type CallHandler, type ExecutionContext, Injectable, type NestInterceptor, Optional } from '@nestjs/common';\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport type { Observable } from 'rxjs';\nimport { catchError, tap } from 'rxjs/operators';\nimport { LoggerService } from '../services/logger.service';\nimport type { HttpLoggerOptions, LogMetadata } from '../types';\nimport { getCorrelationContext } from '../utils';\n\n@Injectable()\nexport class HttpLoggerInterceptor implements NestInterceptor {\n private readonly enableRequestLog: boolean;\n private readonly enableResponseLog: boolean;\n private readonly slowRequestThreshold: number;\n\n constructor(\n private readonly logger: LoggerService,\n @Optional() options?: HttpLoggerOptions,\n ) {\n this.enableRequestLog = options?.enableRequestLog ?? true;\n this.enableResponseLog = options?.enableResponseLog ?? true;\n this.slowRequestThreshold = options?.slowRequestThreshold ?? 3000; // 3 seconds\n }\n\n intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {\n if (context.getType() !== 'http') {\n return next.handle();\n }\n\n const httpContext = context.switchToHttp();\n const request = httpContext.getRequest<FastifyRequest>();\n const response = httpContext.getResponse<FastifyReply>();\n\n const startTime = Date.now();\n\n // Log incoming request\n if (this.enableRequestLog) {\n this.logRequest(request);\n }\n\n // Process request and log response/errors\n return next.handle().pipe(\n tap(() => {\n if (this.enableResponseLog) {\n const duration = Date.now() - startTime;\n this.logResponse(request, response, duration);\n }\n }),\n catchError((error) => {\n const duration = Date.now() - startTime;\n this.logError(request, response, duration, error);\n throw error;\n }),\n );\n }\n\n private logRequest(request: FastifyRequest): void {\n try {\n const correlationContext = getCorrelationContext();\n const metadata: LogMetadata = {\n type: 'http_request',\n method: request.method,\n url: request.url,\n correlationId: correlationContext?.correlationId,\n ip: request.ip,\n userAgent: request.headers['user-agent'],\n };\n\n this.logger.logWithMetadata('log', `Incoming ${request.method} ${request.url}`, metadata);\n } catch (error) {\n this.logger.error('Failed to log HTTP request', (error as Error).stack);\n }\n }\n\n private logResponse(request: FastifyRequest, response: FastifyReply, duration: number): void {\n try {\n const correlationContext = getCorrelationContext();\n const statusCode = response.statusCode;\n\n // Determine log level based on status code\n const logLevel = statusCode >= 500 ? 'error' : statusCode >= 400 ? 'warn' : 'log';\n\n const metadata: LogMetadata = {\n type: 'http_response',\n method: request.method,\n url: request.url,\n statusCode,\n duration,\n correlationId: correlationContext?.correlationId,\n };\n\n // Flag slow requests\n if (duration > this.slowRequestThreshold) {\n metadata.slowRequest = true;\n }\n\n const message = metadata.slowRequest\n ? `SLOW ${request.method} ${request.url} ${statusCode} - ${duration}ms`\n : `${request.method} ${request.url} ${statusCode} - ${duration}ms`;\n\n this.logger.logWithMetadata(logLevel, message, metadata);\n } catch (error) {\n this.logger.error('Failed to log HTTP response', (error as Error).stack);\n }\n }\n\n private logError(request: FastifyRequest, response: FastifyReply, duration: number, error: unknown): void {\n try {\n const correlationContext = getCorrelationContext();\n const err = error as {\n name?: string;\n message?: string;\n detail?: string;\n status?: number;\n statusCode?: number;\n stack?: string;\n response?: unknown;\n };\n const statusCode = err.status ?? err.statusCode ?? response.statusCode ?? 500;\n const errorMessage = err.message || err.detail || 'Unknown error';\n\n const metadata: LogMetadata = {\n type: 'http_error',\n method: request.method,\n url: request.url,\n statusCode,\n duration,\n correlationId: correlationContext?.correlationId,\n errorName: err.name || 'Error',\n errorMessage,\n };\n\n if (err.stack) {\n metadata.trace = err.stack;\n }\n\n if (err.response) {\n metadata.errorDetails = err.response;\n }\n\n const message = `ERROR ${request.method} ${request.url} ${statusCode} - ${errorMessage}`;\n this.logger.logWithMetadata('error', message, metadata);\n } catch (loggingError) {\n this.logger.error('Failed to log HTTP error', (loggingError as Error).stack);\n }\n }\n}\n","import { Injectable, type Logger, type LoggerService as NestLoggerService, Optional } from '@nestjs/common';\nimport { createLogger, format, type LoggerOptions, transports, type Logger as WinstonLogger } from 'winston';\nimport DailyRotateFile from 'winston-daily-rotate-file';\nimport type { LoggerModuleOptions, LogLevel, LogMetadata } from '../types';\nimport { getCorrelationContext } from '../utils';\n\nexport type LogMessage = string | Error | object;\n\n@Injectable()\nexport class LoggerService implements NestLoggerService {\n private readonly activeLogger: NestLoggerService | WinstonLogger;\n private readonly options: LoggerModuleOptions;\n private context?: string;\n\n constructor(\n @Optional() options: LoggerModuleOptions = {},\n @Optional() private readonly defaultLogger?: Logger,\n ) {\n this.options = options;\n const provider = options.provider ?? 'winston';\n\n if (provider === 'default') {\n if (!this.defaultLogger) {\n throw new Error('LoggerService: Default Logger not provided');\n }\n this.activeLogger = this.defaultLogger;\n } else {\n this.activeLogger = this.createWinstonLogger(options);\n }\n }\n\n // Creates a Winston logger instance with inline transports and format configuration\n private createWinstonLogger(opts: LoggerModuleOptions): WinstonLogger {\n const level = opts.level ?? 'debug';\n const logFormat = opts.format ?? 'text';\n\n // Base formatters\n // Winston automatically merges metadata into the info object, so all properties\n // (context, correlationId, etc.) are already at the top level\n const baseFormatters = [format.timestamp({ format: 'YYYY-MM-DDTHH:mm:ss.SSSZ' }), format.errors({ stack: true })];\n\n // Console transport\n const consoleTransport =\n logFormat === 'json'\n ? new transports.Console({\n level,\n format: format.combine(...baseFormatters, format.json()),\n })\n : new transports.Console({\n level,\n format: format.combine(\n ...baseFormatters,\n format.printf((info) => {\n const { timestamp, level, message, context, correlationId, trace } = info;\n const parts = [\n timestamp,\n level.toUpperCase().padEnd(7),\n correlationId ? `[${correlationId.toString().slice(-6)}]` : '',\n context ? `[${context}]` : '',\n message,\n ].filter(Boolean);\n let output = parts.join(' ');\n\n // Append stack trace on new line if present\n if (trace) {\n output += `\\n${trace}`;\n }\n\n return output;\n }),\n format.colorize({ all: true }),\n ),\n });\n\n const winstonTransports: (InstanceType<typeof transports.Console> | DailyRotateFile)[] = [consoleTransport];\n\n // File transports\n if (opts.enableFileLogger) {\n const filePath = opts.filePath ?? './logs';\n const maxFiles = opts.maxFiles ?? '14d';\n\n winstonTransports.push(\n new DailyRotateFile({\n level,\n filename: `${filePath}/%DATE%-combined.log`,\n datePattern: 'YYYY-MM-DD',\n maxSize: '20m',\n maxFiles,\n format: format.combine(format.timestamp(), format.json()),\n }),\n new DailyRotateFile({\n level: 'error',\n filename: `${filePath}/%DATE%-error.log`,\n datePattern: 'YYYY-MM-DD',\n maxSize: '20m',\n maxFiles,\n format: format.combine(format.timestamp(), format.json()),\n }),\n );\n }\n\n const config: LoggerOptions = {\n level,\n transports: winstonTransports,\n exitOnError: false,\n };\n\n if (opts.defaultMeta || opts.appName) {\n config.defaultMeta = {\n ...opts.defaultMeta,\n appName: opts.appName,\n environment: opts.environment,\n };\n }\n\n return createLogger(config);\n }\n\n // NestJS LoggerService interface methods\n log(message: LogMessage, context?: string): void {\n this._log('log', message, context);\n }\n\n error(message: LogMessage, trace?: string, context?: string): void {\n this._log('error', message, context, trace);\n }\n\n warn(message: LogMessage, context?: string): void {\n this._log('warn', message, context);\n }\n\n debug(message: LogMessage, context?: string): void {\n this._log('debug', message, context);\n }\n\n verbose(message: LogMessage, context?: string): void {\n this._log('verbose', message, context);\n }\n\n setContext(context: string): void {\n this.context = context;\n }\n\n // Dispatches a log entry to either the Winston or NestJS logger implementation\n private _log(level: LogLevel, message: LogMessage, context?: string, trace?: string): void {\n const ctx = context ?? this.context;\n\n // Check if Winston logger by duck typing\n if ('format' in this.activeLogger && 'transports' in this.activeLogger) {\n // Winston logger path\n const winstonLogger = this.activeLogger as WinstonLogger;\n const winstonLevel = level === 'log' ? 'info' : level;\n const formattedMessage = this.formatMessage(message);\n const metadata = this.enrichMetadata({}, ctx, trace);\n // Winston merges all properties into the info object when using object syntax\n winstonLogger.log({ level: winstonLevel, message: formattedMessage, ...metadata });\n } else {\n // NestJS logger path\n const nestLogger = this.activeLogger as Logger;\n if (level === 'error' && trace) {\n ctx ? nestLogger.error(message, trace, ctx) : nestLogger.error(message, trace);\n } else if (level === 'log') {\n ctx ? nestLogger.log(message, ctx) : nestLogger.log(message);\n } else if (level === 'warn') {\n ctx ? nestLogger.warn(message, ctx) : nestLogger.warn(message);\n } else if (level === 'debug' && nestLogger.debug) {\n ctx ? nestLogger.debug(message, ctx) : nestLogger.debug(message);\n } else if (level === 'verbose' && nestLogger.verbose) {\n ctx ? nestLogger.verbose(message, ctx) : nestLogger.verbose(message);\n }\n }\n }\n\n // Logs a message with custom metadata fields (Winston only)\n logWithMetadata(level: LogLevel, message: LogMessage, metadata?: LogMetadata, context?: string): void {\n const ctx = context ?? this.context;\n\n // Check if Winston logger by duck typing\n if ('format' in this.activeLogger && 'transports' in this.activeLogger) {\n const winstonLogger = this.activeLogger as WinstonLogger;\n const winstonLevel = level === 'log' ? 'info' : level;\n // const enriched = this.enrichMetadata(metadata, ctx);\n // Winston merges all properties into the info object when using object syntax\n winstonLogger.log({ level: winstonLevel, message: this.formatMessage(message), ...metadata });\n } else {\n // Fallback for default logger\n const messageWithMeta = metadata ? `${message} ${JSON.stringify(metadata)}` : message;\n this[level](messageWithMeta, ctx);\n }\n }\n\n private formatMessage(message: LogMessage): string {\n if (message instanceof Error) return message.message;\n if (typeof message === 'object' && message !== null) {\n try {\n return JSON.stringify(message);\n } catch {\n return String(message);\n }\n }\n return String(message);\n }\n\n // Enriches metadata with correlation context from AsyncLocalStorage\n private enrichMetadata(metadata: LogMetadata = {}, context?: string, trace?: string): LogMetadata {\n const enriched: LogMetadata = { ...metadata };\n\n if (context) enriched.context = context;\n\n const correlationContext = getCorrelationContext();\n if (correlationContext) {\n if (correlationContext.correlationId) enriched.correlationId = correlationContext.correlationId;\n for (const [key, value] of Object.entries(correlationContext)) {\n if (key !== 'correlationId') {\n enriched[key] = value;\n }\n }\n }\n\n if (trace) enriched.trace = trace;\n\n return enriched;\n }\n\n child(context: string): LoggerService {\n const childLogger = new LoggerService(this.options, this.defaultLogger);\n childLogger.setContext(context);\n return childLogger;\n }\n}\n","import { AsyncLocalStorage } from 'node:async_hooks';\nimport { randomUUID } from 'node:crypto';\nimport type { FastifyReply } from 'fastify';\nimport type { CorrelationContext } from '../types';\n\n// ============================================================================\n// Async Context Management (AsyncLocalStorage)\n// ============================================================================\n\nexport const correlationStorage = new AsyncLocalStorage<CorrelationContext>();\n\n// Returns the current correlation context from AsyncLocalStorage\nexport function getCorrelationContext(): CorrelationContext | undefined {\n return correlationStorage.getStore();\n}\n\n// Runs a callback within the given correlation context\nexport function runWithCorrelationContext<T>(context: CorrelationContext, callback: () => T): T {\n return correlationStorage.run(context, callback);\n}\n\n// Updates the current correlation context with new values\nexport function updateCorrelationContext(updates: Partial<CorrelationContext>): void {\n const context = correlationStorage.getStore();\n if (context) {\n Object.assign(context, updates);\n }\n}\n\n// ============================================================================\n// Correlation ID Management\n// ============================================================================\n\nexport const DEFAULT_CORRELATION_HEADER = 'x-correlation-id';\n\n// Generates a new UUID v4 correlation ID for the current request\nexport function generateCorrelationId(): string {\n return randomUUID();\n}\n\n// Adds the correlation ID to Fastify response headers\nexport function addCorrelationIdToResponse(\n reply: FastifyReply,\n correlationId: string,\n headerName: string = DEFAULT_CORRELATION_HEADER,\n): void {\n if (typeof reply.header === 'function') {\n reply.header(headerName, correlationId);\n } else if (reply.raw && typeof reply.raw.setHeader === 'function') {\n reply.raw.setHeader(headerName, correlationId);\n }\n}\n","import {\n type DynamicModule,\n Global,\n Logger,\n type MiddlewareConsumer,\n Module,\n type NestModule,\n type Provider,\n} from '@nestjs/common';\nimport { HttpLoggerInterceptor } from './interceptors/http-logger.interceptor';\nimport { CorrelationIdMiddleware } from './middleware/correlation-id.middleware';\nimport { LoggerService } from './services/logger.service';\nimport type { LoggerModuleAsyncOptions, LoggerModuleOptions, LoggerOptionsFactory } from './types';\n\n// ============================================================================\n// Constants (inline from constants.ts)\n// ============================================================================\n\nexport const LOGGER_MODULE_OPTIONS = Symbol('LOGGER_MODULE_OPTIONS');\n\nconst DEFAULT_LOGGER_OPTIONS = {\n provider: 'winston' as const,\n enableCorrelationId: true,\n enableHttpLogger: true,\n filePath: './logs',\n maxFiles: '14d',\n} as const;\n\n// ============================================================================\n// Environment Presets (NEW - replaces process.env auto-detection)\n// ============================================================================\n\nconst ENVIRONMENT_PRESETS: Record<string, Partial<LoggerModuleOptions>> = {\n development: {\n provider: 'winston',\n level: 'debug',\n format: 'text',\n enableFileLogger: false,\n enableCorrelationId: true,\n enableHttpLogger: true,\n httpLogger: {\n enableRequestLog: true,\n enableResponseLog: true,\n slowRequestThreshold: 1000, // 1 second - lower threshold for dev\n },\n },\n\n staging: {\n provider: 'winston',\n level: 'log',\n format: 'json',\n enableFileLogger: true,\n enableCorrelationId: true,\n enableHttpLogger: true,\n httpLogger: {\n enableRequestLog: true,\n enableResponseLog: true,\n slowRequestThreshold: 3000, // 3 seconds\n },\n },\n\n production: {\n provider: 'winston',\n level: 'warn',\n format: 'json',\n enableFileLogger: true,\n enableCorrelationId: true,\n enableHttpLogger: true,\n httpLogger: {\n enableRequestLog: false, // Reduce noise in production\n enableResponseLog: true,\n slowRequestThreshold: 5000, // 5 seconds - higher threshold for prod\n },\n },\n\n test: {\n provider: 'winston',\n level: 'error',\n format: 'json',\n enableFileLogger: false,\n enableCorrelationId: false,\n enableHttpLogger: false,\n },\n} as const;\n\n// ============================================================================\n// Configuration Merging (refactored to use presets instead of process.env)\n// ============================================================================\n\n// Merges user-provided options with default and environment preset values\nfunction mergeWithDefaults(options: LoggerModuleOptions = {}): LoggerModuleOptions {\n // Select preset based on explicit environment option (defaults to development)\n const preset = options.environment\n ? (ENVIRONMENT_PRESETS[options.environment] ?? ENVIRONMENT_PRESETS.development)\n : ENVIRONMENT_PRESETS.development;\n\n // Filter out undefined values from user options to avoid overriding preset defaults\n const filteredOptions = Object.fromEntries(Object.entries(options).filter(([_, value]) => value !== undefined));\n\n // Handle nested httpLogger object - merge with preset httpLogger if both exist\n if (filteredOptions.httpLogger && preset?.httpLogger) {\n filteredOptions.httpLogger = {\n ...preset.httpLogger,\n ...Object.fromEntries(Object.entries(filteredOptions.httpLogger).filter(([_, value]) => value !== undefined)),\n };\n }\n\n // Merge: base defaults < preset < user options (with undefined values removed)\n const merged = {\n ...DEFAULT_LOGGER_OPTIONS,\n ...preset,\n ...filteredOptions,\n };\n\n return merged;\n}\n\n// ============================================================================\n// Provider Factories (inline from logging.providers.ts)\n// ============================================================================\n\n// Creates the default NestJS Logger provider with optional log level configuration\nfunction createDefaultLoggerProvider(options: LoggerModuleOptions): Provider {\n return {\n provide: Logger,\n useFactory: () => {\n const logger = new Logger();\n\n // Set log levels if specified and method exists\n if (options.level) {\n const levels = getLevelsUpTo(options.level);\n (logger as { setLogLevels?: (levels: NestLogLevel[]) => void }).setLogLevels?.(levels);\n }\n\n return logger;\n },\n };\n}\n\n// Builds all logger providers for the module based on merged configuration\nfunction createLoggerProviders(options: LoggerModuleOptions = {}): Provider[] {\n // Merge user options with preset defaults\n const mergedOptions = mergeWithDefaults(options);\n\n // Base providers (always included)\n const providers: Provider[] = [\n // Options provider\n {\n provide: LOGGER_MODULE_OPTIONS,\n useValue: mergedOptions,\n },\n ];\n\n // Default logger provider (only if using default provider)\n if (mergedOptions.provider === 'default') {\n providers.push(createDefaultLoggerProvider(mergedOptions));\n }\n\n // Unified LoggerService facade (always included)\n providers.push({\n provide: LoggerService,\n useFactory: (opts: LoggerModuleOptions, defaultLogger?: Logger) => {\n return new LoggerService(opts, defaultLogger);\n },\n inject: [LOGGER_MODULE_OPTIONS, { token: Logger, optional: true }],\n });\n\n // Correlation ID middleware\n providers.push({\n provide: CorrelationIdMiddleware,\n useFactory: () => {\n return new CorrelationIdMiddleware({\n includeInResponse: true,\n responseHeader: 'x-correlation-id',\n });\n },\n });\n\n // HTTP logger interceptor\n providers.push({\n provide: HttpLoggerInterceptor,\n useFactory: (logger: LoggerService, opts: LoggerModuleOptions) => {\n // Use detailed httpLogger config if provided, otherwise fall back to simple enableHttpLogger\n const httpLoggerOptions = opts.httpLogger ?? {\n enableRequestLog: opts.enableHttpLogger,\n enableResponseLog: opts.enableHttpLogger,\n };\n return new HttpLoggerInterceptor(logger, httpLoggerOptions);\n },\n inject: [LoggerService, LOGGER_MODULE_OPTIONS],\n });\n\n return providers;\n}\n\ntype NestLogLevel = 'error' | 'warn' | 'log' | 'debug' | 'verbose';\n\n// Returns all NestJS log levels up to and including the specified level\nfunction getLevelsUpTo(level: string): NestLogLevel[] {\n const allLevels: NestLogLevel[] = ['error', 'warn', 'log', 'debug', 'verbose'];\n\n // Check if level is a valid NestLogLevel\n const isValidLevel = (l: string): l is NestLogLevel => allLevels.includes(l as NestLogLevel);\n\n if (!isValidLevel(level)) {\n return ['error', 'warn', 'log'];\n }\n\n const levelIndex = allLevels.indexOf(level);\n return allLevels.slice(0, levelIndex + 1);\n}\n\n// ============================================================================\n// Logger Module\n// ============================================================================\n\n@Global()\n@Module({})\nexport class LoggerModule implements NestModule {\n // Configures the logger module with static options and environment preset\n static forRoot(options: LoggerModuleOptions = {}): DynamicModule {\n const providers = createLoggerProviders(options);\n\n return {\n module: LoggerModule,\n providers,\n exports: [LoggerService, CorrelationIdMiddleware, HttpLoggerInterceptor, LOGGER_MODULE_OPTIONS],\n };\n }\n\n // Configures the logger module with async options (useFactory, useClass, useExisting)\n static forRootAsync<T extends unknown[] = unknown[]>(options: LoggerModuleAsyncOptions<T>): DynamicModule {\n const asyncProviders = LoggerModule.createAsyncProviders(options as LoggerModuleAsyncOptions<unknown[]>);\n\n return {\n module: LoggerModule,\n imports: options.imports || [],\n providers: [\n ...asyncProviders,\n // Default logger provider\n {\n provide: Logger,\n useFactory: (opts: LoggerModuleOptions) => {\n if (opts.provider === 'default') {\n const logger = new Logger();\n if (opts.level) {\n const levels = getLevelsUpTo(opts.level);\n (logger as { setLogLevels?: (levels: NestLogLevel[]) => void }).setLogLevels?.(levels);\n }\n return logger;\n }\n return null;\n },\n inject: [LOGGER_MODULE_OPTIONS],\n },\n // Unified logger service\n {\n provide: LoggerService,\n useFactory: (opts: LoggerModuleOptions, defaultLogger?: Logger) => {\n return new LoggerService(opts, defaultLogger);\n },\n inject: [LOGGER_MODULE_OPTIONS, { token: Logger, optional: true }],\n },\n // Correlation ID middleware\n {\n provide: CorrelationIdMiddleware,\n useFactory: () => {\n return new CorrelationIdMiddleware({\n includeInResponse: true,\n responseHeader: 'x-correlation-id',\n });\n },\n },\n // HTTP logger interceptor\n {\n provide: HttpLoggerInterceptor,\n useFactory: (logger: LoggerService, opts: LoggerModuleOptions) => {\n // Use detailed httpLogger config if provided, otherwise fall back to simple enableHttpLogger\n const httpLoggerOptions = opts.httpLogger ?? {\n enableRequestLog: opts.enableHttpLogger,\n enableResponseLog: opts.enableHttpLogger,\n };\n return new HttpLoggerInterceptor(logger, httpLoggerOptions);\n },\n inject: [LoggerService, LOGGER_MODULE_OPTIONS],\n },\n ],\n exports: [LoggerService, CorrelationIdMiddleware, HttpLoggerInterceptor, LOGGER_MODULE_OPTIONS],\n };\n }\n\n // Middleware registration is handled globally in main.ts via Fastify hooks\n configure(_consumer: MiddlewareConsumer): void {\n // Middleware is registered globally in main.ts using Fastify's addHook('onRequest')\n // This avoids DI issues with the middleware constructor\n }\n\n // Creates async providers for dynamic module configuration\n private static createAsyncProviders(options: LoggerModuleAsyncOptions<unknown[]>): Provider[] {\n if (options.useFactory) {\n return [LoggerModule.createAsyncOptionsProvider(options)];\n }\n\n const providers: Provider[] = [LoggerModule.createAsyncOptionsProvider(options)];\n\n if (options.useClass) {\n providers.push({\n provide: options.useClass,\n useClass: options.useClass,\n });\n }\n\n return providers;\n }\n\n // Creates the DI provider that resolves and merges async logger options\n private static createAsyncOptionsProvider(options: LoggerModuleAsyncOptions<unknown[]>): Provider {\n if (options.useFactory) {\n return {\n provide: LOGGER_MODULE_OPTIONS,\n useFactory: async (...args: unknown[]) => {\n const userOptions = await options.useFactory?.(...args);\n return mergeWithDefaults(userOptions);\n },\n inject: options.inject || [],\n };\n }\n\n if (options.useClass) {\n return {\n provide: LOGGER_MODULE_OPTIONS,\n useFactory: async (optionsFactory: LoggerOptionsFactory) => {\n const userOptions = await optionsFactory.createLoggerOptions();\n return mergeWithDefaults(userOptions);\n },\n inject: [options.useClass],\n };\n }\n\n if (options.useExisting) {\n return {\n provide: LOGGER_MODULE_OPTIONS,\n useFactory: async (optionsFactory: LoggerOptionsFactory) => {\n const userOptions = await optionsFactory.createLoggerOptions();\n return mergeWithDefaults(userOptions);\n },\n inject: [options.useExisting],\n };\n }\n\n throw new Error('LoggerModule.forRootAsync() requires one of: useFactory, useClass, or useExisting');\n }\n}\n","import { Injectable, type NestMiddleware } from '@nestjs/common';\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport {\n addCorrelationIdToResponse,\n correlationStorage,\n DEFAULT_CORRELATION_HEADER,\n generateCorrelationId,\n runWithCorrelationContext,\n} from '../utils';\n\nexport interface CorrelationIdMiddlewareOptions {\n includeInResponse?: boolean;\n responseHeader?: string;\n}\n\n@Injectable()\nexport class CorrelationIdMiddleware implements NestMiddleware {\n private readonly includeInResponse: boolean;\n private readonly responseHeader: string;\n\n constructor(options: CorrelationIdMiddlewareOptions = {}) {\n this.includeInResponse = options.includeInResponse ?? true;\n this.responseHeader = options.responseHeader ?? DEFAULT_CORRELATION_HEADER;\n }\n\n // Generates and stores a correlation ID for the incoming request\n use(_req: FastifyRequest, reply: FastifyReply, next: () => void): void {\n // Generate new correlation ID for this request\n const correlationId = generateCorrelationId();\n\n // Add to response headers if enabled\n if (this.includeInResponse) {\n addCorrelationIdToResponse(reply, correlationId, this.responseHeader);\n }\n\n // Run the rest of the request in AsyncLocalStorage context\n runWithCorrelationContext({ correlationId }, () => {\n next();\n });\n }\n\n // Fastify onRequest hook that initializes correlation context in AsyncLocalStorage\n async onRequest(_req: FastifyRequest, reply: FastifyReply): Promise<void> {\n // Generate new correlation ID for this request\n const correlationId = generateCorrelationId();\n\n // Add to response headers if enabled\n if (this.includeInResponse) {\n addCorrelationIdToResponse(reply, correlationId, this.responseHeader);\n }\n\n // Store in AsyncLocalStorage for the request lifecycle\n // Note: We don't wrap in runWithCorrelationContext here because\n // Fastify's async context tracking handles it automatically\n const store = correlationStorage.getStore();\n if (!store) {\n // Initialize new store\n correlationStorage.enterWith({ correlationId });\n }\n }\n}\n","import { createParamDecorator, type ExecutionContext, InternalServerErrorException } from '@nestjs/common';\nimport { NatsContext } from '@nestjs/microservices';\nimport { parseNatsHeaders } from '../nats-context';\n\n// Extracts parsed NatsContext from NATS message headers\nexport const RpcNatsHeaders = createParamDecorator((_data: unknown, ctx: ExecutionContext) => {\n const rpcCtx = ctx.switchToRpc().getContext<NatsContext>();\n return parseNatsHeaders(rpcCtx.getHeaders());\n});\n\n// Extracts buId from NATS headers — throws if missing or empty\nexport const RpcBuId = createParamDecorator((_data: unknown, ctx: ExecutionContext): string => {\n const rpcCtx = ctx.switchToRpc().getContext<NatsContext>();\n const headers = parseNatsHeaders(rpcCtx.getHeaders());\n if (!headers?.buId) throw new InternalServerErrorException('Missing buId in NATS headers.');\n return headers.buId;\n});\n\n// Extracts buCurrencyCode from NATS headers — throws if missing or empty\nexport const RpcBuCurrencyCode = createParamDecorator((_data: unknown, ctx: ExecutionContext): string => {\n const rpcCtx = ctx.switchToRpc().getContext<NatsContext>();\n const headers = parseNatsHeaders(rpcCtx.getHeaders());\n if (!headers?.buCurrencyCode) throw new InternalServerErrorException('Missing buCurrencyCode in NATS headers.');\n return headers.buCurrencyCode;\n});\n","export interface NatsHeaders {\n orgId: string;\n userId: string;\n buId: string;\n buTimezone: string;\n buCurrencyCode: string;\n buAncestorIds: string[];\n buDescendantIds: string[];\n}\n\n// Header keys for NATS context transport\nexport const NATS_HEADER_KEYS = {\n ORG_ID: 'x-org-id',\n USER_ID: 'x-user-id',\n BU_ID: 'x-bu-id',\n BU_TIMEZONE: 'x-bu-timezone',\n BU_CURRENCY_CODE: 'x-bu-currency-code',\n BU_ANCESTOR_IDS: 'x-bu-ancestor-ids',\n BU_DESCENDANT_IDS: 'x-bu-descendant-ids',\n} as const;\n\n// Reads a header value from either a plain object or a NATS MsgHdrsImpl\nfunction getHeader(headers: unknown, key: string): string | undefined {\n if (!headers) return undefined;\n // MsgHdrsImpl uses .get(), plain objects use bracket access\n if (typeof (headers as { get?: unknown }).get === 'function') {\n const val = (headers as { get(key: string): string[] }).get(key);\n return Array.isArray(val) ? val[0] : (val as string | undefined);\n }\n return (headers as Record<string, string>)[key];\n}\n\n// Parses NATS message headers into a NatsHeaders object\nexport function parseNatsHeaders(headers: unknown): NatsHeaders | null {\n if (!headers) return null;\n\n const orgId = getHeader(headers, NATS_HEADER_KEYS.ORG_ID);\n const userId = getHeader(headers, NATS_HEADER_KEYS.USER_ID);\n const buId = getHeader(headers, NATS_HEADER_KEYS.BU_ID);\n\n if (!orgId || !userId || !buId) return null;\n\n return {\n orgId,\n userId,\n buId,\n buTimezone: getHeader(headers, NATS_HEADER_KEYS.BU_TIMEZONE) || 'UTC',\n buCurrencyCode: getHeader(headers, NATS_HEADER_KEYS.BU_CURRENCY_CODE) || '',\n buAncestorIds: JSON.parse(getHeader(headers, NATS_HEADER_KEYS.BU_ANCESTOR_IDS) || '[]'),\n buDescendantIds: JSON.parse(getHeader(headers, NATS_HEADER_KEYS.BU_DESCENDANT_IDS) || '[]'),\n };\n}\n","import { type DynamicModule, Global, Logger, Module, type OnModuleDestroy, type Provider } from '@nestjs/common';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\nimport type { ClientProxy } from '@nestjs/microservices';\nimport { ClientProxyFactory, Transport } from '@nestjs/microservices';\nimport { NATS_CONTEXT_RESOLVER, NATS_MODULE_OPTIONS } from './constants';\nimport type {\n NatsMicroserviceModuleAsyncOptions,\n NatsModuleBaseOptions,\n NatsRootModuleAsyncOptions,\n NatsRootModuleOptions,\n} from './nats-client.interfaces';\nimport { NATS_CLIENTS, NatsClientService } from './nats-client.service';\nimport { NATS_MS_CLIENTS, NatsMicroserviceClientService } from './nats-microservice-client.service';\n\nconst NATS_MS_OPTIONS = Symbol('NATS_MS_OPTIONS');\n\n@Global()\n@Module({})\nexport class NatsClientModule implements OnModuleDestroy {\n private static readonly logger = new Logger(NatsClientModule.name);\n private static allClients: ClientProxy[] = [];\n\n async onModuleDestroy() {\n await Promise.all(NatsClientModule.allClients.map((c) => c.close()));\n NatsClientModule.allClients = [];\n }\n\n // Builds a Map of named NATS ClientProxy instances\n private static buildClients(options: NatsModuleBaseOptions, natsUrl: string): Map<string, ClientProxy> {\n const clients = new Map<string, ClientProxy>();\n\n for (const svc of options.services) {\n const proxy = ClientProxyFactory.create({\n transport: Transport.NATS,\n options: { servers: [natsUrl] },\n });\n clients.set(svc.name, proxy);\n NatsClientModule.allClients.push(proxy);\n NatsClientModule.logger.log(`Registered NATS client: ${svc.name} → ${natsUrl}`);\n }\n\n return clients;\n }\n\n // Gateway mode — request-scoped, resolves context from sessionInfo via callback\n static forRoot(asyncOptions: NatsRootModuleAsyncOptions): DynamicModule {\n const optionsProvider: Provider = {\n provide: NATS_MODULE_OPTIONS,\n useFactory: asyncOptions.useFactory,\n inject: asyncOptions.inject || [],\n };\n\n const resolverProvider: Provider = {\n provide: NATS_CONTEXT_RESOLVER,\n useFactory: (options: NatsRootModuleOptions) => options.contextResolver,\n inject: [NATS_MODULE_OPTIONS],\n };\n\n const clientsProvider: Provider = {\n provide: NATS_CLIENTS,\n useFactory: (options: NatsRootModuleOptions, config: ConfigService): Map<string, ClientProxy> => {\n const natsUrl = options.natsUrl ?? config.get<string>('NATS_URL', 'nats://localhost:4222');\n return NatsClientModule.buildClients(options, natsUrl);\n },\n inject: [NATS_MODULE_OPTIONS, ConfigService],\n };\n\n return {\n module: NatsClientModule,\n imports: [ConfigModule, ...(asyncOptions.imports ?? [])],\n providers: [optionsProvider, resolverProvider, clientsProvider, NatsClientService],\n exports: [NatsClientService],\n };\n }\n\n // Microservice mode — singleton, forwards context from incoming NATS payload\n static forMicroservice(asyncOptions: NatsMicroserviceModuleAsyncOptions): DynamicModule {\n const optionsProvider: Provider = {\n provide: NATS_MS_OPTIONS,\n useFactory: asyncOptions.useFactory,\n inject: asyncOptions.inject || [],\n };\n\n const clientsProvider: Provider = {\n provide: NATS_MS_CLIENTS,\n useFactory: (options: NatsModuleBaseOptions, config: ConfigService): Map<string, ClientProxy> => {\n const natsUrl = options.natsUrl ?? config.get<string>('NATS_URL', 'nats://localhost:4222');\n return NatsClientModule.buildClients(options, natsUrl);\n },\n inject: [NATS_MS_OPTIONS, ConfigService],\n };\n\n return {\n module: NatsClientModule,\n imports: [ConfigModule, ...(asyncOptions.imports ?? [])],\n providers: [optionsProvider, clientsProvider, NatsMicroserviceClientService],\n exports: [NatsMicroserviceClientService],\n };\n }\n}\n","export const NATS_MODULE_OPTIONS = Symbol('NATS_MODULE_OPTIONS');\nexport const NATS_CONTEXT_RESOLVER = Symbol('NATS_CONTEXT_RESOLVER');\n","import { Inject, Injectable, Scope } from '@nestjs/common';\nimport { REQUEST } from '@nestjs/core';\nimport type { ClientProxy } from '@nestjs/microservices';\nimport { NatsRecordBuilder } from '@nestjs/microservices';\nimport type { FastifyRequest } from 'fastify';\nimport { headers as natsHeaders } from 'nats';\nimport { NATS_CONTEXT_RESOLVER } from './constants';\nimport type { ContextResolverFn } from './nats-client.interfaces';\nimport { NATS_HEADER_KEYS, type NatsHeaders } from './nats-context';\n\nexport const NATS_CLIENTS = Symbol('NATS_CLIENTS');\n\n@Injectable({ scope: Scope.REQUEST })\nexport class NatsClientService {\n private cachedContext: NatsHeaders | null = null;\n\n constructor(\n @Inject(REQUEST) private readonly request: FastifyRequest,\n @Inject(NATS_CONTEXT_RESOLVER) private readonly contextResolver: ContextResolverFn,\n @Inject(NATS_CLIENTS) private readonly clients: Map<string, ClientProxy>,\n ) {}\n\n // Sends a message to a named microservice with NatsHeaders as NATS headers\n async send<T>(service: string, cmd: string, data?: object): Promise<T> {\n const client = this.clients.get(service);\n if (!client) {\n throw new Error(\n `NATS service \"${service}\" is not registered. Available: [${[...this.clients.keys()].join(', ')}]`,\n );\n }\n\n if (!this.cachedContext) {\n const sessionInfo = this.request.sessionInfo;\n if (!sessionInfo) {\n throw new Error('No sessionInfo on request — is the auth guard active?');\n }\n this.cachedContext = await this.contextResolver(sessionInfo);\n }\n\n const headers = contextToHeaders(this.cachedContext);\n const record = new NatsRecordBuilder(data ?? {}).setHeaders(headers).build();\n\n return client.send<T>({ cmd }, record).toPromise() as Promise<T>;\n }\n}\n\n// Converts NatsHeaders to a NATS MsgHdrs object for NATS transport\nfunction contextToHeaders(ctx: NatsHeaders): import('nats').MsgHdrs {\n const hdrs = natsHeaders();\n hdrs.set(NATS_HEADER_KEYS.ORG_ID, ctx.orgId);\n hdrs.set(NATS_HEADER_KEYS.USER_ID, ctx.userId);\n hdrs.set(NATS_HEADER_KEYS.BU_ID, ctx.buId);\n hdrs.set(NATS_HEADER_KEYS.BU_TIMEZONE, ctx.buTimezone);\n hdrs.set(NATS_HEADER_KEYS.BU_CURRENCY_CODE, ctx.buCurrencyCode);\n hdrs.set(NATS_HEADER_KEYS.BU_ANCESTOR_IDS, JSON.stringify(ctx.buAncestorIds));\n hdrs.set(NATS_HEADER_KEYS.BU_DESCENDANT_IDS, JSON.stringify(ctx.buDescendantIds));\n return hdrs;\n}\n","import { Inject, Injectable } from '@nestjs/common';\nimport type { ClientProxy } from '@nestjs/microservices';\nimport { NatsRecordBuilder } from '@nestjs/microservices';\nimport { NATS_HEADER_KEYS, type NatsHeaders } from './nats-context';\n\nexport const NATS_MS_CLIENTS = Symbol('NATS_MS_CLIENTS');\n\n@Injectable()\nexport class NatsMicroserviceClientService {\n constructor(@Inject(NATS_MS_CLIENTS) private readonly clients: Map<string, ClientProxy>) {}\n\n // Forwards a message to another microservice with NatsHeaders\n async send<T>(service: string, cmd: string, natsHeaders: NatsHeaders, data?: object): Promise<T> {\n const client = this.clients.get(service);\n if (!client) {\n throw new Error(\n `NATS service \"${service}\" is not registered. Available: [${[...this.clients.keys()].join(', ')}]`,\n );\n }\n\n const headers: Record<string, string> = {\n [NATS_HEADER_KEYS.ORG_ID]: natsHeaders.orgId,\n [NATS_HEADER_KEYS.USER_ID]: natsHeaders.userId,\n [NATS_HEADER_KEYS.BU_ID]: natsHeaders.buId,\n [NATS_HEADER_KEYS.BU_TIMEZONE]: natsHeaders.buTimezone,\n [NATS_HEADER_KEYS.BU_ANCESTOR_IDS]: JSON.stringify(natsHeaders.buAncestorIds),\n [NATS_HEADER_KEYS.BU_DESCENDANT_IDS]: JSON.stringify(natsHeaders.buDescendantIds),\n };\n\n const record = new NatsRecordBuilder(data ?? {}).setHeaders(headers).build();\n return client.send<T>({ cmd }, record).toPromise() as Promise<T>;\n }\n}\n","import { Module } from '@nestjs/common';\nimport { AppController } from './controllers/app.controller';\nimport { CsrfController } from './controllers/csrf.controller';\nimport { AppService } from './services/app.service';\n\n@Module({\n controllers: [AppController, CsrfController],\n providers: [AppService],\n})\nexport class RootModule {}\n","import { Controller, Get } from '@nestjs/common';\nimport { ApiTags } from '@nestjs/swagger';\nimport { Public } from '../../auth/decorators/public.decorator';\nimport { ApiHealthCheck } from '../docs/app.docs';\nimport { AppService } from '../services/app.service';\n\n@ApiTags('Health')\n@Controller()\nexport class AppController {\n constructor(private readonly appService: AppService) {}\n\n // Returns a welcome message indicating the API is running\n @Get()\n @Public()\n @ApiHealthCheck()\n getHello(): string {\n return this.appService.getHello();\n }\n}\n","import { applyDecorators } from '@nestjs/common';\nimport { ApiOperation, ApiResponse } from '@nestjs/swagger';\n\nexport function ApiHealthCheck() {\n return applyDecorators(\n ApiOperation({ summary: 'Health check endpoint' }),\n ApiResponse({\n status: 200,\n description: 'Returns a welcome message indicating the API is running',\n type: String,\n }),\n );\n}\n","import { Injectable } from '@nestjs/common';\n\n@Injectable()\nexport class AppService {\n // Returns the API welcome message\n getHello(): string {\n return `Hello World!`;\n }\n}\n","import { Controller, Get, HttpCode, HttpStatus, Res } from '@nestjs/common';\nimport { ApiTags } from '@nestjs/swagger';\nimport type { FastifyReply } from 'fastify';\nimport { Public } from '../../auth/decorators/public.decorator';\nimport { ApiGetCsrfToken } from '../docs/csrf.docs';\n\n// Type augmentation for @fastify/csrf-protection — added by the consuming server at runtime\ntype FastifyReplyWithCsrf = FastifyReply & { generateCsrf(): string };\n\n@ApiTags('CSRF')\n@Controller('csrf')\nexport class CsrfController {\n // Generates a CSRF token via Fastify's csrf-protection plugin\n @Get('token')\n @Public()\n @HttpCode(HttpStatus.OK)\n @ApiGetCsrfToken()\n getToken(@Res({ passthrough: true }) reply: FastifyReply): { csrfToken: string } {\n const csrfToken = (reply as FastifyReplyWithCsrf).generateCsrf();\n return { csrfToken };\n }\n}\n","import { applyDecorators } from '@nestjs/common';\nimport { ApiOperation, ApiResponse } from '@nestjs/swagger';\n\nexport function ApiGetCsrfToken() {\n return applyDecorators(\n ApiOperation({\n summary: 'Get CSRF token',\n description:\n 'Generates and returns a CSRF token that must be included in all state-changing requests (POST, PUT, PATCH, DELETE). The token should be sent in the X-CSRF-Token header.',\n }),\n ApiResponse({\n status: 200,\n description: 'CSRF token generated successfully',\n schema: {\n type: 'object',\n properties: {\n csrfToken: {\n type: 'string',\n description: 'The CSRF token to use in subsequent requests',\n example: 'abc123xyz789',\n },\n },\n required: ['csrfToken'],\n },\n }),\n );\n}\n","// Returns the greatest common divisor of two integers using the Euclidean algorithm\nexport function gcd(a: number, b: number): number {\n return b === 0 ? a : gcd(b, a % b);\n}\n","const CALLING_CODE_TO_COUNTRY: Record<string, string> = {\n // 3-digit codes\n '355': 'AL',\n '213': 'DZ',\n '376': 'AD',\n '244': 'AO',\n '672': 'AQ',\n '374': 'AM',\n '297': 'AW',\n '994': 'AZ',\n '973': 'BH',\n '880': 'BD',\n '375': 'BY',\n '501': 'BZ',\n '229': 'BJ',\n '975': 'BT',\n '591': 'BO',\n '387': 'BA',\n '267': 'BW',\n '673': 'BN',\n '359': 'BG',\n '226': 'BF',\n '257': 'BI',\n '855': 'KH',\n '237': 'CM',\n '238': 'CV',\n '236': 'CF',\n '235': 'TD',\n '269': 'KM',\n '242': 'CG',\n '243': 'CD',\n '506': 'CR',\n '385': 'HR',\n '357': 'CY',\n '420': 'CZ',\n '253': 'DJ',\n '593': 'EC',\n '503': 'SV',\n '240': 'GQ',\n '291': 'ER',\n '372': 'EE',\n '251': 'ET',\n '679': 'FJ',\n '358': 'FI',\n '241': 'GA',\n '220': 'GM',\n '995': 'GE',\n '233': 'GH',\n '350': 'GI',\n '299': 'GL',\n '502': 'GT',\n '224': 'GN',\n '245': 'GW',\n '592': 'GY',\n '509': 'HT',\n '504': 'HN',\n '354': 'IS',\n '964': 'IQ',\n '353': 'IE',\n '972': 'IL',\n '225': 'CI',\n '962': 'JO',\n '254': 'KE',\n '686': 'KI',\n '965': 'KW',\n '996': 'KG',\n '856': 'LA',\n '371': 'LV',\n '961': 'LB',\n '266': 'LS',\n '231': 'LR',\n '218': 'LY',\n '423': 'LI',\n '370': 'LT',\n '352': 'LU',\n '389': 'MK',\n '261': 'MG',\n '265': 'MW',\n '960': 'MV',\n '223': 'ML',\n '356': 'MT',\n '692': 'MH',\n '222': 'MR',\n '230': 'MU',\n '262': 'YT',\n '691': 'FM',\n '373': 'MD',\n '377': 'MC',\n '976': 'MN',\n '382': 'ME',\n '258': 'MZ',\n '264': 'NA',\n '674': 'NR',\n '977': 'NP',\n '505': 'NI',\n '227': 'NE',\n '234': 'NG',\n '683': 'NU',\n '968': 'OM',\n '680': 'PW',\n '970': 'PS',\n '507': 'PA',\n '675': 'PG',\n '595': 'PY',\n '351': 'PT',\n '974': 'QA',\n '250': 'RW',\n '685': 'WS',\n '378': 'SM',\n '239': 'ST',\n '966': 'SA',\n '221': 'SN',\n '381': 'RS',\n '248': 'SC',\n '232': 'SL',\n '421': 'SK',\n '386': 'SI',\n '677': 'SB',\n '252': 'SO',\n '211': 'SS',\n '249': 'SD',\n '597': 'SR',\n '268': 'SZ',\n '963': 'SY',\n '992': 'TJ',\n '255': 'TZ',\n '228': 'TG',\n '676': 'TO',\n '216': 'TN',\n '993': 'TM',\n '688': 'TV',\n '256': 'UG',\n '380': 'UA',\n '971': 'AE',\n '598': 'UY',\n '998': 'UZ',\n '678': 'VU',\n '379': 'VA',\n '967': 'YE',\n '260': 'ZM',\n '263': 'ZW',\n\n // 2-digit codes\n '93': 'AF',\n '54': 'AR',\n '61': 'AU',\n '43': 'AT',\n '32': 'BE',\n '55': 'BR',\n '56': 'CL',\n '86': 'CN',\n '57': 'CO',\n '53': 'CU',\n '45': 'DK',\n '20': 'EG',\n '33': 'FR',\n '49': 'DE',\n '30': 'GR',\n '36': 'HU',\n '91': 'IN',\n '62': 'ID',\n '98': 'IR',\n '39': 'IT',\n '81': 'JP',\n '82': 'KR',\n '60': 'MY',\n '52': 'MX',\n '31': 'NL',\n '64': 'NZ',\n '47': 'NO',\n '92': 'PK',\n '51': 'PE',\n '63': 'PH',\n '48': 'PL',\n '40': 'RO',\n '65': 'SG',\n '27': 'ZA',\n '34': 'ES',\n '94': 'LK',\n '46': 'SE',\n '41': 'CH',\n '66': 'TH',\n '90': 'TR',\n '44': 'GB',\n '58': 'VE',\n '84': 'VN',\n\n // 1-digit codes (shared codes default to most common country)\n '1': 'US', // Also CA, but default to US\n '7': 'RU', // Also KZ, but default to RU\n};\n\n// Extracts ISO 3166-1 alpha-2 country code from an E.164 phone number\nexport function extractCountryFromPhone(phone: string): string | undefined {\n // Remove + prefix if present\n const digits = phone.startsWith('+') ? phone.slice(1) : phone;\n\n // Try matching from longest to shortest prefix (3, 2, 1 digits)\n for (const length of [3, 2, 1]) {\n const prefix = digits.slice(0, length);\n if (CALLING_CODE_TO_COUNTRY[prefix]) {\n return CALLING_CODE_TO_COUNTRY[prefix];\n }\n }\n\n return undefined;\n}\n\n// Normalizes a phone number to E.164 format by ensuring a + prefix\nexport function normalizePhoneNumber(phone: string): string {\n return phone.startsWith('+') ? phone : `+${phone}`;\n}\n"],"mappings":"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CAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,WACK;AAGP;6BAAc;AAEd,IAAMC,MAAM;EAAEC,MAAM;EAAOC,MAAM;EAAKC,UAAU;AAAG;AACnD,IAAMC,MAAM;EAAEH,MAAM;EAAOC,MAAM;EAAKC,UAAU;AAAG;AACnD,IAAME,MAAM;EAAEJ,MAAM;EAAOC,MAAM;EAAKC,UAAU;AAAG;AACnD,IAAMG,MAAM;EAAEL,MAAM;EAAOC,MAAM;EAAKC,UAAU;AAAG;AACnD,IAAMI,MAAM;EAAEN,MAAM;EAAOC,MAAM;EAAKC,UAAU;AAAG;AACnD,IAAMK,MAAM;EAAEP,MAAM;EAAOC,MAAM;EAAKC,UAAU;AAAG;AACnD,IAAMM,MAAM;EAAER,MAAM;EAAOC,MAAM;EAAKC,UAAU;AAAG;AACnD,IAAMO,MAAM;EAAET,MAAM;EAAOC,MAAM;EAAKC,UAAU;AAAG;AAE5C,IAAMQ,uBAAuB;EAClCC;EACAC;EACAC;EACAC;EACAf;EACAgB;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAlE;EACAmE;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACAC;EACApK;EACAC;EACAoK;EACAC;EACApK;EACAqK;EACApK;EACAqK;EACApK;EACAqK;EACAC;EACAC;EACAC;EACAvK;AACF;AAOO,SAASwK,gBAAgBC,cAA0B;AACxD,SAAOxK,qBAAqBwK,YAAAA;AAC9B;AAFgBD;AAIT,SAASE,aACdC,OACAF,cACAG,WAA0C;AAE1C,QAAMC,WAAWL,gBAAgBC,YAAAA;AACjC,QAAMK,SAASC,OAAO;IAAED,QAAQH;IAAOE;EAAS,CAAA;AAEhD,MAAI,CAACD,WAAW;AACd,WAAOI,UAAUF,MAAAA;EACnB;AAEA,SAAOE,UAAUF,QAAQ,CAAC,EAAEG,OAAOJ,UAAUK,iBAAgB,MAAON,UAAU;IAAEK;IAAOJ,UAAUK;EAAiB,CAAA,CAAA;AACpH;AAbgBR;AAkBT,SAASS,aAAaC,OAAeX,cAA4BY,QAAQ,UAAQ;AACtF,QAAM,EAAE5L,SAAQ,IAAK+K,gBAAgBC,YAAAA;AACrC,QAAMa,QAAQ,OAAO7L,aAAa,WAAW8L,OAAO9L,QAAAA,IAAYA;AAChE,QAAM+L,UAAUJ,MAAMK,KAAI;AAE1B,MAAI,CAAC,kBAAkBC,KAAKF,OAAAA,GAAU;AACpC,UAAM,IAAIG,oBAAoB;MAC5BC,QAAQ,oBAAoBR,KAAAA;MAC5BS,QAAQ;QAAC;UAAER;UAAOS,SAAS;QAAwB;;IACrD,CAAA;EACF;AAEA,QAAMC,aAAaP,QAAQQ,WAAW,GAAA;AACtC,QAAMC,gBAAgBF,aAAaP,QAAQU,MAAM,CAAA,IAAKV;AACtD,QAAM,CAACW,WAAWC,iBAAiB,EAAE,IAAIH,cAAcI,MAAM,GAAA;AAE7D,MAAID,eAAeE,SAAShB,OAAO;AACjC,UAAM,IAAIK,oBAAoB;MAC5BC,QAAQ,+BAA+BnB,YAAAA,wBAAoCa,KAAAA;MAC3EO,QAAQ;QAAC;UAAER;UAAOS,SAAS,GAAGrB,YAAAA,iBAA6Ba,KAAAA,iBAAsBA,UAAU,IAAI,KAAK,GAAA;QAAO;;IAC7G,CAAA;EACF;AAEA,QAAMiB,iBAAiBH,eAAeI,OAAOlB,OAAO,GAAA;AACpD,QAAMmB,mBAAmB,GAAGN,SAAAA,GAAYI,cAAAA,GAAiBG,QAAQ,aAAa,EAAA;AAC9E,QAAM/B,QAAQgC,OAAOF,oBAAoB,GAAA;AAEzC,SAAOV,aAAa,CAACpB,QAAQA;AAC/B;AA5BgBQ;;;ADnXT,SAASyB,WAAWC,mBAAqC;AAC9D,SAAO,CAACC,QAAgBC,iBAAAA;AACtBC,sBAAkB;MAChBC,MAAM;MACNH,QAAQA,OAAO;MACfC,cAAcG,OAAOH,YAAAA;MACrBI,SAASN;MACTO,WAAW;QACTC,SAASC,OAAc;AACrB,cAAI,CAACA,SAAS,OAAOA,UAAU,SAAU,QAAO;AAChD,gBAAM,EAAEC,UAAUD,OAAOE,OAAM,IAAKF;AACpC,cAAI,OAAOC,aAAa,YAAY,OAAOC,WAAW,SAAU,QAAO;AACvE,cAAI,EAAED,YAAYE,sBAAuB,QAAO;AAChD,cAAI;AACFC,yBAAaF,QAAQD,QAAAA;AACrB,mBAAO;UACT,QAAQ;AACN,mBAAO;UACT;QACF;QACAI,eAAeC,MAAyB;AACtC,iBAAO,GAAGA,KAAKC,QAAQ;QACzB;MACF;IACF,CAAA;EACF;AACF;AA1BgBjB;;;AEfhB,SAASkB,qBAAAA,0BAA2E;AAG7E,SAASC,eAAeC,mBAAqC;AAClE,SAAO,CAACC,QAAgBC,iBAAAA;AACtBC,IAAAA,mBAAkB;MAChBC,MAAM;MACNH,QAAQA,OAAO;MACfC,cAAcG,OAAOH,YAAAA;MACrBI,SAASN;MACTO,WAAW;QACTC,SAASC,OAAc;AACrB,cAAI,OAAOA,UAAU,SAAU,QAAO;AACtC,iBAAOA,SAASC;QAClB;QACAC,eAAeC,MAAyB;AACtC,iBAAO,GAAGA,KAAKC,QAAQ;QACzB;MACF;IACF,CAAA;EACF;AACF;AAlBgBd;;;ACHhB,SAASe,qBAAAA,0BAA2E;AAEpF,IAAMC,yBAAyB;AAExB,SAASC,WAAWC,mBAAqC;AAC9D,SAAO,CAACC,QAAgBC,iBAAAA;AACtBC,IAAAA,mBAAkB;MAChBC,MAAM;MACNH,QAAQA,OAAO;MACfC,cAAcG,OAAOH,YAAAA;MACrBI,SAASN;MACTO,WAAW;QACTC,SAASC,OAAc;AACrB,cAAI,OAAOA,UAAU,SAAU,QAAO;AACtC,cAAI,CAACX,uBAAuBY,KAAKD,KAAAA,EAAQ,QAAO;AAChD,iBAAO,CAACE,OAAOC,MAAMC,KAAKC,MAAML,KAAAA,CAAAA;QAClC;QACAM,eAAeC,MAAyB;AACtC,iBAAO,GAAGA,KAAKC,QAAQ;QACzB;MACF;IACF,CAAA;EACF;AACF;AAnBgBlB;;;ACHhB,SAASmB,wBAAAA,8BAAmD;AAU5D,eAAeC,aACbC,SACAC,WAAkB;AAGlB,MAAI,CAACA,WAAW;AACd,UAAMC,OAAO,MAAMF,QAAQE,KAAI;AAC/B,WAAO;MAAEC,OAAOD,OAAO;QAACA;UAAQ,CAAA;MAAIE,UAAU;IAAK;EACrD;AAEA,QAAMC,UAA2B,CAAA;AACjC,mBAAiBH,QAAQF,QAAQG,MAAK,GAAI;AACxC,QAAID,KAAKI,cAAcL,WAAW;AAChCI,cAAQE,KAAKL,IAAAA;IACf;EACF;AACA,SAAO;IAAEC,OAAOE;IAASD,UAAU;EAAK;AAC1C;AAjBeL;AAoCR,IAAMS,eAAeC,uBAC1B,OAAOR,WAA+BS,QAAAA;AACpC,QAAMV,UAAUU,IAAIC,aAAY,EAAGC,WAAU;AAC7C,QAAM,EAAET,MAAK,IAAK,MAAMJ,aAAaC,SAASC,SAAAA;AAC9C,QAAMC,OAAOC,MAAM,CAAA;AAEnB,MAAI,CAACD,MAAM;AACT,UAAMW,QAAQZ,aAAa;AAC3B,UAAM,IAAIa,oBAAoB;MAC5BC,OAAO;MACPC,QAAQ,uBAAuBf,YAAY,WAAWA,SAAAA,MAAe,EAAA;MACrEgB,QAAQ;QAAC;UAAEJ;UAAOK,SAAS;QAAgB;;IAC7C,CAAA;EACF;AAEA,QAAMC,SAAS,MAAMjB,KAAKkB,SAAQ;AAClC,SAAO;IAAED;IAAQE,UAAUnB,KAAKmB;IAAUC,UAAUpB,KAAKoB;EAAS;AACpE,CAAA;AAoBK,IAAMC,gBAAgBd,uBAC3B,OAAOR,WAA+BS,QAAAA;AACpC,QAAMV,UAAUU,IAAIC,aAAY,EAAGC,WAAU;AAC7C,QAAM,EAAET,MAAK,IAAK,MAAMJ,aAAaC,SAASC,SAAAA;AAE9C,MAAIE,MAAMqB,WAAW,GAAG;AACtB,UAAMX,QAAQZ,aAAa;AAC3B,UAAM,IAAIa,oBAAoB;MAC5BC,OAAO;MACPC,QAAQ,kCAAkCf,YAAY,WAAWA,SAAAA,MAAe,EAAA;MAChFgB,QAAQ;QAAC;UAAEJ;UAAOK,SAAS;QAAgC;;IAC7D,CAAA;EACF;AAEA,QAAMO,UAAgC,CAAA;AACtC,aAAWvB,QAAQC,OAAO;AACxB,UAAMgB,SAAS,MAAMjB,KAAKkB,SAAQ;AAClCK,YAAQlB,KAAK;MAAEY;MAAQE,UAAUnB,KAAKmB;MAAUC,UAAUpB,KAAKoB;IAAS,CAAA;EAC1E;AACA,SAAOG;AACT,CAAA;;;ACtGK,IAAMC,oBAAN,MAAMA,mBAAAA;EAFb,OAEaA;;;EACXC;EACAC;EAIA,OAAOC,KAAKC,OAAkCC,cAAgD;AAC5F,QAAID,SAAS,KAAM,QAAO;AAC1B,UAAME,MAAM,IAAIN,mBAAAA;AAChBM,QAAIL,WAAWI;AACfC,QAAIJ,QAAQK,aAAaH,OAAOC,YAAAA;AAChC,WAAOC;EACT;AACF;;;ACfA,SAASE,UAAAA,SAAQC,UAAAA,eAAc;AAC/B,SAASC,gBAAAA,qBAAoB;;;ACD7B,SAASC,aAAaC,YAAYC,yBAAyB;AAC3D,SAASC,cAAAA,cAAYC,UAAAA,gBAAc;AACnC,SAASC,iBAAAA,sBAAqB;;;;;;;;;;;;AAGvB,IAAMC,eAAN,MAAMA,cAAAA;SAAAA;;;;EACMC,SAAS,IAAIC,SAAOF,cAAaG,IAAI;EACrCC;EACAC;EACAC;EAEjB,YAA6BC,eAA8B;SAA9BA,gBAAAA;AAC3B,UAAMC,SAAS,KAAKD,cAAcE,IAAY,eAAA;AAE9C,QAAI,CAACD,QAAQ;AACX,WAAKP,OAAOS,MAAM,2DAAA;AAClB,YAAM,IAAIC,MAAM,0DAAA;IAClB;AAGA,SAAKP,cAAc,IAAIQ,YAAY;MAAEJ;MAAQK,YAAY;IAAE,CAAA;AAG3D,UAAMR,cAAc,KAAKE,cAAcE,IAAY,cAAA;AACnD,UAAMH,aAAa,KAAKC,cAAcE,IAAY,aAAA;AAElD,QAAI,CAACJ,eAAe,CAACC,YAAY;AAC/B,WAAKL,OAAOS,MAAM,yCAAA;AAClB,YAAM,IAAIC,MAAM,wEAAA;IAClB;AAEA,SAAKN,cAAcA;AACnB,SAAKC,aAAaA;AAElB,SAAKL,OAAOa,IAAI,8CAAA;EAClB;;EAGA,MAAMC,sBAAsBC,OAAeC,KAAaC,WAAiBC,aAAqC;AAC5G,UAAMhB,OAAOgB,eAAe;AAC5B,UAAMC,gBAAgBC,KAAKC,MAAMJ,UAAUK,QAAO,IAAKC,KAAKC,IAAG,KAAM,GAAA;AACrE,UAAMC,UAAU;AAEhB,UAAMC,cAAc;;;;;;;;;;;;;;;;;;;;;;;wCAuBgBxB,IAAAA;;;;;;;;;4BASZc,GAAAA;;;;;uFAK2DG,aAAAA,UAAuBA,kBAAkB,IAAI,KAAK,GAAA;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BrI,UAAMQ,cAAc;QAChBzB,IAAAA;;;;qBAIac,GAAAA;;2BAEMG,aAAAA,UAAuBA,kBAAkB,IAAI,KAAK,GAAA;;;;;;;MAOvES,KAAI;AAEN,UAAM,KAAKC,UAAU;MACnBC,IAAI;QAAC;UAAEf;UAAOb;QAAK;;MACnBuB;MACAC;MACAC;IACF,CAAA;AAEA,SAAK3B,OAAOa,IAAI,8BAA8BE,KAAAA,EAAO;EACvD;;EAGA,MAAMgB,uBAAuBhB,OAAeC,KAAaC,WAAiBC,aAAqC;AAC7G,UAAMhB,OAAOgB,eAAe;AAC5B,UAAMC,gBAAgBC,KAAKC,MAAMJ,UAAUK,QAAO,IAAKC,KAAKC,IAAG,KAAM,GAAA;AACrE,UAAMC,UAAU;AAEhB,UAAMC,cAAc;;;;;;;;;;;;;;;;;;;;;;;wCAuBgBxB,IAAAA;;;;;;;;;4BASZc,GAAAA;;;;;uFAK2DG,aAAAA,UAAuBA,kBAAkB,IAAI,KAAK,GAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCrI,UAAMQ,cAAc;QAChBzB,IAAAA;;;;cAIMc,GAAAA;;2BAEaG,aAAAA,UAAuBA,kBAAkB,IAAI,KAAK,GAAA;;;;;;;;;MASvES,KAAI;AAEN,UAAM,KAAKC,UAAU;MACnBC,IAAI;QAAC;UAAEf;UAAOb;QAAK;;MACnBuB;MACAC;MACAC;IACF,CAAA;AAEA,SAAK3B,OAAOa,IAAI,gCAAgCE,KAAAA,EAAO;EACzD;;EAGA,MAAMiB,4BACJC,UACAC,UACAC,aACAC,iBACAlB,aACe;AACf,UAAMhB,OAAOgB,eAAe;AAC5B,UAAMO,UAAU;AAGhB,UAAMY,mBAAmBjB,KAAKkB,OAAOF,gBAAgBd,QAAO,IAAKC,KAAKC,IAAG,MAAO,MAAO,KAAK,GAAC;AAG7F,UAAMe,aAAa,uEAAuEJ,WAAAA;AAE1F,UAAMT,cAAc;;;;;;;;;;;;;;;;;;;;;;;wCAuBgBxB,IAAAA;;;;;;;;;;;4BAWZ+B,QAAAA;;;;;;4BAMAC,QAAAA;;;;;;;;;4GASgFG,gBAAAA;;;qCAGvEE,UAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BjC,UAAMZ,cAAc;QAChBzB,IAAAA;;;;kBAIU+B,QAAAA;aACLC,QAAAA;;;;0EAI6DG,gBAAAA;EACxEE,UAAAA;;;;;;;MAOIX,KAAI;AAEN,UAAM,KAAKC,UAAU;MACnBC,IAAI;QAAC;UAAEf,OAAOkB;UAAU/B;QAAK;;MAC7BuB;MACAC;MACAC;IACF,CAAA;AAEA,SAAK3B,OAAOa,IAAI,qCAAqCoB,QAAAA,EAAU;EACjE;;EAGA,MAAMO,4BAA4BzB,OAAeG,aAAqC;AACpF,UAAMhB,OAAOgB,eAAe;AAC5B,UAAMO,UAAU;AAEhB,UAAMC,cAAc;;;;;;;;;;;;;;;;;;;;;;;wCAuBgBxB,IAAAA;;;;;;;;4BAQZa,KAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BxB,UAAMY,cAAc;QAChBzB,IAAAA;;;;EAINa,KAAAA;;;;;;;MAOIa,KAAI;AAEN,UAAM,KAAKC,UAAU;MACnBC,IAAI;QAAC;UAAEf;UAAOb;QAAK;;MACnBuB;MACAC;MACAC;IACF,CAAA;AAEA,SAAK3B,OAAOa,IAAI,qCAAqCE,KAAAA,EAAO;EAC9D;;EAGA,MAAM0B,gBAAgBC,QAAwE;AAC5F,UAAM,EAAEZ,IAAI5B,MAAMyC,UAAS,IAAKD;AAChC,UAAMjB,UAAU;AAEhB,UAAMC,cAAc;;;;;;;;;;;;;;;;;;;;;;;wCAuBgBxB,IAAAA;;;;;;;mCAOLyC,SAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8B/B,UAAMhB,cAAc;QAChBzB,IAAAA;;;;EAINyC,SAAAA;;;;;;;MAOIf,KAAI;AAEN,UAAM,KAAKC,UAAU;MACnBC,IAAI;QAAC;UAAEf,OAAOe;UAAI5B;QAAK;;MACvBuB;MACAC;MACAC;IACF,CAAA;AAEA,SAAK3B,OAAOa,IAAI,wBAAwBiB,EAAAA,EAAI;EAC9C;;EAGA,MAAMc,uBAAuBF,QAKX;AAChB,UAAM,KAAKb,UAAU;MACnBC,IAAI;QAACY,OAAOZ;;MACZL,SAASiB,OAAOjB;MAChBC,aAAagB,OAAOhB;MACpBC,aAAae,OAAOf;IACtB,CAAA;AACA,SAAK3B,OAAOa,IAAI,+BAA+B6B,OAAOZ,GAAGf,KAAK,EAAE;EAClE;;EAGA,MAAM8B,mBAAqC;AACzC,QAAI;AACF,YAAM,KAAK1C,YAAY2C,oBAAoBC,iBAAiB;QAC1DC,QAAQ;UAAEjC,OAAO,KAAKX;UAAaF,MAAM,KAAKG;QAAW;QACzDyB,IAAI;UAAC;YAAEf,OAAO,KAAKX;UAAY;;QAC/BqB,SAAS;QACTC,aAAa;MACf,CAAA;AACA,aAAO;IACT,SAASuB,KAAK;AAEZ,UAAIA,eAAeC,cAAcD,IAAIE,eAAe,KAAK;AACvD,eAAO;MACT;AACA,WAAKnD,OAAOS,MAAM,yCAAyCwC,GAAAA;AAC3D,aAAO;IACT;EACF;;EAGA,MAAcpB,UAAUuB,WAKN;AAChB,QAAI;AACF,YAAMC,SAAS,MAAM,KAAKlD,YAAY2C,oBAAoBC,iBAAiB;QACzEC,QAAQ;UAAEjC,OAAO,KAAKX;UAAaF,MAAM,KAAKG;QAAW;QACzDyB,IAAIsB,UAAUtB;QACdL,SAAS2B,UAAU3B;QACnBC,aAAa0B,UAAU1B;QACvBC,aAAayB,UAAUzB;MACzB,CAAA;AACA,WAAK3B,OAAOsD,MAAM,wCAAwCD,OAAOE,SAAS,EAAE;IAC9E,SAASN,KAAK;AACZ,UAAIA,eAAeO,mBAAmB;AACpC,aAAKxD,OAAOS,MAAM,wCAAA;AAClB,cAAM,IAAIC,MAAM,+BAAA;MAClB;AACA,UAAIuC,eAAeC,YAAY;AAC7B,YAAID,IAAIE,eAAe,KAAK;AAC1B,eAAKnD,OAAOS,MAAM,0CAAA;AAClB,gBAAM,IAAIC,MAAM,2CAAA;QAClB;AACA,YAAIuC,IAAIE,eAAe,KAAK;AAC1B,eAAKnD,OAAOS,MAAM,kDAAA;AAClB,gBAAM,IAAIC,MAAM,qCAAA;QAClB;AACA,YAAIuC,IAAIE,eAAe,KAAK;AAC1B,eAAKnD,OAAOS,MAAM,6BAA6BwC,IAAIQ,OAAO;AAC1D,gBAAM,IAAI/C,MAAM,6BAA6BuC,IAAIQ,OAAO,EAAE;QAC5D;AACA,aAAKzD,OAAOS,MAAM,mBAAmBwC,IAAIE,UAAU,KAAKF,IAAIQ,OAAO;AACnE,cAAM,IAAI/C,MAAM,yBAAyBuC,IAAIQ,OAAO,EAAE;MACxD;AACA,YAAMR;IACR;EACF;AACF;;;;;;;;;;;;;;;;;ADlmBO,IAAMS,cAAN,MAAMA;SAAAA;;;AAAa;;;;IAJxBC,SAAS;MAACC;;IACVC,WAAW;MAACC;;IACZC,SAAS;MAACD;;;;;;AERZ,SAEEE,OAGAC,cAAAA,cACAC,UAAAA,gBACK;;;ACGP,IAAMC,sBAAsB;AAerB,SAASC,oBAAoBC,OAAc;AAChD,QAAMC,UAAUC,YAAYF,KAAAA;AAC5B,MAAI,CAACC,QAAS,QAAOE;AACrB,QAAM,EAAEC,MAAMC,YAAYC,OAAOC,OAAM,IAAKN;AAC5C,MAAIG,SAASN,oBAAqB,QAAOK;AACzC,SAAO,IAAIK,kBAAkB;IAC3BC,OAAO;IACPF,QAAQA,QAAQG,KAAAA,KAAU;IAC1BC,QAAQ,CAAA;IACR,GAAIN,cAAcC,QAAQ;MAAEM,MAAM;QAAEP;QAAYC;MAAM;IAAE,IAAI,CAAC;EAC/D,CAAA;AACF;AAXgBP;AAehB,SAASG,YAAYF,OAAgBa,QAAQ,GAAC;AAC5C,MAAI,CAACb,SAAS,OAAOA,UAAU,YAAYa,QAAQ,EAAG,QAAOV;AAC7D,QAAMW,YAAYd;AAClB,MAAI,OAAOc,UAAUV,SAAS,SAAU,QAAOU;AAC/C,SAAOZ,YAAYY,UAAUC,OAAOF,QAAQ,CAAA;AAC9C;AALSX;;;;;;;;;;ADRF,SAASc,mBAAmBC,QAAc;AAE/C,QAAMC,UAAUC,OAAOC,QAAQC,YAAAA,EAAYC,KAAK,CAAC,CAACC,KAAKC,KAAAA,MAAWA,UAAUP,UAAUQ,OAAOC,MAAMD,OAAOF,GAAAA,CAAAA,CAAAA,IAAS,CAAA;AAEnH,MAAI,CAACL,SAAS;AACZ,WAAO;EACT;AAGA,SAAOA,QACJS,MAAM,GAAA,EACNC,IAAI,CAACC,SAASA,KAAKC,OAAO,CAAA,EAAGC,YAAW,IAAKF,KAAKG,MAAM,CAAA,EAAGC,YAAW,CAAA,EACtEC,KAAK,GAAA;AACV;AAbgBlB;AAgBT,IAAMmB,sBAAN,MAAMA,qBAAAA;SAAAA;;;EACMC,SAAS,IAAIC,SAAOF,qBAAoBG,IAAI;EAE7DC,MAAMC,WAAoBC,MAAqB;AAC7C,UAAMC,MAAMD,KAAKE,aAAY;AAC7B,UAAMC,WAAWF,IAAIG,YAAW;AAChC,UAAMC,UAAUJ,IAAIK,WAAU;AAI9B,UAAMC,oBAAoBC,oBAAoBT,SAAAA;AAC9C,QAAIQ,kBAAmBR,aAAYQ;AAEnC,QAAI/B,SAASI,aAAW6B;AACxB,QAAIC,OAAO;AACX,QAAIC;AACJ,QAAIC,SAAS;AACb,QAAIC,SAAuB,CAAA;AAE3B,QAAI,KAAKC,gBAAgBf,SAAAA,GAAY;AACnCvB,eAASuB,UAAUgB,UAAS;AAC5B,YAAMC,oBAAoBjB,UAAUK,YAAW;AAE/C,UAAI,OAAOY,sBAAsB,YAAYA,sBAAsB,MAAM;AACvE,cAAMC,cAAcD;AAGpB,YAAI,UAAUC,eAAe,WAAWA,eAAe,YAAYA,aAAa;AAC9E,gBAAMC,kBAAkBD;AACxBP,iBAAOQ,gBAAgBR,QAAQ;AAC/BC,kBAAQO,gBAAgBP;AACxBC,mBAASM,gBAAgBN,UAAUb,UAAUoB,WAAW5C,mBAAmBC,MAAAA;AAC3EqC,mBAASK,gBAAgBL,UAAU,CAAA;QACrC,WAES,aAAaI,eAAeG,MAAMC,QAAQJ,YAAYE,OAAO,GAAG;AACvEN,mBAASI,YAAYE,QAClBhC,IAAI,CAACmC,QAAAA;AACJ,gBAAI,OAAOA,QAAQ,YAAY,cAAcA,OAAO,iBAAiBA,KAAK;AACxE,oBAAMC,mBAAmB7C,OAAO8C,OAAOF,IAAIG,WAAW;AACtD,qBAAO;gBACLC,OAAOJ,IAAIK;gBACXR,SAASI,iBAAiB,CAAA,KAAM;cAClC;YACF;AAGA,mBAAO;UACT,CAAA,EACCK,OAAO,CAACC,UAA+BA,UAAU,IAAA;AACpDjB,mBAAS;QACX,WAES,aAAaK,aAAa;AACjC,gBAAME,UAAUF,YAAYE;AAC5BP,mBAASQ,MAAMC,QAAQF,OAAAA,IAAWA,QAAQ1B,KAAK,IAAA,IAAQ0B;QACzD;MACF,WAAW,OAAOH,sBAAsB,UAAU;AAChDJ,iBAASI;MACX;IACF,WAAW,KAAKc,oBAAoB/B,SAAAA,GAAY;AAC9C,YAAMgC,aAAahC;AACnB,YAAMiC,kBAAkBD,WAAWvD,UAAUuD,WAAWE;AACxD,UAAI,OAAOD,oBAAoB,YAAYA,mBAAmB,OAAOA,mBAAmB,KAAK;AAC3FxD,iBAASwD;MACX;AACAtB,aAAO,OAAOqB,WAAWrB,SAAS,WAAWqB,WAAWrB,OAAO;AAC/DC,cAAQ,OAAOoB,WAAWpB,UAAU,WAAWoB,WAAWpB,QAAQuB;AAClEtB,eACE,OAAOmB,WAAWnB,WAAW,WACzBmB,WAAWnB,SACX,OAAOmB,WAAWZ,YAAY,WAC5BY,WAAWZ,UACX5C,mBAAmBC,MAAAA;AAC3BqC,eAASO,MAAMC,QAAQU,WAAWlB,MAAM,IAAKkB,WAAWlB,SAA0B,CAAA;IACpF,WAAW,KAAKsB,aAAapC,SAAAA,GAAY;AAEvC,YAAMqC,cAAcrC,UAAUI,UAAU3B;AACxC,YAAM6D,cAActC,UAAUI,UAAUmC,MAAMnB,WAAWpB,UAAUI,UAAUmC,MAAM1B,UAAUb,UAAUoB;AACvG,YAAMoB,MAAMxC,UAAUyC,QAAQD;AAC9B/D,eAASI,aAAW6D;AACpB7B,eAAS,yBAAyBwB,cAAc,KAAKA,WAAAA,MAAiB,EAAA,KAAOC,WAAAA;AAC7E,WAAK1C,OAAOkC,MAAM,uBAAuBO,WAAAA,MAAiBC,WAAAA,gBAAsBE,GAAAA,IAAOxC,UAAU2C,KAAK;IACxG,OAAO;AAEL9B,eAAS;IACX;AAEA,UAAM+B,iBAAmC;MACvCjC;MACAkC,OAAOrE,mBAAmBC,MAAAA;MAC1BA;MACA,GAAImC,SAAS;QAAEA;MAAM;MACrBC;MACAiC,UAAUxC,QAAQkC;MAClB1B;IACF;AAEAV,aAAS2C,OAAO,gBAAgB,0BAAA,EAA4BtE,OAAOA,MAAAA,EAAQuE,KAAKJ,cAAAA;EAClF;;EAGQ7B,gBAAgBe,OAAwC;AAC9D,WACEA,iBAAiBmB,SACjB,OAAQnB,MAAkCd,cAAc,cACxD,OAAQc,MAAoCzB,gBAAgB;EAEhE;;EAGQ+B,aAAaN,OAInB;AACA,WAAOA,iBAAiBmB,SAAUnB,MAAqCM,iBAAiB;EAC1F;EAEQL,oBAAoBD,OAAkD;AAC5E,QAAI,CAACA,SAAS,OAAOA,UAAU,SAAU,QAAO;AAChD,UAAMoB,MAAMpB;AACZ,WACE,OAAOoB,IAAIzE,WAAW,YACtB,OAAOyE,IAAIhB,eAAe,YAC1B,OAAOgB,IAAIrC,WAAW,YACtBQ,MAAMC,QAAQ4B,IAAIpC,MAAM;EAE5B;AACF;;;;;;AEjLA,SAA6BqC,SAAAA,QAA2BC,cAAAA,cAAYC,UAAAA,gBAAc;AAClF,SAASC,oBAAoB;AAC7B,SAA0BC,kBAAkB;;;;;;;;AAmBrC,IAAMC,4BAAN,MAAMA,2BAAAA;SAAAA;;;EACMC,SAAS,IAAIC,SAAOF,2BAA0BG,IAAI;EAEnEC,MAAMC,WAAoBC,OAAyC;AAGjE,UAAMC,oBAAoBC,oBAAoBH,SAAAA;AAC9C,QAAIE,kBAAmBF,aAAYE;AAEnC,QAAIF,qBAAqBI,cAAc;AACrC,aAAOC,WAAW,MAAML,UAAUM,SAAQ,CAAA;IAC5C;AAEA,QAAI,KAAKC,gBAAgBP,SAAAA,GAAY;AACnC,YAAMQ,SAASR,UAAUS,UAAS;AAClC,YAAMC,WAAWV,UAAUW,YAAW;AACtC,aAAON,WAAW,MAAM,KAAKO,iBAAiBF,UAAUF,MAAAA,CAAAA;IAC1D;AAEA,QAAIR,qBAAqBa,OAAO;AAC9B,YAAMC,QAASd,UAAkCc;AACjD,YAAMC,eAAeD,iBAAiBD,QAAQC,MAAME,UAAUC;AAC9D,YAAMC,aAAaJ,iBAAiBD,QAAQC,MAAMK,QAAQF;AAC1D,WAAKrB,OAAOwB,MAAML,gBAAgBf,UAAUgB,SAASE,cAAclB,UAAUmB,KAAK;AAClF,UAAIL,SAASA,UAAUd,WAAW;AAChC,aAAKJ,OAAOwB,MAAM,eAAepB,UAAUgB,OAAO,EAAE;MACtD;AACA,aAAOX,WAAW,MAChB,KAAKO,iBACH;QACES,MAAM;QACNC,QAAQP,gBAAgBf,UAAUgB;QAClCO,QAAQ,CAAA;MACV,GACAC,aAAWC,qBAAqB,CAAA;IAGtC;AAEA,SAAK7B,OAAOwB,MAAM,kCAAkCM,KAAKC,UAAU3B,SAAAA,CAAAA,EAAY;AAC/E,WAAOK,WAAW,MAChB,KAAKO,iBACH;MACES,MAAM;MACNC,QAAQ;MACRC,QAAQ,CAAA;IACV,GACAC,aAAWC,qBAAqB,CAAA;EAGtC;EAEQb,iBAAiBF,UAAmBF,QAAgC;AAC1E,QAAI,OAAOE,aAAa,UAAU;AAChC,aAAO;QACLW,MAAM;QACNC,QAAQZ;QACRM,SAASN;QACTa,QAAQ,CAAA;QACRf;QACAoB,YAAYpB;MACd;IACF;AAEA,UAAMqB,MAAOnB,YAAY,CAAC;AAC1B,UAAMY,SAAS,OAAOO,IAAIP,WAAW,WAAWO,IAAIP,SAAS;AAC7D,WAAO;MACLD,MAAM,OAAOQ,IAAIR,SAAS,WAAWQ,IAAIR,OAAO;MAChDS,OAAO,OAAOD,IAAIC,UAAU,WAAWD,IAAIC,QAAQb;MACnDK;MACAN,SAASM;MACTC,QAAQQ,MAAMC,QAAQH,IAAIN,MAAM,IAAKM,IAAIN,SAA0B,CAAA;MACnEf;MACAoB,YAAYpB;IACd;EACF;EAEQD,gBAAgBa,OAAwC;AAC9D,WACEA,iBAAiBP,SACjB,OAAQO,MAAkCX,cAAc,cACxD,OAAQW,MAAoCT,gBAAgB;EAEhE;AACF;;;;;;ACzGA,SAAkDsB,cAAAA,cAAkCC,YAAAA,iBAAgB;AAGpG,SAASC,YAAYC,WAAW;;;ACHhC,SAASC,cAAAA,cAAkEC,gBAAgB;AAC3F,SAASC,cAAcC,QAA4BC,kBAAgD;AACnG,OAAOC,qBAAqB;;;ACF5B,SAASC,qBAAAA,0BAAyB;AAClC,SAASC,kBAAkB;AAQpB,IAAMC,qBAAqB,IAAIC,mBAAAA;AAG/B,SAASC,wBAAAA;AACd,SAAOF,mBAAmBG,SAAQ;AACpC;AAFgBD;AAKT,SAASE,0BAA6BC,SAA6BC,UAAiB;AACzF,SAAON,mBAAmBO,IAAIF,SAASC,QAAAA;AACzC;AAFgBF;AAKT,SAASI,yBAAyBC,SAAoC;AAC3E,QAAMJ,UAAUL,mBAAmBG,SAAQ;AAC3C,MAAIE,SAAS;AACXK,WAAOC,OAAON,SAASI,OAAAA;EACzB;AACF;AALgBD;AAWT,IAAMI,6BAA6B;AAGnC,SAASC,wBAAAA;AACd,SAAOC,WAAAA;AACT;AAFgBD;AAKT,SAASE,2BACdC,OACAC,eACAC,aAAqBN,4BAA0B;AAE/C,MAAI,OAAOI,MAAMG,WAAW,YAAY;AACtCH,UAAMG,OAAOD,YAAYD,aAAAA;EAC3B,WAAWD,MAAMI,OAAO,OAAOJ,MAAMI,IAAIC,cAAc,YAAY;AACjEL,UAAMI,IAAIC,UAAUH,YAAYD,aAAAA;EAClC;AACF;AAVgBF;;;;;;;;;;;;;;;;;;;;ADhCT,IAAMO,gBAAN,MAAMA,eAAAA;SAAAA;;;;EACMC;EACAC;EACTC;EAER,YACcD,UAA+B,CAAC,GACfE,eAC7B;SAD6BA,gBAAAA;AAE7B,SAAKF,UAAUA;AACf,UAAMG,WAAWH,QAAQG,YAAY;AAErC,QAAIA,aAAa,WAAW;AAC1B,UAAI,CAAC,KAAKD,eAAe;AACvB,cAAM,IAAIE,MAAM,4CAAA;MAClB;AACA,WAAKL,eAAe,KAAKG;IAC3B,OAAO;AACL,WAAKH,eAAe,KAAKM,oBAAoBL,OAAAA;IAC/C;EACF;;EAGQK,oBAAoBC,MAA0C;AACpE,UAAMC,QAAQD,KAAKC,SAAS;AAC5B,UAAMC,YAAYF,KAAKG,UAAU;AAKjC,UAAMC,iBAAiB;MAACD,OAAOE,UAAU;QAAEF,QAAQ;MAA2B,CAAA;MAAIA,OAAOG,OAAO;QAAEC,OAAO;MAAK,CAAA;;AAG9G,UAAMC,mBACJN,cAAc,SACV,IAAIO,WAAWC,QAAQ;MACrBT;MACAE,QAAQA,OAAOQ,QAAO,GAAIP,gBAAgBD,OAAOS,KAAI,CAAA;IACvD,CAAA,IACA,IAAIH,WAAWC,QAAQ;MACrBT;MACAE,QAAQA,OAAOQ,QAAO,GACjBP,gBACHD,OAAOU,OAAO,CAACC,SAAAA;AACb,cAAM,EAAET,WAAAA,YAAWJ,OAAAA,QAAOc,SAASpB,SAASqB,eAAeC,MAAK,IAAKH;AACrE,cAAMI,QAAQ;UACZb;UACAJ,OAAMkB,YAAW,EAAGC,OAAO,CAAA;UAC3BJ,gBAAgB,IAAIA,cAAcK,SAAQ,EAAGC,MAAM,EAAC,CAAA,MAAQ;UAC5D3B,UAAU,IAAIA,OAAAA,MAAa;UAC3BoB;UACAQ,OAAOC,OAAAA;AACT,YAAIC,SAASP,MAAMQ,KAAK,GAAA;AAGxB,YAAIT,OAAO;AACTQ,oBAAU;EAAKR,KAAAA;QACjB;AAEA,eAAOQ;MACT,CAAA,GACAtB,OAAOwB,SAAS;QAAEC,KAAK;MAAK,CAAA,CAAA;IAEhC,CAAA;AAEN,UAAMC,oBAAmF;MAACrB;;AAG1F,QAAIR,KAAK8B,kBAAkB;AACzB,YAAMC,WAAW/B,KAAK+B,YAAY;AAClC,YAAMC,WAAWhC,KAAKgC,YAAY;AAElCH,wBAAkBI,KAChB,IAAIC,gBAAgB;QAClBjC;QACAkC,UAAU,GAAGJ,QAAAA;QACbK,aAAa;QACbC,SAAS;QACTL;QACA7B,QAAQA,OAAOQ,QAAQR,OAAOE,UAAS,GAAIF,OAAOS,KAAI,CAAA;MACxD,CAAA,GACA,IAAIsB,gBAAgB;QAClBjC,OAAO;QACPkC,UAAU,GAAGJ,QAAAA;QACbK,aAAa;QACbC,SAAS;QACTL;QACA7B,QAAQA,OAAOQ,QAAQR,OAAOE,UAAS,GAAIF,OAAOS,KAAI,CAAA;MACxD,CAAA,CAAA;IAEJ;AAEA,UAAM0B,SAAwB;MAC5BrC;MACAQ,YAAYoB;MACZU,aAAa;IACf;AAEA,QAAIvC,KAAKwC,eAAexC,KAAKyC,SAAS;AACpCH,aAAOE,cAAc;QACnB,GAAGxC,KAAKwC;QACRC,SAASzC,KAAKyC;QACdC,aAAa1C,KAAK0C;MACpB;IACF;AAEA,WAAOC,aAAaL,MAAAA;EACtB;;EAGAM,IAAI7B,SAAqBpB,SAAwB;AAC/C,SAAKkD,KAAK,OAAO9B,SAASpB,OAAAA;EAC5B;EAEAmD,MAAM/B,SAAqBE,OAAgBtB,SAAwB;AACjE,SAAKkD,KAAK,SAAS9B,SAASpB,SAASsB,KAAAA;EACvC;EAEA8B,KAAKhC,SAAqBpB,SAAwB;AAChD,SAAKkD,KAAK,QAAQ9B,SAASpB,OAAAA;EAC7B;EAEAqD,MAAMjC,SAAqBpB,SAAwB;AACjD,SAAKkD,KAAK,SAAS9B,SAASpB,OAAAA;EAC9B;EAEAsD,QAAQlC,SAAqBpB,SAAwB;AACnD,SAAKkD,KAAK,WAAW9B,SAASpB,OAAAA;EAChC;EAEAuD,WAAWvD,SAAuB;AAChC,SAAKA,UAAUA;EACjB;;EAGQkD,KAAK5C,OAAiBc,SAAqBpB,SAAkBsB,OAAsB;AACzF,UAAMkC,MAAMxD,WAAW,KAAKA;AAG5B,QAAI,YAAY,KAAKF,gBAAgB,gBAAgB,KAAKA,cAAc;AAEtE,YAAM2D,gBAAgB,KAAK3D;AAC3B,YAAM4D,eAAepD,UAAU,QAAQ,SAASA;AAChD,YAAMqD,mBAAmB,KAAKC,cAAcxC,OAAAA;AAC5C,YAAMyC,WAAW,KAAKC,eAAe,CAAC,GAAGN,KAAKlC,KAAAA;AAE9CmC,oBAAcR,IAAI;QAAE3C,OAAOoD;QAActC,SAASuC;QAAkB,GAAGE;MAAS,CAAA;IAClF,OAAO;AAEL,YAAME,aAAa,KAAKjE;AACxB,UAAIQ,UAAU,WAAWgB,OAAO;AAC9BkC,cAAMO,WAAWZ,MAAM/B,SAASE,OAAOkC,GAAAA,IAAOO,WAAWZ,MAAM/B,SAASE,KAAAA;MAC1E,WAAWhB,UAAU,OAAO;AAC1BkD,cAAMO,WAAWd,IAAI7B,SAASoC,GAAAA,IAAOO,WAAWd,IAAI7B,OAAAA;MACtD,WAAWd,UAAU,QAAQ;AAC3BkD,cAAMO,WAAWX,KAAKhC,SAASoC,GAAAA,IAAOO,WAAWX,KAAKhC,OAAAA;MACxD,WAAWd,UAAU,WAAWyD,WAAWV,OAAO;AAChDG,cAAMO,WAAWV,MAAMjC,SAASoC,GAAAA,IAAOO,WAAWV,MAAMjC,OAAAA;MAC1D,WAAWd,UAAU,aAAayD,WAAWT,SAAS;AACpDE,cAAMO,WAAWT,QAAQlC,SAASoC,GAAAA,IAAOO,WAAWT,QAAQlC,OAAAA;MAC9D;IACF;EACF;;EAGA4C,gBAAgB1D,OAAiBc,SAAqByC,UAAwB7D,SAAwB;AACpG,UAAMwD,MAAMxD,WAAW,KAAKA;AAG5B,QAAI,YAAY,KAAKF,gBAAgB,gBAAgB,KAAKA,cAAc;AACtE,YAAM2D,gBAAgB,KAAK3D;AAC3B,YAAM4D,eAAepD,UAAU,QAAQ,SAASA;AAGhDmD,oBAAcR,IAAI;QAAE3C,OAAOoD;QAActC,SAAS,KAAKwC,cAAcxC,OAAAA;QAAU,GAAGyC;MAAS,CAAA;IAC7F,OAAO;AAEL,YAAMI,kBAAkBJ,WAAW,GAAGzC,OAAAA,IAAW8C,KAAKC,UAAUN,QAAAA,CAAAA,KAAczC;AAC9E,WAAKd,KAAAA,EAAO2D,iBAAiBT,GAAAA;IAC/B;EACF;EAEQI,cAAcxC,SAA6B;AACjD,QAAIA,mBAAmBjB,MAAO,QAAOiB,QAAQA;AAC7C,QAAI,OAAOA,YAAY,YAAYA,YAAY,MAAM;AACnD,UAAI;AACF,eAAO8C,KAAKC,UAAU/C,OAAAA;MACxB,QAAQ;AACN,eAAOgD,OAAOhD,OAAAA;MAChB;IACF;AACA,WAAOgD,OAAOhD,OAAAA;EAChB;;EAGQ0C,eAAeD,WAAwB,CAAC,GAAG7D,SAAkBsB,OAA6B;AAChG,UAAM+C,WAAwB;MAAE,GAAGR;IAAS;AAE5C,QAAI7D,QAASqE,UAASrE,UAAUA;AAEhC,UAAMsE,qBAAqBC,sBAAAA;AAC3B,QAAID,oBAAoB;AACtB,UAAIA,mBAAmBjD,cAAegD,UAAShD,gBAAgBiD,mBAAmBjD;AAClF,iBAAW,CAACmD,KAAKC,KAAAA,KAAUC,OAAOC,QAAQL,kBAAAA,GAAqB;AAC7D,YAAIE,QAAQ,iBAAiB;AAC3BH,mBAASG,GAAAA,IAAOC;QAClB;MACF;IACF;AAEA,QAAInD,MAAO+C,UAAS/C,QAAQA;AAE5B,WAAO+C;EACT;EAEAO,MAAM5E,SAAgC;AACpC,UAAM6E,cAAc,IAAIhF,eAAc,KAAKE,SAAS,KAAKE,aAAa;AACtE4E,gBAAYtB,WAAWvD,OAAAA;AACvB,WAAO6E;EACT;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AD5NO,IAAMC,wBAAN,MAAMA;SAAAA;;;;EACMC;EACAC;EACAC;EAEjB,YACmBC,QACLC,SACZ;SAFiBD,SAAAA;AAGjB,SAAKH,mBAAmBI,SAASJ,oBAAoB;AACrD,SAAKC,oBAAoBG,SAASH,qBAAqB;AACvD,SAAKC,uBAAuBE,SAASF,wBAAwB;EAC/D;EAEAG,UAAUC,SAA2BC,MAAwC;AAC3E,QAAID,QAAQE,QAAO,MAAO,QAAQ;AAChC,aAAOD,KAAKE,OAAM;IACpB;AAEA,UAAMC,cAAcJ,QAAQK,aAAY;AACxC,UAAMC,UAAUF,YAAYG,WAAU;AACtC,UAAMC,WAAWJ,YAAYK,YAAW;AAExC,UAAMC,YAAYC,KAAKC,IAAG;AAG1B,QAAI,KAAKlB,kBAAkB;AACzB,WAAKmB,WAAWP,OAAAA;IAClB;AAGA,WAAOL,KAAKE,OAAM,EAAGW,KACnBC,IAAI,MAAA;AACF,UAAI,KAAKpB,mBAAmB;AAC1B,cAAMqB,WAAWL,KAAKC,IAAG,IAAKF;AAC9B,aAAKO,YAAYX,SAASE,UAAUQ,QAAAA;MACtC;IACF,CAAA,GACAE,WAAW,CAACC,UAAAA;AACV,YAAMH,WAAWL,KAAKC,IAAG,IAAKF;AAC9B,WAAKU,SAASd,SAASE,UAAUQ,UAAUG,KAAAA;AAC3C,YAAMA;IACR,CAAA,CAAA;EAEJ;EAEQN,WAAWP,SAA+B;AAChD,QAAI;AACF,YAAMe,qBAAqBC,sBAAAA;AAC3B,YAAMC,WAAwB;QAC5BC,MAAM;QACNC,QAAQnB,QAAQmB;QAChBC,KAAKpB,QAAQoB;QACbC,eAAeN,oBAAoBM;QACnCC,IAAItB,QAAQsB;QACZC,WAAWvB,QAAQwB,QAAQ,YAAA;MAC7B;AAEA,WAAKjC,OAAOkC,gBAAgB,OAAO,YAAYzB,QAAQmB,MAAM,IAAInB,QAAQoB,GAAG,IAAIH,QAAAA;IAClF,SAASJ,OAAO;AACd,WAAKtB,OAAOsB,MAAM,8BAA+BA,MAAgBa,KAAK;IACxE;EACF;EAEQf,YAAYX,SAAyBE,UAAwBQ,UAAwB;AAC3F,QAAI;AACF,YAAMK,qBAAqBC,sBAAAA;AAC3B,YAAMW,aAAazB,SAASyB;AAG5B,YAAMC,WAAWD,cAAc,MAAM,UAAUA,cAAc,MAAM,SAAS;AAE5E,YAAMV,WAAwB;QAC5BC,MAAM;QACNC,QAAQnB,QAAQmB;QAChBC,KAAKpB,QAAQoB;QACbO;QACAjB;QACAW,eAAeN,oBAAoBM;MACrC;AAGA,UAAIX,WAAW,KAAKpB,sBAAsB;AACxC2B,iBAASY,cAAc;MACzB;AAEA,YAAMC,UAAUb,SAASY,cACrB,QAAQ7B,QAAQmB,MAAM,IAAInB,QAAQoB,GAAG,IAAIO,UAAAA,MAAgBjB,QAAAA,OACzD,GAAGV,QAAQmB,MAAM,IAAInB,QAAQoB,GAAG,IAAIO,UAAAA,MAAgBjB,QAAAA;AAExD,WAAKnB,OAAOkC,gBAAgBG,UAAUE,SAASb,QAAAA;IACjD,SAASJ,OAAO;AACd,WAAKtB,OAAOsB,MAAM,+BAAgCA,MAAgBa,KAAK;IACzE;EACF;EAEQZ,SAASd,SAAyBE,UAAwBQ,UAAkBG,OAAsB;AACxG,QAAI;AACF,YAAME,qBAAqBC,sBAAAA;AAC3B,YAAMe,MAAMlB;AASZ,YAAMc,aAAaI,IAAIC,UAAUD,IAAIJ,cAAczB,SAASyB,cAAc;AAC1E,YAAMM,eAAeF,IAAID,WAAWC,IAAIG,UAAU;AAElD,YAAMjB,WAAwB;QAC5BC,MAAM;QACNC,QAAQnB,QAAQmB;QAChBC,KAAKpB,QAAQoB;QACbO;QACAjB;QACAW,eAAeN,oBAAoBM;QACnCc,WAAWJ,IAAIK,QAAQ;QACvBH;MACF;AAEA,UAAIF,IAAIL,OAAO;AACbT,iBAASoB,QAAQN,IAAIL;MACvB;AAEA,UAAIK,IAAI7B,UAAU;AAChBe,iBAASqB,eAAeP,IAAI7B;MAC9B;AAEA,YAAM4B,UAAU,SAAS9B,QAAQmB,MAAM,IAAInB,QAAQoB,GAAG,IAAIO,UAAAA,MAAgBM,YAAAA;AAC1E,WAAK1C,OAAOkC,gBAAgB,SAASK,SAASb,QAAAA;IAChD,SAASsB,cAAc;AACrB,WAAKhD,OAAOsB,MAAM,4BAA6B0B,aAAuBb,KAAK;IAC7E;EACF;AACF;;;;;;;;;;;;AGjJA,SAEEc,UAAAA,SACAC,UAAAA,UAEAC,UAAAA,eAGK;;;ACRP,SAASC,cAAAA,oBAAuC;;;;;;;;;;;;AAgBzC,IAAMC,0BAAN,MAAMA;SAAAA;;;EACMC;EACAC;EAEjB,YAAYC,UAA0C,CAAC,GAAG;AACxD,SAAKF,oBAAoBE,QAAQF,qBAAqB;AACtD,SAAKC,iBAAiBC,QAAQD,kBAAkBE;EAClD;;EAGAC,IAAIC,MAAsBC,OAAqBC,MAAwB;AAErE,UAAMC,gBAAgBC,sBAAAA;AAGtB,QAAI,KAAKT,mBAAmB;AAC1BU,iCAA2BJ,OAAOE,eAAe,KAAKP,cAAc;IACtE;AAGAU,8BAA0B;MAAEH;IAAc,GAAG,MAAA;AAC3CD,WAAAA;IACF,CAAA;EACF;;EAGA,MAAMK,UAAUP,MAAsBC,OAAoC;AAExE,UAAME,gBAAgBC,sBAAAA;AAGtB,QAAI,KAAKT,mBAAmB;AAC1BU,iCAA2BJ,OAAOE,eAAe,KAAKP,cAAc;IACtE;AAKA,UAAMY,QAAQC,mBAAmBC,SAAQ;AACzC,QAAI,CAACF,OAAO;AAEVC,yBAAmBE,UAAU;QAAER;MAAc,CAAA;IAC/C;EACF;AACF;;;;;;;;;;;;;;;;;AD1CO,IAAMS,wBAAwBC,OAAO,uBAAA;AAE5C,IAAMC,yBAAyB;EAC7BC,UAAU;EACVC,qBAAqB;EACrBC,kBAAkB;EAClBC,UAAU;EACVC,UAAU;AACZ;AAMA,IAAMC,sBAAoE;EACxEC,aAAa;IACXN,UAAU;IACVO,OAAO;IACPC,QAAQ;IACRC,kBAAkB;IAClBR,qBAAqB;IACrBC,kBAAkB;IAClBQ,YAAY;MACVC,kBAAkB;MAClBC,mBAAmB;MACnBC,sBAAsB;IACxB;EACF;EAEAC,SAAS;IACPd,UAAU;IACVO,OAAO;IACPC,QAAQ;IACRC,kBAAkB;IAClBR,qBAAqB;IACrBC,kBAAkB;IAClBQ,YAAY;MACVC,kBAAkB;MAClBC,mBAAmB;MACnBC,sBAAsB;IACxB;EACF;EAEAE,YAAY;IACVf,UAAU;IACVO,OAAO;IACPC,QAAQ;IACRC,kBAAkB;IAClBR,qBAAqB;IACrBC,kBAAkB;IAClBQ,YAAY;MACVC,kBAAkB;MAClBC,mBAAmB;MACnBC,sBAAsB;IACxB;EACF;EAEAG,MAAM;IACJhB,UAAU;IACVO,OAAO;IACPC,QAAQ;IACRC,kBAAkB;IAClBR,qBAAqB;IACrBC,kBAAkB;EACpB;AACF;AAOA,SAASe,mBAAkBC,UAA+B,CAAC,GAAC;AAE1D,QAAMC,SAASD,QAAQE,cAClBf,oBAAoBa,QAAQE,WAAW,KAAKf,oBAAoBC,cACjED,oBAAoBC;AAGxB,QAAMe,kBAAkBC,OAAOC,YAAYD,OAAOE,QAAQN,OAAAA,EAASO,OAAO,CAAC,CAACC,GAAGC,KAAAA,MAAWA,UAAUC,MAAAA,CAAAA;AAGpG,MAAIP,gBAAgBX,cAAcS,QAAQT,YAAY;AACpDW,oBAAgBX,aAAa;MAC3B,GAAGS,OAAOT;MACV,GAAGY,OAAOC,YAAYD,OAAOE,QAAQH,gBAAgBX,UAAU,EAAEe,OAAO,CAAC,CAACC,GAAGC,KAAAA,MAAWA,UAAUC,MAAAA,CAAAA;IACpG;EACF;AAGA,QAAMC,SAAS;IACb,GAAG9B;IACH,GAAGoB;IACH,GAAGE;EACL;AAEA,SAAOQ;AACT;AAzBSZ,OAAAA,oBAAAA;AAgCT,SAASa,4BAA4BZ,SAA4B;AAC/D,SAAO;IACLa,SAASC;IACTC,YAAY,6BAAA;AACV,YAAMC,SAAS,IAAIF,SAAAA;AAGnB,UAAId,QAAQX,OAAO;AACjB,cAAM4B,SAASC,cAAclB,QAAQX,KAAK;AACzC2B,eAA+DG,eAAeF,MAAAA;MACjF;AAEA,aAAOD;IACT,GAVY;EAWd;AACF;AAfSJ;AAkBT,SAASQ,sBAAsBpB,UAA+B,CAAC,GAAC;AAE9D,QAAMqB,gBAAgBtB,mBAAkBC,OAAAA;AAGxC,QAAMsB,YAAwB;;IAE5B;MACET,SAASlC;MACT4C,UAAUF;IACZ;;AAIF,MAAIA,cAAcvC,aAAa,WAAW;AACxCwC,cAAUE,KAAKZ,4BAA4BS,aAAAA,CAAAA;EAC7C;AAGAC,YAAUE,KAAK;IACbX,SAASY;IACTV,YAAY,wBAACW,MAA2BC,kBAAAA;AACtC,aAAO,IAAIF,cAAcC,MAAMC,aAAAA;IACjC,GAFY;IAGZC,QAAQ;MAACjD;MAAuB;QAAEkD,OAAOf;QAAQgB,UAAU;MAAK;;EAClE,CAAA;AAGAR,YAAUE,KAAK;IACbX,SAASkB;IACThB,YAAY,6BAAA;AACV,aAAO,IAAIgB,wBAAwB;QACjCC,mBAAmB;QACnBC,gBAAgB;MAClB,CAAA;IACF,GALY;EAMd,CAAA;AAGAX,YAAUE,KAAK;IACbX,SAASqB;IACTnB,YAAY,wBAACC,QAAuBU,SAAAA;AAElC,YAAMS,oBAAoBT,KAAKlC,cAAc;QAC3CC,kBAAkBiC,KAAK1C;QACvBU,mBAAmBgC,KAAK1C;MAC1B;AACA,aAAO,IAAIkD,sBAAsBlB,QAAQmB,iBAAAA;IAC3C,GAPY;IAQZP,QAAQ;MAACH;MAAe9C;;EAC1B,CAAA;AAEA,SAAO2C;AACT;AArDSF;AA0DT,SAASF,cAAc7B,OAAa;AAClC,QAAM+C,YAA4B;IAAC;IAAS;IAAQ;IAAO;IAAS;;AAGpE,QAAMC,eAAe,wBAACC,MAAiCF,UAAUG,SAASD,CAAAA,GAArD;AAErB,MAAI,CAACD,aAAahD,KAAAA,GAAQ;AACxB,WAAO;MAAC;MAAS;MAAQ;;EAC3B;AAEA,QAAMmD,aAAaJ,UAAUK,QAAQpD,KAAAA;AACrC,SAAO+C,UAAUM,MAAM,GAAGF,aAAa,CAAA;AACzC;AAZStB;AAoBF,IAAMyB,eAAN,MAAMA,cAAAA;SAAAA;;;;EAEX,OAAOC,QAAQ5C,UAA+B,CAAC,GAAkB;AAC/D,UAAMsB,YAAYF,sBAAsBpB,OAAAA;AAExC,WAAO;MACL6C,QAAQF;MACRrB;MACAwB,SAAS;QAACrB;QAAeM;QAAyBG;QAAuBvD;;IAC3E;EACF;;EAGA,OAAOoE,aAA8C/C,SAAqD;AACxG,UAAMgD,iBAAiBL,cAAaM,qBAAqBjD,OAAAA;AAEzD,WAAO;MACL6C,QAAQF;MACRO,SAASlD,QAAQkD,WAAW,CAAA;MAC5B5B,WAAW;WACN0B;;QAEH;UACEnC,SAASC;UACTC,YAAY,wBAACW,SAAAA;AACX,gBAAIA,KAAK5C,aAAa,WAAW;AAC/B,oBAAMkC,SAAS,IAAIF,SAAAA;AACnB,kBAAIY,KAAKrC,OAAO;AACd,sBAAM4B,SAASC,cAAcQ,KAAKrC,KAAK;AACtC2B,uBAA+DG,eAAeF,MAAAA;cACjF;AACA,qBAAOD;YACT;AACA,mBAAO;UACT,GAVY;UAWZY,QAAQ;YAACjD;;QACX;;QAEA;UACEkC,SAASY;UACTV,YAAY,wBAACW,MAA2BC,kBAAAA;AACtC,mBAAO,IAAIF,cAAcC,MAAMC,aAAAA;UACjC,GAFY;UAGZC,QAAQ;YAACjD;YAAuB;cAAEkD,OAAOf;cAAQgB,UAAU;YAAK;;QAClE;;QAEA;UACEjB,SAASkB;UACThB,YAAY,6BAAA;AACV,mBAAO,IAAIgB,wBAAwB;cACjCC,mBAAmB;cACnBC,gBAAgB;YAClB,CAAA;UACF,GALY;QAMd;;QAEA;UACEpB,SAASqB;UACTnB,YAAY,wBAACC,QAAuBU,SAAAA;AAElC,kBAAMS,oBAAoBT,KAAKlC,cAAc;cAC3CC,kBAAkBiC,KAAK1C;cACvBU,mBAAmBgC,KAAK1C;YAC1B;AACA,mBAAO,IAAIkD,sBAAsBlB,QAAQmB,iBAAAA;UAC3C,GAPY;UAQZP,QAAQ;YAACH;YAAe9C;;QAC1B;;MAEFmE,SAAS;QAACrB;QAAeM;QAAyBG;QAAuBvD;;IAC3E;EACF;;EAGAwE,UAAUC,WAAqC;EAG/C;;EAGA,OAAeH,qBAAqBjD,SAA0D;AAC5F,QAAIA,QAAQe,YAAY;AACtB,aAAO;QAAC4B,cAAaU,2BAA2BrD,OAAAA;;IAClD;AAEA,UAAMsB,YAAwB;MAACqB,cAAaU,2BAA2BrD,OAAAA;;AAEvE,QAAIA,QAAQsD,UAAU;AACpBhC,gBAAUE,KAAK;QACbX,SAASb,QAAQsD;QACjBA,UAAUtD,QAAQsD;MACpB,CAAA;IACF;AAEA,WAAOhC;EACT;;EAGA,OAAe+B,2BAA2BrD,SAAwD;AAChG,QAAIA,QAAQe,YAAY;AACtB,aAAO;QACLF,SAASlC;QACToC,YAAY,iCAAUwC,SAAAA;AACpB,gBAAMC,cAAc,MAAMxD,QAAQe,aAAU,GAAMwC,IAAAA;AAClD,iBAAOxD,mBAAkByD,WAAAA;QAC3B,GAHY;QAIZ5B,QAAQ5B,QAAQ4B,UAAU,CAAA;MAC5B;IACF;AAEA,QAAI5B,QAAQsD,UAAU;AACpB,aAAO;QACLzC,SAASlC;QACToC,YAAY,8BAAO0C,mBAAAA;AACjB,gBAAMD,cAAc,MAAMC,eAAeC,oBAAmB;AAC5D,iBAAO3D,mBAAkByD,WAAAA;QAC3B,GAHY;QAIZ5B,QAAQ;UAAC5B,QAAQsD;;MACnB;IACF;AAEA,QAAItD,QAAQ2D,aAAa;AACvB,aAAO;QACL9C,SAASlC;QACToC,YAAY,8BAAO0C,mBAAAA;AACjB,gBAAMD,cAAc,MAAMC,eAAeC,oBAAmB;AAC5D,iBAAO3D,mBAAkByD,WAAAA;QAC3B,GAHY;QAIZ5B,QAAQ;UAAC5B,QAAQ2D;;MACnB;IACF;AAEA,UAAM,IAAIC,MAAM,mFAAA;EAClB;AACF;;;;;;;AEhWA,SAASC,wBAAAA,wBAA6CC,gCAAAA,qCAAoC;;;ACWnF,IAAMC,mBAAmB;EAC9BC,QAAQ;EACRC,SAAS;EACTC,OAAO;EACPC,aAAa;EACbC,kBAAkB;EAClBC,iBAAiB;EACjBC,mBAAmB;AACrB;AAGA,SAASC,UAAUC,SAAkBC,KAAW;AAC9C,MAAI,CAACD,QAAS,QAAOE;AAErB,MAAI,OAAQF,QAA8BG,QAAQ,YAAY;AAC5D,UAAMC,MAAOJ,QAA2CG,IAAIF,GAAAA;AAC5D,WAAOI,MAAMC,QAAQF,GAAAA,IAAOA,IAAI,CAAA,IAAMA;EACxC;AACA,SAAQJ,QAAmCC,GAAAA;AAC7C;AARSF;AAWF,SAASQ,iBAAiBP,SAAgB;AAC/C,MAAI,CAACA,QAAS,QAAO;AAErB,QAAMQ,QAAQT,UAAUC,SAAST,iBAAiBC,MAAM;AACxD,QAAMiB,SAASV,UAAUC,SAAST,iBAAiBE,OAAO;AAC1D,QAAMiB,OAAOX,UAAUC,SAAST,iBAAiBG,KAAK;AAEtD,MAAI,CAACc,SAAS,CAACC,UAAU,CAACC,KAAM,QAAO;AAEvC,SAAO;IACLF;IACAC;IACAC;IACAC,YAAYZ,UAAUC,SAAST,iBAAiBI,WAAW,KAAK;IAChEiB,gBAAgBb,UAAUC,SAAST,iBAAiBK,gBAAgB,KAAK;IACzEiB,eAAeC,KAAKC,MAAMhB,UAAUC,SAAST,iBAAiBM,eAAe,KAAK,IAAA;IAClFmB,iBAAiBF,KAAKC,MAAMhB,UAAUC,SAAST,iBAAiBO,iBAAiB,KAAK,IAAA;EACxF;AACF;AAlBgBS;;;AD5BT,IAAMU,iBAAiBC,uBAAqB,CAACC,OAAgBC,QAAAA;AAClE,QAAMC,SAASD,IAAIE,YAAW,EAAGC,WAAU;AAC3C,SAAOC,iBAAiBH,OAAOI,WAAU,CAAA;AAC3C,CAAA;AAGO,IAAMC,UAAUR,uBAAqB,CAACC,OAAgBC,QAAAA;AAC3D,QAAMC,SAASD,IAAIE,YAAW,EAAGC,WAAU;AAC3C,QAAMI,UAAUH,iBAAiBH,OAAOI,WAAU,CAAA;AAClD,MAAI,CAACE,SAASC,KAAM,OAAM,IAAIC,8BAA6B,+BAAA;AAC3D,SAAOF,QAAQC;AACjB,CAAA;AAGO,IAAME,oBAAoBZ,uBAAqB,CAACC,OAAgBC,QAAAA;AACrE,QAAMC,SAASD,IAAIE,YAAW,EAAGC,WAAU;AAC3C,QAAMI,UAAUH,iBAAiBH,OAAOI,WAAU,CAAA;AAClD,MAAI,CAACE,SAASI,eAAgB,OAAM,IAAIF,8BAA6B,yCAAA;AACrE,SAAOF,QAAQI;AACjB,CAAA;;;AExBA,SAA6BC,UAAAA,SAAQC,UAAAA,UAAQC,UAAAA,eAAmD;AAChG,SAASC,gBAAAA,eAAcC,iBAAAA,sBAAqB;AAE5C,SAASC,oBAAoBC,iBAAiB;;;ACHvC,IAAMC,sBAAsBC,OAAO,qBAAA;AACnC,IAAMC,wBAAwBD,OAAO,uBAAA;;;ACD5C,SAASE,UAAAA,SAAQC,cAAAA,cAAYC,SAAAA,cAAa;AAC1C,SAASC,WAAAA,gBAAe;AAExB,SAASC,yBAAyB;AAElC,SAASC,WAAWC,mBAAmB;;;;;;;;;;;;;;;;;;AAKhC,IAAMC,eAAeC,OAAO,cAAA;AAG5B,IAAMC,oBAAN,MAAMA;SAAAA;;;;;;EACHC,gBAAoC;EAE5C,YACoCC,SACcC,iBACTC,SACvC;SAHkCF,UAAAA;SACcC,kBAAAA;SACTC,UAAAA;EACtC;;EAGH,MAAMC,KAAQC,SAAiBC,KAAaC,MAA2B;AACrE,UAAMC,SAAS,KAAKL,QAAQM,IAAIJ,OAAAA;AAChC,QAAI,CAACG,QAAQ;AACX,YAAM,IAAIE,MACR,iBAAiBL,OAAAA,oCAA2C;WAAI,KAAKF,QAAQQ,KAAI;QAAIC,KAAK,IAAA,CAAA,GAAQ;IAEtG;AAEA,QAAI,CAAC,KAAKZ,eAAe;AACvB,YAAMa,cAAc,KAAKZ,QAAQY;AACjC,UAAI,CAACA,aAAa;AAChB,cAAM,IAAIH,MAAM,4DAAA;MAClB;AACA,WAAKV,gBAAgB,MAAM,KAAKE,gBAAgBW,WAAAA;IAClD;AAEA,UAAMC,UAAUC,iBAAiB,KAAKf,aAAa;AACnD,UAAMgB,SAAS,IAAIC,kBAAkBV,QAAQ,CAAC,CAAA,EAAGW,WAAWJ,OAAAA,EAASK,MAAK;AAE1E,WAAOX,OAAOJ,KAAQ;MAAEE;IAAI,GAAGU,MAAAA,EAAQI,UAAS;EAClD;AACF;;;IAhCcC,OAAOC,OAAMC;;;;;;;;;;;;AAmC3B,SAASR,iBAAiBS,KAAgB;AACxC,QAAMC,OAAOC,YAAAA;AACbD,OAAKE,IAAIC,iBAAiBC,QAAQL,IAAIM,KAAK;AAC3CL,OAAKE,IAAIC,iBAAiBG,SAASP,IAAIQ,MAAM;AAC7CP,OAAKE,IAAIC,iBAAiBK,OAAOT,IAAIU,IAAI;AACzCT,OAAKE,IAAIC,iBAAiBO,aAAaX,IAAIY,UAAU;AACrDX,OAAKE,IAAIC,iBAAiBS,kBAAkBb,IAAIc,cAAc;AAC9Db,OAAKE,IAAIC,iBAAiBW,iBAAiBC,KAAKC,UAAUjB,IAAIkB,aAAa,CAAA;AAC3EjB,OAAKE,IAAIC,iBAAiBe,mBAAmBH,KAAKC,UAAUjB,IAAIoB,eAAe,CAAA;AAC/E,SAAOnB;AACT;AAVSV;;;AC/CT,SAAS8B,UAAAA,SAAQC,cAAAA,oBAAkB;AAEnC,SAASC,qBAAAA,0BAAyB;;;;;;;;;;;;;;;;;;AAG3B,IAAMC,kBAAkBC,OAAO,iBAAA;AAG/B,IAAMC,gCAAN,MAAMA;SAAAA;;;;EACX,YAAsDC,SAAmC;SAAnCA,UAAAA;EAAoC;;EAG1F,MAAMC,KAAQC,SAAiBC,KAAaC,cAA0BC,MAA2B;AAC/F,UAAMC,SAAS,KAAKN,QAAQO,IAAIL,OAAAA;AAChC,QAAI,CAACI,QAAQ;AACX,YAAM,IAAIE,MACR,iBAAiBN,OAAAA,oCAA2C;WAAI,KAAKF,QAAQS,KAAI;QAAIC,KAAK,IAAA,CAAA,GAAQ;IAEtG;AAEA,UAAMC,UAAkC;MACtC,CAACC,iBAAiBC,MAAM,GAAGT,aAAYU;MACvC,CAACF,iBAAiBG,OAAO,GAAGX,aAAYY;MACxC,CAACJ,iBAAiBK,KAAK,GAAGb,aAAYc;MACtC,CAACN,iBAAiBO,WAAW,GAAGf,aAAYgB;MAC5C,CAACR,iBAAiBS,eAAe,GAAGC,KAAKC,UAAUnB,aAAYoB,aAAa;MAC5E,CAACZ,iBAAiBa,iBAAiB,GAAGH,KAAKC,UAAUnB,aAAYsB,eAAe;IAClF;AAEA,UAAMC,SAAS,IAAIC,mBAAkBvB,QAAQ,CAAC,CAAA,EAAGwB,WAAWlB,OAAAA,EAASmB,MAAK;AAC1E,WAAOxB,OAAOL,KAAQ;MAAEE;IAAI,GAAGwB,MAAAA,EAAQI,UAAS;EAClD;AACF;;;;;;;;;;;;;;;;;;AHlBA,IAAMC,kBAAkBC,OAAO,iBAAA;AAIxB,IAAMC,mBAAN,MAAMA,kBAAAA;SAAAA;;;EACX,OAAwBC,SAAS,IAAIC,SAAOF,kBAAiBG,IAAI;EACjE,OAAeC,aAA4B,CAAA;EAE3C,MAAMC,kBAAkB;AACtB,UAAMC,QAAQC,IAAIP,kBAAiBI,WAAWI,IAAI,CAACC,MAAMA,EAAEC,MAAK,CAAA,CAAA;AAChEV,sBAAiBI,aAAa,CAAA;EAChC;;EAGA,OAAeO,aAAaC,SAAgCC,SAA2C;AACrG,UAAMC,UAAU,oBAAIC,IAAAA;AAEpB,eAAWC,OAAOJ,QAAQK,UAAU;AAClC,YAAMC,QAAQC,mBAAmBC,OAAO;QACtCC,WAAWC,UAAUC;QACrBX,SAAS;UAAEY,SAAS;YAACX;;QAAS;MAChC,CAAA;AACAC,cAAQW,IAAIT,IAAIb,MAAMe,KAAAA;AACtBlB,wBAAiBI,WAAWsB,KAAKR,KAAAA;AACjClB,wBAAiBC,OAAO0B,IAAI,2BAA2BX,IAAIb,IAAI,WAAMU,OAAAA,EAAS;IAChF;AAEA,WAAOC;EACT;;EAGA,OAAOc,QAAQC,cAAyD;AACtE,UAAMC,kBAA4B;MAChCC,SAASC;MACTC,YAAYJ,aAAaI;MACzBC,QAAQL,aAAaK,UAAU,CAAA;IACjC;AAEA,UAAMC,mBAA6B;MACjCJ,SAASK;MACTH,YAAY,wBAACrB,YAAmCA,QAAQyB,iBAA5C;MACZH,QAAQ;QAACF;;IACX;AAEA,UAAMM,kBAA4B;MAChCP,SAASQ;MACTN,YAAY,wBAACrB,SAAgC4B,WAAAA;AAC3C,cAAM3B,UAAUD,QAAQC,WAAW2B,OAAOC,IAAY,YAAY,uBAAA;AAClE,eAAOzC,kBAAiBW,aAAaC,SAASC,OAAAA;MAChD,GAHY;MAIZqB,QAAQ;QAACF;QAAqBU;;IAChC;AAEA,WAAO;MACLC,QAAQ3C;MACR4C,SAAS;QAACC;WAAkBhB,aAAae,WAAW,CAAA;;MACpDE,WAAW;QAAChB;QAAiBK;QAAkBG;QAAiBS;;MAChEC,SAAS;QAACD;;IACZ;EACF;;EAGA,OAAOE,gBAAgBpB,cAAiE;AACtF,UAAMC,kBAA4B;MAChCC,SAASjC;MACTmC,YAAYJ,aAAaI;MACzBC,QAAQL,aAAaK,UAAU,CAAA;IACjC;AAEA,UAAMI,kBAA4B;MAChCP,SAASmB;MACTjB,YAAY,wBAACrB,SAAgC4B,WAAAA;AAC3C,cAAM3B,UAAUD,QAAQC,WAAW2B,OAAOC,IAAY,YAAY,uBAAA;AAClE,eAAOzC,kBAAiBW,aAAaC,SAASC,OAAAA;MAChD,GAHY;MAIZqB,QAAQ;QAACpC;QAAiB4C;;IAC5B;AAEA,WAAO;MACLC,QAAQ3C;MACR4C,SAAS;QAACC;WAAkBhB,aAAae,WAAW,CAAA;;MACpDE,WAAW;QAAChB;QAAiBQ;QAAiBa;;MAC9CH,SAAS;QAACG;;IACZ;EACF;AACF;;;;;;;AInGA,SAASC,UAAAA,eAAc;;;ACAvB,SAASC,cAAAA,aAAYC,OAAAA,YAAW;AAChC,SAASC,WAAAA,gBAAe;;;ACDxB,SAASC,mBAAAA,wBAAuB;AAChC,SAASC,gBAAAA,eAAcC,eAAAA,oBAAmB;AAEnC,SAASC,iBAAAA;AACd,SAAOC,iBACLC,cAAa;IAAEC,SAAS;EAAwB,CAAA,GAChDC,aAAY;IACVC,QAAQ;IACRC,aAAa;IACbC,MAAMC;EACR,CAAA,CAAA;AAEJ;AATgBR;;;ACHhB,SAASS,cAAAA,oBAAkB;;;;;;;;AAGpB,IAAMC,aAAN,MAAMA;SAAAA;;;;EAEXC,WAAmB;AACjB,WAAO;EACT;AACF;;;;;;;;;;;;;;;;;AFAO,IAAMC,gBAAN,MAAMA;SAAAA;;;;EACX,YAA6BC,YAAwB;SAAxBA,aAAAA;EAAyB;;EAMtDC,WAAmB;AACjB,WAAO,KAAKD,WAAWC,SAAQ;EACjC;AACF;;;;;;;;;;;;;;;;;;;AGlBA,SAASC,cAAAA,aAAYC,OAAAA,MAAKC,YAAAA,WAAUC,cAAAA,cAAYC,WAAW;AAC3D,SAASC,WAAAA,gBAAe;;;ACDxB,SAASC,mBAAAA,wBAAuB;AAChC,SAASC,gBAAAA,eAAcC,eAAAA,oBAAmB;AAEnC,SAASC,kBAAAA;AACd,SAAOC,iBACLC,cAAa;IACXC,SAAS;IACTC,aACE;EACJ,CAAA,GACAC,aAAY;IACVC,QAAQ;IACRF,aAAa;IACbG,QAAQ;MACNC,MAAM;MACNC,YAAY;QACVC,WAAW;UACTF,MAAM;UACNJ,aAAa;UACbO,SAAS;QACX;MACF;MACAC,UAAU;QAAC;;IACb;EACF,CAAA,CAAA;AAEJ;AAvBgBZ;;;;;;;;;;;;;;;;;;;;ADQT,IAAMa,iBAAN,MAAMA;SAAAA;;;;EAMXC,SAAqCC,OAA4C;AAC/E,UAAMC,YAAaD,MAA+BE,aAAY;AAC9D,WAAO;MAAED;IAAU;EACrB;AACF;;;;yBANuBE,EAAAA;;;IAELC,aAAa;;;;;;;;;;;;;;;;;;;;;AJRxB,IAAMC,aAAN,MAAMA;SAAAA;;;AAAY;;;IAHvBC,aAAa;MAACC;MAAeC;;IAC7BC,WAAW;MAACC;;;;;;AMNP,SAASC,IAAIC,GAAWC,GAAS;AACtC,SAAOA,MAAM,IAAID,IAAID,IAAIE,GAAGD,IAAIC,CAAAA;AAClC;AAFgBF;;;ACDhB,IAAMG,0BAAkD;;EAEtD,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;;EAGP,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;;EAGN,KAAK;EACL,KAAK;AACP;AAGO,SAASC,wBAAwBC,OAAa;AAEnD,QAAMC,SAASD,MAAME,WAAW,GAAA,IAAOF,MAAMG,MAAM,CAAA,IAAKH;AAGxD,aAAWI,UAAU;IAAC;IAAG;IAAG;KAAI;AAC9B,UAAMC,SAASJ,OAAOE,MAAM,GAAGC,MAAAA;AAC/B,QAAIN,wBAAwBO,MAAAA,GAAS;AACnC,aAAOP,wBAAwBO,MAAAA;IACjC;EACF;AAEA,SAAOC;AACT;AAbgBP;AAgBT,SAASQ,qBAAqBP,OAAa;AAChD,SAAOA,MAAME,WAAW,GAAA,IAAOF,QAAQ,IAAIA,KAAAA;AAC7C;AAFgBO;","names":["AUTH_CONFIG","Symbol","AUTH_CONFIG_DEFAULTS","cookie","refreshCookieName","refreshCookieMaxAge","refreshCookiePath","refreshCookieSecure","process","env","NODE_ENV","refreshCookieSameSite","refreshCookieDomain","guard","authHeaderName","tokenPrefix","csrfExemptSessionTypes","refreshTokenBindingExemptSessionTypes","TokenType","Global","Module","ConfigModule","ConfigService","APP_GUARD","Reflector","JwtModule","Global","Module","Inject","Injectable","Scope","REQUEST","RequestService","request","config","getAccessToken","authHeader","headers","guard","authHeaderName","type","token","split","tokenPrefix","getRefreshToken","cookies","refreshToken","cookie","refreshCookieName","_error","getHeader","key","getHostname","hostname","getAllHeaders","scope","Scope","REQUEST","RequestModule","providers","RequestService","exports","ForbiddenException","Inject","Injectable","Logger","Scope","UnauthorizedException","SSE_METADATA","Reflector","SetMetadata","REQUIRE_SESSION_KEY","RequireSession","types","SetMetadata","SetMetadata","SKIP_CSRF_KEY","SkipCsrf","SetMetadata","Inject","Injectable","Logger","UnauthorizedException","JwtService","parseExpiryToMs","expiry","match","Error","value","Number","parseInt","multipliers","s","m","h","d","w","y","crypto","hashToken","token","createHash","update","digest","verifyTokenHash","expectedHash","computedHash","length","timingSafeEqual","Buffer","from","TokenService","logger","Logger","name","jwtService","config","generateAccessToken","sessionInfo","refreshToken","userId","sessionId","sessionType","metadata","sign","tokenType","TokenType","ACCESS","refreshTokenHash","hashToken","expiresIn","tokenExpiry","access","generateRefreshToken","REFRESH","refresh","payload","options","verify","token","expectedType","Error","error","getExpiryTime","type","Date","now","parseExpiryToMs","getExpiryInSeconds","Math","floor","validateAccessToken","decoded","UnauthorizedException","jwtError","validateRefreshToken","validateTokenBinding","accessToken","verifyTokenHash","VrittiAuthGuard","logger","Logger","name","reflector","requestService","tokenService","config","canActivate","context","request","switchToHttp","getRequest","reply","getResponse","route","method","url","authConfig","skipCsrf","getAllAndOverride","SKIP_CSRF_KEY","getHandler","getClass","isPublic","validateCsrf","debug","requiredSessionTypes","REQUIRE_SESSION_KEY","isSseEndpoint","get","SSE_METADATA","handleSseAuth","sessionType","handleHttpAuth","csrfExemptSessionTypes","guard","includes","accessToken","getAccessToken","warn","UnauthorizedException","decoded","validateAccessToken","refreshTokenBindingExemptSessionTypes","refreshToken","getRefreshToken","validateTokenBinding","length","join","tokenType","_tokenType","refreshTokenHash","_hash","exp","_exp","iat","_iat","sessionInfo","onAuthenticated","userId","validateRefreshToken","safeMethods","fastifyInstance","server","csrfProtection","ForbiddenException","Promise","resolve","reject","originalSend","send","bind","Error","err","_error","errors","field","message","scope","Scope","REQUEST","mergeWithDefaults","input","tokenExpiry","cookie","AUTH_CONFIG_DEFAULTS","guard","AuthConfigModule","forRootAsync","options","module","imports","ConfigModule","RequestModule","JwtModule","registerAsync","inject","ConfigService","useFactory","config","secret","getOrThrow","signOptions","algorithm","providers","provide","Reflector","useClass","APP_GUARD","VrittiAuthGuard","AUTH_CONFIG","args","TokenService","exports","createParamDecorator","AccessToken","_data","ctx","request","switchToHttp","getRequest","authHeader","headers","authorization","replace","createParamDecorator","CookieDomain","createParamDecorator","_data","ctx","request","switchToHttp","getRequest","forwarded","headers","raw","Array","isArray","hostStr","hostname","domain","split","baseDomain","authConfig","cookie","refreshCookieDomain","AUTH_CONFIG_DEFAULTS","endsWith","createParamDecorator","CookieName","createParamDecorator","_data","ctx","request","switchToHttp","getRequest","authConfig","cookie","refreshCookieName","AUTH_CONFIG_DEFAULTS","createParamDecorator","Hostname","_data","ctx","request","switchToHttp","getRequest","forwarded","headers","raw","Array","isArray","hostStr","hostname","split","SetMetadata","Public","SetMetadata","createParamDecorator","HttpStatus","HttpException","HttpProblemException","HttpException","detailOrOptions","httpStatus","options","detail","type","label","errors","BadGatewayException","HttpProblemException","detailOrOptions","HttpStatus","BAD_GATEWAY","HttpStatus","BadRequestException","HttpProblemException","detailOrOptions","HttpStatus","BAD_REQUEST","HttpStatus","ConflictException","HttpProblemException","detailOrOptions","HttpStatus","CONFLICT","HttpStatus","ForbiddenException","HttpProblemException","detailOrOptions","HttpStatus","FORBIDDEN","HttpStatus","GoneException","HttpProblemException","detailOrOptions","HttpStatus","GONE","HttpStatus","InternalServerErrorException","HttpProblemException","detailOrOptions","HttpStatus","INTERNAL_SERVER_ERROR","HttpStatus","MethodNotAllowedException","HttpProblemException","detailOrOptions","HttpStatus","METHOD_NOT_ALLOWED","HttpStatus","NotAcceptableException","HttpProblemException","detailOrOptions","HttpStatus","NOT_ACCEPTABLE","HttpStatus","NotFoundException","HttpProblemException","detailOrOptions","HttpStatus","NOT_FOUND","HttpStatus","NotImplementedException","HttpProblemException","detailOrOptions","HttpStatus","NOT_IMPLEMENTED","HttpStatus","PayloadTooLargeException","HttpProblemException","detailOrOptions","HttpStatus","PAYLOAD_TOO_LARGE","HttpStatus","RequestTimeoutException","HttpProblemException","detailOrOptions","HttpStatus","REQUEST_TIMEOUT","HttpStatus","ServiceUnavailableException","HttpProblemException","detailOrOptions","HttpStatus","SERVICE_UNAVAILABLE","HttpStatus","TooManyRequestsException","HttpProblemException","detailOrOptions","HttpStatus","TOO_MANY_REQUESTS","HttpStatus","UnauthorizedException","HttpProblemException","detailOrOptions","HttpStatus","UNAUTHORIZED","HttpStatus","UnprocessableEntityException","HttpProblemException","detailOrOptions","HttpStatus","UNPROCESSABLE_ENTITY","HttpStatus","UnsupportedMediaTypeException","HttpProblemException","detailOrOptions","HttpStatus","UNSUPPORTED_MEDIA_TYPE","HttpStatus","ValidationException","HttpProblemException","detailOrOptions","HttpStatus","UNPROCESSABLE_ENTITY","buildCookieOptionsForHost","cookieConfig","hostname","baseDomain","refreshCookieDomain","Error","endsWith","UnauthorizedException","httpOnly","secure","refreshCookieSecure","sameSite","refreshCookieSameSite","path","refreshCookiePath","maxAge","refreshCookieMaxAge","domain","RefreshCookieOptions","createParamDecorator","_data","ctx","request","switchToHttp","getRequest","forwarded","headers","raw","Array","isArray","hostStr","split","authConfig","cookie","AUTH_CONFIG_DEFAULTS","createParamDecorator","RefreshTokenCookie","createParamDecorator","_data","ctx","request","switchToHttp","getRequest","cookies","cookieName","authConfig","cookie","refreshCookieName","AUTH_CONFIG_DEFAULTS","createParamDecorator","SessionData","createParamDecorator","_data","ctx","request","switchToHttp","getRequest","sessionInfo","sessionId","Error","userId","sessionType","createParamDecorator","Subdomain","_data","ctx","request","switchToHttp","getRequest","origin","headers","url","URL","hostname","split","forwarded","host","Array","isArray","undefined","createParamDecorator","UserId","createParamDecorator","_data","ctx","request","switchToHttp","getRequest","sessionInfo","userId","Error","Module","ConfigModule","Inject","Injectable","Logger","CACHE_PROVIDER","Symbol","CacheService","logger","Logger","name","provider","set","key","value","ttlSeconds","err","error","get","del","keys","join","scanKeys","pattern","getMemoryInfo","Injectable","Logger","ConfigService","Redis","RedisCacheProvider","logger","Logger","name","client","configService","onModuleInit","url","getOrThrow","Redis","lazyConnect","maxRetriesPerRequest","on","log","err","error","onModuleDestroy","quit","set","key","value","ttlSeconds","json","JSON","stringify","setex","get","parse","del","keys","length","scanKeys","pattern","cursor","nextCursor","batch","scan","push","getMemoryInfo","info","CacheModule","imports","ConfigModule","providers","RedisCacheProvider","provide","CACHE_PROVIDER","useExisting","CacheService","exports","Module","ConfigModule","DATA_TABLE_VIEWS_TABLE","Symbol","Body","Controller","HttpCode","HttpStatus","Logger","Post","ApiBearerAuth","ApiTags","applyDecorators","ApiBody","ApiOperation","ApiResponse","ApiProperty","ApiPropertyOptional","IsObject","IsOptional","IsString","IsUUID","MaxLength","UpsertDataTableStateDto","tableSlug","state","activeViewId","description","example","ApiUpsertDataTableState","applyDecorators","ApiOperation","summary","description","ApiBody","type","UpsertDataTableStateDto","ApiResponse","status","Injectable","Logger","ConfigService","EMPTY_TABLE_STATE","filters","sort","columnVisibility","columnOrder","columnSizing","columnPinning","left","right","lockedColumnSizing","density","filterOrder","filterVisibility","search","pagination","limit","offset","DataTableStateService","logger","Logger","name","cacheService","configService","stateTtl","get","upsertCurrentState","userId","dto","key","tableSlug","set","state","activeViewId","log","getCurrentState","cached","DataTableStateController","logger","Logger","name","dataTableStateService","upsertCurrentState","userId","dto","log","tableSlug","OK","Body","Controller","Delete","Get","HttpCode","HttpStatus","Logger","Param","Patch","Post","Query","ApiBearerAuth","ApiTags","applyDecorators","ApiBody","ApiOperation","ApiParam","ApiQuery","ApiResponse","ApiProperty","ApiPropertyOptional","DataTableViewDto","id","name","tableSlug","state","isShared","isOwn","createdAt","updatedAt","from","view","userId","dto","description","nullable","example","ApiProperty","ApiPropertyOptional","IsBoolean","IsObject","IsOptional","IsString","MaxLength","CreateDataTableViewDto","name","tableSlug","state","isShared","description","example","ApiProperty","IsString","MaxLength","MinLength","RenameDataTableViewDto","name","description","example","ApiProperty","IsBoolean","ToggleShareDataTableViewDto","isShared","description","example","ApiProperty","IsObject","UpdateDataTableViewDto","state","description","ApiListDataTableViews","applyDecorators","ApiOperation","summary","description","ApiQuery","name","example","required","ApiResponse","status","type","DataTableViewDto","ApiCreateDataTableView","ApiBody","CreateDataTableViewDto","ApiUpdateDataTableView","ApiParam","UpdateDataTableViewDto","ApiRenameDataTableView","RenameDataTableViewDto","ApiToggleShareDataTableView","ToggleShareDataTableViewDto","ApiDeleteDataTableView","createHash","Injectable","Logger","ConfigService","Inject","Injectable","and","eq","Logger","and","asc","desc","eq","getTableName","ilike","inArray","notInArray","sql","snakeToCamel","str","replace","_","letter","toUpperCase","PrimaryBaseRepository","logger","sequence","tableName","db","database","drizzleClient","model","query","queryKeys","Object","keys","debug","join","error","table","options","dbTableName","getTableName","Logger","name","nextSequenceValue","resolvedSequence","Error","sequenceName","schema","seqName","result","execute","sql","rows","Number","sequence_value","create","data","tx","log","results","insert","values","returning","record","findById","id","findFirst","where","findOne","findMany","buildSelectQuery","select","from","$dynamic","leftJoin","on","leftJoins","groupBy","length","orderBy","limit","offset","findAllAndCount","countResultPromise","subq","named","as","count","countQuery","countResult","Promise","all","update","idColumn","set","eq","updateMany","rowCount","delete","deleteMany","exists","transaction","callback","runInTransaction","findForSelect","config","selectFn","distinct","selectDistinct","bind","parsedValues","split","map","v","trim","filter","Boolean","parsedExcludeIds","excludeIds","tableColumns","joinTables","joins","resolveColumn","key","joinColumns","undefined","valueCol","value","labelCol","label","descriptionCol","description","parseKeys","input","Array","isArray","additionalKeys","additionalEntries","expr","e","entries","additionalExpressions","additionalAlias","selectCols","groupIdKey","groupIdCol","groupId","entry","valuesQuery","type","innerJoin","inArray","row","String","additionals","reduce","acc","hasMore","groups","selectFields","totalCount","mapWith","conditions","search","push","ilike","notInArray","field","val","column","orderByKey","orderDirection","orderByCol","and","orderClauses","asc","desc","resolvedGroups","groupTable","groupTableColumns","groupTableIdKey","groupNameKey","groupLabelKey","groupNameCol","groupRows","r","AsyncLocalStorage","Inject","Injectable","InternalServerErrorException","Logger","drizzle","DATABASE_MODULE_OPTIONS","Symbol","Pool","RlsAwarePool","Pool","rlsAls","txAls","applyRlsContext","options","poolConfig","query","textOrConfig","values","cb","submit","rls","getStore","undefined","runWrapped","client","connect","result","release","err","PrimaryDatabaseService","logger","Logger","name","pool","db","rlsAls","AsyncLocalStorage","txAls","options","onModuleInit","primaryDb","initializeDrizzleClient","host","port","username","password","database","schema","sslMode","RlsAwarePool","user","max","maxConnections","ssl","rejectUnauthorized","applyRlsContext","debug","Object","keys","drizzleRelations","join","drizzle","client","relations","query","log","error","InternalServerErrorException","drizzleClient","pinned","getStore","Error","runWithRlsContext","rls","fn","run","runInTransaction","transaction","sp","applyRls","tx","undefined","sessionClient","session","runWithPinnedConnection","onModuleDestroy","end","NAMED_VIEWS_LIMIT","DataTableViewsRepository","PrimaryBaseRepository","database","table","findPersonalViewsBySlug","userId","tableSlug","t","db","select","from","where","and","eq","isShared","orderBy","createdAt","limit","findSharedViewsBySlug","computeChecksum","value","createHash","update","JSON","stringify","digest","DataTableViewsService","logger","Logger","name","dataTableViewsRepository","cacheService","configService","personalViewsKey","userId","tableSlug","sharedViewsKey","viewsTtl","get","getOrCachePersonalViews","key","cached","debug","rows","findPersonalViewsBySlug","set","getOrCacheSharedViews","findSharedViewsBySlug","invalidateViewsCache","affectsPersonal","affectsShared","toDelete","push","length","del","findViews","personalRows","sharedRows","Promise","all","map","row","DataTableViewDto","from","createView","dto","view","create","state","isShared","log","updateView","id","findById","NotFoundException","BadRequestException","updated","toggleShareView","renameView","existing","findOne","ConflictException","label","detail","errors","field","message","deleteView","delete","DataTableViewsController","logger","Logger","name","dataTableViewsService","findViews","userId","tableSlug","log","createView","dto","updateView","id","renameView","toggleShareView","isShared","deleteView","CREATED","DataTableModule","forRoot","options","global","module","imports","ConfigModule","CacheModule","controllers","DataTableStateController","DataTableViewsController","providers","provide","DATA_TABLE_VIEWS_TABLE","useValue","tableViews","DataTableViewsService","DataTableViewsRepository","DataTableStateService","exports","dataTableViewsColumns","id","uuid","primaryKey","defaultRandom","userId","notNull","tableSlug","varchar","length","name","state","jsonb","$type","isShared","boolean","default","createdAt","timestamp","withTimezone","defaultNow","updatedAt","$onUpdate","Date","dataTableViewsIndexes","table","index","on","uniqueIndex","Global","Module","Reflector","DatabaseModule","forServer","options","asyncProvider","provide","DATABASE_MODULE_OPTIONS","useFactory","inject","module","providers","Reflector","useClass","PrimaryDatabaseService","exports","ApiProperty","CreateResponseDto","success","message","data","example","ApiProperty","ApiPropertyOptional","ValidatedRowDto","index","data","valid","errors","example","code","name","ImportSummaryDto","total","invalid","ImportResponseDto","success","message","created","updated","skipped","rows","summary","type","ApiPropertyOptional","Type","IsIn","IsInt","IsOptional","IsString","Min","SelectOptionsQueryDto","search","limit","offset","values","excludeIds","valueKey","labelKey","descriptionKey","additionalKeys","groupIdKey","orderByKey","orderDirection","description","example","default","Number","enum","ApiProperty","IsBoolean","IsNotEmpty","IsString","SuccessResponseDto","success","message","example","ApiProperty","ApiPropertyOptional","TableResponseDto","result","count","state","activeViewId","nullable","and","asc","desc","eq","gt","gte","ilike","inArray","lt","lte","ne","notIlike","notInArray","or","FilterProcessor","buildWhere","filters","fieldMap","conditions","flatMap","f","def","field","Array","isArray","value","expression","operator","column","col","val","type","eq","ne","ilike","notIlike","gt","gte","lt","lte","inArray","String","notInArray","length","and","undefined","buildSearch","search","columnId","Object","values","filter","map","or","buildOrderBy","sort","s","direction","asc","desc","FilterOperators","EQUALS","NOT_EQUALS","CONTAINS","NOT_CONTAINS","GT","GTE","LT","LTE","IS_ANY_OF","IS_NOT_ANY_OF","registerDecorator","dinero","toDecimal","AED","AFN","ALL","AMD","AOA","ARS","AUD","AWG","AZN","BAM","BBD","BDT","BGN","BHD","BIF","BMD","BND","BOB","BOV","BRL","BSD","BTN","BWP","BYN","BZD","CAD","CDF","CHE","CHF","CHW","CLF","CLP","CNY","COP","COU","CRC","CUP","CVE","CZK","DJF","DKK","DOP","DZD","EGP","ERN","ETB","EUR","FJD","FKP","GBP","GEL","GHS","GIP","GMD","GNF","GTQ","GYD","HKD","HNL","HTG","HUF","IDR","ILS","INR","IQD","IRR","ISK","JMD","JOD","JPY","KES","KGS","KHR","KMF","KPW","KRW","KWD","KYD","KZT","LAK","LBP","LKR","LRD","LSL","LYD","MAD","MDL","MGA","MKD","MMK","MNT","MOP","MRU","MUR","MVR","MWK","MXN","MXV","MYR","MZN","NAD","NGN","NIO","NOK","NPR","NZD","OMR","PAB","PEN","PGK","PHP","PKR","PLN","PYG","QAR","RON","RSD","RUB","RWF","SAR","SBD","SCR","SDG","SEK","SGD","SHP","SLE","SOS","SRD","SSP","STN","SVC","SYP","SZL","THB","TJS","TMT","TND","TOP","TRY","TTD","TWD","TZS","UAH","UGX","USD","USN","UYI","UYU","UYW","UZS","VED","VES","VND","VUV","WST","XAD","XAF","XCD","XCG","XOF","XPF","YER","ZAR","ZMW","ZWG","ANG","code","base","exponent","HRK","XAG","XAU","XDR","XPD","XPT","ZWL","SUPPORTED_CURRENCIES","AED","AFN","ALL","AMD","AOA","ARS","AUD","AWG","AZN","BAM","BBD","BDT","BGN","BHD","BIF","BMD","BND","BOB","BOV","BRL","BSD","BTN","BWP","BYN","BZD","CAD","CDF","CHE","CHF","CHW","CLF","CLP","CNY","COP","COU","CRC","CUP","CVE","CZK","DJF","DKK","DOP","DZD","EGP","ERN","ETB","EUR","FJD","FKP","GBP","GEL","GHS","GIP","GMD","GNF","GTQ","GYD","HKD","HNL","HTG","HUF","IDR","ILS","INR","IQD","IRR","ISK","JMD","JOD","JPY","KES","KGS","KHR","KMF","KPW","KRW","KWD","KYD","KZT","LAK","LBP","LKR","LRD","LSL","LYD","MAD","MDL","MGA","MKD","MMK","MNT","MOP","MRU","MUR","MVR","MWK","MXN","MXV","MYR","MZN","NAD","NGN","NIO","NOK","NPR","NZD","OMR","PAB","PEN","PGK","PHP","PKR","PLN","PYG","QAR","RON","RSD","RUB","RWF","SAR","SBD","SCR","SDG","SEK","SGD","SHP","SLE","SOS","SRD","SSP","STN","SVC","SYP","SZL","THB","TJS","TMT","TND","TOP","TRY","TTD","TWD","TZS","UAH","UGX","USD","USN","UYI","UYU","UYW","UZS","VED","VES","VND","VUV","WST","XAD","XAF","XCD","XCG","XOF","XPF","YER","ZAR","ZMW","ZWG","resolveCurrency","currencyCode","minorToMajor","minor","transform","currency","amount","dinero","toDecimal","value","resolvedCurrency","majorToMinor","major","field","scale","Number","trimmed","trim","test","ValidationException","detail","errors","message","isNegative","startsWith","unsignedValue","slice","wholePart","fractionalPart","split","length","paddedFraction","padEnd","normalizedDigits","replace","BigInt","IsCurrency","validationOptions","target","propertyName","registerDecorator","name","String","options","validator","validate","value","currency","amount","SUPPORTED_CURRENCIES","majorToMinor","defaultMessage","args","property","registerDecorator","IsCurrencyCode","validationOptions","target","propertyName","registerDecorator","name","String","options","validator","validate","value","SUPPORTED_CURRENCIES","defaultMessage","args","property","registerDecorator","UTC_ISO_DATETIME_REGEX","IsDateTime","validationOptions","target","propertyName","registerDecorator","name","String","options","validator","validate","value","test","Number","isNaN","Date","parse","defaultMessage","args","property","createParamDecorator","collectFiles","request","fieldName","file","files","consumed","matched","fieldname","push","UploadedFile","createParamDecorator","ctx","switchToHttp","getRequest","field","BadRequestException","label","detail","errors","message","buffer","toBuffer","filename","mimetype","UploadedFiles","length","results","CurrencyAmountDto","currency","value","from","minor","currencyCode","dto","minorToMajor","Global","Module","ConfigModule","BrevoClient","BrevoError","BrevoTimeoutError","Injectable","Logger","ConfigService","EmailService","logger","Logger","name","brevoClient","senderEmail","senderName","configService","apiKey","get","error","Error","BrevoClient","maxRetries","log","sendVerificationEmail","email","otp","expiresAt","displayName","expiryMinutes","Math","ceil","getTime","Date","now","subject","htmlContent","textContent","trim","sendEmail","to","sendPasswordResetEmail","sendEmailChangeNotification","oldEmail","newEmail","revertToken","revertExpiresAt","hoursUntilExpiry","floor","revertLink","sendEmailRevertConfirmation","sendInviteEmail","params","inviteUrl","sendTransactionalEmail","verifyConnection","transactionalEmails","sendTransacEmail","sender","err","BrevoError","statusCode","emailData","result","debug","messageId","BrevoTimeoutError","message","EmailModule","imports","ConfigModule","providers","EmailService","exports","Catch","HttpStatus","Logger","PG_UNIQUE_VIOLATION","tryTranslatePgError","error","pgError","findPgError","undefined","code","constraint","table","detail","ConflictException","label","trim","errors","meta","depth","candidate","cause","getHttpStatusTitle","status","enumKey","Object","entries","HttpStatus","find","key","value","Number","isNaN","split","map","word","charAt","toUpperCase","slice","toLowerCase","join","HttpExceptionFilter","logger","Logger","name","catch","exception","host","ctx","switchToHttp","response","getResponse","request","getRequest","translatedPgError","tryTranslatePgError","INTERNAL_SERVER_ERROR","type","label","detail","errors","isHttpException","getStatus","exceptionResponse","responseObj","problemResponse","message","Array","isArray","msg","constraintValues","values","constraints","field","property","filter","error","isProblemLikeObject","problemObj","statusCandidate","statusCode","undefined","isAxiosError","axiosStatus","axiosDetail","data","url","config","BAD_GATEWAY","stack","problemDetails","title","instance","header","send","Error","obj","Catch","HttpStatus","Logger","RpcException","throwError","RpcProblemExceptionFilter","logger","Logger","name","catch","exception","_host","translatedPgError","tryTranslatePgError","RpcException","throwError","getError","isHttpException","status","getStatus","response","getResponse","toProblemPayload","Error","cause","causeMessage","message","undefined","causeStack","stack","error","type","detail","errors","HttpStatus","INTERNAL_SERVER_ERROR","JSON","stringify","statusCode","obj","label","Array","isArray","Injectable","Optional","catchError","tap","Injectable","Optional","createLogger","format","transports","DailyRotateFile","AsyncLocalStorage","randomUUID","correlationStorage","AsyncLocalStorage","getCorrelationContext","getStore","runWithCorrelationContext","context","callback","run","updateCorrelationContext","updates","Object","assign","DEFAULT_CORRELATION_HEADER","generateCorrelationId","randomUUID","addCorrelationIdToResponse","reply","correlationId","headerName","header","raw","setHeader","LoggerService","activeLogger","options","context","defaultLogger","provider","Error","createWinstonLogger","opts","level","logFormat","format","baseFormatters","timestamp","errors","stack","consoleTransport","transports","Console","combine","json","printf","info","message","correlationId","trace","parts","toUpperCase","padEnd","toString","slice","filter","Boolean","output","join","colorize","all","winstonTransports","enableFileLogger","filePath","maxFiles","push","DailyRotateFile","filename","datePattern","maxSize","config","exitOnError","defaultMeta","appName","environment","createLogger","log","_log","error","warn","debug","verbose","setContext","ctx","winstonLogger","winstonLevel","formattedMessage","formatMessage","metadata","enrichMetadata","nestLogger","logWithMetadata","messageWithMeta","JSON","stringify","String","enriched","correlationContext","getCorrelationContext","key","value","Object","entries","child","childLogger","HttpLoggerInterceptor","enableRequestLog","enableResponseLog","slowRequestThreshold","logger","options","intercept","context","next","getType","handle","httpContext","switchToHttp","request","getRequest","response","getResponse","startTime","Date","now","logRequest","pipe","tap","duration","logResponse","catchError","error","logError","correlationContext","getCorrelationContext","metadata","type","method","url","correlationId","ip","userAgent","headers","logWithMetadata","stack","statusCode","logLevel","slowRequest","message","err","status","errorMessage","detail","errorName","name","trace","errorDetails","loggingError","Global","Logger","Module","Injectable","CorrelationIdMiddleware","includeInResponse","responseHeader","options","DEFAULT_CORRELATION_HEADER","use","_req","reply","next","correlationId","generateCorrelationId","addCorrelationIdToResponse","runWithCorrelationContext","onRequest","store","correlationStorage","getStore","enterWith","LOGGER_MODULE_OPTIONS","Symbol","DEFAULT_LOGGER_OPTIONS","provider","enableCorrelationId","enableHttpLogger","filePath","maxFiles","ENVIRONMENT_PRESETS","development","level","format","enableFileLogger","httpLogger","enableRequestLog","enableResponseLog","slowRequestThreshold","staging","production","test","mergeWithDefaults","options","preset","environment","filteredOptions","Object","fromEntries","entries","filter","_","value","undefined","merged","createDefaultLoggerProvider","provide","Logger","useFactory","logger","levels","getLevelsUpTo","setLogLevels","createLoggerProviders","mergedOptions","providers","useValue","push","LoggerService","opts","defaultLogger","inject","token","optional","CorrelationIdMiddleware","includeInResponse","responseHeader","HttpLoggerInterceptor","httpLoggerOptions","allLevels","isValidLevel","l","includes","levelIndex","indexOf","slice","LoggerModule","forRoot","module","exports","forRootAsync","asyncProviders","createAsyncProviders","imports","configure","_consumer","createAsyncOptionsProvider","useClass","args","userOptions","optionsFactory","createLoggerOptions","useExisting","Error","createParamDecorator","InternalServerErrorException","NATS_HEADER_KEYS","ORG_ID","USER_ID","BU_ID","BU_TIMEZONE","BU_CURRENCY_CODE","BU_ANCESTOR_IDS","BU_DESCENDANT_IDS","getHeader","headers","key","undefined","get","val","Array","isArray","parseNatsHeaders","orgId","userId","buId","buTimezone","buCurrencyCode","buAncestorIds","JSON","parse","buDescendantIds","RpcNatsHeaders","createParamDecorator","_data","ctx","rpcCtx","switchToRpc","getContext","parseNatsHeaders","getHeaders","RpcBuId","headers","buId","InternalServerErrorException","RpcBuCurrencyCode","buCurrencyCode","Global","Logger","Module","ConfigModule","ConfigService","ClientProxyFactory","Transport","NATS_MODULE_OPTIONS","Symbol","NATS_CONTEXT_RESOLVER","Inject","Injectable","Scope","REQUEST","NatsRecordBuilder","headers","natsHeaders","NATS_CLIENTS","Symbol","NatsClientService","cachedContext","request","contextResolver","clients","send","service","cmd","data","client","get","Error","keys","join","sessionInfo","headers","contextToHeaders","record","NatsRecordBuilder","setHeaders","build","toPromise","scope","Scope","REQUEST","ctx","hdrs","natsHeaders","set","NATS_HEADER_KEYS","ORG_ID","orgId","USER_ID","userId","BU_ID","buId","BU_TIMEZONE","buTimezone","BU_CURRENCY_CODE","buCurrencyCode","BU_ANCESTOR_IDS","JSON","stringify","buAncestorIds","BU_DESCENDANT_IDS","buDescendantIds","Inject","Injectable","NatsRecordBuilder","NATS_MS_CLIENTS","Symbol","NatsMicroserviceClientService","clients","send","service","cmd","natsHeaders","data","client","get","Error","keys","join","headers","NATS_HEADER_KEYS","ORG_ID","orgId","USER_ID","userId","BU_ID","buId","BU_TIMEZONE","buTimezone","BU_ANCESTOR_IDS","JSON","stringify","buAncestorIds","BU_DESCENDANT_IDS","buDescendantIds","record","NatsRecordBuilder","setHeaders","build","toPromise","NATS_MS_OPTIONS","Symbol","NatsClientModule","logger","Logger","name","allClients","onModuleDestroy","Promise","all","map","c","close","buildClients","options","natsUrl","clients","Map","svc","services","proxy","ClientProxyFactory","create","transport","Transport","NATS","servers","set","push","log","forRoot","asyncOptions","optionsProvider","provide","NATS_MODULE_OPTIONS","useFactory","inject","resolverProvider","NATS_CONTEXT_RESOLVER","contextResolver","clientsProvider","NATS_CLIENTS","config","get","ConfigService","module","imports","ConfigModule","providers","NatsClientService","exports","forMicroservice","NATS_MS_CLIENTS","NatsMicroserviceClientService","Module","Controller","Get","ApiTags","applyDecorators","ApiOperation","ApiResponse","ApiHealthCheck","applyDecorators","ApiOperation","summary","ApiResponse","status","description","type","String","Injectable","AppService","getHello","AppController","appService","getHello","Controller","Get","HttpCode","HttpStatus","Res","ApiTags","applyDecorators","ApiOperation","ApiResponse","ApiGetCsrfToken","applyDecorators","ApiOperation","summary","description","ApiResponse","status","schema","type","properties","csrfToken","example","required","CsrfController","getToken","reply","csrfToken","generateCsrf","OK","passthrough","RootModule","controllers","AppController","CsrfController","providers","AppService","gcd","a","b","CALLING_CODE_TO_COUNTRY","extractCountryFromPhone","phone","digits","startsWith","slice","length","prefix","undefined","normalizePhoneNumber"]}