@vritti/api-sdk 0.2.9 → 0.3.1

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.
Files changed (55) hide show
  1. package/dist/cache.cjs +252 -0
  2. package/dist/cache.cjs.map +1 -0
  3. package/dist/cache.d.cts +25 -0
  4. package/dist/cache.d.ts +25 -0
  5. package/dist/cache.js +214 -0
  6. package/dist/cache.js.map +1 -0
  7. package/dist/cache.service-_SuJIcNA.d.cts +20 -0
  8. package/dist/cache.service-_SuJIcNA.d.ts +20 -0
  9. package/dist/catalog-resolver.cjs +364 -0
  10. package/dist/catalog-resolver.cjs.map +1 -0
  11. package/dist/catalog-resolver.d.cts +109 -0
  12. package/dist/catalog-resolver.d.ts +109 -0
  13. package/dist/catalog-resolver.js +330 -0
  14. package/dist/catalog-resolver.js.map +1 -0
  15. package/dist/email.cjs +691 -0
  16. package/dist/email.cjs.map +1 -0
  17. package/dist/email.d.cts +35 -0
  18. package/dist/email.d.ts +35 -0
  19. package/dist/email.js +665 -0
  20. package/dist/email.js.map +1 -0
  21. package/dist/fastify-augmentation-CQPBNS5a.d.cts +105 -0
  22. package/dist/fastify-augmentation-CQPBNS5a.d.ts +105 -0
  23. package/dist/icons.cjs +13803 -0
  24. package/dist/icons.cjs.map +1 -0
  25. package/dist/icons.d.cts +8 -0
  26. package/dist/icons.d.ts +8 -0
  27. package/dist/icons.js +13778 -0
  28. package/dist/icons.js.map +1 -0
  29. package/dist/index.cjs +750 -1368
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +103 -181
  32. package/dist/index.d.ts +103 -181
  33. package/dist/index.js +609 -1234
  34. package/dist/index.js.map +1 -1
  35. package/dist/license.cjs +104 -0
  36. package/dist/license.cjs.map +1 -0
  37. package/dist/license.d.cts +32 -0
  38. package/dist/license.d.ts +32 -0
  39. package/dist/license.js +75 -0
  40. package/dist/license.js.map +1 -0
  41. package/dist/money.cjs +93 -6
  42. package/dist/money.cjs.map +1 -1
  43. package/dist/money.d.cts +13 -1
  44. package/dist/money.d.ts +13 -1
  45. package/dist/money.js +115 -3
  46. package/dist/money.js.map +1 -1
  47. package/dist/nats.cjs +196 -179
  48. package/dist/nats.cjs.map +1 -1
  49. package/dist/nats.d.cts +13 -11
  50. package/dist/nats.d.ts +13 -11
  51. package/dist/nats.js +172 -155
  52. package/dist/nats.js.map +1 -1
  53. package/dist/types-DQRwj5rr.d.cts +113 -0
  54. package/dist/types-DQRwj5rr.d.ts +113 -0
  55. package/package.json +55 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../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/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/math.utils.ts","../src/utils/phone.utils.ts"],"sourcesContent":["import './types/fastify-augmentation';\n\n// Auth (decorators, guards, token utilities)\nexport * from './auth';\n// Token types and config\nexport {\n type AccessTokenPayload,\n AUTH_CONFIG,\n AUTH_CONFIG_DEFAULTS,\n type AuthConfig,\n type CookieConfig,\n type CookieSerializeOptions,\n type DecodedAccessToken,\n type DecodedRefreshToken,\n type GuardConfig,\n type OnAuthenticatedCallback,\n type RefreshTokenPayload,\n type TokenExpiry,\n type TokenExpiryString,\n TokenType,\n} from './auth/auth.config';\n// Auth decorators (SkipCsrf for webhook endpoints)\nexport { SKIP_CSRF_KEY, SkipCsrf } from './auth/decorators/skip-csrf.decorator';\n// Token service — generation, validation, and binding verification\nexport { TokenService } from './auth/services/token.service';\nexport type { ICacheProvider } from './cache';\n// Cache module (Redis provider + ICacheProvider contract)\nexport { CACHE_PROVIDER, CacheModule, CacheService, RedisCacheProvider } from './cache';\n// Data table module (views + ephemeral state)\nexport { DATA_TABLE_VIEWS_TABLE, DataTableModule, type DataTableModuleOptions } from './data-table/data-table.module';\nexport {\n type DataTableViewRecord,\n dataTableViewsColumns,\n dataTableViewsIndexes,\n type NewDataTableViewRecord,\n} from './data-table/schema/data-table-views.table';\nexport { UpsertDataTableStateDto } from './data-table/state/dto/request/upsert-data-table-state.dto';\nexport { DataTableStateService } from './data-table/state/services/data-table-state.service';\nexport { DataTableViewDto } from './data-table/views/dto/entity/data-table-view.dto';\nexport { CreateDataTableViewDto } from './data-table/views/dto/request/create-data-table-view.dto';\nexport { RenameDataTableViewDto } from './data-table/views/dto/request/rename-data-table-view.dto';\nexport { ToggleShareDataTableViewDto } from './data-table/views/dto/request/toggle-share-data-table-view.dto';\nexport { UpdateDataTableViewDto } from './data-table/views/dto/request/update-data-table-view.dto';\nexport { DataTableViewsService } from './data-table/views/services/data-table-views.service';\nexport { DatabaseModule } from './database/database.module';\n// Database DTOs\nexport { CreateResponseDto } from './database/dto/create-response.dto';\nexport { ImportResponseDto, ImportSummaryDto, ValidatedRowDto } from './database/dto/import-response.dto';\nexport { SelectOptionsQueryDto } from './database/dto/select-options-query.dto';\nexport { SuccessResponseDto } from './database/dto/success-response.dto';\nexport { TableResponseDto } from './database/dto/table-response.dto';\n// Filter processor\nexport { type FieldDefinition, type FieldMap, FilterProcessor } from './database/filter/filter.processor';\nexport type {\n ColumnPinning,\n DensityType,\n FilterCondition,\n FilterOperator,\n SearchState,\n SortCondition,\n TableViewState,\n} from './database/filter/filter.types';\nexport { FilterOperators } from './database/filter/filter.types';\n// Interfaces\nexport * from './database/interfaces';\n// Repositories\nexport { PrimaryBaseRepository } from './database/repositories/primary-base.repository';\nexport type { TypedDrizzleClient } from './database/schema.registry';\nexport { PrimaryDatabaseService } from './database/services/primary-database.service';\n// Database types\nexport type {\n FindForSelectConfig,\n FindForSelectJoin,\n SelectQueryGroup,\n SelectQueryOption,\n SelectQueryResult,\n} from './database/types';\nexport { IsCurrency } from './decorators/is-currency.decorator';\nexport { IsCurrencyCode } from './decorators/is-currency-code.decorator';\nexport { IsDateTime } from './decorators/is-date-time.decorator';\n// Decorators\nexport { UploadedFile, type UploadedFileResult, UploadedFiles } from './decorators/uploaded-file.decorator';\nexport { CurrencyAmountDto } from './dto/currency-amount.dto';\n// Email module\nexport { EmailModule } from './email/email.module';\nexport { EmailService } from './email/email.service';\n// Exceptions\nexport * from './exceptions';\n// RFC 7807 Filters (includes HttpExceptionFilter)\nexport * from './filters';\n// Logger utilities\nexport * from './logger';\nexport type { Currency, CurrencyCode } from './money';\nexport { majorToMinor, minorToMajor, SUPPORTED_CURRENCIES } from './money';\n// NATS / microservice exports moved to the './nats' subpath (@vritti/api-sdk/nats) so the main\n// barrel never imports @nestjs/microservices. Non-NATS consumers (cloud-server) stay clean.\n// Root module (health check + CSRF)\nexport { RootModule } from './root/root.module';\n// RFC 7807 Types (using named exports to avoid conflicts)\nexport type { ApiErrorResponse, ProblemDetails } from './types';\n// Math utilities\nexport { gcd } from './utils/math.utils';\n// Phone utilities\nexport { extractCountryFromPhone, normalizePhoneNumber } from './utils/phone.utils';\n// Time utilities\nexport { parseExpiryToMs } from './utils/time.utils';\n","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 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 { 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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAAAA;EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BAAAC;EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACGO,IAAMC,cAAcC,OAAO,aAAA;AAuC3B,IAAMC,uBAAuB;EAClCC,QAAQ;IACNC,mBAAmB;IACnBC,qBAAqB,KAAK,KAAK,KAAK,KAAK;IACzCC,mBAAmB;IACnBC,qBAAqBC,QAAQC,IAAIC,aAAa;IAC9CC,uBAAuB;IACvBC,qBAAqB;EACvB;EACAC,OAAO;IACLC,gBAAgB;IAChBC,aAAa;IACbC,wBAAwB,CAAA;IACxBC,uCAAuC,CAAA;EACzC;AACF;AAWO,IAAKC,YAAAA,0BAAAA,YAAAA;;;SAAAA;;;;ACpEZ,IAAAC,iBAAwE;AACxE,oBAA4C;AAC5C,IAAAC,eAAqC;AACrC,IAAAC,cAA0B;;;ACH1B,IAAAC,iBAA+B;;;ACA/B,oBAA0C;AAC1C,kBAAwB;;;;;;;;;;;;;;;;;;AAKjB,IAAMC,iBAAN,MAAMA;SAAAA;;;;;EACX,YACoCC,SACIC,QACtC;SAFkCD,UAAAA;SACIC,SAAAA;EACrC;;EAGHC,iBAAgC;AAC9B,UAAMC,aAAa,KAAKH,QAAQI,UAAU,KAAKH,OAAOI,MAAMC,cAAc;AAC1E,QAAI,CAACH,cAAc,OAAOA,eAAe,UAAU;AACjD,aAAO;IACT;AACA,UAAM,CAACI,MAAMC,KAAAA,IAASL,WAAWM,MAAM,GAAA,KAAQ,CAAA;AAC/C,WAAOF,SAAS,KAAKN,OAAOI,MAAMK,eAAeF,QAAQA,QAAQ;EACnE;;EAGAG,kBAAiC;AAC/B,QAAI;AACF,YAAMC,UAAW,KAAKZ,QAA4DY;AAClF,UAAIA,WAAW,OAAOA,YAAY,UAAU;AAC1C,cAAMC,eAAeD,QAAQ,KAAKX,OAAOa,OAAOC,iBAAiB;AACjE,YAAIF,cAAc;AAChB,iBAAOA;QACT;MACF;AACA,aAAO;IACT,SAASG,QAAiB;AACxB,aAAO;IACT;EACF;;EAGAC,UAAUC,KAA4C;AACpD,WAAO,KAAKlB,QAAQI,UAAUc,GAAAA;EAChC;;EAGAC,cAAsB;AACpB,WAAO,KAAKnB,QAAQoB,YAAY;EAClC;;EAGAC,gBAA2C;AACzC,WAAO,KAAKrB,QAAQI,WAAW,CAAC;EAClC;AACF;;;IA/CckB,OAAOC,oBAAMC;;;;;;;;;;;;;;;;;;;ADGpB,IAAMC,gBAAN,MAAMA;SAAAA;;;AAAe;;;;IAH1BC,WAAW;MAACC;;IACZC,SAAS;MAACD;;;;;;AENZ,IAAAE,iBASO;AACP,uBAA6B;AAC7B,IAAAC,eAA0B;;;ACX1B,IAAAC,iBAA4B;AAGrB,IAAMC,sBAAsB;AAC5B,IAAMC,iBAAiB,2BAAIC,cAAoBC,4BAAYH,qBAAqBE,KAAAA,GAAzD;;;ACJ9B,IAAAE,iBAA4B;AAErB,IAAMC,gBAAgB;AAEtB,IAAMC,WAAW,iCAAMC,4BAAYF,eAAe,IAAA,GAAjC;;;ACJxB,IAAAG,iBAAkE;AAClE,iBAAgD;;;ACAzC,SAASC,gBAAgBC,QAAc;AAC5C,QAAMC,QAAQD,OAAOC,MAAM,mBAAA;AAC3B,MAAI,CAACA,MAAO,OAAM,IAAIC,MAAM,0BAA0BF,MAAAA,EAAQ;AAE9D,QAAMG,QAAQC,OAAOC,SAASJ,MAAM,CAAA,GAAK,EAAA;AACzC,QAAMK,cAAsC;IAC1CC,GAAG;IACHC,GAAG;IACHC,GAAG;IACHC,GAAG;IACHC,GAAG;IACHC,GAAG;EACL;AAEA,SAAOT,QAAQG,YAAYL,MAAM,CAAA,CAAE;AACrC;AAfgBF;;;ACDhB,aAAwB;AAGjB,SAASc,UAAUC,OAAa;AACrC,SAAcC,kBAAW,QAAA,EAAUC,OAAOF,KAAAA,EAAOG,OAAO,KAAA;AAC1D;AAFgBJ;AAKT,SAASK,gBAAgBJ,OAAeK,cAAoB;AACjE,QAAMC,eAAeP,UAAUC,KAAAA;AAC/B,MAAIM,aAAaC,WAAWF,aAAaE,OAAQ,QAAO;AACxD,SAAcC,uBAAgBC,OAAOC,KAAKJ,cAAc,KAAA,GAAQG,OAAOC,KAAKL,cAAc,KAAA,CAAA;AAC5F;AAJgBD;;;;;;;;;;;;;;;;;;;;AFiBT,IAAMO,eAAN,MAAMA,cAAAA;SAAAA;;;;;EACMC,SAAS,IAAIC,sBAAOF,cAAaG,IAAI;EAEtD,YACmBC,YACqBC,QACtC;SAFiBD,aAAAA;SACqBC,SAAAA;EACrC;;;EAKHC,oBAAoBC,aAA0BC,cAA8B;AAC1E,UAAM,EAAEC,QAAQC,WAAWC,aAAa,GAAGC,SAAAA,IAAaL;AACxD,WAAO,KAAKH,WAAWS,KACrB;MACEF;MACAG,WAAWC,UAAUC;MACrBP;MACAC;MACAO,kBAAkBC,UAAUV,YAAAA;MAC5B,GAAGI;IACL,GACA;MAAEO,WAAW,KAAKd,OAAOe,YAAYC;IAAO,CAAA;EAEhD;;EAGAC,qBAAqBf,aAAkC;AACrD,UAAM,EAAEE,QAAQC,WAAWC,aAAa,GAAGC,SAAAA,IAAaL;AACxD,WAAO,KAAKH,WAAWS,KACrB;MAAEF;MAAaG,WAAWC,UAAUQ;MAASd;MAAQC;MAAW,GAAGE;IAAS,GAC5E;MAAEO,WAAW,KAAKd,OAAOe,YAAYI;IAAQ,CAAA;EAEjD;;EAGAX,KAAKY,SAAiBC,SAAkC;AACtD,WAAO,KAAKtB,WAAWS,KAAKY,SAASC,OAAAA;EACvC;;EAGAC,OACEC,OACAC,cACkF;AAClF,QAAI;AACF,YAAMJ,UAAU,KAAKrB,WAAWuB,OAAOC,KAAAA;AAEvC,UAAIH,QAAQX,cAAce,cAAc;AACtC,cAAM,IAAIC,MAAM,YAAYD,YAAAA,eAA2BJ,QAAQX,SAAS,EAAE;MAC5E;AAEA,aAAOW;IACT,SAASM,OAAO;AACd,WAAK9B,OAAO8B,MAAM,oBAAoBF,YAAAA,UAAsBE,KAAAA;AAC5D,YAAMA;IACR;EACF;;EAGAC,cAAcC,MAAuB;AACnC,WAAO,IAAIC,KAAKA,KAAKC,IAAG,IAAKC,gBAAgB,KAAK/B,OAAOe,YAAYa,IAAAA,CAAK,CAAA;EAC5E;;EAGAI,mBAAmBJ,MAAyB;AAC1C,WAAOK,KAAKC,MAAMH,gBAAgB,KAAK/B,OAAOe,YAAYa,IAAAA,CAAK,IAAI,GAAA;EACrE;;;EAKAO,oBAAoBZ,OAAmC;AACrD,QAAI;AACF,YAAMa,UAAU,KAAKrC,WAAWuB,OAA2BC,KAAAA;AAE3D,UAAIa,QAAQ3B,cAAcC,UAAUC,QAAQ;AAC1C,cAAM,IAAI0B,qCAAsB,oBAAA;MAClC;AAEA,aAAOD;IACT,SAASV,OAAO;AACd,UAAIA,iBAAiBW,qCAAuB,OAAMX;AAElD,YAAMY,WAAWZ;AACjB,cAAQY,SAASxC,MAAI;QACnB,KAAK;AACH,gBAAM,IAAIuC,qCAAsB,0BAAA;QAClC,KAAK;AACH,gBAAM,IAAIA,qCAAsB,sBAAA;QAClC,KAAK;AACH,gBAAM,IAAIA,qCAAsB,4BAAA;QAClC;AACE,gBAAM,IAAIA,qCAAsB,gCAAA;MACpC;IACF;EACF;;EAGAE,qBAAqBhB,OAAoC;AACvD,QAAI;AACF,YAAMa,UAAU,KAAKrC,WAAWuB,OAA4BC,KAAAA;AAE5D,UAAIa,QAAQ3B,cAAcC,UAAUQ,SAAS;AAC3C,cAAM,IAAImB,qCAAsB,oBAAA;MAClC;AAEA,aAAOD;IACT,SAASV,OAAO;AACd,UAAIA,iBAAiBW,qCAAuB,OAAMX;AAClD,YAAM,IAAIW,qCAAsB,4BAAA;IAClC;EACF;;EAGAG,qBAAqBC,aAAiCtC,cAA4B;AAChF,QAAI,CAACuC,gBAAgBvC,cAAcsC,YAAY7B,gBAAgB,GAAG;AAChE,YAAM,IAAIyB,qCAAsB,2BAAA;IAClC;EACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AHtHO,IAAMM,kBAAN,MAAMA,iBAAAA;SAAAA;;;;;;;EACMC,SAAS,IAAIC,sBAAOF,iBAAgBG,IAAI;EAEzD,YACmBC,WACAC,gBACAC,cACqBC,QACtC;SAJiBH,YAAAA;SACAC,iBAAAA;SACAC,eAAAA;SACqBC,SAAAA;EACrC;EAEH,MAAMC,YAAYC,SAA6C;AAC7D,UAAMC,UAAUD,QAAQE,aAAY,EAAGC,WAAU;AACjD,UAAMC,QAAQJ,QAAQE,aAAY,EAAGG,YAAW;AAChD,UAAMC,QAAQ,GAAGL,QAAQM,MAAM,IAAIN,QAAQO,GAAG;AAG9CP,YAAQQ,aAAa,KAAKX;AAE1B,UAAMY,WAAW,KAAKf,UAAUgB,kBAA2BC,eAAe;MACxEZ,QAAQa,WAAU;MAClBb,QAAQc,SAAQ;KACjB;AAGD,UAAMC,WAAW,KAAKpB,UAAUgB,kBAA2B,YAAY;MAACX,QAAQa,WAAU;MAAIb,QAAQc,SAAQ;KAAG;AACjH,QAAIC,UAAU;AACZ,UAAI,CAACL,UAAU;AACb,cAAM,KAAKM,aAAaf,SAASG,KAAAA;MACnC;AACA,WAAKZ,OAAOyB,MAAM,GAAGX,KAAAA,wCAAwC;AAC7D,aAAO;IACT;AAGA,UAAMY,uBAAuB,KAAKvB,UAAUgB,kBAA4BQ,qBAAqB;MAC3FnB,QAAQa,WAAU;MAClBb,QAAQc,SAAQ;KACjB;AAGD,UAAMM,gBAAgB,KAAKzB,UAAU0B,IAAaC,+BAActB,QAAQa,WAAU,CAAA;AAClF,QAAIO,eAAe;AACjB,WAAK5B,OAAOyB,MAAM,GAAGX,KAAAA,yDAAyD;AAC9E,aAAO,KAAKiB,cAActB,SAASiB,oBAAAA;IACrC;AAEA,UAAMM,cAAc,MAAM,KAAKC,eAAexB,SAASiB,oBAAAA;AAEvD,UAAMQ,yBAAyB,KAAK5B,OAAO6B,MAAMD,0BAA0B,CAAA;AAC3E,QAAI,CAAChB,YAAY,CAACgB,uBAAuBE,SAASJ,WAAAA,GAAc;AAC9D,YAAM,KAAKR,aAAaf,SAASG,KAAAA;IACnC;AAEA,WAAO;EACT;;EAGA,MAAcqB,eAAexB,SAAyBiB,sBAAkD;AACtG,UAAMZ,QAAQ,GAAGL,QAAQM,MAAM,IAAIN,QAAQO,GAAG;AAE9C,UAAMqB,cAAc,KAAKjC,eAAekC,eAAc;AACtD,QAAI,CAACD,aAAa;AAChB,WAAKrC,OAAOuC,KAAK,GAAGzB,KAAAA,+BAA+B;AACnD,YAAM,IAAI0B,qCAAsB,wBAAA;IAClC;AAEA,UAAMC,UAAU,KAAKpC,aAAaqC,oBAAoBL,WAAAA;AAEtD,UAAMM,wCAAwC,KAAKrC,OAAO6B,MAAMQ,yCAAyC,CAAA;AAEzG,QAAI,CAACA,sCAAsCP,SAASK,QAAQT,WAAW,GAAG;AACxE,YAAMY,eAAe,KAAKxC,eAAeyC,gBAAe;AACxD,UAAI,CAACD,cAAc;AACjB,cAAM,IAAIJ,qCAAsB,2BAAA;MAClC;AACA,WAAKnC,aAAayC,qBAAqBL,SAASG,YAAAA;IAClD;AAGA,QAAIlB,sBAAsBqB,UAAU,CAACrB,qBAAqBU,SAASK,QAAQT,WAAW,GAAG;AACvF,WAAKhC,OAAOuC,KACV,GAAGzB,KAAAA,wBAAwB2B,QAAQT,WAAW,qBAAqBN,qBAAqBsB,KAAK,IAAA,CAAA,GAAQ;AAEvG,YAAM,IAAIR,qCAAsB,GAAGC,QAAQT,WAAW,uCAAuC;IAC/F;AAGA,UAAM,EAAEiB,WAAWC,YAAYC,kBAAkBC,OAAOC,KAAKC,MAAMC,KAAKC,MAAM,GAAGC,YAAAA,IAAgBhB;AACjGhC,YAAQgD,cAAcA;AAGtB,UAAMC,kBAAkB,KAAKpD,OAAO6B,MAAMuB;AAC1C,QAAIA,iBAAiB;AACnB,YAAMA,gBAAgB,KAAKtD,gBAAgBK,QAAQgD,WAAW;IAChE;AAEA,SAAKzD,OAAOyB,MAAM,GAAGX,KAAAA,+BAA+B2B,QAAQkB,MAAM,KAAKlB,QAAQT,WAAW,GAAG;AAC7F,WAAOS,QAAQT;EACjB;;EAGQD,cAActB,SAAyBiB,sBAA0C;AACvF,UAAMkB,eAAe,KAAKxC,eAAeyC,gBAAe;AACxD,QAAI,CAACD,cAAc;AACjB,WAAK5C,OAAOuC,KAAK,OAAO9B,QAAQO,GAAG,iCAA4B;AAC/D,YAAM,IAAIwB,qCAAsB,yBAAA;IAClC;AAEA,UAAMC,UAAU,KAAKpC,aAAauD,qBAAqBhB,YAAAA;AAEvD,QAAIlB,sBAAsBqB,UAAU,CAACrB,qBAAqBU,SAASK,QAAQT,WAAW,GAAG;AACvF,WAAKhC,OAAOuC,KAAK,OAAO9B,QAAQO,GAAG,wBAAmByB,QAAQT,WAAW,cAAc;AACvF,YAAM,IAAIQ,qCAAsB,GAAGC,QAAQT,WAAW,uCAAuC;IAC/F;AAEA,UAAM,EAAEiB,WAAWC,YAAYG,KAAKC,MAAMC,KAAKC,MAAM,GAAGC,YAAAA,IAAgBhB;AACxEhC,YAAQgD,cAAcA;AAEtB,SAAKzD,OAAOyB,MAAM,OAAOhB,QAAQO,GAAG,+BAA0ByB,QAAQkB,MAAM,KAAKlB,QAAQT,WAAW,GAAG;AACvG,WAAO;EACT;;EAGA,MAAcR,aAAaf,SAAyBG,OAAoC;AACtF,UAAMiD,cAAc;MAAC;MAAO;MAAQ;;AACpC,QAAIA,YAAYzB,SAAS3B,QAAQM,MAAM,EAAG;AAE1C,QAAI;AACF,YAAM+C,kBAAkBrD,QAAQsD;AAChC,YAAMC,iBAAiBF,gBAAgBE;AACvC,UAAI,CAACA,gBAAgB;AACnB,cAAM,IAAIC,kCAAmB,gCAAA;MAC/B;AAEA,YAAM,IAAIC,QAAc,CAACC,SAASC,WAAAA;AAChC,cAAMC,eAAezD,MAAM0D,KAAKC,KAAK3D,KAAAA;AACpCA,cAAyB0D,OAAO,MAAA;AAC9B1D,gBAAyB0D,OAAOD;AACjCD,iBAAO,IAAII,MAAM,wBAAA,CAAA;AACjB,iBAAO5D;QACT;AAEAoD,uBAAevD,SAASG,OAAO,CAAC6D,QAAAA;AAC7B7D,gBAAyB0D,OAAOD;AACjC,cAAII,IAAKL,QAAOK,GAAAA;cACXN,SAAAA;QACP,CAAA;MACF,CAAA;IACF,SAASO,QAAiB;AACxB,WAAK1E,OAAOuC,KAAK,GAAG9B,QAAQM,MAAM,IAAIN,QAAQO,GAAG,gCAA2B;AAC5E,YAAM,IAAIiD,kCAAmB;QAC3BU,QAAQ;UAAC;YAAEC,OAAO;YAAQC,SAAS;UAAgC;;QACnEA,SAAS;MACX,CAAA;IACF;EACF;AACF;;;IA7JcC,OAAOC,qBAAMC;;;;;;;;;;;;;;;;;;;;AHG3B,SAASC,kBAAkBC,OAAsB;AAC/C,SAAO;IACLC,aAAaD,MAAMC;IACnBC,QAAQ;MACN,GAAGC,qBAAqBD;MACxB,GAAIF,MAAME,UAAU,CAAC;IACvB;IACAE,OAAO;MACL,GAAGD,qBAAqBC;MACxB,GAAIJ,MAAMI,SAAS,CAAC;IACtB;EACF;AACF;AAZSL;AAgBF,IAAMM,mBAAN,MAAMA,kBAAAA;SAAAA;;;;EAEX,OAAOC,aAA8CC,SAAoD;AACvG,WAAO;MACLC,QAAQH;MACRI,SAAS;QACPC;QACAC;QACAC,sBAAUC,cAAc;UACtBJ,SAAS;YAACC;;UACVI,QAAQ;YAACC;;UACTC,YAAY,wBAACC,YAA2B;YACtCC,QAAQD,OAAOE,WAAmB,YAAA;YAClCC,aAAa;cAAEC,WAAW;YAAiB;UAC7C,IAHY;QAId,CAAA;;MAEFC,WAAW;QACT;UACEC,SAASC;UACTC,UAAUD;QACZ;QACA;UACED,SAASG;UACTD,UAAUE;QACZ;QACA;UACEJ,SAASK;UACTZ,YAAY,iCAAUa,SAAAA;AACpB,kBAAM7B,QAAQ,MAAMO,QAAQS,WAAU,GAAKa,IAAAA;AAC3C,mBAAO9B,kBAAkBC,KAAAA;UAC3B,GAHY;UAIZc,QAAQP,QAAQO,UAAU,CAAA;QAC5B;QACAgB;;MAEFC,SAAS;QAACnB;QAAWkB;QAAcF;;IACrC;EACF;AACF;;;;;;;ASpFA,IAAAI,iBAA4D;AAIrD,IAAMC,kBAAcC,qCAAqB,CAACC,OAAgBC,QAAAA;AAC/D,QAAMC,UAAUD,IAAIE,aAAY,EAAGC,WAAU;AAC7C,QAAMC,aAAaH,QAAQI,QAAQC;AACnC,SAAOF,YAAYG,QAAQ,WAAW,EAAA,KAAO;AAC/C,CAAA;;;ACRA,IAAAC,iBAA4D;AAKrD,IAAMC,mBAAeC,qCAAqB,CAACC,OAAgBC,QAAAA;AAChE,QAAMC,UAAUD,IAAIE,aAAY,EAAGC,WAAU;AAC7C,QAAMC,YAAYH,QAAQI,QAAQ,kBAAA;AAClC,QAAMC,MAAMC,MAAMC,QAAQJ,SAAAA,IAAaA,UAAU,CAAA,IAAKA;AACtD,QAAMK,UAAUH,OAAOL,QAAQS;AAC/B,QAAMC,SAASF,QAAQG,MAAM,GAAA,EAAK,CAAA,KAAMH;AACxC,QAAMI,aACJZ,QAAQa,YAAYC,OAAOC,uBAAuBC,qBAAqBF,OAAOC,uBAAuB;AACvG,SAAOL,OAAOO,SAAS,IAAIL,UAAAA,EAAY,IAAIF,SAASE;AACtD,CAAA;;;ACdA,IAAAM,kBAA4D;AAKrD,IAAMC,iBAAaC,sCAAqB,CAACC,OAAgBC,QAAAA;AAC9D,QAAMC,UAAUD,IAAIE,aAAY,EAAGC,WAAU;AAC7C,SAAOF,QAAQG,YAAYC,OAAOC,qBAAqBC,qBAAqBF,OAAOC;AACrF,CAAA;;;ACRA,IAAAE,kBAA4D;AAIrD,IAAMC,eAAWC,sCAAqB,CAACC,OAAgBC,QAAAA;AAC5D,QAAMC,UAAUD,IAAIE,aAAY,EAAGC,WAAU;AAC7C,QAAMC,YAAYH,QAAQI,QAAQ,kBAAA;AAClC,QAAMC,MAAMC,MAAMC,QAAQJ,SAAAA,IAAaA,UAAU,CAAA,IAAKA;AACtD,QAAMK,UAAUH,OAAOL,QAAQS;AAC/B,SAAOD,QAAQE,MAAM,GAAA,EAAK,CAAA,KAAMF;AAClC,CAAA;;;ACVA,IAAAG,kBAA4B;AAErB,IAAMC,SAAS,iCAAMC,6BAAY,YAAY,IAAA,GAA9B;;;ACFtB,IAAAC,kBAA4D;;;ACA5D,IAAAC,kBAA2B;;;ACA3B,IAAAC,kBAA0C;AAanC,IAAeC,uBAAf,cAA4CC,8BAAAA;EAbnD,OAamDA;;;EACjD,YAAYC,iBAA0CC,YAAwB;AAC5E,UAAMC,UAAU,OAAOF,oBAAoB,WAAW;MAAEG,QAAQH;IAAgB,IAAIA;AAEpF,UACE;MACEI,MAAMF,QAAQE,QAAQ;MACtBC,OAAOH,QAAQG;MACfF,QAAQD,QAAQC;MAChBG,QAAQJ,QAAQI,UAAU,CAAA;IAC5B,GACAL,UAAAA;EAEJ;AACF;;;ADxBO,IAAMM,sBAAN,cAAkCC,qBAAAA;EAHzC,OAGyCA;;;EACvC,YAAYC,iBAA2C;AACrD,UAAMA,mBAAmB,eAAeC,2BAAWC,WAAW;EAChE;AACF;;;AEPA,IAAAC,kBAA2B;AAGpB,IAAMC,sBAAN,cAAkCC,qBAAAA;EAHzC,OAGyCA;;;EACvC,YAAYC,iBAA2C;AACrD,UAAMA,mBAAmB,eAAeC,2BAAWC,WAAW;EAChE;AACF;;;ACPA,IAAAC,kBAA2B;AAGpB,IAAMC,oBAAN,cAAgCC,qBAAAA;EAHvC,OAGuCA;;;EACrC,YAAYC,iBAA2C;AACrD,UAAMA,mBAAmB,YAAYC,2BAAWC,QAAQ;EAC1D;AACF;;;ACPA,IAAAC,kBAA2B;AAGpB,IAAMC,sBAAN,cAAiCC,qBAAAA;EAHxC,OAGwCA;;;EACtC,YAAYC,iBAA2C;AACrD,UAAMA,mBAAmB,aAAaC,2BAAWC,SAAS;EAC5D;AACF;;;ACPA,IAAAC,kBAA2B;AAGpB,IAAMC,gBAAN,cAA4BC,qBAAAA;EAHnC,OAGmCA;;;EACjC,YAAYC,iBAA2C;AACrD,UAAMA,mBAAmB,QAAQC,2BAAWC,IAAI;EAClD;AACF;;;ACPA,IAAAC,kBAA2B;AAGpB,IAAMC,+BAAN,cAA2CC,qBAAAA;EAHlD,OAGkDA;;;EAChD,YAAYC,iBAA2C;AACrD,UAAMA,mBAAmB,yBAAyBC,2BAAWC,qBAAqB;EACpF;AACF;;;ACPA,IAAAC,kBAA2B;AAGpB,IAAMC,4BAAN,cAAwCC,qBAAAA;EAH/C,OAG+CA;;;EAC7C,YAAYC,iBAA2C;AACrD,UAAMA,mBAAmB,sBAAsBC,2BAAWC,kBAAkB;EAC9E;AACF;;;ACPA,IAAAC,kBAA2B;AAGpB,IAAMC,yBAAN,cAAqCC,qBAAAA;EAH5C,OAG4CA;;;EAC1C,YAAYC,iBAA2C;AACrD,UAAMA,mBAAmB,kBAAkBC,2BAAWC,cAAc;EACtE;AACF;;;ACPA,IAAAC,kBAA2B;AAGpB,IAAMC,oBAAN,cAAgCC,qBAAAA;EAHvC,OAGuCA;;;EACrC,YAAYC,iBAA2C;AACrD,UAAMA,mBAAmB,aAAaC,2BAAWC,SAAS;EAC5D;AACF;;;ACPA,IAAAC,kBAA2B;AAGpB,IAAMC,0BAAN,cAAsCC,qBAAAA;EAH7C,OAG6CA;;;EAC3C,YAAYC,iBAA2C;AACrD,UAAMA,mBAAmB,mBAAmBC,2BAAWC,eAAe;EACxE;AACF;;;ACPA,IAAAC,kBAA2B;AAGpB,IAAMC,2BAAN,cAAuCC,qBAAAA;EAH9C,OAG8CA;;;EAC5C,YAAYC,iBAA2C;AACrD,UAAMA,mBAAmB,qBAAqBC,2BAAWC,iBAAiB;EAC5E;AACF;;;ACPA,IAAAC,kBAA2B;AAGpB,IAAMC,0BAAN,cAAsCC,qBAAAA;EAH7C,OAG6CA;;;EAC3C,YAAYC,iBAA2C;AACrD,UAAMA,mBAAmB,mBAAmBC,2BAAWC,eAAe;EACxE;AACF;;;ACPA,IAAAC,kBAA2B;AAGpB,IAAMC,8BAAN,cAA0CC,qBAAAA;EAHjD,OAGiDA;;;EAC/C,YAAYC,iBAA2C;AACrD,UAAMA,mBAAmB,uBAAuBC,2BAAWC,mBAAmB;EAChF;AACF;;;ACPA,IAAAC,kBAA2B;AAGpB,IAAMC,2BAAN,cAAuCC,qBAAAA;EAH9C,OAG8CA;;;EAC5C,YAAYC,iBAA2C;AACrD,UAAMA,mBAAmB,qBAAqBC,2BAAWC,iBAAiB;EAC5E;AACF;;;ACPA,IAAAC,kBAA2B;AAGpB,IAAMC,yBAAN,cAAoCC,qBAAAA;EAH3C,OAG2CA;;;EACzC,YAAYC,iBAA2C;AACrD,UAAMA,mBAAmB,gBAAgBC,2BAAWC,YAAY;EAClE;AACF;;;ACPA,IAAAC,kBAA2B;AAGpB,IAAMC,+BAAN,cAA2CC,qBAAAA;EAHlD,OAGkDA;;;EAChD,YAAYC,iBAA2C;AACrD,UAAMA,mBAAmB,wBAAwBC,2BAAWC,oBAAoB;EAClF;AACF;;;ACPA,IAAAC,kBAA2B;AAGpB,IAAMC,gCAAN,cAA4CC,qBAAAA;EAHnD,OAGmDA;;;EACjD,YAAYC,iBAA2C;AACrD,UAAMA,mBAAmB,0BAA0BC,2BAAWC,sBAAsB;EACtF;AACF;;;ACPA,IAAAC,kBAA2B;AAGpB,IAAMC,sBAAN,cAAkCC,qBAAAA;EAHzC,OAGyCA;;;EACvC,YAAYC,iBAA2C;AACrD,UAAMA,mBAAmB,qBAAqBC,2BAAWC,oBAAoB;EAC/E;AACF;;;AnBDA,SAASC,0BAA0BC,cAA4BC,UAAgB;AAC7E,QAAMC,aAAaF,aAAaG;AAEhC,MAAI,CAACD,YAAY;AACf,UAAM,IAAIE,MAAM,6EAAA;EAClB;AAEA,MAAI,CAACH,SAASI,SAAS,IAAIH,UAAAA,EAAY,GAAG;AACxC,UAAM,IAAII,uBAAsB,uBAAA;EAClC;AAEA,SAAO;IACLC,UAAU;IACVC,QAAQR,aAAaS;IACrBC,UAAUV,aAAaW;IACvBC,MAAMZ,aAAaa;IACnBC,QAAQd,aAAae;IACrBC,QAAQf;EACV;AACF;AAnBSF;AAsBF,IAAMkB,2BAAuBC,sCAClC,CAACC,OAAgBC,QAAAA;AACf,QAAMC,UAAUD,IAAIE,aAAY,EAAGC,WAAU;AAC7C,QAAMC,YAAYH,QAAQI,QAAQ,kBAAA;AAClC,QAAMC,MAAMC,MAAMC,QAAQJ,SAAAA,IAAaA,UAAU,CAAA,IAAKA;AACtD,QAAMK,UAAUH,OAAOL,QAAQpB;AAC/B,QAAMe,SAASa,QAAQC,MAAM,GAAA,EAAK,CAAA,KAAMD;AACxC,QAAM7B,eAA6BqB,QAAQU,YAAYC,UAAUC,qBAAqBD;AACtF,SAAOjC,0BAA0BC,cAAcgB,MAAAA;AACjD,CAAA;;;AoBrCF,IAAAkB,kBAA4D;AAIrD,IAAMC,yBAAqBC,sCAAqB,CAACC,OAAgBC,QAAAA;AACtE,QAAMC,UAAUD,IAAIE,aAAY,EAAGC,WAAU;AAC7C,QAAMC,UAAUH,QAAQG,WAAW,CAAC;AACpC,QAAMC,aAAaJ,QAAQK,YAAYC,OAAOC,qBAAqBC,qBAAqBF,OAAOC;AAC/F,SAAOJ,QAAQC,UAAAA;AACjB,CAAA;;;ACTA,IAAAK,kBAA4D;AAWrD,IAAMC,kBAAcC,sCAAqB,CAACC,OAAgBC,QAAAA;AAC/D,QAAMC,UAAUD,IAAIE,aAAY,EAAGC,WAAU;AAC7C,QAAMC,cAAcH,QAAQG;AAE5B,MAAI,CAACA,aAAaC,WAAW;AAC3B,UAAM,IAAIC,MAAM,6EAAA;EAClB;AAEA,SAAO;IACLC,QAAQH,YAAYG;IACpBF,WAAWD,YAAYC;IACvBG,aAAaJ,YAAYI;EAC3B;AACF,CAAA;;;ACxBA,IAAAC,kBAA4D;AAIrD,IAAMC,gBAAYC,sCAAqB,CAACC,OAAgBC,QAAAA;AAC7D,QAAMC,UAAUD,IAAIE,aAAY,EAAGC,WAAU;AAG7C,QAAMC,SAASH,QAAQI,QAAQD;AAC/B,MAAIA,QAAQ;AACV,QAAI;AACF,YAAME,MAAM,IAAIC,IAAIH,MAAAA;AACpB,aAAOE,IAAIE,SAASC,MAAM,GAAA,EAAK,CAAA;IACjC,QAAQ;IAER;EACF;AAGA,QAAMC,YAAYT,QAAQI,QAAQ,kBAAA;AAClC,QAAMM,OAAOC,MAAMC,QAAQH,SAAAA,IAAaA,UAAU,CAAA,IAAKA;AACvD,MAAIC,KAAM,QAAOA,KAAKF,MAAM,GAAA,EAAK,CAAA;AAEjC,SAAOK;AACT,CAAA;;;ACxBA,IAAAC,kBAA4D;AAKrD,IAAMC,aAASC,sCAAqB,CAACC,OAAgBC,QAAAA;AAC1D,QAAMC,UAAUD,IAAIE,aAAY,EAAGC,WAAU;AAC7C,QAAMC,cAAcH,QAAQG;AAE5B,MAAI,CAACA,aAAaC,QAAQ;AACxB,UAAM,IAAIC,MAAM,wEAAA;EAClB;AAEA,SAAOF,YAAYC;AACrB,CAAA;;;ACdA,IAAAE,kBAAuB;AACvB,IAAAC,iBAA6B;;;ACD7B,IAAAC,kBAA2C;;;ACCpC,IAAMC,iBAAiBC,OAAO,gBAAA;;;;;;;;;;;;;;;;;;;;ADI9B,IAAMC,eAAN,MAAMA,cAAAA;SAAAA;;;;EACMC,SAAS,IAAIC,uBAAOF,cAAaG,IAAI;EAEtD,YAAqDC,UAA0B;SAA1BA,WAAAA;EAA2B;;EAGhF,MAAMC,IAAOC,KAAaC,OAAUC,YAAmC;AACrE,QAAI;AACF,YAAM,KAAKJ,SAASC,IAAIC,KAAKC,OAAOC,UAAAA;IACtC,SAASC,KAAK;AACZ,WAAKR,OAAOS,MAAM,6BAA6BJ,GAAAA,KAAQG,GAAAA;IACzD;EACF;;EAGA,MAAME,IAAOL,KAAgC;AAC3C,QAAI;AACF,aAAO,MAAM,KAAKF,SAASO,IAAOL,GAAAA;IACpC,SAASG,KAAK;AACZ,WAAKR,OAAOS,MAAM,6BAA6BJ,GAAAA,KAAQG,GAAAA;AACvD,aAAO;IACT;EACF;;EAGA,MAAMG,OAAOC,MAA+B;AAC1C,QAAI;AACF,YAAM,KAAKT,SAASQ,IAAG,GAAIC,IAAAA;IAC7B,SAASJ,KAAK;AACZ,WAAKR,OAAOS,MAAM,8BAA8BG,KAAKC,KAAK,IAAA,CAAA,KAAUL,GAAAA;IACtE;EACF;;EAGA,MAAMM,SAASC,SAAoC;AACjD,QAAI;AACF,aAAO,MAAM,KAAKZ,SAASW,SAASC,OAAAA;IACtC,SAASP,KAAK;AACZ,WAAKR,OAAOS,MAAM,sCAAsCM,OAAAA,KAAYP,GAAAA;AACpE,aAAO,CAAA;IACT;EACF;;EAGA,MAAMQ,gBAAiC;AACrC,QAAI;AACF,aAAO,MAAM,KAAKb,SAASa,cAAa;IAC1C,SAASR,KAAK;AACZ,WAAKR,OAAOS,MAAM,8BAA8BD,GAAAA;AAChD,aAAO;IACT;EACF;AACF;;;;;;;;;;;AEzDA,IAAAS,kBAAkE;AAClE,IAAAC,iBAA8B;AAC9B,qBAAkB;;;;;;;;;;;;AAIX,IAAMC,qBAAN,MAAMA,oBAAAA;SAAAA;;;;EACMC,SAAS,IAAIC,uBAAOF,oBAAmBG,IAAI;EACpDC;EAER,YAA6BC,eAA8B;SAA9BA,gBAAAA;EAA+B;;EAG5DC,eAAqB;AACnB,UAAMC,MAAM,KAAKF,cAAcG,WAAmB,WAAA;AAClD,SAAKJ,SAAS,IAAIK,eAAAA,QAAMF,KAAK;MAC3BG,aAAa;MACbC,sBAAsB;IACxB,CAAA;AACA,SAAKP,OAAOQ,GAAG,WAAW,MAAM,KAAKX,OAAOY,IAAI,iBAAA,CAAA;AAChD,SAAKT,OAAOQ,GAAG,SAAS,CAACE,QAAQ,KAAKb,OAAOc,MAAM,eAAeD,GAAAA,CAAAA;EACpE;;EAGA,MAAME,kBAAiC;AACrC,UAAM,KAAKZ,OAAOa,KAAI;AACtB,SAAKhB,OAAOY,IAAI,oBAAA;EAClB;;EAGA,MAAMK,IAAOC,KAAaC,OAAUC,YAAmC;AACrE,UAAMC,OAAOC,KAAKC,UAAUJ,KAAAA;AAC5B,UAAM,KAAKhB,OAAOqB,MAAMN,KAAKE,YAAYC,IAAAA;EAC3C;;EAGA,MAAMI,IAAOP,KAAgC;AAC3C,UAAMG,OAAO,MAAM,KAAKlB,OAAOsB,IAAIP,GAAAA;AACnC,QAAI,CAACG,KAAM,QAAO;AAClB,WAAOC,KAAKI,MAAML,IAAAA;EACpB;;EAGA,MAAMM,OAAOC,MAA+B;AAC1C,QAAIA,KAAKC,SAAS,GAAG;AACnB,YAAM,KAAK1B,OAAOwB,IAAG,GAAIC,IAAAA;IAC3B;EACF;;EAGA,MAAME,SAASC,SAAoC;AACjD,UAAMH,OAAiB,CAAA;AACvB,QAAII,SAAS;AACb,OAAG;AACD,YAAM,CAACC,YAAYC,KAAAA,IAAS,MAAM,KAAK/B,OAAOgC,KAAKH,QAAQ,SAASD,SAAS,SAAS,GAAA;AACtFC,eAASC;AACTL,WAAKQ,KAAI,GAAIF,KAAAA;IACf,SAASF,WAAW;AACpB,WAAOJ;EACT;;EAGA,MAAMS,gBAAiC;AACrC,WAAO,KAAKlC,OAAOmC,KAAK,QAAA;EAC1B;AACF;;;;;;;;;;;;;;;;;AH3CO,IAAMC,cAAN,MAAMA;SAAAA;;;AAAa;;;IAXxBC,SAAS;MAACC;;IACVC,WAAW;MACTC;MACA;QACEC,SAASC;QACTC,aAAaH;MACf;MACAI;;IAEFC,SAAS;MAACL;MAAoBE;MAAgBE;;;;;;AIpBhD,IAAAE,kBAA2C;AAC3C,IAAAC,iBAA6B;;;ACDtB,IAAMC,yBAAyBC,OAAO,wBAAA;;;ACA7C,IAAAC,kBAAqE;AACrE,IAAAC,kBAAuC;;;ACDvC,IAAAC,kBAAgC;AAChC,IAAAC,kBAAmD;;;ACDnD,qBAAiD;AACjD,6BAAkE;;;;;;;;;;;;AAG3D,IAAMC,0BAAN,MAAMA;SAAAA;;;EAIXC;EAIAC;EAKAC;AACF;;;IAbiBC,aAAa;IAAqCC,SAAS;;;;;;;;IAK3DD,aAAa;;;;;;;;;;;;;ADNvB,SAASE,0BAAAA;AACd,aAAOC,qCACLC,8BAAa;IACXC,SAAS;IACTC,aACE;EACJ,CAAA,OACAC,yBAAQ;IAAEC,MAAMC;EAAwB,CAAA,OACxCC,6BAAY;IAAEC,QAAQ;IAAKL,aAAa;EAAqB,CAAA,OAC7DI,6BAAY;IAAEC,QAAQ;IAAKL,aAAa;EAAwB,CAAA,OAChEI,6BAAY;IAAEC,QAAQ;IAAKL,aAAa;EAAgB,CAAA,CAAA;AAE5D;AAZgBJ;;;AEJhB,IAAAU,kBAAmC;AACnC,IAAAC,iBAA8B;;;;;;;;;;;;AAK9B,IAAMC,oBAAoC;EACxCC,SAAS,CAAA;EACTC,MAAM,CAAA;EACNC,kBAAkB,CAAC;EACnBC,aAAa,CAAA;EACbC,cAAc,CAAC;EACfC,eAAe;IAAEC,MAAM,CAAA;IAAIC,OAAO,CAAA;EAAG;EACrCC,oBAAoB;EACpBC,SAAS;EACTC,aAAa,CAAA;EACbC,kBAAkB,CAAC;EACnBC,QAAQ;EACRC,YAAY;IAAEC,OAAO;IAAIC,QAAQ;EAAE;AACrC;AAGO,IAAMC,wBAAN,MAAMA,uBAAAA;SAAAA;;;;;EACMC,SAAS,IAAIC,uBAAOF,uBAAsBG,IAAI;EAE/D,YACmBC,cACAC,eACjB;SAFiBD,eAAAA;SACAC,gBAAAA;EAChB;;EAGH,IAAYC,WAAmB;AAC7B,WAAO,KAAKD,cAAcE,IAAY,uBAAA,KAA4B;EACpE;;EAGA,MAAMC,mBAAmBC,QAAgBC,KAA6C;AACpF,UAAMC,MAAM,MAAMF,MAAAA,IAAUC,IAAIE,SAAS;AACzC,UAAM,KAAKR,aAAaS,IAAIF,KAAK;MAAEG,OAAOJ,IAAII;MAAOC,cAAcL,IAAIK,gBAAgB;IAAK,GAAG,KAAKT,QAAQ;AAC5G,SAAKL,OAAOe,IAAI,+BAA+BP,MAAAA,YAAkBC,IAAIE,SAAS,EAAE;EAClF;;EAGA,MAAMK,gBACJR,QACAG,WACiE;AACjE,UAAMD,MAAM,MAAMF,MAAAA,IAAUG,SAAAA;AAC5B,UAAMM,SAAS,MAAM,KAAKd,aAAaG,IAA4DI,GAAAA;AACnG,WAAOO,UAAU;MAAEJ,OAAO/B;MAAmBgC,cAAc;IAAK;EAClE;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;AHzCO,IAAMI,2BAAN,MAAMA,0BAAAA;SAAAA;;;;EACMC,SAAS,IAAIC,uBAAOF,0BAAyBG,IAAI;EAElE,YAA6BC,uBAA8C;SAA9CA,wBAAAA;EAA+C;;EAM5EC,mBAA6BC,QAAwBC,KAA6C;AAChG,SAAKN,OAAOO,IAAI,8BAA8BF,MAAAA,YAAkBC,IAAIE,SAAS,EAAE;AAC/E,WAAO,KAAKL,sBAAsBC,mBAAmBC,QAAQC,GAAAA;EAC/D;AACF;;;2DANuBG,EAAAA;;;;;;;;;;;;;;;;;;;;;;AIjBvB,IAAAC,kBAAuG;AACvG,IAAAC,mBAAuC;;;ACDvC,IAAAC,kBAAgC;AAChC,IAAAC,kBAAuE;;;ACDvE,IAAAC,kBAAiD;;;;;;;;;;;;AAI1C,IAAMC,mBAAN,MAAMA,kBAAAA;SAAAA;;;EAEXC;EAGAC;EAGAC;EAGAC;EAGAC;EAGAC;EAGAC;EAGAC;;EAGA,OAAOC,KAAKC,MAA2BC,QAAkC;AACvE,UAAMC,MAAM,IAAIZ,kBAAAA;AAChBY,QAAIX,KAAKS,KAAKT;AACdW,QAAIV,OAAOQ,KAAKR,QAAQ;AACxBU,QAAIT,YAAYO,KAAKP;AACrBS,QAAIR,QAAQM,KAAKN;AACjBQ,QAAIP,WAAWK,KAAKL;AACpBO,QAAIN,QAAQI,KAAKC,WAAWA;AAC5BC,QAAIL,YAAYG,KAAKH;AACrBK,QAAIJ,YAAYE,KAAKF,aAAa;AAClC,WAAOI;EACT;AACF;;;IArCiBC,aAAa;;;;;;IAGLA,aAAa;IAA4BC,UAAU;;;;;;IAG3DD,aAAa;IAA0CE,SAAS;;;;;;IAGhEF,aAAa;;;;;;IAGbA,aAAa;IAA4CE,SAAS;;;;;;IAGlEF,aAAa;IAA8CE,SAAS;;;;;;IAGpEF,aAAa;;;;;;IAGLA,aAAa;IAA0BC,UAAU;;;;;;AC1B1E,IAAAE,kBAAiD;AACjD,IAAAC,0BAAqE;;;;;;;;;;;;AAG9D,IAAMC,yBAAN,MAAMA;SAAAA;;;EAIXC;EAKAC;EAIAC;EAKAC;AACF;;;IAlBiBC,aAAa;IAAmCC,SAAS;;;;;;;;IAKzDD,aAAa;IAAqCC,SAAS;;;;;;;;IAK3DD,aAAa;;;;;;;IAILA,aAAa;IAA6CC,SAAS;;;;;;;;ACnB5F,IAAAC,kBAA4B;AAC5B,IAAAC,0BAA+C;;;;;;;;;;;;AAExC,IAAMC,yBAAN,MAAMA;SAAAA;;;EAKXC;AACF;;;IALiBC,aAAa;IAAiCC,SAAS;;;;;;;;;ACJxE,IAAAC,kBAA4B;AAC5B,IAAAC,0BAA0B;;;;;;;;;;;;AAEnB,IAAMC,8BAAN,MAAMA;SAAAA;;;EAGXC;AACF;;;IAHiBC,aAAa;IAAmDC,SAAS;;;;;;;ACJ1F,IAAAC,kBAA4B;AAC5B,IAAAC,0BAAyB;;;;;;;;;;;;AAIlB,IAAMC,yBAAN,MAAMA;SAAAA;;;EAGXC;AACF;;;IAHiBC,aAAa;;;;;;;ALEvB,SAASC,wBAAAA;AACd,aAAOC,qCACLC,8BAAa;IACXC,SAAS;IACTC,aAAa;EACf,CAAA,OACAC,0BAAS;IACPC,MAAM;IACNF,aAAa;IACbG,SAAS;IACTC,UAAU;EACZ,CAAA,OACAC,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;IAA0BO,MAAM;MAACC;;EAAkB,CAAA,OAC3FH,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;EAAgB,CAAA,CAAA;AAE5D;AAfgBJ;AAiBT,SAASa,yBAAAA;AACd,aAAOZ,qCACLC,8BAAa;IACXC,SAAS;IACTC,aAAa;EACf,CAAA,OACAU,yBAAQ;IAAEH,MAAMI;EAAuB,CAAA,OACvCN,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;IAAuBO,MAAMC;EAAiB,CAAA,OACtFH,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;EAAwB,CAAA,OAChEK,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;EAAgB,CAAA,CAAA;AAE5D;AAXgBS;AAaT,SAASG,yBAAAA;AACd,aAAOf,qCACLC,8BAAa;IACXC,SAAS;IACTC,aAAa;EACf,CAAA,OACAa,0BAAS;IAAEX,MAAM;IAAMF,aAAa;EAAmC,CAAA,OACvEU,yBAAQ;IAAEH,MAAMO;EAAuB,CAAA,OACvCT,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;IAAiBO,MAAMC;EAAiB,CAAA,OAChFH,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;EAA4C,CAAA,OACpFK,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;EAAgB,CAAA,OACxDK,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;EAAkB,CAAA,CAAA;AAE9D;AAbgBY;AAeT,SAASG,yBAAAA;AACd,aAAOlB,qCACLC,8BAAa;IACXC,SAAS;IACTC,aACE;EACJ,CAAA,OACAa,0BAAS;IAAEX,MAAM;IAAMF,aAAa;EAAmC,CAAA,OACvEU,yBAAQ;IAAEH,MAAMS;EAAuB,CAAA,OACvCX,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;IAAiBO,MAAMC;EAAiB,CAAA,OAChFH,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;EAAuB,CAAA,OAC/DK,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;EAAgB,CAAA,OACxDK,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;EAAkB,CAAA,OAC1DK,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;EAAwC,CAAA,CAAA;AAEpF;AAfgBe;AAiBT,SAASE,8BAAAA;AACd,aAAOpB,qCACLC,8BAAa;IACXC,SAAS;IACTC,aACE;EACJ,CAAA,OACAa,0BAAS;IAAEX,MAAM;IAAMF,aAAa;EAAyB,CAAA,OAC7DU,yBAAQ;IAAEH,MAAMW;EAA4B,CAAA,OAC5Cb,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;IAA2BO,MAAMC;EAAiB,CAAA,OAC1FH,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;EAAuB,CAAA,OAC/DK,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;EAAgB,CAAA,OACxDK,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;EAAkB,CAAA,CAAA;AAE9D;AAdgBiB;AAgBT,SAASE,yBAAAA;AACd,aAAOtB,qCACLC,8BAAa;IACXC,SAAS;IACTC,aAAa;EACf,CAAA,OACAa,0BAAS;IAAEX,MAAM;IAAMF,aAAa;EAAmC,CAAA,OACvEK,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;IAAiBO,MAAMC;EAAiB,CAAA,OAChFH,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;EAAuB,CAAA,OAC/DK,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;EAAgB,CAAA,OACxDK,6BAAY;IAAEC,QAAQ;IAAKN,aAAa;EAAkB,CAAA,CAAA;AAE9D;AAZgBmB;;;AMtFhB,yBAA2B;AAC3B,IAAAC,kBAAmC;AACnC,IAAAC,iBAA8B;;;ACF9B,IAAAC,kBAAmC;AACnC,IAAAC,sBAAwB;;;ACDxB,IAAAC,kBAAuB;AACvB,yBAaO;AAQP,SAASC,aAAaC,KAAW;AAC/B,SAAOA,IAAIC,QAAQ,aAAa,CAACC,GAAGC,WAAWA,OAAOC,YAAW,CAAA;AACnE;AAFSL;AAuBF,IAAeM,wBAAf,MAAeA;EA7CtB,OA6CsBA;;;;;EAKDC;EACAC;EAEFC;EAEjB,IAAcC,KAAyB;AACrC,WAAO,KAAKC,SAASC;EACvB;EAEA,IAAcC,QAA8C;AAC1D,UAAMC,QAAQ,KAAKH,SAASC,cAAcE;AAC1C,UAAMC,YAAYC,OAAOC,KAAKH,SAAS,CAAC,CAAA;AACxC,SAAKP,OAAOW,MAAM,gBAAgB,KAAKT,SAAS,qBAAqBM,UAAUI,KAAK,IAAA,CAAA,GAAQ;AAE5F,UAAMN,QAAQC,MAAM,KAAKL,SAAS;AAClC,QAAI,CAACI,OAAO;AACV,WAAKN,OAAOa,MAAM,UAAU,KAAKX,SAAS,4CAA4CM,UAAUI,KAAK,IAAA,CAAA,GAAQ;IAC/G;AAEA,WAAON;EACT;EAEA,YACqBF,UACAU,OACnBC,SAGA;SALmBX,WAAAA;SACAU,QAAAA;AAOnB,UAAME,kBAAcC,iCAAaH,KAAAA;AACjC,SAAKZ,YAAYT,aAAauB,WAAAA;AAC9B,SAAKf,WAAWc,SAASd;AACzB,SAAKD,SAAS,IAAIkB,uBAAO,KAAK,YAAYC,IAAI;AAC9C,SAAKnB,OAAOW,MAAM,eAAe,KAAK,YAAYQ,IAAI,EAAE;AACxD,SAAKnB,OAAOW,MAAM,gBAAgBK,WAAAA,oBAA+B,KAAKd,SAAS,GAAG;EACpF;;EAGA,MAAgBkB,kBAAkBnB,UAAwC;AACxE,UAAMoB,mBAAmBpB,YAAY,KAAKA;AAC1C,QAAI,CAACoB,kBAAkB;AACrB,YAAM,IAAIC,MAAM,GAAG,KAAK,YAAYH,IAAI,8CAA8C;IACxF;AAEA,UAAMI,eAAeF,iBAAiBG,SAClC,GAAGH,iBAAiBG,MAAM,IAAIH,iBAAiBI,OAAO,KACtDJ,iBAAiBI;AAErB,UAAMC,SAAS,MAAM,KAAKvB,GAAGwB,QAC3BC,wCAAqBL,YAAAA,+BAA2C;AAElE,UAAMM,OAAQH,OAAiEG,QAAQ,CAAA;AACvF,WAAOC,OAAOD,KAAK,CAAA,GAAIE,kBAAkB,CAAA;EAC3C;;EAGA,MAAMC,OAAOC,MAAeC,IAA2C;AACrE,SAAKlC,OAAOmC,IAAI,iBAAA;AAChB,UAAMhC,KAAK+B,MAAM,KAAK/B;AACtB,UAAMiC,UAAW,MAAMjC,GACpBkC,OAAO,KAAKvB,KAAK,EACjBwB,OAAOL,IAAAA,EACPM,UAAS;AACZ,UAAMC,SAASJ,QAAQ,CAAA;AACvB,QAAI,CAACI,OAAQ,OAAM,IAAIlB,MAAM,GAAG,KAAKpB,SAAS,yCAAyC;AACvF,WAAOsC;EACT;;EAGA,MAAMC,SAASC,IAA0C;AACvD,SAAK1C,OAAOW,MAAM,yBAAyB+B,EAAAA,EAAI;AAC/C,WAAO,KAAKpC,MAAMqC,UAAU;MAC1BC,OAAO;QAAEF;MAAG;IACd,CAAA;EACF;;EAGA,MAAMG,QAAQD,OAA2D;AACvE,SAAK5C,OAAOW,MAAM,kCAAA;AAClB,WAAO,KAAKL,MAAMqC,UAAU;MAAEC;IAAM,CAAA;EACtC;;EAGA,MAAME,SAAS/B,SAKQ;AACrB,SAAKf,OAAOW,MAAM,0BAAA;AAClB,WAAO,KAAKL,MAAMwC,SAAS/B,OAAAA;EAC7B;;EAGQgC,iBAAiBhC,SAStB;AAID,QAAIR,SACFQ,SAASiC,SACL,KAAK7C,GAAG6C,OAAOjC,QAAQiC,MAAM,EAAoBC,KAAK,KAAKnC,KAAK,IAChE,KAAKX,GAAG6C,OAAM,EAAGC,KAAK,KAAKnC,KAAK,GACpCoC,SAAQ;AAEV,QAAInC,SAASoC,UAAU;AACrB5C,cAAQA,MAAM4C,SAASpC,QAAQoC,SAASrC,OAAOC,QAAQoC,SAASC,EAAE;IACpE;AACA,QAAIrC,SAASsC,WAAW;AACtB,iBAAWzC,QAAQG,QAAQsC,WAAW;AACpC9C,gBAAQA,MAAM4C,SAASvC,KAAKE,OAAOF,KAAKwC,EAAE;MAC5C;IACF;AACA,QAAIrC,SAAS6B,OAAO;AAClBrC,cAAQA,MAAMqC,MAAM7B,QAAQ6B,KAAK;IACnC;AACA,QAAI7B,SAASuC,SAASC,QAAQ;AAC5BhD,cAAQA,MAAM+C,QAAO,GAAIvC,QAAQuC,OAAO;IAC1C;AACA,QAAIvC,SAASyC,SAASD,QAAQ;AAC5BhD,cAAQA,MAAMiD,QAAO,GAAIzC,QAAQyC,OAAO;IAC1C;AACA,QAAIzC,SAAS0C,OAAO;AAClBlD,cAAQA,MAAMkD,MAAM1C,QAAQ0C,KAAK;IACnC;AACA,QAAI1C,SAAS2C,QAAQ;AACnBnD,cAAQA,MAAMmD,OAAO3C,QAAQ2C,MAAM;IACrC;AACA,WAAOnD;EACT;;EAGA,MAAMoD,gBAAmC5C,SASS;AAChD,QAAI6C;AAEJ,QAAI7C,SAASuC,SAASC,QAAQ;AAG5B,UAAIM,OAAO,KAAK1D,GACb6C,OAAO;QAAEpD,GAAGgC;MAAO,CAAA,EACnBqB,KAAK,KAAKnC,KAAK,EACfoC,SAAQ;AACX,UAAInC,QAAQoC,UAAU;AACpBU,eAAOA,KAAKV,SAASpC,QAAQoC,SAASrC,OAAOC,QAAQoC,SAASC,EAAE;MAClE;AACA,UAAIrC,QAAQsC,WAAW;AACrB,mBAAWzC,QAAQG,QAAQsC,WAAW;AACpCQ,iBAAOA,KAAKV,SAASvC,KAAKE,OAAOF,KAAKwC,EAAE;QAC1C;MACF;AACA,UAAIrC,QAAQ6B,OAAO;AACjBiB,eAAOA,KAAKjB,MAAM7B,QAAQ6B,KAAK;MACjC;AACAiB,aAAOA,KAAKP,QAAO,GAAIvC,QAAQuC,OAAO;AAEtC,YAAMQ,QAAQD,KAAKE,GAAG,aAAA;AACtBH,2BAAqB,KAAKzD,GACvB6C,OAAO;QAAEgB,OAAOpC;MAA2B,CAAA,EAC3CqB,KAAKa,KAAAA;IACV,OAAO;AAEL,UAAIG,aAAa,KAAK9D,GACnB6C,OAAO;QAAEgB,OAAOpC;MAA2B,CAAA,EAC3CqB,KAAK,KAAKnC,KAAK,EACfoC,SAAQ;AACX,UAAInC,SAASoC,UAAU;AACrBc,qBAAaA,WAAWd,SAASpC,QAAQoC,SAASrC,OAAOC,QAAQoC,SAASC,EAAE;MAC9E;AACA,UAAIrC,SAASsC,WAAW;AACtB,mBAAWzC,QAAQG,QAAQsC,WAAW;AACpCY,uBAAaA,WAAWd,SAASvC,KAAKE,OAAOF,KAAKwC,EAAE;QACtD;MACF;AACA,UAAIrC,SAAS6B,OAAO;AAClBqB,qBAAaA,WAAWrB,MAAM7B,QAAQ6B,KAAK;MAC7C;AACAgB,2BAAqBK;IACvB;AAEA,UAAM,CAACC,aAAaxC,MAAAA,IAAU,MAAMyC,QAAQC,IAAI;MAC9CR;MACA,KAAKb,iBAAiBhC,OAAAA;KACvB;AACD,WAAO;MAAEW;MAAQsC,OAAQE,YAAY,CAAA,EAAyBF;IAAM;EACtE;;EAGA,MAAMK,OAAO3B,IAAYT,MAAwBC,IAA2C;AAC1F,SAAKlC,OAAOmC,IAAI,4BAA4BO,EAAAA,EAAI;AAChD,UAAMvC,KAAK+B,MAAM,KAAK/B;AACtB,UAAMmE,WAAY,KAAKxD,MAA8C4B;AACrE,QAAI,CAAC4B,SAAU,OAAM,IAAIhD,MAAM,UAAU,KAAKpB,SAAS,sBAAsB;AAC7E,UAAMkC,UAAW,MAAMjC,GACpBkE,OAAO,KAAKvD,KAAK,EACjByD,IAAItC,IAAAA,EACJW,UAAM4B,uBAAGF,UAAU5B,EAAAA,CAAAA,EACnBH,UAAS;AACZ,UAAMC,SAASJ,QAAQ,CAAA;AACvB,QAAI,CAACI,OAAQ,OAAM,IAAIlB,MAAM,GAAG,KAAKpB,SAAS,yCAAyC;AACvF,WAAOsC;EACT;;EAGA,MAAMiC,WAAW7B,OAAYX,MAAwBC,IAAqD;AACxG,SAAKlC,OAAOmC,IAAI,2BAAA;AAChB,UAAMhC,KAAK+B,MAAM,KAAK/B;AACtB,UAAMuB,SAAS,MAAMvB,GAClBkE,OAAO,KAAKvD,KAAK,EACjByD,IAAItC,IAAAA,EACJW,MAAMA,KAAAA;AACT,WAAO;MAAEoB,OAAOtC,OAAOgD,YAAY;IAAE;EACvC;;EAGA,MAAMC,OAAOjC,IAAYR,IAA2C;AAClE,SAAKlC,OAAOmC,IAAI,4BAA4BO,EAAAA,EAAI;AAChD,UAAMvC,KAAK+B,MAAM,KAAK/B;AACtB,UAAMmE,WAAY,KAAKxD,MAA8C4B;AACrE,QAAI,CAAC4B,SAAU,OAAM,IAAIhD,MAAM,UAAU,KAAKpB,SAAS,sBAAsB;AAC7E,UAAMkC,UAAW,MAAMjC,GACpBwE,OAAO,KAAK7D,KAAK,EACjB8B,UAAM4B,uBAAGF,UAAU5B,EAAAA,CAAAA,EACnBH,UAAS;AACZ,UAAMC,SAASJ,QAAQ,CAAA;AACvB,QAAI,CAACI,OAAQ,OAAM,IAAIlB,MAAM,GAAG,KAAKpB,SAAS,yCAAyC;AACvF,WAAOsC;EACT;;EAGA,MAAMoC,WAAWhC,OAAYV,IAAqD;AAChF,SAAKlC,OAAOmC,IAAI,2BAAA;AAChB,UAAMhC,KAAK+B,MAAM,KAAK/B;AACtB,UAAMuB,SAAS,MAAMvB,GAAGwE,OAAO,KAAK7D,KAAK,EAAa8B,MAAMA,KAAAA;AAC5D,WAAO;MAAEoB,OAAOtC,OAAOgD,YAAY;IAAE;EACvC;;EAGA,MAAMV,MAAMpB,OAA8B;AACxC,SAAK5C,OAAOW,MAAM,kBAAA;AAElB,QAAIJ,QAAQ,KAAKJ,GACd6C,OAAO;MAAEgB,OAAOpC;IAA2B,CAAA,EAC3CqB,KAAK,KAAKnC,KAAK,EACfoC,SAAQ;AAEX,QAAIN,OAAO;AACTrC,cAAQA,MAAMqC,MAAMA,KAAAA;IACtB;AAEA,UAAMR,UAAU,MAAM7B;AACtB,WAAQ6B,QAAQ,CAAA,EAAyB4B;EAC3C;;EAGA,MAAMa,OAAOjC,OAA8B;AACzC,UAAMoB,QAAQ,MAAM,KAAKA,MAAMpB,KAAAA;AAC/B,WAAOoB,QAAQ;EACjB;;;;EAKA,MAAMc,YAAeC,UAA8D;AACjF,WAAO,KAAK3E,SAAS4E,iBAAiB,YAAYD,SAAS,KAAK3E,SAASC,aAAa,CAAA;EACxF;;EAGA,MAAM4E,cAAcC,QAAyD;AAC3E,SAAKlF,OAAOW,MAAM,qCAAA;AAGlB,UAAMwE,WAAWD,OAAOE,WAAW,KAAKjF,GAAGkF,eAAeC,KAAK,KAAKnF,EAAE,IAAI,KAAKA,GAAG6C,OAAOsC,KAAK,KAAKnF,EAAE;AAarG,UAAMoF,eACJ,OAAOL,OAAO5C,WAAW,WACrB4C,OAAO5C,OACJkD,MAAM,GAAA,EACNC,IAAI,CAACC,MAAMA,EAAEC,KAAI,CAAA,EACjBC,OAAOC,OAAAA,IACVX,OAAO5C;AAGb,UAAMwD,mBACJ,OAAOZ,OAAOa,eAAe,WACzBb,OAAOa,WACJP,MAAM,GAAA,EACNC,IAAI,CAACC,MAAMA,EAAEC,KAAI,CAAA,EACjBC,OAAOC,OAAAA,IACTX,OAAOa,cAAc,CAAA;AAE5B,UAAMC,eAAe,KAAKlF;AAE1B,UAAMmF,aAAaf,OAAOgB,OAAOT,IAAI,CAAC7E,SAASA,KAAKE,KAAK,KAA4C,CAAA;AACrG,UAAMqF,gBAAgB,wBAACC,QAAAA;AACrB,UAAIJ,aAAaI,GAAAA,EAAM,QAAOJ,aAAaI,GAAAA;AAC3C,iBAAWC,eAAeJ,YAAY;AACpC,YAAII,YAAYD,GAAAA,EAAM,QAAOC,YAAYD,GAAAA;MAC3C;AACA,aAAOE;IACT,GANsB;AAQtB,UAAMC,WAAWJ,cAAcjB,OAAOsB,KAAK;AAC3C,QAAI,CAACD,SAAU,OAAM,IAAIjF,MAAM,WAAW4D,OAAOsB,KAAK,yBAAyB,KAAKtG,SAAS,gBAAgB;AAE7G,UAAMuG,WAAWN,cAAcjB,OAAOwB,KAAK;AAC3C,QAAI,CAACD,SAAU,OAAM,IAAInF,MAAM,WAAW4D,OAAOwB,KAAK,yBAAyB,KAAKxG,SAAS,gBAAgB;AAE7G,UAAMyG,iBAAiBzB,OAAO0B,cAAcT,cAAcjB,OAAO0B,WAAW,IAAIN;AAEhF,UAAMO,YAAY,wBAACC,UAAAA;AACjB,UAAI,CAACA,MAAO,QAAO,CAAA;AACnB,YAAMxE,SAASyE,MAAMC,QAAQF,KAAAA,IAASA,QAAQA,MAAMtB,MAAM,GAAA;AAC1D,aAAOlD,OAAOmD,IAAI,CAACC,MAAMA,EAAEC,KAAI,CAAA,EAAIC,OAAOC,OAAAA;IAC5C,GAJkB;AAKlB,UAAMoB,iBAAiBJ,UAAU3B,OAAO+B,cAAc;AACtD,UAAMC,oBAA6D;SAC9DD,eACAxB,IAAI,CAACW,SAAS;QAAEA;QAAKe,MAAMhB,cAAcC,GAAAA;MAA6B,EAAA,EACtER,OAAO,CAACwB,MAA4CvB,QAAQuB,EAAED,IAAI,CAAA;SAClE1G,OAAO4G,QAAQnC,OAAOoC,yBAAyB,CAAC,CAAA,EAAG7B,IAAI,CAAC,CAACW,KAAKe,IAAAA,OAAW;QAAEf;QAAKe;MAAK,EAAA;;AAE1F,UAAMI,kBAAkB,wBAACnB,QAAgB,gBAAgBA,GAAAA,IAAjC;AAGxB,QAAIb,gBAAgBA,aAAahC,SAAS,GAAG;AAC3C,YAAMiE,aAA6C;QAAEhB,OAAOD;QAAUG,OAAOD;MAAS;AACtF,UAAIE,eAAgBa,YAAWZ,cAAcD;AAC7C,UAAIzB,OAAOuC,YAAY;AACrB,cAAMC,aAAavB,cAAcjB,OAAOuC,UAAU;AAClD,YAAIC,WAAYF,YAAWG,UAAUD;MACvC;AACA,iBAAWE,SAASV,mBAAmB;AACrCM,mBAAWD,gBAAgBK,MAAMxB,GAAG,CAAA,IAAKwB,MAAMT;MACjD;AAEA,UAAIU,cAAc1C,SAASqC,UAAAA,EACxBvE,KAAK,KAAKnC,KAAK,EACfoC,SAAQ;AAEX,UAAIgC,OAAOgB,OAAO;AAChB,mBAAWtF,QAAQsE,OAAOgB,OAAO;AAC/B,cAAItF,KAAKkH,SAAS,SAAS;AACzBD,0BAAcA,YAAYE,UAAUnH,KAAKE,OAAOF,KAAKwC,EAAE;UACzD,OAAO;AACLyE,0BAAcA,YAAY1E,SAASvC,KAAKE,OAAOF,KAAKwC,EAAE;UACxD;QACF;MACF;AAEA,YAAMvB,QAAO,MAAMgG,YAAYjF,UAAMoF,4BAAQzB,UAAUhB,YAAAA,CAAAA;AAEvD,aAAO;QACLxE,SAAUc,MAAgC4D,IAAI,CAACwC,SAAS;UACtDzB,OAAOyB,IAAIzB;UACXE,OAAOwB,OAAOD,IAAIvB,KAAK;UACvB,GAAIC,kBAAkBsB,IAAIrB,eAAe,OAAO;YAAEA,aAAasB,OAAOD,IAAIrB,WAAW;UAAE,IAAI,CAAC;UAC5F,GAAI1B,OAAOuC,cAAcQ,IAAIN,WAAW,OAAO;YAAEA,SAASM,IAAIN;UAAQ,IAAI,CAAC;UAC3E,GAAIT,kBAAkB3D,SAAS,IAC3B;YACE4E,aAAajB,kBAAkBkB,OAC7B,CAACC,KAAKT,UAAAA;AACJ,oBAAMpB,QAASyB,IAA2CV,gBAAgBK,MAAMxB,GAAG,CAAA;AACnF,kBAAII,UAAUF,QAAW;AACvB,oBACE,OAAOE,UAAU,YACjB,OAAOA,UAAU,YACjB,OAAOA,UAAU,aACjBA,UAAU,MACV;AACA6B,sBAAIT,MAAMxB,GAAG,IAAII;gBACnB,OAAO;AACL6B,sBAAIT,MAAMxB,GAAG,IAAI8B,OAAO1B,KAAAA;gBAC1B;cACF;AACA,qBAAO6B;YACT,GACA,CAAC,CAAA;UAEL,IACA,CAAC;QACP,EAAA;QACAC,SAAS;QACT,GAAIpD,OAAOqD,SAAS;UAAEA,QAAQrD,OAAOqD;QAAO,IAAI,CAAC;MACnD;IACF;AAGA,UAAMC,eAA+C;MACnDhC,OAAOD;MACPG,OAAOD;MACPgC,YAAY7G,wCAA6B8G,QAAQ5G,MAAAA;IACnD;AACA,QAAI6E,eAAgB6B,cAAa5B,cAAcD;AAC/C,QAAIzB,OAAOuC,YAAY;AACrB,YAAMC,aAAavB,cAAcjB,OAAOuC,UAAU;AAClD,UAAIC,WAAYc,cAAab,UAAUD;IACzC;AACA,eAAWE,SAASV,mBAAmB;AACrCsB,mBAAajB,gBAAgBK,MAAMxB,GAAG,CAAA,IAAKwB,MAAMT;IACnD;AAEA,UAAMwB,aAAoB,CAAA;AAC1B,QAAIzD,OAAO0D,QAAQ;AACjBD,iBAAWE,SAAKC,0BAAMrC,UAAU,IAAIvB,OAAO0D,MAAM,GAAG,CAAA;IACtD;AACA,QAAI9C,iBAAiBvC,SAAS,GAAG;AAC/BoF,iBAAWE,SAAKE,+BAAWxC,UAAUT,gBAAAA,CAAAA;IACvC;AACA,QAAIZ,OAAOtC,OAAO;AAChB,iBAAW,CAACoG,OAAOC,GAAAA,KAAQxI,OAAO4G,QAAQnC,OAAOtC,KAAK,GAAG;AACvD,cAAMsG,SAASlD,aAAagD,KAAAA;AAC5B,YAAIE,QAAQ;AACVP,qBAAWE,SAAKrE,uBAAG0E,QAAQD,GAAAA,CAAAA;QAC7B;MACF;IACF;AAEA,QAAI/D,OAAOyD,YAAY;AACrBA,iBAAWE,KAAI,GAAI3D,OAAOyD,UAAU;IACtC;AAEA,UAAMQ,aAAajE,OAAOiE,eAAejE,OAAO1B,UAAU/C,OAAOC,KAAKwE,OAAO1B,OAAO,EAAE,CAAA,IAAK8C;AAC3F,UAAM8C,iBAAiBlE,OAAOkE,mBAAmBlE,OAAO1B,UAAU/C,OAAO6B,OAAO4C,OAAO1B,OAAO,EAAE,CAAA,IAAK8C;AACrG,UAAM+C,aAAaF,aAAcnD,aAAamD,UAAAA,KAAe1C,WAAYA;AACzE,UAAMhD,QAAQ3B,OAAOoD,OAAOzB,KAAK,KAAK;AACtC,UAAMC,SAAS5B,OAAOoD,OAAOxB,MAAM,KAAK;AAExC,QAAInD,QAAQ4E,SAASqD,YAAAA,EAClBvF,KAAK,KAAKnC,KAAK,EACfoC,SAAQ;AAGX,QAAIgC,OAAOgB,OAAO;AAChB,iBAAWtF,QAAQsE,OAAOgB,OAAO;AAC/B,YAAItF,KAAKkH,SAAS,SAAS;AACzBvH,kBAAQA,MAAMwH,UAAUnH,KAAKE,OAAOF,KAAKwC,EAAE;QAC7C,OAAO;AACL7C,kBAAQA,MAAM4C,SAASvC,KAAKE,OAAOF,KAAKwC,EAAE;QAC5C;MACF;IACF;AAEA,QAAIuF,WAAWpF,SAAS,GAAG;AACzBhD,cAAQA,MAAMqC,MAAM+F,WAAWpF,WAAW,IAAIoF,WAAW,CAAA,QAAMW,wBAAAA,GAAOX,UAAAA,CAAAA;IACxE;AAEA,UAAMY,eAAsB,CAAA;AAC5B,QAAIrE,OAAOuC,YAAY;AACrB,YAAMC,aAAavB,cAAcjB,OAAOuC,UAAU;AAClD,UAAIC,WAAY6B,cAAaV,SAAKW,wBAAI9B,UAAAA,CAAAA;IACxC;AACA6B,iBAAaV,KAAKO,mBAAmB,aAASK,yBAAKJ,UAAAA,QAAcG,wBAAIH,UAAAA,CAAAA;AAErE9I,YAAQA,MACLiD,QAAO,GAAI+F,YAAAA,EACX9F,MAAMA,KAAAA,EACNC,OAAOA,MAAAA;AAEV,UAAM7B,OAAO,MAAMtB;AAEnB,UAAMkI,aAAa5G,KAAK0B,SAAS,IAAK1B,KAAK,CAAA,EAAqC4G,aAAa;AAE7F,UAAM1H,UAAWc,KAAgC4D,IAAI,CAACwC,SAAS;MAC7DzB,OAAOyB,IAAIzB;MACXE,OAAOwB,OAAOD,IAAIvB,KAAK;MACvB,GAAIC,kBAAkBsB,IAAIrB,eAAe,OAAO;QAAEA,aAAasB,OAAOD,IAAIrB,WAAW;MAAE,IAAI,CAAC;MAC5F,GAAI1B,OAAOuC,cAAcQ,IAAIN,WAAW,OAAO;QAAEA,SAASM,IAAIN;MAAQ,IAAI,CAAC;MAC3E,GAAIT,kBAAkB3D,SAAS,IAC3B;QACE4E,aAAajB,kBAAkBkB,OAAyD,CAACC,KAAKT,UAAAA;AAC5F,gBAAMpB,QAASyB,IAA2CV,gBAAgBK,MAAMxB,GAAG,CAAA;AACnF,cAAII,UAAUF,QAAW;AACvB,gBACE,OAAOE,UAAU,YACjB,OAAOA,UAAU,YACjB,OAAOA,UAAU,aACjBA,UAAU,MACV;AACA6B,kBAAIT,MAAMxB,GAAG,IAAII;YACnB,OAAO;AACL6B,kBAAIT,MAAMxB,GAAG,IAAI8B,OAAO1B,KAAAA;YAC1B;UACF;AACA,iBAAO6B;QACT,GAAG,CAAC,CAAA;MACN,IACA,CAAC;IACP,EAAA;AAGA,QAAIqB,iBAAiBxE,OAAOqD;AAE5B,QAAIrD,OAAOyE,cAAczE,OAAOuC,YAAY;AAC1C,YAAMmC,oBAAoB1E,OAAOyE;AACjC,YAAMlC,aAAavC,OAAO2E,mBAAmB;AAC7C,YAAMC,eAAe5E,OAAO6E,iBAAiB;AAC7C,YAAMrC,aAAakC,kBAAkBnC,UAAAA;AACrC,UAAI,CAACC,WAAY,OAAM,IAAIpG,MAAM,WAAWmG,UAAAA,4BAAsC;AAClF,YAAMuC,eAAeJ,kBAAkBE,YAAAA;AACvC,UAAI,CAACE,aAAc,OAAM,IAAI1I,MAAM,WAAWwI,YAAAA,4BAAwC;AAEtF,YAAMG,YAAY,MAAM,KAAK9J,GAC1B6C,OAAO;QAAEN,IAAIgF;QAAYvG,MAAM6I;MAAa,CAAA,EAC5C/G,KAAKiC,OAAOyE,UAAU,EACtBnG,YAAQgG,wBAAIQ,YAAAA,CAAAA;AAEfN,uBAAkBO,UAAsExE,IAAI,CAACyE,OAAO;QAClGxH,IAAIwH,EAAExH;QACNvB,MAAM+G,OAAOgC,EAAE/I,IAAI;MACrB,EAAA;IACF;AAEA,WAAO;MACLJ;MACAuH,SAAS5E,SAASD,QAAQgF;MAC1BA;MACA,GAAIiB,iBAAiB;QAAEnB,QAAQmB;MAAe,IAAI,CAAC;IACrD;EACF;AACF;;;ACvlBA,8BAAkC;AAClC,IAAAS,kBAOO;AACP,2BAAwB;;;ACTjB,IAAMC,0BAA0BC,OAAO,yBAAA;;;ACC9C,gBAAgH;AAczG,IAAMC,eAAN,cAA2BC,eAAAA;EAdlC,OAckCA;;;EACfC;EACAC;EACAC;EAEjB,YAAYC,SAA8B;AACxC,UAAM,EAAEH,QAAQC,OAAOC,iBAAiB,GAAGE,WAAAA,IAAeD;AAC1D,UAAMC,UAAAA;AACN,SAAKJ,SAASA;AACd,SAAKC,QAAQA;AACb,SAAKC,kBAAkBA;EACzB;;EAGSG,MAAMC,cAAmBC,QAAcC,IAAe;AAE7D,QAAI,OAAOF,iBAAiB,YAAY;AACtC,aAAO,MAAMD,MAAMC,YAAAA;IACrB;AAEA,QAAIA,gBAAgB,OAAQA,aAA6BG,WAAW,YAAY;AAC9E,aAAO,MAAMJ,MAAMC,cAAcC,QAAQC,EAAAA;IAC3C;AAEA,QAAI,OAAOD,WAAW,cAAc,OAAOC,OAAO,YAAY;AAC5D,aAAO,MAAMH,MAAMC,cAAcC,QAAQC,EAAAA;IAC3C;AAEA,UAAME,MAAM,KAAKV,OAAOW,SAAQ;AAEhC,QAAID,QAAQE,UAAa,KAAKX,MAAMU,SAAQ,MAAOC,UAAa,CAAC,KAAKV,iBAAiB;AACrF,aAAO,MAAMG,MAAMC,cAAcC,MAAAA;IACnC;AAEA,WAAO,KAAKM,WAAWP,cAAcC,QAAQG,GAAAA;EAC/C;;EAGA,MAAcG,WAAWP,cAAmBC,QAAaG,KAAoD;AAC3G,UAAMI,SAAS,MAAM,MAAMC,QAAAA;AAC3B,QAAI;AACF,YAAMD,OAAOT,MAAM,OAAA;AAEnB,YAAO,KAAKH,gBAAsCY,QAAQJ,GAAAA;AAC1D,YAAMM,SAAS,MAAMF,OAAOT,MAAMC,cAAcC,MAAAA;AAChD,YAAMO,OAAOT,MAAM,QAAA;AACnBS,aAAOG,QAAO;AACd,aAAOD;IACT,SAASE,KAAK;AACZ,UAAI;AACF,cAAMJ,OAAOT,MAAM,UAAA;MACrB,QAAQ;MAER;AAEAS,aAAOG,QAAQC,GAAAA;AACf,YAAMA;IACR;EACF;AACF;;;;;;;;;;;;;;;;;;;;AFzDO,IAAMC,yBAAN,MAAMA,wBAAAA;SAAAA;;;;EACMC,SAAS,IAAIC,uBAAOF,wBAAuBG,IAAI;EAExDC,OAA4B;EAC5BC,KAAgC;;;EAIvBC,SAAS,IAAIC,0CAAAA;;;;EAKbC,QAAQ,IAAID,0CAAAA;EAE7B,YAEmBE,SACjB;SADiBA,UAAAA;EAChB;EAEH,MAAMC,eAAe;AACnB,QAAI,KAAKD,QAAQE,WAAW;AAC1B,YAAM,KAAKC,wBAAuB;IACpC;EACF;;EAGA,MAAcA,0BAAyC;AACrD,QAAI;AACF,YAAM,EAAEC,MAAMC,OAAO,MAAMC,UAAUC,UAAUC,UAAUC,QAAQC,UAAU,UAAS,IAAK,KAAKV,QAAQE;AAEtG,WAAKP,OAAO,IAAIgB,aAAa;QAC3BP;QACAC;QACAO,MAAMN;QACNC;QACAC;QACAK,KAAK,KAAKb,QAAQc,kBAAkB;QACpCC,KAAKL,YAAY,YAAY,QAAQ;UAAEM,oBAAoBN,YAAY;QAAY;QACnF,GAAID,UAAU;UAAET,SAAS,iBAAiBS,MAAAA;QAAS;QACnDZ,QAAQ,KAAKA;QACbE,OAAO,KAAKA;QACZkB,iBAAiB,KAAKjB,QAAQiB;MAChC,CAAA;AAEA,WAAKzB,OAAO0B,MACV,sCAAsCC,OAAOC,KAAK,KAAKpB,QAAQqB,oBAAoB,CAAC,CAAA,EAAGC,KAAK,IAAA,CAAA,GAAQ;AAEtG,WAAK1B,SAAK2B,8BAAQ;QAChBC,QAAQ,KAAK7B;QACb8B,WAAW,KAAKzB,QAAQqB;MAC1B,CAAA;AAGA,YAAM,KAAK1B,KAAK+B,MAAM,UAAA;AACtB,WAAKlC,OAAOmC,IAAI,0CAA0ClB,UAAU,QAAA,GAAW;IACjF,SAASmB,OAAO;AACd,WAAKpC,OAAOoC,MAAM,yCAAyCA,KAAAA;AAC3D,YAAM,IAAIC,6CAA6B,0CAAA;IACzC;EACF;;;;EAKA,IAAIC,gBAAoC;AACtC,UAAMC,SAAS,KAAKhC,MAAMiC,SAAQ;AAClC,QAAID,OAAQ,QAAOA;AACnB,QAAI,CAAC,KAAKnC,IAAI;AACZ,YAAM,IAAIqC,MAAM,yCAAA;IAClB;AACA,WAAO,KAAKrC;EACd;;;;EAKAsC,kBAAqBC,KAAcC,IAAkC;AACnE,WAAO,KAAKvC,OAAOwC,IAAIF,KAAKC,EAAAA;EAC9B;;;;EAKA,MAAME,iBAAoBF,IAAkC;AAC1D,UAAML,SAAS,KAAKhC,MAAMiC,SAAQ;AAClC,QAAID,QAAQ;AACV,aAAOA,OAAOQ,YAAY,OAAOC,OAAO,KAAKzC,MAAMsC,IAAIG,IAA0BJ,EAAAA,CAAAA;IACnF;AAEA,QAAI,CAAC,KAAKxC,IAAI;AACZ,YAAM,IAAIqC,MAAM,yCAAA;IAClB;AACA,UAAME,MAAM,KAAKtC,OAAOmC,SAAQ;AAChC,UAAMS,WAAW,KAAKzC,QAAQiB;AAE9B,WAAO,KAAKrB,GAAG2C,YAAY,OAAOG,OAAAA;AAChC,UAAIP,QAAQQ,UAAaF,UAAU;AAIjC,cAAMG,gBAAiBF,IAAYG,SAASrB;AAC5C,YAAIoB,eAAe;AACjB,gBAAMH,SAASG,eAAeT,GAAAA;QAChC;MACF;AACA,aAAO,KAAKpC,MAAMsC,IAAIK,IAA0BN,EAAAA;IAClD,CAAA;EACF;;EAGA,MAAMU,wBAA2BV,IAAkC;AACjE,WAAO,KAAKE,iBAAiBF,EAAAA;EAC/B;EAEA,MAAMW,kBAAkB;AACtB,QAAI,KAAKpD,MAAM;AACb,YAAM,KAAKA,KAAKqD,IAAG;AACnB,WAAKxD,OAAOmC,IAAI,oCAAA;IAClB;EACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;AFlIA,IAAMsB,oBAAoB;AAGnB,IAAMC,2BAAN,cAAuCC,sBAAAA;SAAAA;;;EAK5C,YAAYC,UAAkEC,OAAgB;AAC5F,UAAMD,UAAUC,KAAAA;EAClB;;EAGA,MAAMC,wBAAwBC,QAAgBC,WAAmD;AAE/F,UAAMC,IAAI,KAAKJ;AACf,WAAO,KAAKK,GACTC,OAAM,EACNC,KAAK,KAAKP,KAAK,EACfQ,UAAMC,6BAAIC,wBAAGN,EAAED,WAAWA,SAAAA,OAAYO,wBAAGN,EAAEF,QAAQA,MAAAA,OAASQ,wBAAGN,EAAEO,UAAU,KAAA,CAAA,CAAA,EAC3EC,QAAQR,EAAES,SAAS,EACnBC,MAAMlB,iBAAAA;EACX;;EAGA,MAAMmB,sBAAsBZ,WAAmD;AAE7E,UAAMC,IAAI,KAAKJ;AACf,WAAO,KAAKK,GACTC,OAAM,EACNC,KAAK,KAAKP,KAAK,EACfQ,UAAMC,6BAAIC,wBAAGN,EAAED,WAAWA,SAAAA,OAAYO,wBAAGN,EAAEO,UAAU,IAAA,CAAA,CAAA,EACrDC,QAAQR,EAAES,SAAS,EACnBC,MAAMlB,iBAAAA;EACX;AACF;;;;;;;;;;;;;;;;;;;;;;;AD/BA,SAASoB,gBAAgBC,OAAc;AACrC,aAAOC,+BAAW,QAAA,EAAUC,OAAOC,KAAKC,UAAUJ,KAAAA,CAAAA,EAAQK,OAAO,KAAA;AACnE;AAFSN;AAKF,IAAMO,wBAAN,MAAMA,uBAAAA;SAAAA;;;;;;EACMC,SAAS,IAAIC,uBAAOF,uBAAsBG,IAAI;EAE/D,YACmBC,0BACAC,cACAC,eACjB;SAHiBF,2BAAAA;SACAC,eAAAA;SACAC,gBAAAA;EAChB;;EAGKC,iBAAiBC,QAAgBC,WAA2B;AAClE,WAAO,kBAAkBD,MAAAA,IAAUC,SAAAA;EACrC;;EAGQC,eAAeD,WAA2B;AAChD,WAAO,gBAAgBA,SAAAA;EACzB;;EAGA,IAAYE,WAAmB;AAC7B,WAAO,KAAKL,cAAcM,IAAY,uBAAA,KAA4B;EACpE;;EAGA,MAAcC,wBAAwBL,QAAgBC,WAAmD;AACvG,UAAMK,MAAM,KAAKP,iBAAiBC,QAAQC,SAAAA;AAC1C,UAAMM,SAAS,MAAM,KAAKV,aAAaO,IAA2BE,GAAAA;AAClE,QAAIC,QAAQ;AACV,WAAKd,OAAOe,MAAM,sCAAsCR,MAAAA,WAAiBC,SAAAA,EAAW;AACpF,aAAOM;IACT;AACA,UAAME,OAAO,MAAM,KAAKb,yBAAyBc,wBAAwBV,QAAQC,SAAAA;AACjF,UAAM,KAAKJ,aAAac,IAAIL,KAAKG,MAAM,KAAKN,QAAQ;AACpD,WAAOM;EACT;;EAGA,MAAcG,sBAAsBX,WAAmD;AACrF,UAAMK,MAAM,KAAKJ,eAAeD,SAAAA;AAChC,UAAMM,SAAS,MAAM,KAAKV,aAAaO,IAA2BE,GAAAA;AAClE,QAAIC,QAAQ;AACV,WAAKd,OAAOe,MAAM,qCAAqCP,SAAAA,EAAW;AAClE,aAAOM;IACT;AACA,UAAME,OAAO,MAAM,KAAKb,yBAAyBiB,sBAAsBZ,SAAAA;AACvE,UAAM,KAAKJ,aAAac,IAAIL,KAAKG,MAAM,KAAKN,QAAQ;AACpD,WAAOM;EACT;;EAGA,MAAcK,qBACZd,QACAC,WACAc,iBACAC,eACe;AACf,UAAMC,WAAqB,CAAA;AAC3B,QAAIF,gBAAiBE,UAASC,KAAK,KAAKnB,iBAAiBC,QAAQC,SAAAA,CAAAA;AACjE,QAAIe,cAAeC,UAASC,KAAK,KAAKhB,eAAeD,SAAAA,CAAAA;AACrD,QAAIgB,SAASE,SAAS,EAAG,OAAM,KAAKtB,aAAauB,IAAG,GAAIH,QAAAA;EAC1D;;EAGA,MAAMI,UAAUrB,QAAgBC,WAAgD;AAC9E,UAAM,CAACqB,cAAcC,UAAAA,IAAc,MAAMC,QAAQC,IAAI;MACnD,KAAKpB,wBAAwBL,QAAQC,SAAAA;MACrC,KAAKW,sBAAsBX,SAAAA;KAC5B;AACD,WAAO;SAAIqB;SAAiBC;MAAYG,IAAI,CAACC,QAAQC,iBAAiBC,KAAKF,KAAK3B,MAAAA,CAAAA;EAClF;;EAGA,MAAM8B,WAAW9B,QAAgB+B,KAAwD;AACvF,UAAMC,OAAO,MAAM,KAAKpC,yBAAyBqC,OAAO;MACtDjC;MACAC,WAAW8B,IAAI9B;MACfN,MAAMoC,IAAIpC;MACVuC,OAAOH,IAAIG;MACXC,UAAUJ,IAAII,YAAY;IAC5B,CAAA;AACA,SAAK1C,OAAO2C,IAAI,iBAAiBL,IAAIpC,IAAI,eAAeK,MAAAA,YAAkB+B,IAAI9B,SAAS,EAAE;AACzF,UAAMkC,WAAWJ,IAAII,YAAY;AACjC,UAAM,KAAKrB,qBAAqBd,QAAQ+B,IAAI9B,WAAW,CAACkC,UAAUA,QAAAA;AAClE,WAAOP,iBAAiBC,KAAKG,MAAMhC,MAAAA;EACrC;;EAGA,MAAMqC,WAAWrC,QAAgBsC,IAAYP,KAAwD;AACnG,UAAMC,OAAO,MAAM,KAAKpC,yBAAyB2C,SAASD,EAAAA;AAC1D,QAAI,CAACN,KAAM,OAAM,IAAIQ,kBAAkB,uBAAA;AACvC,QAAIR,KAAKhC,WAAWA,OAAQ,OAAM,IAAIyC,oBAAoB,iDAAA;AAG1D,QAAIxD,gBAAgB8C,IAAIG,KAAK,MAAMjD,gBAAgB+C,KAAKE,KAAK,GAAG;AAC9D,WAAKzC,OAAO2C,IAAI,4BAA4BE,EAAAA,2BAAwB;AACpE,aAAOV,iBAAiBC,KAAKG,MAAMhC,MAAAA;IACrC;AAEA,UAAM0C,UAAU,MAAM,KAAK9C,yBAAyBR,OAAOkD,IAAI;MAAEJ,OAAOH,IAAIG;IAAM,CAAA;AAClF,SAAKzC,OAAO2C,IAAI,0BAA0BE,EAAAA,WAAatC,MAAAA,EAAQ;AAC/D,UAAM,KAAKc,qBAAqBd,QAAQgC,KAAK/B,WAAW,CAAC+B,KAAKG,UAAUH,KAAKG,QAAQ;AACrF,WAAOP,iBAAiBC,KAAKa,SAAS1C,MAAAA;EACxC;;EAGA,MAAM2C,gBAAgB3C,QAAgBsC,IAAYH,UAA8C;AAC9F,UAAMH,OAAO,MAAM,KAAKpC,yBAAyB2C,SAASD,EAAAA;AAC1D,QAAI,CAACN,KAAM,OAAM,IAAIQ,kBAAkB,uBAAA;AACvC,QAAIR,KAAKhC,WAAWA,OAAQ,OAAM,IAAIyC,oBAAoB,gDAAA;AAE1D,UAAMC,UAAU,MAAM,KAAK9C,yBAAyBR,OAAOkD,IAAI;MAAEH;IAAS,CAAA;AAC1E,SAAK1C,OAAO2C,IAAI,gBAAgBD,QAAAA,aAAqBG,EAAAA,WAAatC,MAAAA,EAAQ;AAE1E,UAAM,KAAKc,qBAAqBd,QAAQgC,KAAK/B,WAAW,MAAM,IAAA;AAC9D,WAAO2B,iBAAiBC,KAAKa,SAAS1C,MAAAA;EACxC;;EAGA,MAAM4C,WAAW5C,QAAgBsC,IAAY3C,MAAyC;AACpF,UAAMqC,OAAO,MAAM,KAAKpC,yBAAyB2C,SAASD,EAAAA;AAC1D,QAAI,CAACN,KAAM,OAAM,IAAIQ,kBAAkB,uBAAA;AACvC,QAAIR,KAAKhC,WAAWA,OAAQ,OAAM,IAAIyC,oBAAoB,iDAAA;AAG1D,UAAMI,WAAW,MAAM,KAAKjD,yBAAyBkD,QAAQ;MAC3D9C;MACAC,WAAW+B,KAAK/B;MAChBN;MACAwC,UAAU;IACZ,CAAA;AACA,QAAIU,YAAYA,SAASP,OAAOA,IAAI;AAClC,YAAM,IAAIS,kBAAkB;QAC1BC,OAAO;QACPC,QAAQ;QACRC,QAAQ;UAAC;YAAEC,OAAO;YAAQC,SAAS;UAAqB;;MAC1D,CAAA;IACF;AAEA,UAAMV,UAAU,MAAM,KAAK9C,yBAAyBR,OAAOkD,IAAI;MAAE3C;IAAK,CAAA;AACtE,SAAKF,OAAO2C,IAAI,gBAAgBE,EAAAA,QAAU3C,IAAAA,eAAmBK,MAAAA,EAAQ;AAErE,UAAM,KAAKc,qBAAqBd,QAAQgC,KAAK/B,WAAW,CAAC+B,KAAKG,UAAUH,KAAKG,QAAQ;AACrF,WAAOP,iBAAiBC,KAAKa,SAAS1C,MAAAA;EACxC;;EAGA,MAAMqD,WAAWrD,QAAgBsC,IAAuC;AACtE,UAAMN,OAAO,MAAM,KAAKpC,yBAAyB2C,SAASD,EAAAA;AAC1D,QAAI,CAACN,KAAM,OAAM,IAAIQ,kBAAkB,uBAAA;AACvC,QAAIR,KAAKhC,WAAWA,OAAQ,OAAM,IAAIyC,oBAAoB,iDAAA;AAE1D,UAAM,KAAK7C,yBAAyB0D,OAAOhB,EAAAA;AAC3C,SAAK7C,OAAO2C,IAAI,gBAAgBE,EAAAA,cAAgBtC,MAAAA,EAAQ;AACxD,UAAM,KAAKc,qBAAqBd,QAAQgC,KAAK/B,WAAW,CAAC+B,KAAKG,UAAUH,KAAKG,QAAQ;AACrF,WAAOP,iBAAiBC,KAAKG,MAAMhC,MAAAA;EACrC;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;APzJO,IAAMuD,2BAAN,MAAMA,0BAAAA;SAAAA;;;;EACMC,SAAS,IAAIC,uBAAOF,0BAAyBG,IAAI;EAElE,YAA6BC,uBAA8C;SAA9CA,wBAAAA;EAA+C;;EAK5EC,UAAoBC,QAAoCC,WAAgD;AACtG,SAAKN,OAAOO,IAAI,8BAA8BD,SAAAA,YAAqBD,MAAAA,EAAQ;AAC3E,WAAO,KAAKF,sBAAsBC,UAAUC,QAAQC,SAAAA;EACtD;;EAMAE,WAAqBH,QAAwBI,KAAwD;AACnG,SAAKT,OAAOO,IAAI,6BAA6BF,MAAAA,YAAkBI,IAAIH,SAAS,EAAE;AAC9E,WAAO,KAAKH,sBAAsBK,WAAWH,QAAQI,GAAAA;EACvD;;EAKAC,WACYL,QACGM,IACLF,KACmB;AAC3B,SAAKT,OAAOO,IAAI,sBAAsBI,EAAAA,YAAcN,MAAAA,EAAQ;AAC5D,WAAO,KAAKF,sBAAsBO,WAAWL,QAAQM,IAAIF,GAAAA;EAC3D;;EAKAG,WACYP,QACGM,IACLF,KACmB;AAC3B,SAAKT,OAAOO,IAAI,sBAAsBI,EAAAA,mBAAqBN,MAAAA,EAAQ;AACnE,WAAO,KAAKF,sBAAsBS,WAAWP,QAAQM,IAAIF,IAAIP,IAAI;EACnE;;EAKAW,gBACYR,QACGM,IACLF,KACmB;AAC3B,SAAKT,OAAOO,IAAI,sBAAsBI,EAAAA,kBAAoBN,MAAAA,EAAQ;AAClE,WAAO,KAAKF,sBAAsBU,gBAAgBR,QAAQM,IAAIF,IAAIK,QAAQ;EAC5E;;EAKAC,WAAqBV,QAA6BM,IAAuC;AACvF,SAAKX,OAAOO,IAAI,uBAAuBI,EAAAA,YAAcN,MAAAA,EAAQ;AAC7D,WAAO,KAAKF,sBAAsBY,WAAWV,QAAQM,EAAAA;EACvD;AACF;;;;;;;;;;;;;;;2DAlDuBK,OAAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;A;;;;;;;;;ANlBhB,IAAMC,kBAAN,MAAMA,iBAAAA;SAAAA;;;EACX,OAAOC,QAAQC,SAAgD;AAC7D,WAAO;MACLC,QAAQ;MACRC,QAAQJ;MACRK,SAAS;QAACC;QAAcC;;MACxBC,aAAa;QAACC;QAA0BC;;MACxCC,WAAW;QACT;UACEC,SAASC;UACTC,UAAUZ,QAAQa;QACpB;QACAC;QACAC;QACAC;;MAEFC,SAAS;QAACH;QAAuBE;;IACnC;EACF;AACF;;;;;;AmBrCA;AACA,oCAAc;;;ACGP,SAASE,wBAAAA;AACd,SAAO;IACLC,QAAIC,8BAAK,IAAA,EAAMC,WAAU,EAAGC,cAAa;IACzCC,YAAQH,8BAAK,SAAA,EAAWI,QAAO;IAC/BC,eAAWC,iCAAQ,cAAc;MAAEC,QAAQ;IAAI,CAAA,EAAGH,QAAO;IACzDI,UAAMF,iCAAQ,QAAQ;MAAEC,QAAQ;IAAI,CAAA,EAAGH,QAAO;IAC9CK,WAAOC,+BAAM,OAAA,EAASN,QAAO,EAAGO,MAAK;IACrCC,cAAUC,iCAAQ,WAAA,EAAaT,QAAO,EAAGU,QAAQ,KAAA;IACjDC,eAAWC,mCAAU,cAAc;MAAEC,cAAc;IAAK,CAAA,EAAGb,QAAO,EAAGc,WAAU;IAC/EC,eAAWH,mCAAU,cAAc;MAAEC,cAAc;IAAK,CAAA,EAAGG,UAAU,MAAM,oBAAIC,KAAAA,CAAAA;EACjF;AACF;AAXgBvB;AAeT,SAASwB,sBAAsBC,OAAU;AAC9C,SAAO;QACLC,+BAAM,4BAAA,EAA8BC,GAAGF,MAAMpB,QAAQoB,MAAMlB,SAAS;QACpEmB,+BAAM,6BAAA,EAA+BC,GAAGF,MAAMlB,WAAWkB,MAAMX,QAAQ;QACvEc,qCAAY,2CAAA,EAA6CD,GACvDF,MAAMpB,QACNoB,MAAMlB,WACNkB,MAAMf,MACNe,MAAMX,QAAQ;;AAGpB;AAXgBU;;;ACnBhB,IAAAK,kBAAuF;AACvF,IAAAC,eAA0B;;;;;;;;AAOnB,IAAMC,iBAAN,MAAMA,gBAAAA;SAAAA;;;;EAEX,OAAOC,UAA2CC,SAGhC;AAChB,UAAMC,gBAA0B;MAC9BC,SAASC;MACTC,YAAYJ,QAAQI;MACpBC,QAAQL,QAAQK,UAAU,CAAA;IAC5B;AAEA,WAAO;MACLC,QAAQR;MACRS,WAAW;QAAC;UAAEL,SAASM;UAAWC,UAAUD;QAAU;QAAGP;QAAeS;;MACxEC,SAAS;QAACD;QAAwBT;;IACpC;EACF;AACF;;;;;;;AC1BA,IAAAW,mBAA4B;;;;;;;;;;;;AAGrB,IAAMC,oBAAN,MAAMA;SAAAA;;;EAEXC;EAGAC;EAGAC;AACF;;;IARiBC,SAAS;;;;;;IAGTA,SAAS;;;;;;;;;;ACP1B,IAAAC,mBAAiD;;;;;;;;;;;;AAE1C,IAAMC,kBAAN,MAAMA;SAAAA;;;EAEXC;EAGAC;EAGAC;EAGAC;AACF;;;IAXiBC,SAAS;;;;;;IAGTA,SAAS;MAAEC,MAAM;MAAYC,MAAM;IAAW;;;;;;IAG9CF,SAAS;;;;;;IAGTA,SAAS;MAAC;;;;;AAIpB,IAAMG,mBAAN,MAAMA;SAAAA;;;EAEXC;EAGAN;EAGAO;AACF;;;IARiBL,SAAS;;;;;;IAGTA,SAAS;;;;;;IAGTA,SAAS;;;;AAInB,IAAMM,oBAAN,MAAMA;SAAAA;;;EAEXC;EAGAC;EAGAC;EAGAC;EAGAC;EAGAC;EAGAC;AACF;;;IApBiBb,SAAS;;;;;;IAGTA,SAAS;;;;;;IAGDA,SAAS;;;;;;IAGTA,SAAS;;;;;;IAGTA,SAAS;;;;;;IAGTc,MAAM;MAACnB;;;;;;;IAGPmB,MAAMX;;;;;;AC9C/B,IAAAY,mBAAoC;AACpC,+BAAqB;AACrB,IAAAC,0BAAuD;;;;;;;;;;;;AAGhD,IAAMC,wBAAN,MAAMA;SAAAA;;;EAIXC;EAOAC;EAOAC;EAKAC;EAQAC;EAKAC;EAKAC;EAKAC;EAQAC;EAKAC;EAKAC;EAWAC;AACF;;;IA3EyBC,aAAa;IAAkCC,SAAS;;;;;;;;IAKxDD,aAAa;IAA6BC,SAAS;IAAIC,SAAS;;;2CAE3EC,MAAAA;;;;;;;IAKWH,aAAa;IAA6BC,SAAS;IAAGC,SAAS;;;2CAE1EC,MAAAA;;;;;;;IAKWH,aAAa;IAAoDC,SAAS;;;;;;;;IAM/FD,aAAa;IACbC,SAAS;;;;;;;;IAMYD,aAAa;IAAgCC,SAAS;IAAMC,SAAS;;;;;;;;IAKrEF,aAAa;IAAgCC,SAAS;IAAQC,SAAS;;;;;;;;IAKvEF,aAAa;IAAsCC,SAAS;;;;;;;;IAMjFD,aAAa;IACbC,SAAS;;;;;;;;IAMYD,aAAa;IAA4BC,SAAS;;;;;;;;IAKlDD,aAAa;IAAkCC,SAAS;IAAQC,SAAS;;;;;;;;IAM9FF,aAAa;IACbC,SAAS;IACTC,SAAS;IACTE,MAAM;MAAC;MAAO;;;;;;IAIT;IAAO;;;;;;AC/EhB,IAAAC,mBAA4B;AAC5B,IAAAC,0BAAgD;;;;;;;;;;;;AAEzC,IAAMC,qBAAN,MAAMA;SAAAA;;;EAIXC;EAKAC;AACF;;;IATiBC,SAAS;;;;;;;;IAKTA,SAAS;;;;;;;;ACT1B,IAAAC,mBAAiD;;;;;;;;;;;;AAG1C,IAAMC,mBAAN,MAAMA;SAAAA;;;EAEXC;EAGAC;EAGAC;EAGAC;AACF;;;;;;;;;;;;;;;IAFyBC,UAAU;;;;;;ACbnC,IAAAC,sBAA0H;AAQnH,IAAMC,kBAAN,MAAMA;EARb,OAQaA;;;;EAEX,OAAOC,WAAWC,UAA6B,CAAA,GAAIC,UAAqC;AACtF,UAAMC,aAAaF,QAAQG,QAAQ,CAACC,MAAAA;AAClC,YAAMC,MAAMJ,SAASG,EAAEE,KAAK;AAC5B,UAAI,CAACD,IAAK,QAAO,CAAA;AAEjB,UAAI,gBAAgBA,IAAK,QAAOE,MAAMC,QAAQJ,EAAEK,KAAK,IAAI,CAAA,IAAK;QAACJ,IAAIK,WAAWN,EAAEK,OAAOL,EAAEO,QAAQ;;AACjG,YAAM,EAAEC,QAAQC,IAAG,IAAKR;AACxB,YAAMS,MAAMV,EAAEK;AACd,cAAQL,EAAEO,UAAQ;QAChB,KAAK;AACH,cAAIN,IAAIU,SAAS,UAAW,QAAO;gBAACC,wBAAGH,KAAKC,QAAQ,UAAUA,QAAQ,CAAA;;AACtE,iBAAO;gBAACE,wBAAGH,KAAKC,GAAAA;;QAClB,KAAK;AACH,cAAIT,IAAIU,SAAS,UAAW,QAAO;gBAACE,wBAAGJ,KAAKC,QAAQ,UAAUA,QAAQ,CAAA;;AACtE,iBAAO;gBAACG,wBAAGJ,KAAKC,GAAAA;;QAClB,KAAK;AACH,iBAAO;gBAACI,2BAAML,KAAK,IAAIC,GAAAA,GAAM;;QAC/B,KAAK;AACH,iBAAO;gBAACK,8BAASN,KAAK,IAAIC,GAAAA,GAAM;;QAClC,KAAK;AACH,iBAAO;gBAACM,wBAAGP,KAAKC,GAAAA;;QAClB,KAAK;AACH,iBAAO;gBAACO,yBAAIR,KAAKC,GAAAA;;QACnB,KAAK;AACH,iBAAO;gBAACQ,wBAAGT,KAAKC,GAAAA;;QAClB,KAAK;AACH,iBAAO;gBAACS,yBAAIV,KAAKC,GAAAA;;QACnB,KAAK;AACH,iBAAO;gBAACU,6BAAQX,KAAKN,MAAMC,QAAQM,GAAAA,IAAOA,MAAM;cAACW,OAAOX,GAAAA;aAAK;;QAC/D,KAAK;AACH,iBAAO;gBAACY,gCAAWb,KAAKN,MAAMC,QAAQM,GAAAA,IAAOA,MAAM;cAACW,OAAOX,GAAAA;aAAK;;QAClE;AACE,iBAAO,CAAA;MACX;IACF,CAAA;AACA,WAAOZ,WAAWyB,aAASC,yBAAAA,GAAO1B,UAAAA,IAAc2B;EAClD;;EAGA,OAAOC,YAAYC,QAAwC9B,UAAqC;AAC9F,QAAI,CAAC8B,QAAQtB,MAAO,QAAOoB;AAE3B,QAAIE,OAAOC,aAAa,OAAO;AAC7B,YAAM9B,aAAa+B,OAAOC,OAAOjC,QAAAA,EAC9BkC,OACC,CAAC9B,SACC,YAAYA,QAAOA,KAAIU,SAAS,QAAA,EAEnCqB,IAAI,CAAC/B,aAAQa,2BAAMb,KAAIO,QAAQ,IAAImB,OAAOtB,KAAK,GAAG,CAAA;AACrD,aAAOP,WAAWyB,aAASU,wBAAAA,GAAMnC,UAAAA,IAAc2B;IACjD;AAEA,UAAMxB,MAAMJ,SAAS8B,OAAOC,QAAQ;AACpC,QAAI,CAAC3B,OAAO,EAAE,YAAYA,KAAM,QAAOwB;AACvC,eAAOX,2BAAMb,IAAIO,QAAQ,IAAImB,OAAOtB,KAAK,GAAG;EAC9C;;EAGA,OAAO6B,aAAaC,OAAwB,CAAA,GAAItC,UAA2B;AACzE,WAAOsC,KAAKpC,QAAQ,CAACqC,MAAAA;AACnB,YAAMnC,MAAMJ,SAASuC,EAAElC,KAAK;AAC5B,UAAI,CAACD,OAAO,EAAE,YAAYA,KAAM,QAAO,CAAA;AACvC,aAAO;QAACmC,EAAEC,cAAc,YAAQC,yBAAIrC,IAAIO,MAAM,QAAI+B,0BAAKtC,IAAIO,MAAM;;IACnE,CAAA;EACF;AACF;;;ACzEO,IAAMgC,kBAAkB;EAC7BC,QAAQ;EACRC,YAAY;EACZC,UAAU;EACVC,cAAc;EACdC,IAAI;EACJC,KAAK;EACLC,IAAI;EACJC,KAAK;EACLC,WAAW;EACXC,eAAe;AACjB;;;ACbA,IAAAC,0BAAoF;;;ACApF;;;;;;;AAAA,oBAAkC;AAClC,wBAuKO;AAGP,0BAAc;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;EACAp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","names":["ForbiddenException","UnauthorizedException","AUTH_CONFIG","Symbol","AUTH_CONFIG_DEFAULTS","cookie","refreshCookieName","refreshCookieMaxAge","refreshCookiePath","refreshCookieSecure","process","env","NODE_ENV","refreshCookieSameSite","refreshCookieDomain","guard","authHeaderName","tokenPrefix","csrfExemptSessionTypes","refreshTokenBindingExemptSessionTypes","TokenType","import_common","import_core","import_jwt","import_common","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","import_common","import_core","import_common","REQUIRE_SESSION_KEY","RequireSession","types","SetMetadata","import_common","SKIP_CSRF_KEY","SkipCsrf","SetMetadata","import_common","parseExpiryToMs","expiry","match","Error","value","Number","parseInt","multipliers","s","m","h","d","w","y","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","import_common","AccessToken","createParamDecorator","_data","ctx","request","switchToHttp","getRequest","authHeader","headers","authorization","replace","import_common","CookieDomain","createParamDecorator","_data","ctx","request","switchToHttp","getRequest","forwarded","headers","raw","Array","isArray","hostStr","hostname","domain","split","baseDomain","authConfig","cookie","refreshCookieDomain","AUTH_CONFIG_DEFAULTS","endsWith","import_common","CookieName","createParamDecorator","_data","ctx","request","switchToHttp","getRequest","authConfig","cookie","refreshCookieName","AUTH_CONFIG_DEFAULTS","import_common","Hostname","createParamDecorator","_data","ctx","request","switchToHttp","getRequest","forwarded","headers","raw","Array","isArray","hostStr","hostname","split","import_common","Public","SetMetadata","import_common","import_common","import_common","HttpProblemException","HttpException","detailOrOptions","httpStatus","options","detail","type","label","errors","BadGatewayException","HttpProblemException","detailOrOptions","HttpStatus","BAD_GATEWAY","import_common","BadRequestException","HttpProblemException","detailOrOptions","HttpStatus","BAD_REQUEST","import_common","ConflictException","HttpProblemException","detailOrOptions","HttpStatus","CONFLICT","import_common","ForbiddenException","HttpProblemException","detailOrOptions","HttpStatus","FORBIDDEN","import_common","GoneException","HttpProblemException","detailOrOptions","HttpStatus","GONE","import_common","InternalServerErrorException","HttpProblemException","detailOrOptions","HttpStatus","INTERNAL_SERVER_ERROR","import_common","MethodNotAllowedException","HttpProblemException","detailOrOptions","HttpStatus","METHOD_NOT_ALLOWED","import_common","NotAcceptableException","HttpProblemException","detailOrOptions","HttpStatus","NOT_ACCEPTABLE","import_common","NotFoundException","HttpProblemException","detailOrOptions","HttpStatus","NOT_FOUND","import_common","NotImplementedException","HttpProblemException","detailOrOptions","HttpStatus","NOT_IMPLEMENTED","import_common","PayloadTooLargeException","HttpProblemException","detailOrOptions","HttpStatus","PAYLOAD_TOO_LARGE","import_common","RequestTimeoutException","HttpProblemException","detailOrOptions","HttpStatus","REQUEST_TIMEOUT","import_common","ServiceUnavailableException","HttpProblemException","detailOrOptions","HttpStatus","SERVICE_UNAVAILABLE","import_common","TooManyRequestsException","HttpProblemException","detailOrOptions","HttpStatus","TOO_MANY_REQUESTS","import_common","UnauthorizedException","HttpProblemException","detailOrOptions","HttpStatus","UNAUTHORIZED","import_common","UnprocessableEntityException","HttpProblemException","detailOrOptions","HttpStatus","UNPROCESSABLE_ENTITY","import_common","UnsupportedMediaTypeException","HttpProblemException","detailOrOptions","HttpStatus","UNSUPPORTED_MEDIA_TYPE","import_common","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","import_common","RefreshTokenCookie","createParamDecorator","_data","ctx","request","switchToHttp","getRequest","cookies","cookieName","authConfig","cookie","refreshCookieName","AUTH_CONFIG_DEFAULTS","import_common","SessionData","createParamDecorator","_data","ctx","request","switchToHttp","getRequest","sessionInfo","sessionId","Error","userId","sessionType","import_common","Subdomain","createParamDecorator","_data","ctx","request","switchToHttp","getRequest","origin","headers","url","URL","hostname","split","forwarded","host","Array","isArray","undefined","import_common","UserId","createParamDecorator","_data","ctx","request","switchToHttp","getRequest","sessionInfo","userId","Error","import_common","import_config","import_common","CACHE_PROVIDER","Symbol","CacheService","logger","Logger","name","provider","set","key","value","ttlSeconds","err","error","get","del","keys","join","scanKeys","pattern","getMemoryInfo","import_common","import_config","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","import_common","import_config","DATA_TABLE_VIEWS_TABLE","Symbol","import_common","import_swagger","import_common","import_swagger","UpsertDataTableStateDto","tableSlug","state","activeViewId","description","example","ApiUpsertDataTableState","applyDecorators","ApiOperation","summary","description","ApiBody","type","UpsertDataTableStateDto","ApiResponse","status","import_common","import_config","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","import_common","import_swagger","import_common","import_swagger","import_swagger","DataTableViewDto","id","name","tableSlug","state","isShared","isOwn","createdAt","updatedAt","from","view","userId","dto","description","nullable","example","import_swagger","import_class_validator","CreateDataTableViewDto","name","tableSlug","state","isShared","description","example","import_swagger","import_class_validator","RenameDataTableViewDto","name","description","example","import_swagger","import_class_validator","ToggleShareDataTableViewDto","isShared","description","example","import_swagger","import_class_validator","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","import_common","import_config","import_common","import_drizzle_orm","import_common","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","import_common","DATABASE_MODULE_OPTIONS","Symbol","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","import_common","import_core","DatabaseModule","forServer","options","asyncProvider","provide","DATABASE_MODULE_OPTIONS","useFactory","inject","module","providers","Reflector","useClass","PrimaryDatabaseService","exports","import_swagger","CreateResponseDto","success","message","data","example","import_swagger","ValidatedRowDto","index","data","valid","errors","example","code","name","ImportSummaryDto","total","invalid","ImportResponseDto","success","message","created","updated","skipped","rows","summary","type","import_swagger","import_class_validator","SelectOptionsQueryDto","search","limit","offset","values","excludeIds","valueKey","labelKey","descriptionKey","additionalKeys","groupIdKey","orderByKey","orderDirection","description","example","default","Number","enum","import_swagger","import_class_validator","SuccessResponseDto","success","message","example","import_swagger","TableResponseDto","result","count","state","activeViewId","nullable","import_drizzle_orm","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","import_class_validator","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","import_class_validator","IsCurrencyCode","validationOptions","target","propertyName","registerDecorator","name","String","options","validator","validate","value","SUPPORTED_CURRENCIES","defaultMessage","args","property","import_class_validator","UTC_ISO_DATETIME_REGEX","IsDateTime","validationOptions","target","propertyName","registerDecorator","name","String","options","validator","validate","value","test","Number","isNaN","Date","parse","defaultMessage","args","property","import_common","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","import_common","import_config","import_common","import_config","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","import_common","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","import_common","import_common","import_node_async_hooks","import_node_crypto","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","import_common","import_common","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","import_common","import_common","import_swagger","import_common","import_swagger","ApiHealthCheck","applyDecorators","ApiOperation","summary","ApiResponse","status","description","type","String","import_common","AppService","getHello","AppController","appService","getHello","import_common","import_swagger","import_common","import_swagger","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"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/auth/auth.config.ts","../src/auth/auth-config.module.ts","../src/request/request.module.ts","../src/request/services/request.service.ts","../src/context/resolve-request.ts","../src/auth/guards/vritti-auth.guard.ts","../src/context/extractors/graphql.extractor.ts","../src/context/extractors/http.extractor.ts","../src/context/context.registry.ts","../src/context/get-request.ts","../src/context/get-response.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/client-ip.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-agent.decorator.ts","../src/auth/decorators/user-id.decorator.ts","../src/data-table/data-table.module.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.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/cursor-list-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/cursor.codec.ts","../src/database/filter/filter.processor.ts","../src/database/filter/filter.types.ts","../src/database/filter/keyset.processor.ts","../src/decorators/is-date-time.decorator.ts","../src/decorators/uploaded-file.decorator.ts","../src/filters/error-code.ts","../src/filters/problem-extraction.ts","../src/filters/graphql-format-error.ts","../src/filters/http-exception.filter.ts","../src/filters/pg-error.translator.ts","../src/filters/transport-aware-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/math.utils.ts","../src/utils/phone.utils.ts"],"sourcesContent":["import './types/fastify-augmentation';\n\n// Auth (decorators, guards, token utilities)\nexport * from './auth';\n// Token types and config\nexport {\n type AccessTokenPayload,\n AUTH_CONFIG,\n AUTH_CONFIG_DEFAULTS,\n type AuthConfig,\n type CookieConfig,\n type CookieSerializeOptions,\n type DecodedAccessToken,\n type DecodedRefreshToken,\n type GuardConfig,\n type OnAuthenticatedCallback,\n type RefreshTokenPayload,\n type TokenExpiry,\n type TokenExpiryString,\n TokenType,\n} from './auth/auth.config';\n// Auth decorators (SkipCsrf for webhook endpoints)\nexport { SKIP_CSRF_KEY, SkipCsrf } from './auth/decorators/skip-csrf.decorator';\n// Token service — generation, validation, and binding verification\nexport { TokenService } from './auth/services/token.service';\n// Cache module moved to the './cache' subpath (@vritti/api-sdk/cache) so the main barrel never imports ioredis.\n// Catalog resolver moved to the './catalog-resolver' subpath (@vritti/api-sdk/catalog-resolver).\n// Context module — transport-agnostic request/response access + extensible transport registry\nexport * from './context';\n// Data table module (views + ephemeral state)\nexport { DATA_TABLE_VIEWS_TABLE, DataTableModule, type DataTableModuleOptions } from './data-table/data-table.module';\nexport {\n type DataTableViewRecord,\n dataTableViewsColumns,\n dataTableViewsIndexes,\n type NewDataTableViewRecord,\n} from './data-table/schema/data-table-views.table';\nexport { UpsertDataTableStateDto } from './data-table/state/dto/request/upsert-data-table-state.dto';\nexport { DataTableStateService } from './data-table/state/services/data-table-state.service';\nexport { DataTableViewDto } from './data-table/views/dto/entity/data-table-view.dto';\nexport { CreateDataTableViewDto } from './data-table/views/dto/request/create-data-table-view.dto';\nexport { RenameDataTableViewDto } from './data-table/views/dto/request/rename-data-table-view.dto';\nexport { ToggleShareDataTableViewDto } from './data-table/views/dto/request/toggle-share-data-table-view.dto';\nexport { UpdateDataTableViewDto } from './data-table/views/dto/request/update-data-table-view.dto';\nexport { DataTableViewsService } from './data-table/views/services/data-table-views.service';\nexport { DatabaseModule } from './database/database.module';\n// Database DTOs\nexport { CreateResponseDto } from './database/dto/create-response.dto';\nexport { CursorListResponseDto } from './database/dto/cursor-list-response.dto';\nexport { ImportResponseDto, ImportSummaryDto, ValidatedRowDto } from './database/dto/import-response.dto';\nexport { SelectOptionsQueryDto } from './database/dto/select-options-query.dto';\nexport { SuccessResponseDto } from './database/dto/success-response.dto';\nexport { TableResponseDto } from './database/dto/table-response.dto';\n// Cursor / keyset pagination\nexport { CursorCodec } from './database/filter/cursor.codec';\n// Filter processor\nexport { type FieldDefinition, type FieldMap, FilterProcessor } from './database/filter/filter.processor';\nexport type {\n ColumnPinning,\n DensityType,\n FilterCondition,\n FilterOperator,\n SearchState,\n SortCondition,\n TableViewState,\n} from './database/filter/filter.types';\nexport { FilterOperators } from './database/filter/filter.types';\nexport { type KeysetOrderBy, KeysetProcessor } from './database/filter/keyset.processor';\n// Interfaces\nexport * from './database/interfaces';\n// Repositories\nexport { PrimaryBaseRepository } from './database/repositories/primary-base.repository';\nexport type { TypedDrizzleClient } from './database/schema.registry';\nexport { PrimaryDatabaseService } from './database/services/primary-database.service';\n// Database types\nexport type {\n FindForSelectConfig,\n FindForSelectJoin,\n SelectQueryGroup,\n SelectQueryOption,\n SelectQueryResult,\n} from './database/types';\nexport { IsDateTime } from './decorators/is-date-time.decorator';\n// Decorators\nexport { UploadedFile, type UploadedFileResult, UploadedFiles } from './decorators/uploaded-file.decorator';\n// Icon-name validation (IsIconName, ICON_NAMES, isIconName) is intentionally NOT re-exported\n// here — import it from the '@vritti/api-sdk/icons' subpath so the large icon-names.json (~352KB)\n// stays out of the main bundle and only loads where it's used.\n// Email module moved to the './email' subpath (@vritti/api-sdk/email) so the main barrel never imports @getbrevo/brevo.\n// Exceptions\nexport * from './exceptions';\n// RFC 7807 Filters (includes HttpExceptionFilter)\nexport * from './filters';\n// License module moved to the './license' subpath (@vritti/api-sdk/license).\n// Logger utilities\nexport * from './logger';\n// Money module (utilities, IsCurrency, IsCurrencyCode, CurrencyAmountDto) lives on the './money'\n// subpath (@vritti/api-sdk/money) — the only entry that touches dinero.js.\n// NATS / microservice exports moved to the './nats' subpath (@vritti/api-sdk/nats) so the main\n// barrel never imports @nestjs/microservices. Non-NATS consumers (cloud-server) stay clean.\n// Root module (health check + CSRF)\nexport { RootModule } from './root/root.module';\n// RFC 7807 Types (using named exports to avoid conflicts)\nexport type { ApiErrorResponse, ProblemDetails } from './types';\n// Math utilities\nexport { gcd } from './utils/math.utils';\n// Phone utilities\nexport { extractCountryFromPhone, normalizePhoneNumber } from './utils/phone.utils';\n// Time utilities\nexport { parseExpiryToMs } from './utils/time.utils';\n","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 // Transports (matched against ExecutionContext.getType(), e.g. 'graphql') that skip the\n // cookie-based CSRF check entirely — for bearer-token, cookie-less transports where CSRF\n // does not apply. Skips CSRF for both @Public() and authenticated requests on that transport.\n csrfExemptTransports?: 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 csrfExemptTransports: [],\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';\nimport { resolveInjectedRequest } from '../../context/resolve-request';\n\n@Injectable({ scope: Scope.REQUEST })\nexport class RequestService {\n constructor(\n @Inject(REQUEST) private readonly injectedRequest: FastifyRequest,\n @Inject(AUTH_CONFIG) private readonly config: AuthConfig,\n ) {}\n\n // For GraphQL, @Inject(REQUEST) is the { req, reply } context wrapper, not the Fastify request;\n // unwrap so every accessor below works identically across both transports.\n private get request(): FastifyRequest {\n return resolveInjectedRequest(this.injectedRequest);\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 type { FastifyRequest } from 'fastify';\n\n// NestJS injects the raw Fastify request via @Inject(REQUEST) for HTTP, but for GraphQL it injects\n// the GraphQL context object ({ req, reply }) — which has no `.headers` / `.sessionInfo`. Any\n// request-scoped service that reads the request off @Inject(REQUEST) (RequestService,\n// NatsClientService, …) calls this to unwrap to the real Fastify request, so it behaves identically\n// across both transports. (The guard sets `sessionInfo` on this same unwrapped request.)\nexport function resolveInjectedRequest(injected: FastifyRequest): FastifyRequest {\n const candidate = injected as unknown as { headers?: unknown; req?: FastifyRequest };\n if (candidate && candidate.headers === undefined && candidate.req) {\n return candidate.req;\n }\n return injected;\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 { getRequestFromContext, getResponseFromContext } from '../../context';\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 = getRequestFromContext(context);\n const reply = getResponseFromContext(context);\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 // CSRF is skipped via @SkipCsrf(), or when the request transport is CSRF-exempt (e.g. 'graphql'\n // — a bearer-token, cookie-less transport where the cookie-based CSRF check does not apply).\n const csrfExemptTransports = this.config.guard.csrfExemptTransports ?? [];\n const skipCsrf =\n this.reflector.getAllAndOverride<boolean>(SKIP_CSRF_KEY, [context.getHandler(), context.getClass()]) ||\n csrfExemptTransports.includes(context.getType<string>());\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 type { ArgumentsHost } from '@nestjs/common';\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport type { RequestExtractor } from '../context.types';\n\n// The GraphQL context is the 3rd resolver argument: (root, args, context, info). The core-server\n// GraphQLModule sets `context: (request, reply) => ({ req: request, reply })`, so the host's\n// arg #2 IS that `{ req, reply }` object. This is exactly what @nestjs/graphql's\n// `GqlArgumentsHost.getContext()` returns internally — so we read it directly and avoid a runtime\n// dependency on @nestjs/graphql. That matters: api-sdk is linked from OUTSIDE the consumer's\n// node_modules tree, so `require('@nestjs/graphql')` from here cannot resolve the consumer's copy\n// (it throws \"Cannot find module '@nestjs/graphql'\" at runtime).\ninterface GqlContext {\n req: FastifyRequest;\n reply?: FastifyReply;\n}\n\nexport const graphqlExtractor: RequestExtractor = {\n getRequest: (host: ArgumentsHost) => host.getArgByIndex<GqlContext>(2).req,\n getResponse: (host: ArgumentsHost) => host.getArgByIndex<GqlContext>(2).reply as FastifyReply,\n};\n","import type { FastifyReply, FastifyRequest } from 'fastify';\nimport type { RequestExtractor } from '../context.types';\n\n// Default transport: standard HTTP via the Fastify adapter.\nexport const httpExtractor: RequestExtractor = {\n getRequest: (host) => host.switchToHttp().getRequest<FastifyRequest>(),\n getResponse: (host) => host.switchToHttp().getResponse<FastifyReply>(),\n};\n","import type { RequestExtractor, TransportType } from './context.types';\nimport { graphqlExtractor } from './extractors/graphql.extractor';\nimport { httpExtractor } from './extractors/http.extractor';\n\n// Central transport → extractor registry. Adding a new API transport (ws, rpc, ...) is a\n// single registerTransport() call; the guard, decorators, RLS interceptor, and the\n// transport-aware exception filter all resolve through this map and need no changes.\nconst registry = new Map<TransportType, RequestExtractor>([\n ['http', httpExtractor],\n ['graphql', graphqlExtractor],\n]);\n\n// Registers (or overrides) the extractor for a transport type, letting apps add new\n// transports without modifying the SDK.\nexport function registerTransport(type: TransportType, extractor: RequestExtractor): void {\n registry.set(type, extractor);\n}\n\n// Resolves the extractor for the host's reported transport, falling back to HTTP.\nexport function resolveExtractor(type: string): RequestExtractor {\n return registry.get(type as TransportType) ?? httpExtractor;\n}\n","import type { ArgumentsHost } from '@nestjs/common';\nimport type { FastifyRequest } from 'fastify';\nimport { resolveExtractor } from './context.registry';\n\n// Returns the underlying Fastify request for any registered transport (HTTP, GraphQL, ...).\n// Resolves via the transport registry, so new transports need no change here or in callers.\nexport function getRequestFromContext(host: ArgumentsHost): FastifyRequest {\n return resolveExtractor(host.getType()).getRequest(host);\n}\n","import type { ArgumentsHost } from '@nestjs/common';\nimport type { FastifyReply } from 'fastify';\nimport { resolveExtractor } from './context.registry';\n\n// Returns the underlying Fastify reply for any registered transport (HTTP, GraphQL, ...).\nexport function getResponseFromContext(host: ArgumentsHost): FastifyReply {\n return resolveExtractor(host.getType()).getResponse(host);\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 [, digits = '', unit = ''] = match;\n const value = Number.parseInt(digits, 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 const multiplier = multipliers[unit];\n if (multiplier === undefined) throw new Error(`Invalid expiry format: ${expiry}`);\n\n return value * multiplier;\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 { getRequestFromContext } from '../../context';\n\n// Extracts the bearer token from the Authorization header\nexport const AccessToken = createParamDecorator((_data: unknown, ctx: ExecutionContext): string => {\n const request = getRequestFromContext(ctx);\n const authHeader = request.headers.authorization;\n return authHeader?.replace('Bearer ', '') || '';\n});\n","import { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport { getRequestFromContext } from '../../context';\n\n// Extracts the client IP from the request, working across HTTP and GraphQL transports\nexport const ClientIp = createParamDecorator((_data: unknown, ctx: ExecutionContext): string => {\n return getRequestFromContext(ctx).ip;\n});\n","import { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport { getRequestFromContext } from '../../context';\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 = getRequestFromContext(ctx);\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 { getRequestFromContext } from '../../context';\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 = getRequestFromContext(ctx);\n return request.authConfig?.cookie.refreshCookieName ?? AUTH_CONFIG_DEFAULTS.cookie.refreshCookieName;\n});\n","import { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport { getRequestFromContext } from '../../context';\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 = getRequestFromContext(ctx);\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 { getRequestFromContext } from '../../context';\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 = getRequestFromContext(ctx);\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 { getRequestFromContext } from '../../context';\nimport { AUTH_CONFIG_DEFAULTS } from '../auth.config';\n\nexport const RefreshTokenCookie = createParamDecorator((_data: unknown, ctx: ExecutionContext): string | undefined => {\n const request = getRequestFromContext(ctx);\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 { getRequestFromContext } from '../../context';\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 = getRequestFromContext(ctx);\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 { getRequestFromContext } from '../../context';\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 = getRequestFromContext(ctx);\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 { getRequestFromContext } from '../../context';\n\n// Extracts the User-Agent header from the request, working across HTTP and GraphQL transports\nexport const UserAgent = createParamDecorator((_data: unknown, ctx: ExecutionContext): string | undefined => {\n const userAgent = getRequestFromContext(ctx).headers['user-agent'];\n return Array.isArray(userAgent) ? userAgent[0] : userAgent;\n});\n","import { createParamDecorator, type ExecutionContext } from '@nestjs/common';\nimport { getRequestFromContext } from '../../context';\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 = getRequestFromContext(ctx);\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 { 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","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","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 getViewName,\n type InferInsertModel,\n type InferSelectModel,\n type InferSelectViewModel,\n ilike,\n inArray,\n is,\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 { PgViewBase } from 'drizzle-orm/pg-core/view-base';\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 | PgViewBase,\n TInsert = TTable extends PgTable ? InferInsertModel<TTable> : never,\n TSelect = TTable extends PgTable\n ? InferSelectModel<TTable>\n : TTable extends PgViewBase\n ? InferSelectViewModel<TTable>\n : never,\n> {\n protected readonly logger: Logger;\n protected readonly sequence?: PgSequence;\n\n private readonly tableName: string;\n private readonly isView: boolean;\n\n protected get db(): TypedDrizzleClient {\n return this.database.drizzleClient;\n }\n\n protected get model(): TypedRelationalQueryBuilder<TSelect> {\n if (this.isView) {\n throw new Error(\n `${this.constructor.name}: relational queries (.model) are not supported on the view '${this.tableName}'. Use findForSelect / findAllAndCount instead.`,\n );\n }\n\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/view name to camelCase to match Drizzle query object keys\n // Example: 'email_verifications' -> 'emailVerifications'\n this.isView = is(table, PgViewBase);\n const dbTableName = this.isView ? getViewName(table as PgViewBase) : getTableName(table as PgTable);\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.select({ count: sql<number>`count(*)::int` }).from(named) as unknown as Promise<\n { count: number }[]\n >;\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 // Fetches limit+1 rows for keyset/cursor pagination and trims, returning rows plus hasMore.\n // The WHERE must already include the keyset \"after\" predicate; orderBy must be a total order.\n async findKeyset<TResult = TSelect>(options: {\n select?: Record<string, unknown>;\n where?: SQL;\n orderBy: SQL[];\n limit: number;\n leftJoin?: { table: PgTable; on: SQL | undefined };\n leftJoins?: { table: PgTable; on: SQL | undefined }[];\n groupBy?: (PgColumn | SQL)[];\n }): Promise<{ rows: TResult[]; hasMore: boolean }> {\n const rows = (await this.buildSelectQuery({\n ...options,\n limit: options.limit + 1,\n })) as unknown as TResult[];\n const hasMore = rows.length > options.limit;\n return { rows: hasMore ? rows.slice(0, options.limit) : rows, hasMore };\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 CursorListResponseDto<T> {\n @ApiProperty()\n items: T[];\n\n @ApiPropertyOptional({ nullable: true })\n nextCursor: string | null;\n\n @ApiProperty()\n hasMore: boolean;\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","type SerializedValue = { __t: 'date'; v: string } | string | number | boolean | null;\n\nexport class CursorCodec {\n // Encodes ORDER BY boundary values (id tie-breaker last) into a base64url JSON string\n static encode(values: unknown[]): string {\n const serialized = values.map<SerializedValue>((v) => {\n if (v instanceof Date) return { __t: 'date', v: v.toISOString() };\n if (v === null || v === undefined) return null;\n if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') return v;\n return String(v);\n });\n const json = JSON.stringify(serialized);\n return Buffer.from(json, 'utf8').toString('base64url');\n }\n\n // Decodes a cursor back into the ordered boundary values, rehydrating ISO strings as Dates\n static decode(cursor: string): unknown[] {\n const json = Buffer.from(cursor, 'base64url').toString('utf8');\n const parsed = JSON.parse(json) as SerializedValue[];\n return parsed.map((v) => {\n if (v && typeof v === 'object' && '__t' in v && v.__t === 'date') return new Date(v.v);\n return v;\n });\n }\n}\n","import {\n and,\n asc,\n type Column,\n desc,\n eq,\n gt,\n gte,\n ilike,\n inArray,\n lt,\n lte,\n ne,\n notIlike,\n notInArray,\n or,\n type SQL,\n} 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 =\n | 'equals'\n | 'notEquals'\n | 'contains'\n | 'notContains'\n | 'gt'\n | 'gte'\n | 'lt'\n | 'lte'\n | 'isAnyOf'\n | '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 { and, type Column, eq, gt, lt, or, type SQL } from 'drizzle-orm';\n\nexport interface KeysetOrderBy {\n column: Column;\n direction: 'asc' | 'desc';\n}\n\nexport class KeysetProcessor {\n // Builds the \"after this row\" predicate for keyset pagination via lexicographic OR-expansion.\n // Correct for multi-column AND mixed directions: OR over i of [ AND over j<i of eq(col_j, v_j) AND cmp(col_i, v_i) ].\n static buildAfter(orderBy: KeysetOrderBy[], values: unknown[]): SQL {\n const groups: SQL[] = [];\n for (let i = 0; i < orderBy.length; i++) {\n const current = orderBy[i];\n if (!current) continue;\n const conditions: SQL[] = [];\n // Tie on every earlier column\n for (let j = 0; j < i; j++) {\n const prior = orderBy[j];\n if (prior) conditions.push(eq(prior.column, values[j]));\n }\n // Then strictly past the boundary on the i-th column, respecting its direction\n const cmp = current.direction === 'asc' ? gt : lt;\n conditions.push(cmp(current.column, values[i]));\n const group = conditions.length === 1 ? conditions[0] : and(...conditions);\n if (group) groups.push(group);\n }\n const first = groups[0];\n if (groups.length === 1 && first) return first;\n return or(...groups) as SQL;\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 { HttpStatus } from '@nestjs/common';\n\n// Machine-readable error contract surfaced on the wire as `extensions.code` (GraphQL) so clients\n// branch on a stable enum instead of HTTP status codes or human-readable messages. This is a plain\n// TypeScript enum today; registering it as a GraphQL schema enum is a later client-codegen concern.\nexport enum ErrorCode {\n UNAUTHENTICATED = 'UNAUTHENTICATED',\n FORBIDDEN = 'FORBIDDEN',\n NOT_FOUND = 'NOT_FOUND',\n VALIDATION_FAILED = 'VALIDATION_FAILED',\n CONFLICT = 'CONFLICT',\n RATE_LIMITED = 'RATE_LIMITED',\n BAD_REQUEST = 'BAD_REQUEST',\n INTERNAL = 'INTERNAL',\n}\n\n// Maps an HTTP status code to the canonical ErrorCode. Keeps the GraphQL `extensions.code` aligned\n// with the same status the RFC 9457 HTTP filter would emit, so both transports classify identically.\nexport function errorCodeFromStatus(status: number): ErrorCode {\n switch (status) {\n case HttpStatus.UNAUTHORIZED: // 401\n return ErrorCode.UNAUTHENTICATED;\n case HttpStatus.FORBIDDEN: // 403\n return ErrorCode.FORBIDDEN;\n case HttpStatus.NOT_FOUND: // 404\n return ErrorCode.NOT_FOUND;\n case HttpStatus.BAD_REQUEST: // 400\n case HttpStatus.UNPROCESSABLE_ENTITY: // 422\n return ErrorCode.VALIDATION_FAILED;\n case HttpStatus.CONFLICT: // 409\n return ErrorCode.CONFLICT;\n case HttpStatus.TOO_MANY_REQUESTS: // 429\n return ErrorCode.RATE_LIMITED;\n default:\n // Any other client error (4xx) is a generic bad request; everything else\n // (5xx and unknown/non-numeric) collapses to INTERNAL.\n if (status >= 400 && status < 500) {\n return ErrorCode.BAD_REQUEST;\n }\n return ErrorCode.INTERNAL;\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport type { FieldError } from '../types/error-response.types';\n\n// Shape of the @vritti/api-sdk HttpProblemException response body (type/label/detail/errors[]).\ninterface ProblemExceptionResponse {\n type?: string;\n label?: string;\n detail?: string;\n errors?: FieldError[];\n}\n\n// Shape of a class-validator ValidationPipe error body (message is an array of constraints).\ninterface ValidationExceptionResponse {\n message: Array<string | { property: string; constraints: Record<string, string> }>;\n error?: string;\n}\n\n// Shape of a standard NestJS exception body (message is a string or string[]).\ninterface StandardExceptionResponse {\n message: string | string[];\n error?: string;\n}\n\ntype ExceptionResponseObject = ProblemExceptionResponse | ValidationExceptionResponse | StandardExceptionResponse;\n\n// Normalized problem information extracted from a NestJS HttpException's response body.\n// Shared by HttpExceptionFilter (RFC 9457 HTTP responses) and the GraphQL formatError so the\n// SAME label/detail/field-errors surface across both transports. `detail` is undefined when the\n// response body carried no usable detail, letting each caller apply its own fallback.\nexport interface ExtractedProblem {\n type: string;\n label?: string;\n detail?: string;\n errors: FieldError[];\n}\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// Extracts field-specific errors from a class-validator ValidationPipe message array. Mirrors the\n// RFC 9457 errors[] that the HTTP filter produces so GraphQL fieldErrors carry the same info.\nfunction extractValidationFieldErrors(\n message: Array<string | { property: string; constraints: Record<string, string> }>,\n): FieldError[] {\n return 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 here; they belong at the detail level.\n return null;\n })\n .filter((error): error is FieldError => error !== null);\n}\n\n// Parses a NestJS HttpException response body into normalized problem fields. Handles the three\n// body shapes the SDK encounters: custom HttpProblemException, class-validator errors, and\n// standard NestJS exceptions. `problemFallbackDetail` supplies the detail for the\n// HttpProblemException branch when its body omits one (mirrors the HTTP filter's prior\n// `problemResponse.detail ?? exception.message ?? title`). `detail` is left undefined for an\n// object body that matches no known shape, so the caller keeps its own initial detail.\nexport function extractProblemFromResponse(\n exceptionResponse: string | object,\n problemFallbackDetail: string,\n): ExtractedProblem {\n let type = 'about:blank';\n let label: string | undefined;\n let detail: string | undefined;\n let errors: FieldError[] = [];\n\n if (typeof exceptionResponse === 'string') {\n detail = exceptionResponse;\n return { type, label, detail, errors };\n }\n\n if (exceptionResponse !== null && typeof exceptionResponse === 'object') {\n const responseObj = exceptionResponse as ExceptionResponseObject;\n\n // 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 ?? problemFallbackDetail;\n errors = problemResponse.errors ?? [];\n }\n // class-validator DTO validation errors\n else if ('message' in responseObj && Array.isArray(responseObj.message)) {\n errors = extractValidationFieldErrors(responseObj.message);\n detail = 'Validation failed';\n }\n // Standard NestJS exceptions\n else if ('message' in responseObj) {\n const message = (responseObj as StandardExceptionResponse).message;\n detail = Array.isArray(message) ? message.join(', ') : message;\n }\n }\n\n return { type, label, detail, errors };\n}\n","import { type ErrorCode, errorCodeFromStatus } from './error-code';\nimport { extractProblemFromResponse, getHttpStatusTitle } from './problem-extraction';\n\n// ---------------------------------------------------------------------------\n// Optional-peer typing\n// ---------------------------------------------------------------------------\n// `graphql` and `@nestjs/graphql` are optional peers — they are NOT installed in this package's\n// own node_modules. A real `import type { GraphQLFormattedError } from 'graphql'` would therefore\n// fail `tsc` (\"cannot find module\"). So, mirroring src/context/extractors/graphql.extractor.ts,\n// we declare the minimal structural shapes locally. They are erased at compile time and add no\n// runtime dependency; consumers (core-server) that DO have graphql installed pass the real objects.\n\n// Minimal shape of graphql's GraphQLFormattedError (what Apollo's formatError receives/returns).\ninterface GraphqlFormattedErrorShape {\n message: string;\n locations?: ReadonlyArray<{ line: number; column: number }>;\n path?: ReadonlyArray<string | number>;\n extensions?: Record<string, unknown>;\n}\n\n// Minimal shape of graphql's GraphQLError (the 2nd `formatError` arg). For a NestJS HttpException\n// thrown in a resolver, graphql wraps it and exposes the original under `originalError`.\ninterface GraphqlErrorShape {\n message: string;\n originalError?: unknown;\n extensions?: Record<string, unknown>;\n}\n\n// Structural shape of a NestJS HttpException — duck-typed (getStatus/getResponse), so we avoid\n// importing @nestjs/common's HttpException across pnpm package boundaries (same approach the\n// HttpExceptionFilter uses for its instanceof-free check).\ninterface HttpExceptionLike {\n getStatus(): number;\n getResponse(): string | object;\n message: string;\n}\n\n// ---------------------------------------------------------------------------\n// Public options + emitted-extensions contract\n// ---------------------------------------------------------------------------\n\nexport interface GraphqlFormatErrorOptions {\n // When true (production), strip stacktrace + internal originalError and genericize INTERNAL\n // messages so server internals never leak to clients.\n isProduction: boolean;\n // Ambient accessor for the current request's correlation/trace id. formatError has no request\n // argument, so the id must come from an out-of-band source (e.g. AsyncLocalStorage).\n getTraceId?: () => string | undefined;\n}\n\n// The shape of the `extensions` object this formatter guarantees on every formatted error.\nexport interface FormattedErrorExtensions {\n code: ErrorCode;\n traceId?: string;\n timestamp: string;\n // Field-specific validation errors, mirroring the RFC 9457 errors[] the HTTP filter emits.\n fieldErrors?: Array<{ field: string; message: string }>;\n // Passthrough for any other extension keys (e.g. stacktrace in dev).\n [key: string]: unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n// Duck-types a NestJS HttpException without importing @nestjs/common (cross-package-instance safe).\nfunction isHttpExceptionLike(error: unknown): error is HttpExceptionLike {\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// A plain RFC 9457 problem object (no HttpException methods). This is what a downstream microservice\n// rejection leaks when forwarded over a transport like NATS: the resolver throws the raw problem body,\n// and graphql-js wraps that non-Error throw as a `NonErrorThrown` whose original is stashed under\n// `.thrownValue`. We detect it by a numeric `status`/`statusCode` so it maps exactly like an HttpException\n// (otherwise it falls through to the default 500 → INTERNAL, hiding a legitimate 4xx + its message).\ninterface ProblemLike {\n status?: number;\n statusCode?: number;\n detail?: string;\n message?: string;\n}\n\nfunction isProblemLike(error: unknown): error is ProblemLike {\n if (error == null || typeof error !== 'object') {\n return false;\n }\n const o = error as Record<string, unknown>;\n return typeof o.status === 'number' || typeof o.statusCode === 'number';\n}\n\n// Normalized problem source: a status plus a body `extractProblemFromResponse` understands.\ninterface ProblemSource {\n status: number;\n response: string | object;\n fallback: string;\n}\n\n// Walks the error chain to find the underlying problem — either a NestJS HttpException or a plain RFC 9457\n// object leaked across a transport. graphql wraps the thrown error under `originalError`, and a non-Error\n// throw additionally under `originalError.thrownValue`, so the walk follows both links.\nfunction findProblemSource(error: GraphqlErrorShape | undefined): ProblemSource | undefined {\n let current: unknown = error;\n // Bounded walk — guard against cyclic chains.\n for (let depth = 0; current && depth < 10; depth++) {\n if (isHttpExceptionLike(current)) {\n const status = current.getStatus();\n return { status, response: current.getResponse(), fallback: current.message ?? getHttpStatusTitle(status) };\n }\n if (isProblemLike(current)) {\n const status = current.status ?? current.statusCode ?? 500;\n return { status, response: current, fallback: current.detail ?? current.message ?? getHttpStatusTitle(status) };\n }\n const next = current as { originalError?: unknown; thrownValue?: unknown };\n current = next.originalError ?? next.thrownValue;\n }\n return undefined;\n}\n\nconst GENERIC_INTERNAL_MESSAGE = 'Internal server error';\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n// Builds an Apollo `formatError(formattedError, error)` that normalizes every GraphQL error into a\n// stable, transport-consistent shape:\n// - extensions.code canonical ErrorCode (derived from HTTP status; NOT Apollo's default)\n// - extensions.traceId correlation id from opts.getTraceId() (omitted if unavailable)\n// - extensions.timestamp ISO timestamp of formatting\n// - extensions.fieldErrors validation field errors mirroring the RFC 9457 errors[] (when present)\n// - message human-readable; genericized for INTERNAL in production\n// In production it also strips stacktrace and the internal originalError so nothing leaks.\nexport function createGraphqlFormatError(\n opts: GraphqlFormatErrorOptions,\n): (formattedError: GraphqlFormattedErrorShape, error: unknown) => GraphqlFormattedErrorShape {\n const { isProduction, getTraceId } = opts;\n\n return (formattedError, error) => {\n const gqlError = (error ?? undefined) as GraphqlErrorShape | undefined;\n const source = findProblemSource(gqlError);\n\n // Derive status + problem body from the underlying problem source — a NestJS HttpException OR a plain\n // RFC 9457 object leaked across a transport (e.g. a NATS microservice rejection). Apollo only copies\n // the .message into the formatted error and defaults extensions.code to INTERNAL_SERVER_ERROR — it\n // never reads the body — so we read the real status/detail ourselves here.\n let status = 500;\n let detail: string | undefined;\n let label: string | undefined;\n let fieldErrors: Array<{ field: string; message: string }> = [];\n\n if (source) {\n status = source.status;\n const extracted = extractProblemFromResponse(source.response, source.fallback);\n detail = extracted.detail;\n label = extracted.label;\n fieldErrors = extracted.errors;\n }\n\n const code = errorCodeFromStatus(status);\n\n // Human-readable message: prefer the problem detail, then the formatted message. For INTERNAL\n // in production, never surface server internals.\n let message = detail ?? formattedError.message;\n if (code === 'INTERNAL' && isProduction) {\n message = GENERIC_INTERNAL_MESSAGE;\n }\n\n // Start from Apollo's extensions so any framework-set keys survive, then normalize ours on top.\n const incoming: Record<string, unknown> = { ...(formattedError.extensions ?? {}) };\n\n const traceId = getTraceId?.();\n const timestamp = new Date().toISOString();\n\n const extensions: FormattedErrorExtensions = {\n ...incoming,\n // Always our canonical code — overrides Apollo's default INTERNAL_SERVER_ERROR.\n code,\n ...(traceId !== undefined ? { traceId } : {}),\n timestamp,\n ...(label !== undefined ? { label } : {}),\n ...(fieldErrors.length > 0 ? { fieldErrors } : {}),\n };\n\n if (isProduction) {\n // Strip anything that could leak server internals to clients.\n delete extensions.stacktrace;\n delete extensions.exception;\n delete extensions.originalError;\n }\n\n const result: GraphqlFormattedErrorShape = {\n message,\n extensions,\n };\n // Preserve location/path metadata GraphQL attaches (useful to clients, leaks nothing).\n if (formattedError.locations) result.locations = formattedError.locations;\n if (formattedError.path) result.path = formattedError.path;\n\n return result;\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';\nimport { extractProblemFromResponse, getHttpStatusTitle } from './problem-extraction';\n\nexport { getHttpStatusTitle };\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 // Reuse the shared extractor so HTTP and GraphQL surface identical problem details.\n const extracted = extractProblemFromResponse(exceptionResponse, exception.message ?? getHttpStatusTitle(status));\n type = extracted.type;\n label = extracted.label;\n // An object body that matched no known shape leaves detail undefined; keep the\n // initial 'Internal server error' to preserve byte-identical HTTP output.\n detail = extracted.detail ?? detail;\n errors = extracted.errors;\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\nexport type PgErrorShape = {\n code?: string;\n message?: string;\n constraint?: string;\n table?: string;\n schema?: string;\n column?: string;\n detail?: string;\n hint?: 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.\nexport function 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 ExceptionFilter } from '@nestjs/common';\nimport { HttpExceptionFilter } from './http-exception.filter';\n\n// Transport-aware global exception filter. HTTP errors get the SDK's RFC 9457 formatting;\n// non-HTTP transports (GraphQL today, others later) re-throw so their own driver formats the\n// error — the HTTP filter writes to a Fastify reply that those transports lack. Shared so any\n// app adding GraphQL (or another transport) reuses it instead of re-deriving the routing.\n@Catch()\nexport class TransportAwareExceptionFilter implements ExceptionFilter {\n private readonly httpFilter = new HttpExceptionFilter();\n\n catch(exception: unknown, host: ArgumentsHost): void {\n if (host.getType() !== 'http') {\n throw exception;\n }\n this.httpFilter.catch(exception, host);\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 { findPgError } from '../../filters/pg-error.translator';\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 // Drizzle wraps pg errors in DrizzleQueryError whose `.message` is only the failed query —\n // the real reason (e.g. \"permission denied for table\") lives on `.cause`. Unwrap it.\n const pgCause = findPgError(error);\n let errorMessage = err.message || err.detail || 'Unknown error';\n if (pgCause?.message && pgCause.message !== err.message) {\n errorMessage = `${errorMessage} — cause: ${pgCause.message}${pgCause.code ? ` [${pgCause.code}]` : ''}`;\n }\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 // Attach the structured pg cause so log sinks capture SQLSTATE, constraint, table, etc.\n if (pgCause) {\n metadata.pgError = pgCause;\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 { 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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","names":["ForbiddenException","UnauthorizedException","AUTH_CONFIG","Symbol","AUTH_CONFIG_DEFAULTS","cookie","refreshCookieName","refreshCookieMaxAge","refreshCookiePath","refreshCookieSecure","process","env","NODE_ENV","refreshCookieSameSite","refreshCookieDomain","guard","authHeaderName","tokenPrefix","csrfExemptSessionTypes","csrfExemptTransports","refreshTokenBindingExemptSessionTypes","TokenType","import_common","import_core","import_jwt","import_common","resolveInjectedRequest","injected","candidate","headers","undefined","req","RequestService","injectedRequest","config","request","resolveInjectedRequest","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","import_common","import_core","graphqlExtractor","getRequest","host","getArgByIndex","req","getResponse","reply","httpExtractor","getRequest","host","switchToHttp","getResponse","registry","Map","httpExtractor","graphqlExtractor","registerTransport","type","extractor","set","resolveExtractor","get","getRequestFromContext","host","resolveExtractor","getType","getRequest","getResponseFromContext","host","resolveExtractor","getType","getResponse","import_common","REQUIRE_SESSION_KEY","RequireSession","types","SetMetadata","import_common","SKIP_CSRF_KEY","SkipCsrf","SetMetadata","import_common","parseExpiryToMs","expiry","match","Error","digits","unit","value","Number","parseInt","multipliers","s","m","h","d","w","y","multiplier","undefined","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","getRequestFromContext","reply","getResponseFromContext","route","method","url","authConfig","csrfExemptTransports","guard","skipCsrf","getAllAndOverride","SKIP_CSRF_KEY","getHandler","getClass","includes","getType","isPublic","validateCsrf","debug","requiredSessionTypes","REQUIRE_SESSION_KEY","isSseEndpoint","get","SSE_METADATA","handleSseAuth","sessionType","handleHttpAuth","csrfExemptSessionTypes","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","import_common","AccessToken","createParamDecorator","_data","ctx","request","getRequestFromContext","authHeader","headers","authorization","replace","import_common","ClientIp","createParamDecorator","_data","ctx","getRequestFromContext","ip","import_common","CookieDomain","createParamDecorator","_data","ctx","request","getRequestFromContext","forwarded","headers","raw","Array","isArray","hostStr","hostname","domain","split","baseDomain","authConfig","cookie","refreshCookieDomain","AUTH_CONFIG_DEFAULTS","endsWith","import_common","CookieName","createParamDecorator","_data","ctx","request","getRequestFromContext","authConfig","cookie","refreshCookieName","AUTH_CONFIG_DEFAULTS","import_common","Hostname","createParamDecorator","_data","ctx","request","getRequestFromContext","forwarded","headers","raw","Array","isArray","hostStr","hostname","split","import_common","Public","SetMetadata","import_common","import_common","import_common","HttpProblemException","HttpException","detailOrOptions","httpStatus","options","detail","type","label","errors","BadGatewayException","HttpProblemException","detailOrOptions","HttpStatus","BAD_GATEWAY","import_common","BadRequestException","HttpProblemException","detailOrOptions","HttpStatus","BAD_REQUEST","import_common","ConflictException","HttpProblemException","detailOrOptions","HttpStatus","CONFLICT","import_common","ForbiddenException","HttpProblemException","detailOrOptions","HttpStatus","FORBIDDEN","import_common","GoneException","HttpProblemException","detailOrOptions","HttpStatus","GONE","import_common","InternalServerErrorException","HttpProblemException","detailOrOptions","HttpStatus","INTERNAL_SERVER_ERROR","import_common","MethodNotAllowedException","HttpProblemException","detailOrOptions","HttpStatus","METHOD_NOT_ALLOWED","import_common","NotAcceptableException","HttpProblemException","detailOrOptions","HttpStatus","NOT_ACCEPTABLE","import_common","NotFoundException","HttpProblemException","detailOrOptions","HttpStatus","NOT_FOUND","import_common","NotImplementedException","HttpProblemException","detailOrOptions","HttpStatus","NOT_IMPLEMENTED","import_common","PayloadTooLargeException","HttpProblemException","detailOrOptions","HttpStatus","PAYLOAD_TOO_LARGE","import_common","RequestTimeoutException","HttpProblemException","detailOrOptions","HttpStatus","REQUEST_TIMEOUT","import_common","ServiceUnavailableException","HttpProblemException","detailOrOptions","HttpStatus","SERVICE_UNAVAILABLE","import_common","TooManyRequestsException","HttpProblemException","detailOrOptions","HttpStatus","TOO_MANY_REQUESTS","import_common","UnauthorizedException","HttpProblemException","detailOrOptions","HttpStatus","UNAUTHORIZED","import_common","UnprocessableEntityException","HttpProblemException","detailOrOptions","HttpStatus","UNPROCESSABLE_ENTITY","import_common","UnsupportedMediaTypeException","HttpProblemException","detailOrOptions","HttpStatus","UNSUPPORTED_MEDIA_TYPE","import_common","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","getRequestFromContext","forwarded","headers","raw","Array","isArray","hostStr","split","authConfig","cookie","AUTH_CONFIG_DEFAULTS","import_common","RefreshTokenCookie","createParamDecorator","_data","ctx","request","getRequestFromContext","cookies","cookieName","authConfig","cookie","refreshCookieName","AUTH_CONFIG_DEFAULTS","import_common","SessionData","createParamDecorator","_data","ctx","request","getRequestFromContext","sessionInfo","sessionId","Error","userId","sessionType","import_common","Subdomain","createParamDecorator","_data","ctx","request","getRequestFromContext","origin","headers","url","URL","hostname","split","forwarded","host","Array","isArray","undefined","import_common","UserAgent","createParamDecorator","_data","ctx","userAgent","getRequestFromContext","headers","Array","isArray","import_common","UserId","createParamDecorator","_data","ctx","request","getRequestFromContext","sessionInfo","userId","Error","import_common","import_config","import_common","import_config","import_common","CACHE_PROVIDER","Symbol","CacheService","logger","Logger","name","provider","set","key","value","ttlSeconds","err","error","get","del","keys","join","scanKeys","pattern","getMemoryInfo","import_common","import_config","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","DATA_TABLE_VIEWS_TABLE","Symbol","import_common","import_swagger","import_common","import_swagger","UpsertDataTableStateDto","tableSlug","state","activeViewId","description","example","ApiUpsertDataTableState","applyDecorators","ApiOperation","summary","description","ApiBody","type","UpsertDataTableStateDto","ApiResponse","status","import_common","import_config","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","import_common","import_swagger","import_common","import_swagger","import_swagger","DataTableViewDto","id","name","tableSlug","state","isShared","isOwn","createdAt","updatedAt","from","view","userId","dto","description","nullable","example","import_swagger","import_class_validator","CreateDataTableViewDto","name","tableSlug","state","isShared","description","example","import_swagger","import_class_validator","RenameDataTableViewDto","name","description","example","import_swagger","import_class_validator","ToggleShareDataTableViewDto","isShared","description","example","import_swagger","import_class_validator","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","import_common","import_config","import_common","import_drizzle_orm","import_common","snakeToCamel","str","replace","_","letter","toUpperCase","PrimaryBaseRepository","logger","sequence","tableName","isView","db","database","drizzleClient","model","Error","name","query","queryKeys","Object","keys","debug","join","error","table","options","is","PgViewBase","dbTableName","getViewName","getTableName","Logger","nextSequenceValue","resolvedSequence","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","findKeyset","hasMore","slice","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","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","import_common","DATABASE_MODULE_OPTIONS","Symbol","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","import_common","import_core","DatabaseModule","forServer","options","asyncProvider","provide","DATABASE_MODULE_OPTIONS","useFactory","inject","module","providers","Reflector","useClass","PrimaryDatabaseService","exports","import_swagger","CreateResponseDto","success","message","data","example","import_swagger","CursorListResponseDto","items","nextCursor","hasMore","nullable","import_swagger","ValidatedRowDto","index","data","valid","errors","example","code","name","ImportSummaryDto","total","invalid","ImportResponseDto","success","message","created","updated","skipped","rows","summary","type","import_swagger","import_class_validator","SelectOptionsQueryDto","search","limit","offset","values","excludeIds","valueKey","labelKey","descriptionKey","additionalKeys","groupIdKey","orderByKey","orderDirection","description","example","default","Number","enum","import_swagger","import_class_validator","SuccessResponseDto","success","message","example","import_swagger","TableResponseDto","result","count","state","activeViewId","nullable","CursorCodec","encode","values","serialized","map","v","Date","__t","toISOString","undefined","String","json","JSON","stringify","Buffer","from","toString","decode","cursor","parsed","parse","import_drizzle_orm","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","import_drizzle_orm","KeysetProcessor","buildAfter","orderBy","values","groups","i","length","current","conditions","j","prior","push","eq","column","cmp","direction","gt","lt","group","and","first","or","import_class_validator","UTC_ISO_DATETIME_REGEX","IsDateTime","validationOptions","target","propertyName","registerDecorator","name","String","options","validator","validate","value","test","Number","isNaN","Date","parse","defaultMessage","args","property","import_common","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","import_common","ErrorCode","errorCodeFromStatus","status","HttpStatus","UNAUTHORIZED","FORBIDDEN","NOT_FOUND","BAD_REQUEST","UNPROCESSABLE_ENTITY","CONFLICT","TOO_MANY_REQUESTS","import_common","getHttpStatusTitle","status","enumKey","Object","entries","HttpStatus","find","key","value","Number","isNaN","split","map","word","charAt","toUpperCase","slice","toLowerCase","join","extractValidationFieldErrors","message","msg","constraintValues","values","constraints","field","property","filter","error","extractProblemFromResponse","exceptionResponse","problemFallbackDetail","type","label","detail","errors","responseObj","problemResponse","Array","isArray","isHttpExceptionLike","error","Error","getStatus","getResponse","isProblemLike","o","status","statusCode","findProblemSource","current","depth","response","fallback","message","getHttpStatusTitle","detail","next","originalError","thrownValue","undefined","GENERIC_INTERNAL_MESSAGE","createGraphqlFormatError","opts","isProduction","getTraceId","formattedError","gqlError","source","label","fieldErrors","extracted","extractProblemFromResponse","errors","code","errorCodeFromStatus","incoming","extensions","traceId","timestamp","Date","toISOString","length","stacktrace","exception","result","locations","path","import_common","PG_UNIQUE_VIOLATION","tryTranslatePgError","error","pgError","findPgError","undefined","code","constraint","table","detail","ConflictException","label","trim","errors","meta","depth","candidate","cause","HttpExceptionFilter","logger","Logger","name","catch","exception","host","ctx","switchToHttp","response","getResponse","request","getRequest","translatedPgError","tryTranslatePgError","status","HttpStatus","INTERNAL_SERVER_ERROR","type","label","detail","errors","isHttpException","getStatus","exceptionResponse","extracted","extractProblemFromResponse","message","getHttpStatusTitle","isProblemLikeObject","problemObj","statusCandidate","statusCode","undefined","Array","isArray","isAxiosError","axiosStatus","axiosDetail","data","url","config","BAD_GATEWAY","error","stack","problemDetails","title","instance","header","send","Error","obj","import_common","TransportAwareExceptionFilter","httpFilter","HttpExceptionFilter","catch","exception","host","getType","import_common","import_common","import_node_async_hooks","import_node_crypto","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","pgCause","findPgError","errorMessage","detail","code","errorName","name","pgError","trace","errorDetails","loggingError","import_common","import_common","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","import_common","import_common","import_swagger","import_common","import_swagger","ApiHealthCheck","applyDecorators","ApiOperation","summary","ApiResponse","status","description","type","String","import_common","AppService","getHello","AppController","appService","getHello","import_common","import_swagger","import_common","import_swagger","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"]}