@vritti/api-sdk 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,17 @@
1
1
  var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
2
5
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
6
+ var __copyProps = (to, from, except, desc2) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc2 = __getOwnPropDesc(from, key)) || desc2.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
3
15
 
4
16
  // src/auth/auth-config.module.ts
5
17
  import { Global as Global2, Module as Module2 } from "@nestjs/common";
@@ -251,7 +263,10 @@ var defaultConfig = {
251
263
  guard: {
252
264
  tenantHeaderName: "x-tenant-id",
253
265
  authHeaderName: "authorization",
254
- tokenPrefix: "Bearer"
266
+ tokenPrefix: "Bearer",
267
+ defaultSessionTypes: [
268
+ "CLOUD"
269
+ ]
255
270
  }
256
271
  };
257
272
  var currentConfig = {
@@ -439,10 +454,10 @@ import { ConfigService } from "@nestjs/config";
439
454
  import { Reflector } from "@nestjs/core";
440
455
  import { JwtService } from "@nestjs/jwt";
441
456
 
442
- // src/auth/decorators/reset.decorator.ts
457
+ // src/auth/decorators/require-session.decorator.ts
443
458
  import { SetMetadata } from "@nestjs/common";
444
- var RESET_KEY = "isReset";
445
- var Reset = /* @__PURE__ */ __name(() => SetMetadata(RESET_KEY, true), "Reset");
459
+ var REQUIRE_SESSION_KEY = "requiredSessionTypes";
460
+ var RequireSession = /* @__PURE__ */ __name((...types) => SetMetadata(REQUIRE_SESSION_KEY, types), "RequireSession");
446
461
 
447
462
  // src/auth/decorators/skip-csrf.decorator.ts
448
463
  import { SetMetadata as SetMetadata2 } from "@nestjs/common";
@@ -506,17 +521,13 @@ var VrittiAuthGuard = class _VrittiAuthGuard {
506
521
  if (isPublic) {
507
522
  return true;
508
523
  }
509
- const isOnboarding = this.reflector.getAllAndOverride("isOnboarding", [
510
- context.getHandler(),
511
- context.getClass()
512
- ]);
513
- const isReset = this.reflector.getAllAndOverride(RESET_KEY, [
524
+ const requiredSessionTypes = this.reflector.getAllAndOverride(REQUIRE_SESSION_KEY, [
514
525
  context.getHandler(),
515
526
  context.getClass()
516
527
  ]);
517
528
  const isSseEndpoint = this.reflector.get(SSE_METADATA, context.getHandler());
518
529
  if (isSseEndpoint) {
519
- return this.handleSseAuth(request, isOnboarding);
530
+ return this.handleSseAuth(request, requiredSessionTypes);
520
531
  }
521
532
  try {
522
533
  const accessToken = this.requestService.getAccessToken();
@@ -528,14 +539,10 @@ var VrittiAuthGuard = class _VrittiAuthGuard {
528
539
  throw new UnauthorizedException2("Invalid token type");
529
540
  }
530
541
  this.validateRefreshTokenBinding(decodedAccessToken);
531
- if (isOnboarding && decodedAccessToken.sessionType !== "ONBOARDING") {
532
- throw new UnauthorizedException2("This endpoint requires an onboarding session");
533
- }
534
- if (isReset && decodedAccessToken.sessionType !== "RESET") {
535
- throw new UnauthorizedException2("This endpoint requires a reset session");
536
- }
537
- if (!isOnboarding && !isReset && (decodedAccessToken.sessionType === "ONBOARDING" || decodedAccessToken.sessionType === "RESET")) {
538
- throw new UnauthorizedException2(`${decodedAccessToken.sessionType} sessions cannot access this endpoint`);
542
+ const sessionType = decodedAccessToken.sessionType;
543
+ const allowed = requiredSessionTypes ?? getConfig().guard.defaultSessionTypes;
544
+ if (!allowed.includes(sessionType)) {
545
+ throw new UnauthorizedException2(`${sessionType} sessions cannot access this endpoint`);
539
546
  }
540
547
  request.sessionInfo = {
541
548
  userId: decodedAccessToken.userId,
@@ -584,7 +591,7 @@ var VrittiAuthGuard = class _VrittiAuthGuard {
584
591
  }
585
592
  }
586
593
  // Authenticates SSE connections using the refresh token httpOnly cookie
587
- handleSseAuth(request, isOnboarding) {
594
+ handleSseAuth(request, requiredSessionTypes) {
588
595
  const refreshToken = this.requestService.getRefreshToken();
589
596
  if (!refreshToken) {
590
597
  throw new UnauthorizedException2("Authentication required");
@@ -598,8 +605,9 @@ var VrittiAuthGuard = class _VrittiAuthGuard {
598
605
  if (decoded.tokenType !== "refresh") {
599
606
  throw new UnauthorizedException2("Invalid token type");
600
607
  }
601
- if (isOnboarding && decoded.sessionType !== "ONBOARDING") {
602
- throw new UnauthorizedException2("This endpoint requires an onboarding session");
608
+ const allowed = requiredSessionTypes ?? getConfig().guard.defaultSessionTypes;
609
+ if (!allowed.includes(decoded.sessionType)) {
610
+ throw new UnauthorizedException2(`${decoded.sessionType} sessions cannot access this endpoint`);
603
611
  }
604
612
  request.sessionInfo = {
605
613
  userId: decoded.userId,
@@ -861,13 +869,9 @@ var CookieDomain = createParamDecorator2((_data, ctx) => {
861
869
  return domain.endsWith(`.${baseDomain}`) ? domain : baseDomain;
862
870
  });
863
871
 
864
- // src/auth/decorators/onboarding.decorator.ts
865
- import { SetMetadata as SetMetadata3 } from "@nestjs/common";
866
- var Onboarding = /* @__PURE__ */ __name(() => SetMetadata3("isOnboarding", true), "Onboarding");
867
-
868
872
  // src/auth/decorators/public.decorator.ts
869
- import { SetMetadata as SetMetadata4 } from "@nestjs/common";
870
- var Public = /* @__PURE__ */ __name(() => SetMetadata4("isPublic", true), "Public");
873
+ import { SetMetadata as SetMetadata3 } from "@nestjs/common";
874
+ var Public = /* @__PURE__ */ __name(() => SetMetadata3("isPublic", true), "Public");
871
875
 
872
876
  // src/auth/decorators/refresh-cookie-options.decorator.ts
873
877
  import { createParamDecorator as createParamDecorator3 } from "@nestjs/common";
@@ -889,9 +893,27 @@ var RefreshTokenCookie = createParamDecorator4((_data, ctx) => {
889
893
  return cookies[config.cookie.refreshCookieName];
890
894
  });
891
895
 
892
- // src/auth/decorators/session-data.decorator.ts
896
+ // src/auth/decorators/subdomain.decorator.ts
893
897
  import { createParamDecorator as createParamDecorator5 } from "@nestjs/common";
894
- var SessionData = createParamDecorator5((_data, ctx) => {
898
+ var Subdomain = createParamDecorator5((_data, ctx) => {
899
+ const request = ctx.switchToHttp().getRequest();
900
+ const origin = request.headers.origin;
901
+ if (origin) {
902
+ try {
903
+ const url = new URL(origin);
904
+ return url.hostname.split(".")[0];
905
+ } catch {
906
+ }
907
+ }
908
+ const forwarded = request.headers["x-forwarded-host"];
909
+ const host = Array.isArray(forwarded) ? forwarded[0] : forwarded;
910
+ if (host) return host.split(".")[0];
911
+ return void 0;
912
+ });
913
+
914
+ // src/auth/decorators/session-data.decorator.ts
915
+ import { createParamDecorator as createParamDecorator6 } from "@nestjs/common";
916
+ var SessionData = createParamDecorator6((_data, ctx) => {
895
917
  const request = ctx.switchToHttp().getRequest();
896
918
  const sessionInfo = request.sessionInfo;
897
919
  if (!sessionInfo?.sessionId) {
@@ -905,8 +927,8 @@ var SessionData = createParamDecorator5((_data, ctx) => {
905
927
  });
906
928
 
907
929
  // src/auth/decorators/user-id.decorator.ts
908
- import { createParamDecorator as createParamDecorator6 } from "@nestjs/common";
909
- var UserId = createParamDecorator6((_data, ctx) => {
930
+ import { createParamDecorator as createParamDecorator7 } from "@nestjs/common";
931
+ var UserId = createParamDecorator7((_data, ctx) => {
910
932
  const request = ctx.switchToHttp().getRequest();
911
933
  const sessionInfo = request.sessionInfo;
912
934
  if (!sessionInfo?.userId) {
@@ -1129,7 +1151,6 @@ var DATABASE_MODULE_OPTIONS = Symbol("DATABASE_MODULE_OPTIONS");
1129
1151
 
1130
1152
  // src/database/services/primary-database.service.ts
1131
1153
  import { Inject as Inject3, Injectable as Injectable6, InternalServerErrorException as InternalServerErrorException2, Logger as Logger6 } from "@nestjs/common";
1132
- import { eq, or } from "drizzle-orm";
1133
1154
  import { drizzle } from "drizzle-orm/node-postgres";
1134
1155
  import { Pool } from "pg";
1135
1156
  function _ts_decorate9(decorators, target, key, desc2) {
@@ -1157,11 +1178,8 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
1157
1178
  logger = new Logger6(_PrimaryDatabaseService.name);
1158
1179
  pool = null;
1159
1180
  db = null;
1160
- tenantConfigCache = /* @__PURE__ */ new Map();
1161
- cacheTTL;
1162
1181
  constructor(options) {
1163
1182
  this.options = options;
1164
- this.cacheTTL = options.connectionCacheTTL || 3e5;
1165
1183
  }
1166
1184
  async onModuleInit() {
1167
1185
  if (this.options.primaryDb) {
@@ -1171,10 +1189,20 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
1171
1189
  // Initializes connection to primary database using Drizzle
1172
1190
  async initializeDrizzleClient() {
1173
1191
  try {
1174
- const databaseUrl = this.buildPrimaryDbUrl();
1192
+ const { host, port = 5432, username, password, database, schema, sslMode = "require" } = this.options.primaryDb;
1175
1193
  this.pool = new Pool({
1176
- connectionString: databaseUrl,
1177
- max: this.options.maxConnections || 10
1194
+ host,
1195
+ port,
1196
+ user: username,
1197
+ password,
1198
+ database,
1199
+ max: this.options.maxConnections || 10,
1200
+ ssl: sslMode === "disable" ? false : {
1201
+ rejectUnauthorized: sslMode !== "no-verify"
1202
+ },
1203
+ ...schema && {
1204
+ options: `-csearch_path=${schema}`
1205
+ }
1178
1206
  });
1179
1207
  this.logger.debug(`Schema keys passed to drizzle: [${Object.keys(this.options.drizzleSchema || {}).join(", ")}]`);
1180
1208
  this.logger.debug(`Relations keys passed to drizzle: [${Object.keys(this.options.drizzleRelations || {}).join(", ")}]`);
@@ -1185,110 +1213,13 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
1185
1213
  });
1186
1214
  this.logger.debug(`Drizzle query keys after init: [${Object.keys(this.db.query || {}).join(", ")}]`);
1187
1215
  await this.pool.query("SELECT 1");
1188
- this.logger.log("Connected to primary database (tenant registry)");
1216
+ this.logger.log(`Connected to primary database (schema: ${schema ?? "public"})`);
1189
1217
  } catch (error) {
1190
1218
  this.logger.error("Failed to connect to primary database", error);
1191
- throw new InternalServerErrorException2("Failed to initialize tenant registry");
1192
- }
1193
- }
1194
- // Builds the PostgreSQL connection URL from primary database config properties
1195
- buildPrimaryDbUrl() {
1196
- if (!this.options.primaryDb) {
1197
- throw new Error("Primary database configuration not provided");
1198
- }
1199
- const { host, port = 5432, username, password, database, schema = "public", sslMode = "require" } = this.options.primaryDb;
1200
- let url = `postgresql://${username}:${encodeURIComponent(password)}@${host}:${port}/${database}`;
1201
- const params = new URLSearchParams();
1202
- if (schema) {
1203
- params.set("schema", schema);
1204
- }
1205
- params.set("sslmode", sslMode);
1206
- const queryString = params.toString();
1207
- if (queryString) {
1208
- url += `?${queryString}`;
1209
- }
1210
- this.logger.debug(`Primary DB connection URL: ${this.maskPassword(url)}`);
1211
- return url;
1212
- }
1213
- // Masks password in connection URL for safe logging
1214
- maskPassword(url) {
1215
- return url.replace(/:([^@]+)@/, ":****@");
1216
- }
1217
- // Retrieves tenant configuration by ID or subdomain, with in-memory caching
1218
- async getTenantInfo(tenantIdentifier) {
1219
- const cached = this.tenantConfigCache.get(tenantIdentifier);
1220
- if (cached) {
1221
- this.logger.debug(`Cache hit for tenant: ${tenantIdentifier}`);
1222
- return cached;
1223
- }
1224
- try {
1225
- if (!this.db) {
1226
- throw new Error("Primary database client not initialized");
1227
- }
1228
- this.logger.debug(`Querying primary database for tenant: ${tenantIdentifier}`);
1229
- const schema = this.options.drizzleSchema;
1230
- const { tenants, tenantDatabaseConfigs } = schema;
1231
- const result = await this.db.select().from(tenants).leftJoin(tenantDatabaseConfigs, eq(tenants.id, tenantDatabaseConfigs.tenantId)).where(or(eq(tenants.id, tenantIdentifier), eq(tenants.subdomain, tenantIdentifier))).limit(1);
1232
- if (!result.length) {
1233
- this.logger.warn(`Tenant not found: ${tenantIdentifier}`);
1234
- return null;
1235
- }
1236
- const row = result[0];
1237
- const tenant = row.tenants;
1238
- const config = row.tenant_database_configs;
1239
- if (tenant.status !== "ACTIVE") {
1240
- this.logger.warn(`Tenant not active: ${tenantIdentifier}`);
1241
- return null;
1242
- }
1243
- const info = {
1244
- id: tenant.id,
1245
- subdomain: tenant.subdomain,
1246
- type: tenant.dbType,
1247
- status: tenant.status,
1248
- // For SHARED tenants: schema name
1249
- schemaName: config?.dbSchema || void 0,
1250
- // For DEDICATED tenants: database configuration from TenantDatabaseConfig table
1251
- databaseName: config?.dbName || void 0,
1252
- databaseHost: config?.dbHost || void 0,
1253
- databasePort: config?.dbPort || void 0,
1254
- databaseUsername: config?.dbUsername ? this.decrypt(config.dbUsername) : void 0,
1255
- databasePassword: config?.dbPassword ? this.decrypt(config.dbPassword) : void 0,
1256
- databaseSslMode: config?.dbSslMode || void 0,
1257
- connectionPoolSize: config?.connectionPoolSize || void 0
1258
- };
1259
- this.cacheInfo(info);
1260
- return info;
1261
- } catch (error) {
1262
- this.logger.error(`Failed to fetch tenant info: ${tenantIdentifier}`, error);
1263
- throw new InternalServerErrorException2("Failed to resolve tenant");
1264
- }
1265
- }
1266
- // Caches tenant info by both ID and subdomain with TTL expiration
1267
- cacheInfo(info) {
1268
- this.tenantConfigCache.set(info.id, info);
1269
- this.tenantConfigCache.set(info.subdomain, info);
1270
- setTimeout(() => {
1271
- this.tenantConfigCache.delete(info.id);
1272
- this.tenantConfigCache.delete(info.subdomain);
1273
- this.logger.debug(`Cache expired for tenant: ${info.subdomain}`);
1274
- }, this.cacheTTL);
1275
- }
1276
- // Clears cached tenant info for the given ID or subdomain
1277
- clearTenantCache(tenantIdentifier) {
1278
- const config = this.tenantConfigCache.get(tenantIdentifier);
1279
- if (config) {
1280
- this.tenantConfigCache.delete(config.id);
1281
- this.tenantConfigCache.delete(config.subdomain);
1282
- this.logger.log(`Cleared cache for tenant: ${tenantIdentifier}`);
1219
+ throw new InternalServerErrorException2("Failed to initialize database connection");
1283
1220
  }
1284
1221
  }
1285
- // Clears all cached tenant configurations
1286
- clearAllCaches() {
1287
- const size = this.tenantConfigCache.size;
1288
- this.tenantConfigCache.clear();
1289
- this.logger.log(`Cleared ${size} cached tenant configs`);
1290
- }
1291
- // Returns the initialized Drizzle client, throwing if not yet initialized
1222
+ // Returns the initialized Drizzle client
1292
1223
  get drizzleClient() {
1293
1224
  if (!this.db) {
1294
1225
  throw new Error("Primary database client not initialized");
@@ -1299,10 +1230,6 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
1299
1230
  get schema() {
1300
1231
  return this.options.drizzleSchema;
1301
1232
  }
1302
- // Decrypts a database credential value (placeholder for actual decryption)
1303
- decrypt(encrypted) {
1304
- return encrypted;
1305
- }
1306
1233
  async onModuleDestroy() {
1307
1234
  if (this.pool) {
1308
1235
  await this.pool.end();
@@ -1319,8 +1246,7 @@ PrimaryDatabaseService = _ts_decorate9([
1319
1246
  ])
1320
1247
  ], PrimaryDatabaseService);
1321
1248
 
1322
- // src/database/services/tenant-context.service.ts
1323
- import { Injectable as Injectable7, Scope as Scope3, UnauthorizedException as UnauthorizedException3 } from "@nestjs/common";
1249
+ // src/database/database.module.ts
1324
1250
  function _ts_decorate10(decorators, target, key, desc2) {
1325
1251
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
1326
1252
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
@@ -1328,52 +1254,63 @@ function _ts_decorate10(decorators, target, key, desc2) {
1328
1254
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1329
1255
  }
1330
1256
  __name(_ts_decorate10, "_ts_decorate");
1331
- var TenantContextService = class {
1257
+ var DatabaseModule = class _DatabaseModule {
1332
1258
  static {
1333
- __name(this, "TenantContextService");
1334
- }
1335
- tenantInfo = null;
1336
- // Sets tenant info for this request, throwing if already set to prevent overwrites
1337
- setTenant(tenantInfo) {
1338
- if (this.tenantInfo) {
1339
- throw new Error("Tenant context already set for this request");
1340
- }
1341
- this.tenantInfo = tenantInfo;
1342
- }
1343
- // Returns the tenant info for this request, throwing if context is not set
1344
- getTenant() {
1345
- if (!this.tenantInfo) {
1346
- throw new UnauthorizedException3("Tenant context not set");
1347
- }
1348
- return this.tenantInfo;
1349
- }
1350
- // Returns true if tenant context has been set for this request
1351
- hasTenant() {
1352
- return this.tenantInfo !== null;
1353
- }
1354
- // Clears the tenant context (useful for RabbitMQ message handler cleanup)
1355
- clearTenant() {
1356
- this.tenantInfo = null;
1357
- }
1358
- // Returns the tenant ID or null if context is not set
1359
- getTenantIdSafe() {
1360
- return this.tenantInfo?.id ?? null;
1259
+ __name(this, "DatabaseModule");
1361
1260
  }
1362
- // Returns the tenant subdomain or null if context is not set
1363
- getTenantSubdomainSafe() {
1364
- return this.tenantInfo?.subdomain ?? null;
1261
+ // Configures the database module with a single primary connection
1262
+ static forServer(options) {
1263
+ const asyncProvider = {
1264
+ provide: DATABASE_MODULE_OPTIONS,
1265
+ useFactory: options.useFactory,
1266
+ inject: options.inject || []
1267
+ };
1268
+ return {
1269
+ module: _DatabaseModule,
1270
+ imports: [
1271
+ RequestModule
1272
+ ],
1273
+ providers: [
1274
+ {
1275
+ provide: Reflector3,
1276
+ useClass: Reflector3
1277
+ },
1278
+ asyncProvider,
1279
+ PrimaryDatabaseService
1280
+ ],
1281
+ exports: [
1282
+ PrimaryDatabaseService,
1283
+ asyncProvider
1284
+ ]
1285
+ };
1365
1286
  }
1366
1287
  };
1367
- TenantContextService = _ts_decorate10([
1368
- Injectable7({
1369
- scope: Scope3.REQUEST
1370
- })
1371
- ], TenantContextService);
1288
+ DatabaseModule = _ts_decorate10([
1289
+ Global3(),
1290
+ Module4({})
1291
+ ], DatabaseModule);
1292
+
1293
+ // src/decorators/uploaded-file.decorator.ts
1294
+ import { createParamDecorator as createParamDecorator8 } from "@nestjs/common";
1295
+ var UploadedFile = createParamDecorator8(async (_data, ctx) => {
1296
+ const request = ctx.switchToHttp().getRequest();
1297
+ const file = await request.file();
1298
+ if (!file) {
1299
+ throw new BadRequestException({
1300
+ label: "File Required",
1301
+ detail: "Please attach a file to your request."
1302
+ });
1303
+ }
1304
+ const buffer = await file.toBuffer();
1305
+ return {
1306
+ buffer,
1307
+ filename: file.filename,
1308
+ mimetype: file.mimetype
1309
+ };
1310
+ });
1372
1311
 
1373
- // src/database/services/tenant-database.service.ts
1374
- import { Inject as Inject4, Injectable as Injectable8, InternalServerErrorException as InternalServerErrorException3, Logger as Logger7 } from "@nestjs/common";
1375
- import { drizzle as drizzle2 } from "drizzle-orm/node-postgres";
1376
- import { Pool as Pool2 } from "pg";
1312
+ // src/database/dto/create-response.dto.ts
1313
+ import { ApiProperty } from "@nestjs/swagger";
1377
1314
  function _ts_decorate11(decorators, target, key, desc2) {
1378
1315
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
1379
1316
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
@@ -1385,161 +1322,33 @@ function _ts_metadata7(k, v) {
1385
1322
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1386
1323
  }
1387
1324
  __name(_ts_metadata7, "_ts_metadata");
1388
- function _ts_param4(paramIndex, decorator) {
1389
- return function(target, key) {
1390
- decorator(target, key, paramIndex);
1391
- };
1392
- }
1393
- __name(_ts_param4, "_ts_param");
1394
- var TenantDatabaseService = class _TenantDatabaseService {
1325
+ var CreateResponseDto = class {
1395
1326
  static {
1396
- __name(this, "TenantDatabaseService");
1397
- }
1398
- options;
1399
- tenantContext;
1400
- logger = new Logger7(_TenantDatabaseService.name);
1401
- clients = /* @__PURE__ */ new Map();
1402
- clientLastUsed = /* @__PURE__ */ new Map();
1403
- cleanupInterval;
1404
- constructor(options, tenantContext) {
1405
- this.options = options;
1406
- this.tenantContext = tenantContext;
1407
- this.startConnectionCleaner();
1408
- }
1409
- // Returns the Drizzle client scoped to the current tenant's database
1410
- get drizzleClient() {
1411
- return this.getDbClient();
1412
- }
1413
- // Returns the Drizzle schema passed in module options
1414
- get schema() {
1415
- return this.options.drizzleSchema;
1416
- }
1417
- // Returns a cached or new Drizzle client for the current tenant context
1418
- getDbClient() {
1419
- const tenant = this.tenantContext.getTenant();
1420
- const cacheKey = this.buildCacheKey(tenant);
1421
- const existing = this.clients.get(cacheKey);
1422
- if (existing) {
1423
- this.clientLastUsed.set(cacheKey, Date.now());
1424
- this.logger.debug(`Reusing cached connection: ${cacheKey}`);
1425
- return existing.db;
1426
- }
1427
- this.logger.log(`Creating new database connection: ${cacheKey}`);
1428
- const connection = this.createDbClientSync(tenant);
1429
- this.clients.set(cacheKey, connection);
1430
- this.clientLastUsed.set(cacheKey, Date.now());
1431
- return connection.db;
1432
- }
1433
- // Creates a new pool and Drizzle client for the given tenant
1434
- createDbClientSync(tenant) {
1435
- try {
1436
- const databaseUrl = this.buildTenantDbUrl(tenant);
1437
- const pool = new Pool2({
1438
- connectionString: databaseUrl,
1439
- max: tenant.connectionPoolSize || this.options.maxConnections || 10
1440
- });
1441
- const db = drizzle2({
1442
- client: pool,
1443
- schema: this.options.drizzleSchema
1444
- });
1445
- this.logger.log(`Connected to database for tenant: ${tenant.subdomain}`);
1446
- return {
1447
- pool,
1448
- db
1449
- };
1450
- } catch (error) {
1451
- this.logger.error(`Failed to create database connection for tenant: ${tenant.subdomain}`, error);
1452
- throw new InternalServerErrorException3("Failed to connect to tenant database");
1453
- }
1454
- }
1455
- // Builds the PostgreSQL connection URL for a dedicated tenant database
1456
- buildTenantDbUrl(tenant) {
1457
- const { databaseHost, databasePort, databaseName, databaseUsername, databasePassword, databaseSslMode } = tenant;
1458
- if (!databaseHost || !databaseName || !databaseUsername) {
1459
- throw new Error(`Tenant ${tenant.subdomain} missing database configuration`);
1460
- }
1461
- const port = databasePort || 5432;
1462
- const sslMode = databaseSslMode || "require";
1463
- const connectionUrl = `postgresql://${databaseUsername}:${encodeURIComponent(databasePassword || "")}@${databaseHost}:${port}/${databaseName}?sslmode=${sslMode}`;
1464
- this.logger.debug(`Tenant connection URL: ${this.maskPassword(connectionUrl)}`);
1465
- return connectionUrl;
1466
- }
1467
- // Builds a cache key for connection pooling from tenant database coordinates
1468
- buildCacheKey(tenant) {
1469
- return `${tenant.type}:${tenant.databaseName}@${tenant.databaseHost}`;
1470
- }
1471
- // Starts a periodic interval to close idle database connections
1472
- startConnectionCleaner() {
1473
- const interval = this.options.connectionCacheTTL || 3e5;
1474
- this.cleanupInterval = setInterval(() => {
1475
- this.cleanupIdleConnections();
1476
- }, interval);
1477
- this.logger.log(`Connection cleanup scheduled every ${interval / 1e3} seconds`);
1478
- }
1479
- // Closes and removes connections that have been idle beyond the TTL
1480
- async cleanupIdleConnections() {
1481
- const now = Date.now();
1482
- const maxIdle = this.options.connectionCacheTTL || 3e5;
1483
- let cleaned = 0;
1484
- for (const [key, lastUsed] of this.clientLastUsed.entries()) {
1485
- if (now - lastUsed > maxIdle) {
1486
- const connection = this.clients.get(key);
1487
- if (connection) {
1488
- try {
1489
- await connection.pool.end();
1490
- this.logger.debug(`Cleaned up idle connection: ${key}`);
1491
- } catch (error) {
1492
- this.logger.error(`Error disconnecting idle client: ${key}`, error);
1493
- }
1494
- this.clients.delete(key);
1495
- this.clientLastUsed.delete(key);
1496
- cleaned++;
1497
- }
1498
- }
1499
- }
1500
- if (cleaned > 0) {
1501
- this.logger.log(`Cleaned up ${cleaned} idle connections`);
1502
- }
1503
- }
1504
- // Returns the current number of active pooled connections and their tenant keys
1505
- getPoolStats() {
1506
- return {
1507
- activeConnections: this.clients.size,
1508
- tenants: Array.from(this.clients.keys())
1509
- };
1510
- }
1511
- // Masks password in connection URL for safe logging
1512
- maskPassword(url) {
1513
- return url.replace(/:([^@]+)@/, ":****@");
1514
- }
1515
- async onModuleDestroy() {
1516
- if (this.cleanupInterval) {
1517
- clearInterval(this.cleanupInterval);
1518
- }
1519
- this.logger.log(`Disconnecting ${this.clients.size} database connections`);
1520
- const disconnectPromises = Array.from(this.clients.entries()).map(async ([key, connection]) => {
1521
- try {
1522
- await connection.pool.end();
1523
- this.logger.debug(`Disconnected: ${key}`);
1524
- } catch (error) {
1525
- this.logger.error(`Error disconnecting client: ${key}`, error);
1526
- }
1527
- });
1528
- await Promise.all(disconnectPromises);
1529
- this.logger.log("All database connections closed");
1327
+ __name(this, "CreateResponseDto");
1530
1328
  }
1329
+ success;
1330
+ message;
1331
+ data;
1531
1332
  };
1532
- TenantDatabaseService = _ts_decorate11([
1533
- Injectable8(),
1534
- _ts_param4(0, Inject4(DATABASE_MODULE_OPTIONS)),
1535
- _ts_metadata7("design:type", Function),
1536
- _ts_metadata7("design:paramtypes", [
1537
- typeof DatabaseModuleOptions === "undefined" ? Object : DatabaseModuleOptions,
1538
- typeof TenantContextService === "undefined" ? Object : TenantContextService
1539
- ])
1540
- ], TenantDatabaseService);
1333
+ _ts_decorate11([
1334
+ ApiProperty({
1335
+ example: true
1336
+ }),
1337
+ _ts_metadata7("design:type", Boolean)
1338
+ ], CreateResponseDto.prototype, "success", void 0);
1339
+ _ts_decorate11([
1340
+ ApiProperty({
1341
+ example: "Resource created successfully"
1342
+ }),
1343
+ _ts_metadata7("design:type", String)
1344
+ ], CreateResponseDto.prototype, "message", void 0);
1345
+ _ts_decorate11([
1346
+ ApiProperty(),
1347
+ _ts_metadata7("design:type", typeof T === "undefined" ? Object : T)
1348
+ ], CreateResponseDto.prototype, "data", void 0);
1541
1349
 
1542
- // src/database/database.module.ts
1350
+ // src/database/dto/import-response.dto.ts
1351
+ import { ApiProperty as ApiProperty2, ApiPropertyOptional } from "@nestjs/swagger";
1543
1352
  function _ts_decorate12(decorators, target, key, desc2) {
1544
1353
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
1545
1354
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
@@ -1547,69 +1356,133 @@ function _ts_decorate12(decorators, target, key, desc2) {
1547
1356
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1548
1357
  }
1549
1358
  __name(_ts_decorate12, "_ts_decorate");
1550
- var DatabaseModule = class _DatabaseModule {
1359
+ function _ts_metadata8(k, v) {
1360
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1361
+ }
1362
+ __name(_ts_metadata8, "_ts_metadata");
1363
+ var ValidatedRowDto = class {
1551
1364
  static {
1552
- __name(this, "DatabaseModule");
1553
- }
1554
- // Configures the module for gateway/HTTP mode with TenantContextInterceptor
1555
- static forServer(options) {
1556
- return _DatabaseModule.createDynamicModule(options, "server");
1365
+ __name(this, "ValidatedRowDto");
1557
1366
  }
1558
- // Configures the module for microservice mode with MessageTenantContextInterceptor
1559
- static forMicroservice(options) {
1560
- return _DatabaseModule.createDynamicModule(options, "microservice");
1561
- }
1562
- // Creates the dynamic module configuration with the appropriate interceptor for the given mode
1563
- static createDynamicModule(options, mode) {
1564
- const asyncProvider = {
1565
- provide: DATABASE_MODULE_OPTIONS,
1566
- useFactory: options.useFactory,
1567
- inject: options.inject || []
1568
- };
1569
- const providers = [
1570
- // Required for external packages - NestJS global Reflector not available
1571
- {
1572
- provide: Reflector3,
1573
- useClass: Reflector3
1574
- },
1575
- asyncProvider,
1576
- TenantContextService,
1577
- PrimaryDatabaseService,
1578
- TenantDatabaseService
1579
- ];
1580
- return {
1581
- module: _DatabaseModule,
1582
- imports: [
1583
- RequestModule
1584
- ],
1585
- providers,
1586
- exports: [
1587
- TenantDatabaseService,
1588
- TenantContextService,
1589
- PrimaryDatabaseService,
1590
- asyncProvider
1591
- ]
1592
- };
1367
+ index;
1368
+ data;
1369
+ valid;
1370
+ errors;
1371
+ };
1372
+ _ts_decorate12([
1373
+ ApiProperty2({
1374
+ example: 1
1375
+ }),
1376
+ _ts_metadata8("design:type", Number)
1377
+ ], ValidatedRowDto.prototype, "index", void 0);
1378
+ _ts_decorate12([
1379
+ ApiProperty2({
1380
+ example: {
1381
+ code: "products",
1382
+ name: "Products"
1383
+ }
1384
+ }),
1385
+ _ts_metadata8("design:type", typeof Record === "undefined" ? Object : Record)
1386
+ ], ValidatedRowDto.prototype, "data", void 0);
1387
+ _ts_decorate12([
1388
+ ApiProperty2({
1389
+ example: true
1390
+ }),
1391
+ _ts_metadata8("design:type", Boolean)
1392
+ ], ValidatedRowDto.prototype, "valid", void 0);
1393
+ _ts_decorate12([
1394
+ ApiProperty2({
1395
+ example: [
1396
+ "Code already exists"
1397
+ ]
1398
+ }),
1399
+ _ts_metadata8("design:type", Array)
1400
+ ], ValidatedRowDto.prototype, "errors", void 0);
1401
+ var ImportSummaryDto = class {
1402
+ static {
1403
+ __name(this, "ImportSummaryDto");
1593
1404
  }
1405
+ total;
1406
+ valid;
1407
+ invalid;
1594
1408
  };
1595
- DatabaseModule = _ts_decorate12([
1596
- Global3(),
1597
- Module4({})
1598
- ], DatabaseModule);
1599
-
1600
- // src/database/decorators/tenant.decorator.ts
1601
- import { createParamDecorator as createParamDecorator7 } from "@nestjs/common";
1602
- var Tenant = createParamDecorator7((_data, ctx) => {
1603
- const request = ctx.switchToHttp().getRequest();
1604
- const tenantContext = request.app?.get?.(TenantContextService);
1605
- if (!tenantContext) {
1606
- throw new Error("TenantContextService not found.");
1409
+ _ts_decorate12([
1410
+ ApiProperty2({
1411
+ example: 10
1412
+ }),
1413
+ _ts_metadata8("design:type", Number)
1414
+ ], ImportSummaryDto.prototype, "total", void 0);
1415
+ _ts_decorate12([
1416
+ ApiProperty2({
1417
+ example: 8
1418
+ }),
1419
+ _ts_metadata8("design:type", Number)
1420
+ ], ImportSummaryDto.prototype, "valid", void 0);
1421
+ _ts_decorate12([
1422
+ ApiProperty2({
1423
+ example: 2
1424
+ }),
1425
+ _ts_metadata8("design:type", Number)
1426
+ ], ImportSummaryDto.prototype, "invalid", void 0);
1427
+ var ImportResponseDto = class {
1428
+ static {
1429
+ __name(this, "ImportResponseDto");
1607
1430
  }
1608
- return tenantContext.getTenant();
1609
- });
1431
+ success;
1432
+ message;
1433
+ created;
1434
+ updated;
1435
+ skipped;
1436
+ rows;
1437
+ summary;
1438
+ };
1439
+ _ts_decorate12([
1440
+ ApiProperty2({
1441
+ example: true
1442
+ }),
1443
+ _ts_metadata8("design:type", Boolean)
1444
+ ], ImportResponseDto.prototype, "success", void 0);
1445
+ _ts_decorate12([
1446
+ ApiProperty2({
1447
+ example: "Import complete."
1448
+ }),
1449
+ _ts_metadata8("design:type", String)
1450
+ ], ImportResponseDto.prototype, "message", void 0);
1451
+ _ts_decorate12([
1452
+ ApiPropertyOptional({
1453
+ example: 3
1454
+ }),
1455
+ _ts_metadata8("design:type", Number)
1456
+ ], ImportResponseDto.prototype, "created", void 0);
1457
+ _ts_decorate12([
1458
+ ApiPropertyOptional({
1459
+ example: 2
1460
+ }),
1461
+ _ts_metadata8("design:type", Number)
1462
+ ], ImportResponseDto.prototype, "updated", void 0);
1463
+ _ts_decorate12([
1464
+ ApiPropertyOptional({
1465
+ example: 1
1466
+ }),
1467
+ _ts_metadata8("design:type", Number)
1468
+ ], ImportResponseDto.prototype, "skipped", void 0);
1469
+ _ts_decorate12([
1470
+ ApiPropertyOptional({
1471
+ type: [
1472
+ ValidatedRowDto
1473
+ ]
1474
+ }),
1475
+ _ts_metadata8("design:type", Array)
1476
+ ], ImportResponseDto.prototype, "rows", void 0);
1477
+ _ts_decorate12([
1478
+ ApiPropertyOptional({
1479
+ type: ImportSummaryDto
1480
+ }),
1481
+ _ts_metadata8("design:type", typeof ImportSummaryDto === "undefined" ? Object : ImportSummaryDto)
1482
+ ], ImportResponseDto.prototype, "summary", void 0);
1610
1483
 
1611
1484
  // src/database/dto/select-options-query.dto.ts
1612
- import { ApiPropertyOptional } from "@nestjs/swagger";
1485
+ import { ApiPropertyOptional as ApiPropertyOptional2 } from "@nestjs/swagger";
1613
1486
  import { Type } from "class-transformer";
1614
1487
  import { IsInt, IsOptional, IsString, Min } from "class-validator";
1615
1488
  function _ts_decorate13(decorators, target, key, desc2) {
@@ -1619,10 +1492,10 @@ function _ts_decorate13(decorators, target, key, desc2) {
1619
1492
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1620
1493
  }
1621
1494
  __name(_ts_decorate13, "_ts_decorate");
1622
- function _ts_metadata8(k, v) {
1495
+ function _ts_metadata9(k, v) {
1623
1496
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1624
1497
  }
1625
- __name(_ts_metadata8, "_ts_metadata");
1498
+ __name(_ts_metadata9, "_ts_metadata");
1626
1499
  var SelectOptionsQueryDto = class {
1627
1500
  static {
1628
1501
  __name(this, "SelectOptionsQueryDto");
@@ -1638,16 +1511,16 @@ var SelectOptionsQueryDto = class {
1638
1511
  groupIdKey;
1639
1512
  };
1640
1513
  _ts_decorate13([
1641
- ApiPropertyOptional({
1514
+ ApiPropertyOptional2({
1642
1515
  description: "Search term to filter by label",
1643
1516
  example: "united"
1644
1517
  }),
1645
1518
  IsOptional(),
1646
1519
  IsString(),
1647
- _ts_metadata8("design:type", String)
1520
+ _ts_metadata9("design:type", String)
1648
1521
  ], SelectOptionsQueryDto.prototype, "search", void 0);
1649
1522
  _ts_decorate13([
1650
- ApiPropertyOptional({
1523
+ ApiPropertyOptional2({
1651
1524
  description: "Maximum number of results",
1652
1525
  example: 20,
1653
1526
  default: 20
@@ -1656,10 +1529,10 @@ _ts_decorate13([
1656
1529
  Type(() => Number),
1657
1530
  IsInt(),
1658
1531
  Min(1),
1659
- _ts_metadata8("design:type", Number)
1532
+ _ts_metadata9("design:type", Number)
1660
1533
  ], SelectOptionsQueryDto.prototype, "limit", void 0);
1661
1534
  _ts_decorate13([
1662
- ApiPropertyOptional({
1535
+ ApiPropertyOptional2({
1663
1536
  description: "Number of results to skip",
1664
1537
  example: 0,
1665
1538
  default: 0
@@ -1668,67 +1541,67 @@ _ts_decorate13([
1668
1541
  Type(() => Number),
1669
1542
  IsInt(),
1670
1543
  Min(0),
1671
- _ts_metadata8("design:type", Number)
1544
+ _ts_metadata9("design:type", Number)
1672
1545
  ], SelectOptionsQueryDto.prototype, "offset", void 0);
1673
1546
  _ts_decorate13([
1674
- ApiPropertyOptional({
1547
+ ApiPropertyOptional2({
1675
1548
  description: "Comma-separated values to fetch specific options",
1676
1549
  example: "1,2,3"
1677
1550
  }),
1678
1551
  IsOptional(),
1679
1552
  IsString(),
1680
- _ts_metadata8("design:type", String)
1553
+ _ts_metadata9("design:type", String)
1681
1554
  ], SelectOptionsQueryDto.prototype, "values", void 0);
1682
1555
  _ts_decorate13([
1683
- ApiPropertyOptional({
1556
+ ApiPropertyOptional2({
1684
1557
  description: "Comma-separated IDs to exclude from results (already selected)",
1685
1558
  example: "5,10"
1686
1559
  }),
1687
1560
  IsOptional(),
1688
1561
  IsString(),
1689
- _ts_metadata8("design:type", String)
1562
+ _ts_metadata9("design:type", String)
1690
1563
  ], SelectOptionsQueryDto.prototype, "excludeIds", void 0);
1691
1564
  _ts_decorate13([
1692
- ApiPropertyOptional({
1565
+ ApiPropertyOptional2({
1693
1566
  description: "Column name for option value",
1694
1567
  example: "id",
1695
1568
  default: "id"
1696
1569
  }),
1697
1570
  IsOptional(),
1698
1571
  IsString(),
1699
- _ts_metadata8("design:type", String)
1572
+ _ts_metadata9("design:type", String)
1700
1573
  ], SelectOptionsQueryDto.prototype, "valueKey", void 0);
1701
1574
  _ts_decorate13([
1702
- ApiPropertyOptional({
1575
+ ApiPropertyOptional2({
1703
1576
  description: "Column name for option label",
1704
1577
  example: "name",
1705
1578
  default: "name"
1706
1579
  }),
1707
1580
  IsOptional(),
1708
1581
  IsString(),
1709
- _ts_metadata8("design:type", String)
1582
+ _ts_metadata9("design:type", String)
1710
1583
  ], SelectOptionsQueryDto.prototype, "labelKey", void 0);
1711
1584
  _ts_decorate13([
1712
- ApiPropertyOptional({
1585
+ ApiPropertyOptional2({
1713
1586
  description: "Column name for option description",
1714
1587
  example: "description"
1715
1588
  }),
1716
1589
  IsOptional(),
1717
1590
  IsString(),
1718
- _ts_metadata8("design:type", String)
1591
+ _ts_metadata9("design:type", String)
1719
1592
  ], SelectOptionsQueryDto.prototype, "descriptionKey", void 0);
1720
1593
  _ts_decorate13([
1721
- ApiPropertyOptional({
1594
+ ApiPropertyOptional2({
1722
1595
  description: "Column name for group ID",
1723
1596
  example: "regionId"
1724
1597
  }),
1725
1598
  IsOptional(),
1726
1599
  IsString(),
1727
- _ts_metadata8("design:type", String)
1600
+ _ts_metadata9("design:type", String)
1728
1601
  ], SelectOptionsQueryDto.prototype, "groupIdKey", void 0);
1729
1602
 
1730
1603
  // src/database/dto/success-response.dto.ts
1731
- import { ApiProperty } from "@nestjs/swagger";
1604
+ import { ApiProperty as ApiProperty3 } from "@nestjs/swagger";
1732
1605
  import { IsBoolean, IsNotEmpty, IsString as IsString2 } from "class-validator";
1733
1606
  function _ts_decorate14(decorators, target, key, desc2) {
1734
1607
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
@@ -1737,10 +1610,10 @@ function _ts_decorate14(decorators, target, key, desc2) {
1737
1610
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1738
1611
  }
1739
1612
  __name(_ts_decorate14, "_ts_decorate");
1740
- function _ts_metadata9(k, v) {
1613
+ function _ts_metadata10(k, v) {
1741
1614
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1742
1615
  }
1743
- __name(_ts_metadata9, "_ts_metadata");
1616
+ __name(_ts_metadata10, "_ts_metadata");
1744
1617
  var SuccessResponseDto = class {
1745
1618
  static {
1746
1619
  __name(this, "SuccessResponseDto");
@@ -1749,24 +1622,24 @@ var SuccessResponseDto = class {
1749
1622
  message;
1750
1623
  };
1751
1624
  _ts_decorate14([
1752
- ApiProperty({
1625
+ ApiProperty3({
1753
1626
  example: true
1754
1627
  }),
1755
1628
  IsNotEmpty(),
1756
1629
  IsBoolean(),
1757
- _ts_metadata9("design:type", Boolean)
1630
+ _ts_metadata10("design:type", Boolean)
1758
1631
  ], SuccessResponseDto.prototype, "success", void 0);
1759
1632
  _ts_decorate14([
1760
- ApiProperty({
1633
+ ApiProperty3({
1761
1634
  example: "Operation completed successfully"
1762
1635
  }),
1763
1636
  IsNotEmpty(),
1764
1637
  IsString2(),
1765
- _ts_metadata9("design:type", String)
1638
+ _ts_metadata10("design:type", String)
1766
1639
  ], SuccessResponseDto.prototype, "message", void 0);
1767
1640
 
1768
1641
  // src/database/dto/table-response.dto.ts
1769
- import { ApiProperty as ApiProperty2, ApiPropertyOptional as ApiPropertyOptional2 } from "@nestjs/swagger";
1642
+ import { ApiProperty as ApiProperty4, ApiPropertyOptional as ApiPropertyOptional3 } from "@nestjs/swagger";
1770
1643
  function _ts_decorate15(decorators, target, key, desc2) {
1771
1644
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
1772
1645
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
@@ -1774,10 +1647,10 @@ function _ts_decorate15(decorators, target, key, desc2) {
1774
1647
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1775
1648
  }
1776
1649
  __name(_ts_decorate15, "_ts_decorate");
1777
- function _ts_metadata10(k, v) {
1650
+ function _ts_metadata11(k, v) {
1778
1651
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1779
1652
  }
1780
- __name(_ts_metadata10, "_ts_metadata");
1653
+ __name(_ts_metadata11, "_ts_metadata");
1781
1654
  var TableResponseDto = class {
1782
1655
  static {
1783
1656
  __name(this, "TableResponseDto");
@@ -1788,26 +1661,26 @@ var TableResponseDto = class {
1788
1661
  activeViewId;
1789
1662
  };
1790
1663
  _ts_decorate15([
1791
- ApiProperty2(),
1792
- _ts_metadata10("design:type", Array)
1664
+ ApiProperty4(),
1665
+ _ts_metadata11("design:type", Array)
1793
1666
  ], TableResponseDto.prototype, "result", void 0);
1794
1667
  _ts_decorate15([
1795
- ApiProperty2(),
1796
- _ts_metadata10("design:type", Number)
1668
+ ApiProperty4(),
1669
+ _ts_metadata11("design:type", Number)
1797
1670
  ], TableResponseDto.prototype, "count", void 0);
1798
1671
  _ts_decorate15([
1799
- ApiProperty2(),
1800
- _ts_metadata10("design:type", typeof TableViewState === "undefined" ? Object : TableViewState)
1672
+ ApiProperty4(),
1673
+ _ts_metadata11("design:type", typeof TableViewState === "undefined" ? Object : TableViewState)
1801
1674
  ], TableResponseDto.prototype, "state", void 0);
1802
1675
  _ts_decorate15([
1803
- ApiPropertyOptional2({
1676
+ ApiPropertyOptional3({
1804
1677
  nullable: true
1805
1678
  }),
1806
- _ts_metadata10("design:type", Object)
1679
+ _ts_metadata11("design:type", Object)
1807
1680
  ], TableResponseDto.prototype, "activeViewId", void 0);
1808
1681
 
1809
1682
  // src/database/filter/filter.processor.ts
1810
- import { and, asc, desc, eq as eq2, gt, gte, ilike, lt, lte, ne, notIlike, or as or2 } from "drizzle-orm";
1683
+ import { and, asc, desc, eq, gt, gte, ilike, lt, lte, ne, notIlike, or } from "drizzle-orm";
1811
1684
  var FilterProcessor = class {
1812
1685
  static {
1813
1686
  __name(this, "FilterProcessor");
@@ -1825,10 +1698,10 @@ var FilterProcessor = class {
1825
1698
  switch (f.operator) {
1826
1699
  case "equals":
1827
1700
  if (def.type === "boolean") return [
1828
- eq2(col, val === "true" || val === 1)
1701
+ eq(col, val === "true" || val === 1)
1829
1702
  ];
1830
1703
  return [
1831
- eq2(col, val)
1704
+ eq(col, val)
1832
1705
  ];
1833
1706
  case "notEquals":
1834
1707
  if (def.type === "boolean") return [
@@ -1872,7 +1745,7 @@ var FilterProcessor = class {
1872
1745
  if (!search?.value) return void 0;
1873
1746
  if (search.columnId === "all") {
1874
1747
  const conditions = Object.values(fieldMap).filter((def2) => "column" in def2 && def2.type === "string").map((def2) => ilike(def2.column, `%${search.value}%`));
1875
- return conditions.length ? or2(...conditions) : void 0;
1748
+ return conditions.length ? or(...conditions) : void 0;
1876
1749
  }
1877
1750
  const def = fieldMap[search.columnId];
1878
1751
  if (!def || !("column" in def)) return void 0;
@@ -1891,8 +1764,8 @@ var FilterProcessor = class {
1891
1764
  };
1892
1765
 
1893
1766
  // src/database/repositories/primary-base.repository.ts
1894
- import { Logger as Logger8 } from "@nestjs/common";
1895
- import { and as and2, asc as asc2, eq as eq3, getTableName, ilike as ilike2, inArray, notInArray, sql } from "drizzle-orm";
1767
+ import { Logger as Logger7 } from "@nestjs/common";
1768
+ import { and as and2, asc as asc2, eq as eq2, getTableName, ilike as ilike2, inArray, notInArray, sql } from "drizzle-orm";
1896
1769
  function snakeToCamel(str) {
1897
1770
  return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
1898
1771
  }
@@ -1923,14 +1796,15 @@ var PrimaryBaseRepository = class {
1923
1796
  this.table = table;
1924
1797
  const dbTableName = getTableName(table);
1925
1798
  this.tableName = snakeToCamel(dbTableName);
1926
- this.logger = new Logger8(this.constructor.name);
1799
+ this.logger = new Logger7(this.constructor.name);
1927
1800
  this.logger.debug(`Initialized ${this.constructor.name}`);
1928
1801
  this.logger.debug(`Table name: '${dbTableName}' -> query key: '${this.tableName}'`);
1929
1802
  }
1930
1803
  // Creates a new record and returns it
1931
- async create(data) {
1804
+ async create(data, tx) {
1932
1805
  this.logger.log("Creating record");
1933
- const results = await this.db.insert(this.table).values(data).returning();
1806
+ const db = tx ?? this.db;
1807
+ const results = await db.insert(this.table).values(data).returning();
1934
1808
  const record = results[0];
1935
1809
  if (!record) throw new Error(`${this.tableName}: database operation returned no record`);
1936
1810
  return record;
@@ -1956,16 +1830,35 @@ var PrimaryBaseRepository = class {
1956
1830
  this.logger.debug("Finding multiple records");
1957
1831
  return this.model.findMany(options);
1958
1832
  }
1959
- // Builds a select query with optional custom fields, join, filter, ordering, and pagination
1833
+ // Builds a select query with optional custom fields, joins, filter, grouping, ordering, and pagination
1960
1834
  buildSelectQuery(options) {
1961
- const base = options?.select ? this.db.select(options.select).from(this.table) : this.db.select().from(this.table);
1962
- const joined = options?.leftJoin ? base.leftJoin(options.leftJoin.table, options.leftJoin.on) : base;
1963
- const filtered = options?.where ? joined.where(options.where) : joined;
1964
- const ordered = options?.orderBy?.length ? filtered.orderBy(...options.orderBy) : filtered;
1965
- const limited = options?.limit ? ordered.limit(options.limit) : ordered;
1966
- return options?.offset ? limited.offset(options.offset) : limited;
1967
- }
1968
- // Returns paginated result and total count, with optional custom select, LEFT JOIN, and ordering
1835
+ let query = (options?.select ? this.db.select(options.select).from(this.table) : this.db.select().from(this.table)).$dynamic();
1836
+ if (options?.leftJoin) {
1837
+ query = query.leftJoin(options.leftJoin.table, options.leftJoin.on);
1838
+ }
1839
+ if (options?.leftJoins) {
1840
+ for (const join of options.leftJoins) {
1841
+ query = query.leftJoin(join.table, join.on);
1842
+ }
1843
+ }
1844
+ if (options?.where) {
1845
+ query = query.where(options.where);
1846
+ }
1847
+ if (options?.groupBy?.length) {
1848
+ query = query.groupBy(...options.groupBy);
1849
+ }
1850
+ if (options?.orderBy?.length) {
1851
+ query = query.orderBy(...options.orderBy);
1852
+ }
1853
+ if (options?.limit) {
1854
+ query = query.limit(options.limit);
1855
+ }
1856
+ if (options?.offset) {
1857
+ query = query.offset(options.offset);
1858
+ }
1859
+ return query;
1860
+ }
1861
+ // Returns paginated result and total count, with optional custom select, LEFT JOINs, GROUP BY, and ordering
1969
1862
  async findAllAndCount(options) {
1970
1863
  const [count, result] = await Promise.all([
1971
1864
  this.count(options?.where),
@@ -1977,37 +1870,41 @@ var PrimaryBaseRepository = class {
1977
1870
  };
1978
1871
  }
1979
1872
  // Updates a record by ID and returns the updated record
1980
- async update(id, data) {
1873
+ async update(id, data, tx) {
1981
1874
  this.logger.log(`Updating record with ID: ${id}`);
1875
+ const db = tx ?? this.db;
1982
1876
  const idColumn = this.table.id;
1983
1877
  if (!idColumn) throw new Error(`Table '${this.tableName}' has no 'id' column`);
1984
- const results = await this.db.update(this.table).set(data).where(eq3(idColumn, id)).returning();
1878
+ const results = await db.update(this.table).set(data).where(eq2(idColumn, id)).returning();
1985
1879
  const record = results[0];
1986
1880
  if (!record) throw new Error(`${this.tableName}: database operation returned no record`);
1987
1881
  return record;
1988
1882
  }
1989
1883
  // Updates all records matching the SQL condition and returns the affected count
1990
- async updateMany(where, data) {
1884
+ async updateMany(where, data, tx) {
1991
1885
  this.logger.log("Updating multiple records");
1992
- const result = await this.db.update(this.table).set(data).where(where);
1886
+ const db = tx ?? this.db;
1887
+ const result = await db.update(this.table).set(data).where(where);
1993
1888
  return {
1994
1889
  count: result.rowCount ?? 0
1995
1890
  };
1996
1891
  }
1997
1892
  // Deletes a record by ID and returns the deleted record
1998
- async delete(id) {
1893
+ async delete(id, tx) {
1999
1894
  this.logger.log(`Deleting record with ID: ${id}`);
1895
+ const db = tx ?? this.db;
2000
1896
  const idColumn = this.table.id;
2001
1897
  if (!idColumn) throw new Error(`Table '${this.tableName}' has no 'id' column`);
2002
- const results = await this.db.delete(this.table).where(eq3(idColumn, id)).returning();
1898
+ const results = await db.delete(this.table).where(eq2(idColumn, id)).returning();
2003
1899
  const record = results[0];
2004
1900
  if (!record) throw new Error(`${this.tableName}: database operation returned no record`);
2005
1901
  return record;
2006
1902
  }
2007
1903
  // Deletes all records matching the SQL condition and returns the affected count
2008
- async deleteMany(where) {
1904
+ async deleteMany(where, tx) {
2009
1905
  this.logger.log("Deleting multiple records");
2010
- const result = await this.db.delete(this.table).where(where);
1906
+ const db = tx ?? this.db;
1907
+ const result = await db.delete(this.table).where(where);
2011
1908
  return {
2012
1909
  count: result.rowCount ?? 0
2013
1910
  };
@@ -2029,9 +1926,14 @@ var PrimaryBaseRepository = class {
2029
1926
  const count = await this.count(where);
2030
1927
  return count > 0;
2031
1928
  }
1929
+ // Executes the callback within a database transaction
1930
+ async transaction(callback) {
1931
+ return this.db.transaction(callback);
1932
+ }
2032
1933
  // Finds records formatted as select dropdown options with optional search, pagination, and grouping
2033
1934
  async findForSelect(config) {
2034
1935
  this.logger.debug("Finding records for select dropdown");
1936
+ const selectFn = config.distinct ? this.db.selectDistinct.bind(this.db) : this.db.select.bind(this.db);
2035
1937
  const parsedValues = typeof config.values === "string" ? config.values.split(",").map((v) => v.trim()).filter(Boolean) : config.values;
2036
1938
  const parsedExcludeIds = typeof config.excludeIds === "string" ? config.excludeIds.split(",").map((v) => v.trim()).filter(Boolean) : config.excludeIds ?? [];
2037
1939
  const tableColumns = this.table;
@@ -2059,7 +1961,7 @@ var PrimaryBaseRepository = class {
2059
1961
  const groupIdCol = tableColumns[config.groupId];
2060
1962
  if (groupIdCol) selectCols.groupId = groupIdCol;
2061
1963
  }
2062
- let valuesQuery = this.db.select(selectCols).from(this.table).$dynamic();
1964
+ let valuesQuery = selectFn(selectCols).from(this.table).$dynamic();
2063
1965
  if (config.joins) {
2064
1966
  for (const join of config.joins) {
2065
1967
  if (join.type === "inner") {
@@ -2108,7 +2010,7 @@ var PrimaryBaseRepository = class {
2108
2010
  for (const [field, val] of Object.entries(config.where)) {
2109
2011
  const column = tableColumns[field];
2110
2012
  if (column) {
2111
- conditions.push(eq3(column, val));
2013
+ conditions.push(eq2(column, val));
2112
2014
  }
2113
2015
  }
2114
2016
  }
@@ -2119,7 +2021,7 @@ var PrimaryBaseRepository = class {
2119
2021
  const orderByCol = orderByKey ? tableColumns[orderByKey] ?? labelCol : labelCol;
2120
2022
  const limit = Number(config.limit) || 20;
2121
2023
  const offset = Number(config.offset) || 0;
2122
- let query = this.db.select(selectFields).from(this.table).$dynamic();
2024
+ let query = selectFn(selectFields).from(this.table).$dynamic();
2123
2025
  if (config.joins) {
2124
2026
  for (const join of config.joins) {
2125
2027
  if (join.type === "inner") {
@@ -2180,241 +2082,13 @@ var PrimaryBaseRepository = class {
2180
2082
  }
2181
2083
  };
2182
2084
 
2183
- // src/database/repositories/tenant-base.repository.ts
2184
- import { Logger as Logger9 } from "@nestjs/common";
2185
- import { and as and3, asc as asc3, eq as eq4, getTableName as getTableName2, ilike as ilike3, inArray as inArray2, notInArray as notInArray2, sql as sql2 } from "drizzle-orm";
2186
- var TenantBaseRepository = class {
2187
- static {
2188
- __name(this, "TenantBaseRepository");
2189
- }
2190
- database;
2191
- table;
2192
- logger;
2193
- tableName;
2194
- get db() {
2195
- return this.database.drizzleClient;
2196
- }
2197
- get model() {
2198
- return this.database.drizzleClient.query[this.tableName];
2199
- }
2200
- constructor(database, table) {
2201
- this.database = database;
2202
- this.table = table;
2203
- this.tableName = getTableName2(table);
2204
- this.logger = new Logger9(this.constructor.name);
2205
- this.logger.debug(`Initialized ${this.constructor.name}`);
2206
- }
2207
- // Creates a new record and returns it
2208
- async create(data) {
2209
- this.logger.log("Creating record");
2210
- const results = await this.db.insert(this.table).values(data).returning();
2211
- const record = results[0];
2212
- if (!record) throw new Error(`${this.tableName}: database operation returned no record`);
2213
- return record;
2214
- }
2215
- // Finds a single record by primary key ID
2216
- async findById(id) {
2217
- this.logger.debug(`Finding record by ID: ${id}`);
2218
- const idColumn = this.table.id;
2219
- if (!idColumn) throw new Error(`Table '${this.tableName}' has no 'id' column`);
2220
- const results = await this.db.select().from(this.table).where(eq4(idColumn, id)).limit(1);
2221
- return results[0] ?? null;
2222
- }
2223
- // Finds a single record matching the given SQL condition
2224
- async findOne(where) {
2225
- this.logger.debug("Finding record with custom query");
2226
- const results = await this.db.select().from(this.table).where(where).limit(1);
2227
- return results[0] ?? null;
2228
- }
2229
- // Finds multiple records with optional SQL filtering, ordering, and pagination
2230
- async findMany(options) {
2231
- this.logger.debug("Finding multiple records");
2232
- let query = this.db.select().from(this.table).$dynamic();
2233
- if (options?.where) {
2234
- query = query.where(options.where);
2235
- }
2236
- if (options?.orderBy) {
2237
- query = query.orderBy(options.orderBy);
2238
- }
2239
- if (options?.limit) {
2240
- query = query.limit(options.limit);
2241
- }
2242
- if (options?.offset) {
2243
- query = query.offset(options.offset);
2244
- }
2245
- return await query;
2246
- }
2247
- // Updates a record by ID and returns the updated record
2248
- async update(id, data) {
2249
- this.logger.log(`Updating record with ID: ${id}`);
2250
- const idColumn = this.table.id;
2251
- if (!idColumn) throw new Error(`Table '${this.tableName}' has no 'id' column`);
2252
- const results = await this.db.update(this.table).set(data).where(eq4(idColumn, id)).returning();
2253
- const record = results[0];
2254
- if (!record) throw new Error(`${this.tableName}: database operation returned no record`);
2255
- return record;
2256
- }
2257
- // Updates all records matching the SQL condition and returns the affected count
2258
- async updateMany(where, data) {
2259
- this.logger.log("Updating multiple records");
2260
- const result = await this.db.update(this.table).set(data).where(where);
2261
- return {
2262
- count: result.rowCount ?? 0
2263
- };
2264
- }
2265
- // Deletes a record by ID and returns the deleted record
2266
- async delete(id) {
2267
- this.logger.log(`Deleting record with ID: ${id}`);
2268
- const idColumn = this.table.id;
2269
- if (!idColumn) throw new Error(`Table '${this.tableName}' has no 'id' column`);
2270
- const results = await this.db.delete(this.table).where(eq4(idColumn, id)).returning();
2271
- const record = results[0];
2272
- if (!record) throw new Error(`${this.tableName}: database operation returned no record`);
2273
- return record;
2274
- }
2275
- // Deletes all records matching the SQL condition and returns the affected count
2276
- async deleteMany(where) {
2277
- this.logger.log("Deleting multiple records");
2278
- const result = await this.db.delete(this.table).where(where);
2279
- return {
2280
- count: result.rowCount ?? 0
2281
- };
2282
- }
2283
- // Counts records matching the optional SQL condition
2284
- async count(where) {
2285
- this.logger.debug("Counting records");
2286
- let query = this.db.select({
2287
- count: sql2`count(*)::int`
2288
- }).from(this.table).$dynamic();
2289
- if (where) {
2290
- query = query.where(where);
2291
- }
2292
- const results = await query;
2293
- return results[0].count;
2294
- }
2295
- // Returns true if at least one record matches the SQL condition
2296
- async exists(where) {
2297
- const count = await this.count(where);
2298
- return count > 0;
2299
- }
2300
- // Finds records formatted as select dropdown options with optional search, pagination, and grouping
2301
- async findForSelect(config) {
2302
- this.logger.debug("Finding records for select dropdown");
2303
- const parsedValues = typeof config.values === "string" ? config.values.split(",").map((v) => v.trim()).filter(Boolean) : config.values;
2304
- const parsedExcludeIds = typeof config.excludeIds === "string" ? config.excludeIds.split(",").map((v) => v.trim()).filter(Boolean) : config.excludeIds ?? [];
2305
- const tableColumns = this.table;
2306
- const valueCol = tableColumns[config.value];
2307
- if (!valueCol) throw new Error(`Column '${config.value}' not found in table '${this.tableName}'`);
2308
- const labelCol = tableColumns[config.label];
2309
- if (!labelCol) throw new Error(`Column '${config.label}' not found in table '${this.tableName}'`);
2310
- if (parsedValues && parsedValues.length > 0) {
2311
- const selectCols = {
2312
- value: valueCol,
2313
- label: labelCol
2314
- };
2315
- if (config.groupId) {
2316
- const groupIdCol = tableColumns[config.groupId];
2317
- if (groupIdCol) selectCols.groupId = groupIdCol;
2318
- }
2319
- const rows2 = await this.db.select(selectCols).from(this.table).where(inArray2(valueCol, parsedValues));
2320
- return {
2321
- options: rows2.map((row) => ({
2322
- value: row.value,
2323
- label: String(row.label),
2324
- ...config.groupId && row.groupId != null ? {
2325
- groupId: row.groupId
2326
- } : {}
2327
- })),
2328
- hasMore: false,
2329
- ...config.groups ? {
2330
- groups: config.groups
2331
- } : {}
2332
- };
2333
- }
2334
- const selectFields = {
2335
- value: valueCol,
2336
- label: labelCol,
2337
- totalCount: sql2`count(*) over()`.mapWith(Number)
2338
- };
2339
- if (config.groupId) {
2340
- const groupIdCol = tableColumns[config.groupId];
2341
- if (groupIdCol) selectFields.groupId = groupIdCol;
2342
- }
2343
- const conditions = [];
2344
- if (config.search) {
2345
- conditions.push(ilike3(labelCol, `%${config.search}%`));
2346
- }
2347
- if (parsedExcludeIds.length > 0) {
2348
- conditions.push(notInArray2(valueCol, parsedExcludeIds));
2349
- }
2350
- if (config.where) {
2351
- for (const [field, val] of Object.entries(config.where)) {
2352
- const column = tableColumns[field];
2353
- if (column) {
2354
- conditions.push(eq4(column, val));
2355
- }
2356
- }
2357
- }
2358
- const orderByKey = config.orderBy ? Object.keys(config.orderBy)[0] : void 0;
2359
- const orderByCol = orderByKey ? tableColumns[orderByKey] ?? labelCol : labelCol;
2360
- const limit = Number(config.limit) || 20;
2361
- const offset = Number(config.offset) || 0;
2362
- let query = this.db.select(selectFields).from(this.table).$dynamic();
2363
- if (conditions.length > 0) {
2364
- query = query.where(conditions.length === 1 ? conditions[0] : and3(...conditions));
2365
- }
2366
- const orderClauses = [];
2367
- if (config.groupId) {
2368
- const groupIdCol = tableColumns[config.groupId];
2369
- if (groupIdCol) orderClauses.push(asc3(groupIdCol));
2370
- }
2371
- orderClauses.push(asc3(orderByCol));
2372
- query = query.orderBy(...orderClauses).limit(limit).offset(offset);
2373
- const rows = await query;
2374
- const totalCount = rows.length > 0 ? rows[0].totalCount : 0;
2375
- const options = rows.map((row) => ({
2376
- value: row.value,
2377
- label: String(row.label),
2378
- ...config.groupId && row.groupId != null ? {
2379
- groupId: row.groupId
2380
- } : {}
2381
- }));
2382
- let resolvedGroups = config.groups;
2383
- if (config.groupTable && config.groupId) {
2384
- const groupTableColumns = config.groupTable;
2385
- const groupIdKey = config.groupIdKey ?? "id";
2386
- const groupNameKey = config.groupLabelKey ?? "name";
2387
- const groupIdCol = groupTableColumns[groupIdKey];
2388
- if (!groupIdCol) throw new Error(`Column '${groupIdKey}' not found in group table`);
2389
- const groupNameCol = groupTableColumns[groupNameKey];
2390
- if (!groupNameCol) throw new Error(`Column '${groupNameKey}' not found in group table`);
2391
- const groupRows = await this.db.select({
2392
- id: groupIdCol,
2393
- name: groupNameCol
2394
- }).from(config.groupTable).orderBy(asc3(groupNameCol));
2395
- resolvedGroups = groupRows.map((r) => ({
2396
- id: r.id,
2397
- name: String(r.name)
2398
- }));
2399
- }
2400
- return {
2401
- options,
2402
- hasMore: offset + limit < totalCount,
2403
- totalCount,
2404
- ...resolvedGroups ? {
2405
- groups: resolvedGroups
2406
- } : {}
2407
- };
2408
- }
2409
- };
2410
-
2411
2085
  // src/email/email.module.ts
2412
2086
  import { Global as Global4, Module as Module5 } from "@nestjs/common";
2413
2087
  import { ConfigModule as ConfigModule3 } from "@nestjs/config";
2414
2088
 
2415
2089
  // src/email/email.service.ts
2416
2090
  import { BrevoClient, BrevoError, BrevoTimeoutError } from "@getbrevo/brevo";
2417
- import { Injectable as Injectable9, Logger as Logger10 } from "@nestjs/common";
2091
+ import { Injectable as Injectable7, Logger as Logger8 } from "@nestjs/common";
2418
2092
  import { ConfigService as ConfigService5 } from "@nestjs/config";
2419
2093
  function _ts_decorate16(decorators, target, key, desc2) {
2420
2094
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
@@ -2423,16 +2097,16 @@ function _ts_decorate16(decorators, target, key, desc2) {
2423
2097
  return c > 3 && r && Object.defineProperty(target, key, r), r;
2424
2098
  }
2425
2099
  __name(_ts_decorate16, "_ts_decorate");
2426
- function _ts_metadata11(k, v) {
2100
+ function _ts_metadata12(k, v) {
2427
2101
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2428
2102
  }
2429
- __name(_ts_metadata11, "_ts_metadata");
2103
+ __name(_ts_metadata12, "_ts_metadata");
2430
2104
  var EmailService = class _EmailService {
2431
2105
  static {
2432
2106
  __name(this, "EmailService");
2433
2107
  }
2434
2108
  configService;
2435
- logger = new Logger10(_EmailService.name);
2109
+ logger = new Logger8(_EmailService.name);
2436
2110
  brevoClient;
2437
2111
  senderEmail;
2438
2112
  senderName;
@@ -2865,44 +2539,133 @@ This is an automated message, please do not reply.
2865
2539
  });
2866
2540
  this.logger.log(`Email revert confirmation sent to ${email}`);
2867
2541
  }
2868
- // Verifies Brevo API connectivity a 400 response means the API is reachable
2869
- async verifyConnection() {
2870
- try {
2871
- await this.brevoClient.transactionalEmails.sendTransacEmail({
2872
- sender: {
2873
- email: this.senderEmail,
2874
- name: this.senderName
2875
- },
2876
- to: [
2877
- {
2878
- email: this.senderEmail
2879
- }
2880
- ],
2881
- subject: "Connection Test",
2882
- htmlContent: "<p>Test</p>"
2883
- });
2884
- return true;
2885
- } catch (err) {
2886
- if (err instanceof BrevoError && err.statusCode === 400) {
2887
- return true;
2888
- }
2889
- this.logger.error("Brevo connection verification failed:", err);
2890
- return false;
2891
- }
2892
- }
2893
- // Sends a transactional email via Brevo — retries handled internally by BrevoClient
2894
- async sendEmail(emailData) {
2895
- try {
2896
- const result = await this.brevoClient.transactionalEmails.sendTransacEmail({
2897
- sender: {
2898
- email: this.senderEmail,
2899
- name: this.senderName
2900
- },
2901
- to: emailData.to,
2902
- subject: emailData.subject,
2903
- htmlContent: emailData.htmlContent,
2904
- textContent: emailData.textContent
2905
- });
2542
+ // Sends an invite email to a new portal user with their set-password link
2543
+ async sendInviteEmail(params) {
2544
+ const { to, name, inviteUrl } = params;
2545
+ const subject = "You have been invited to Vritti AI";
2546
+ const htmlContent = `
2547
+ <!DOCTYPE html>
2548
+ <html>
2549
+ <head>
2550
+ <meta charset="UTF-8">
2551
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
2552
+ </head>
2553
+ <body style="margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background-color: #f5f5f5;">
2554
+ <table role="presentation" style="width: 100%; border-collapse: collapse;">
2555
+ <tr>
2556
+ <td style="padding: 40px 20px;">
2557
+ <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);">
2558
+ <!-- Header -->
2559
+ <tr>
2560
+ <td style="padding: 40px 40px 20px; text-align: center; border-bottom: 1px solid #e0e0e0;">
2561
+ <h1 style="margin: 0; color: #1a1a1a; font-size: 24px; font-weight: 600;">You're Invited</h1>
2562
+ </td>
2563
+ </tr>
2564
+
2565
+ <!-- Content -->
2566
+ <tr>
2567
+ <td style="padding: 40px;">
2568
+ <p style="margin: 0 0 20px; color: #333333; font-size: 16px; line-height: 1.6;">
2569
+ Hello <strong>${name}</strong>,
2570
+ </p>
2571
+ <p style="margin: 0 0 30px; color: #333333; font-size: 16px; line-height: 1.6;">
2572
+ You have been invited to join Vritti AI. Click the button below to set your password and get started.
2573
+ </p>
2574
+
2575
+ <div style="text-align: center; margin: 30px 0;">
2576
+ <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;">
2577
+ Set Your Password
2578
+ </a>
2579
+ </div>
2580
+
2581
+ <p style="margin: 30px 0 0; color: #666666; font-size: 14px; line-height: 1.6;">
2582
+ If you did not expect this invitation, you can safely ignore this email.
2583
+ </p>
2584
+ </td>
2585
+ </tr>
2586
+
2587
+ <!-- Footer -->
2588
+ <tr>
2589
+ <td style="padding: 30px 40px; border-top: 1px solid #e0e0e0; text-align: center;">
2590
+ <p style="margin: 0; color: #999999; font-size: 12px; line-height: 1.5;">
2591
+ Vritti AI Cloud - Cloud Management Platform
2592
+ </p>
2593
+ <p style="margin: 8px 0 0; color: #999999; font-size: 12px; line-height: 1.5;">
2594
+ This is an automated message, please do not reply.
2595
+ </p>
2596
+ </td>
2597
+ </tr>
2598
+ </table>
2599
+ </td>
2600
+ </tr>
2601
+ </table>
2602
+ </body>
2603
+ </html>
2604
+ `;
2605
+ const textContent = `
2606
+ Hello ${name},
2607
+
2608
+ You have been invited to join Vritti AI. Visit the link below to set your password and get started:
2609
+
2610
+ ${inviteUrl}
2611
+
2612
+ If you did not expect this invitation, you can safely ignore this email.
2613
+
2614
+ ---
2615
+ Vritti AI Cloud - Cloud Management Platform
2616
+ This is an automated message, please do not reply.
2617
+ `.trim();
2618
+ await this.sendEmail({
2619
+ to: [
2620
+ {
2621
+ email: to,
2622
+ name
2623
+ }
2624
+ ],
2625
+ subject,
2626
+ htmlContent,
2627
+ textContent
2628
+ });
2629
+ this.logger.log(`Invite email sent to ${to}`);
2630
+ }
2631
+ // Verifies Brevo API connectivity — a 400 response means the API is reachable
2632
+ async verifyConnection() {
2633
+ try {
2634
+ await this.brevoClient.transactionalEmails.sendTransacEmail({
2635
+ sender: {
2636
+ email: this.senderEmail,
2637
+ name: this.senderName
2638
+ },
2639
+ to: [
2640
+ {
2641
+ email: this.senderEmail
2642
+ }
2643
+ ],
2644
+ subject: "Connection Test",
2645
+ htmlContent: "<p>Test</p>"
2646
+ });
2647
+ return true;
2648
+ } catch (err) {
2649
+ if (err instanceof BrevoError && err.statusCode === 400) {
2650
+ return true;
2651
+ }
2652
+ this.logger.error("Brevo connection verification failed:", err);
2653
+ return false;
2654
+ }
2655
+ }
2656
+ // Sends a transactional email via Brevo — retries handled internally by BrevoClient
2657
+ async sendEmail(emailData) {
2658
+ try {
2659
+ const result = await this.brevoClient.transactionalEmails.sendTransacEmail({
2660
+ sender: {
2661
+ email: this.senderEmail,
2662
+ name: this.senderName
2663
+ },
2664
+ to: emailData.to,
2665
+ subject: emailData.subject,
2666
+ htmlContent: emailData.htmlContent,
2667
+ textContent: emailData.textContent
2668
+ });
2906
2669
  this.logger.debug(`Email sent successfully. Message ID: ${result.messageId}`);
2907
2670
  } catch (err) {
2908
2671
  if (err instanceof BrevoTimeoutError) {
@@ -2930,9 +2693,9 @@ This is an automated message, please do not reply.
2930
2693
  }
2931
2694
  };
2932
2695
  EmailService = _ts_decorate16([
2933
- Injectable9(),
2934
- _ts_metadata11("design:type", Function),
2935
- _ts_metadata11("design:paramtypes", [
2696
+ Injectable7(),
2697
+ _ts_metadata12("design:type", Function),
2698
+ _ts_metadata12("design:paramtypes", [
2936
2699
  typeof ConfigService5 === "undefined" ? Object : ConfigService5
2937
2700
  ])
2938
2701
  ], EmailService);
@@ -2966,7 +2729,7 @@ EmailModule = _ts_decorate17([
2966
2729
  ], EmailModule);
2967
2730
 
2968
2731
  // src/filters/http-exception.filter.ts
2969
- import { Catch, HttpException as HttpException2, HttpStatus as HttpStatus19, Logger as Logger11 } from "@nestjs/common";
2732
+ import { Catch, HttpStatus as HttpStatus19, Logger as Logger9 } from "@nestjs/common";
2970
2733
  function _ts_decorate18(decorators, target, key, desc2) {
2971
2734
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
2972
2735
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
@@ -2986,7 +2749,7 @@ var HttpExceptionFilter = class _HttpExceptionFilter {
2986
2749
  static {
2987
2750
  __name(this, "HttpExceptionFilter");
2988
2751
  }
2989
- logger = new Logger11(_HttpExceptionFilter.name);
2752
+ logger = new Logger9(_HttpExceptionFilter.name);
2990
2753
  catch(exception, host) {
2991
2754
  const ctx = host.switchToHttp();
2992
2755
  const response = ctx.getResponse();
@@ -2996,7 +2759,7 @@ var HttpExceptionFilter = class _HttpExceptionFilter {
2996
2759
  let label;
2997
2760
  let detail = "Internal server error";
2998
2761
  let errors = [];
2999
- if (exception instanceof HttpException2) {
2762
+ if (this.isHttpException(exception)) {
3000
2763
  status = exception.getStatus();
3001
2764
  const exceptionResponse = exception.getResponse();
3002
2765
  if (typeof exceptionResponse === "object" && exceptionResponse !== null) {
@@ -3049,6 +2812,10 @@ var HttpExceptionFilter = class _HttpExceptionFilter {
3049
2812
  };
3050
2813
  response.header("Content-Type", "application/problem+json").status(status).send(problemDetails);
3051
2814
  }
2815
+ // Duck-type check for HttpException — avoids instanceof failing across pnpm package instances
2816
+ isHttpException(error) {
2817
+ return error instanceof Error && typeof error.getStatus === "function" && typeof error.getResponse === "function";
2818
+ }
3052
2819
  // Duck-type check for AxiosError without importing axios
3053
2820
  isAxiosError(error) {
3054
2821
  return error instanceof Error && error.isAxiosError === true;
@@ -3059,11 +2826,11 @@ HttpExceptionFilter = _ts_decorate18([
3059
2826
  ], HttpExceptionFilter);
3060
2827
 
3061
2828
  // src/logger/interceptors/http-logger.interceptor.ts
3062
- import { Injectable as Injectable11, Optional as Optional2 } from "@nestjs/common";
2829
+ import { Injectable as Injectable9, Optional as Optional2 } from "@nestjs/common";
3063
2830
  import { catchError, tap } from "rxjs/operators";
3064
2831
 
3065
2832
  // src/logger/services/logger.service.ts
3066
- import { Injectable as Injectable10, Optional } from "@nestjs/common";
2833
+ import { Injectable as Injectable8, Optional } from "@nestjs/common";
3067
2834
  import { createLogger, format, transports } from "winston";
3068
2835
  import DailyRotateFile from "winston-daily-rotate-file";
3069
2836
 
@@ -3108,16 +2875,16 @@ function _ts_decorate19(decorators, target, key, desc2) {
3108
2875
  return c > 3 && r && Object.defineProperty(target, key, r), r;
3109
2876
  }
3110
2877
  __name(_ts_decorate19, "_ts_decorate");
3111
- function _ts_metadata12(k, v) {
2878
+ function _ts_metadata13(k, v) {
3112
2879
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
3113
2880
  }
3114
- __name(_ts_metadata12, "_ts_metadata");
3115
- function _ts_param5(paramIndex, decorator) {
2881
+ __name(_ts_metadata13, "_ts_metadata");
2882
+ function _ts_param4(paramIndex, decorator) {
3116
2883
  return function(target, key) {
3117
2884
  decorator(target, key, paramIndex);
3118
2885
  };
3119
2886
  }
3120
- __name(_ts_param5, "_ts_param");
2887
+ __name(_ts_param4, "_ts_param");
3121
2888
  var LoggerService = class _LoggerService {
3122
2889
  static {
3123
2890
  __name(this, "LoggerService");
@@ -3157,9 +2924,9 @@ var LoggerService = class _LoggerService {
3157
2924
  }) : new transports.Console({
3158
2925
  level,
3159
2926
  format: format.combine(...baseFormatters, format.printf((info) => {
3160
- const { timestamp, level: level2, message, context, correlationId, trace } = info;
2927
+ const { timestamp: timestamp2, level: level2, message, context, correlationId, trace } = info;
3161
2928
  const parts = [
3162
- timestamp,
2929
+ timestamp2,
3163
2930
  level2.toUpperCase().padEnd(7),
3164
2931
  correlationId ? `[${correlationId.toString().slice(-6)}]` : "",
3165
2932
  context ? `[${context}]` : "",
@@ -3310,11 +3077,11 @@ ${trace}`;
3310
3077
  }
3311
3078
  };
3312
3079
  LoggerService = _ts_decorate19([
3313
- Injectable10(),
3314
- _ts_param5(0, Optional()),
3315
- _ts_param5(1, Optional()),
3316
- _ts_metadata12("design:type", Function),
3317
- _ts_metadata12("design:paramtypes", [
3080
+ Injectable8(),
3081
+ _ts_param4(0, Optional()),
3082
+ _ts_param4(1, Optional()),
3083
+ _ts_metadata13("design:type", Function),
3084
+ _ts_metadata13("design:paramtypes", [
3318
3085
  typeof LoggerModuleOptions === "undefined" ? Object : LoggerModuleOptions,
3319
3086
  typeof Logger === "undefined" ? Object : Logger
3320
3087
  ])
@@ -3328,16 +3095,16 @@ function _ts_decorate20(decorators, target, key, desc2) {
3328
3095
  return c > 3 && r && Object.defineProperty(target, key, r), r;
3329
3096
  }
3330
3097
  __name(_ts_decorate20, "_ts_decorate");
3331
- function _ts_metadata13(k, v) {
3098
+ function _ts_metadata14(k, v) {
3332
3099
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
3333
3100
  }
3334
- __name(_ts_metadata13, "_ts_metadata");
3335
- function _ts_param6(paramIndex, decorator) {
3101
+ __name(_ts_metadata14, "_ts_metadata");
3102
+ function _ts_param5(paramIndex, decorator) {
3336
3103
  return function(target, key) {
3337
3104
  decorator(target, key, paramIndex);
3338
3105
  };
3339
3106
  }
3340
- __name(_ts_param6, "_ts_param");
3107
+ __name(_ts_param5, "_ts_param");
3341
3108
  var HttpLoggerInterceptor = class {
3342
3109
  static {
3343
3110
  __name(this, "HttpLoggerInterceptor");
@@ -3441,20 +3208,20 @@ var HttpLoggerInterceptor = class {
3441
3208
  }
3442
3209
  };
3443
3210
  HttpLoggerInterceptor = _ts_decorate20([
3444
- Injectable11(),
3445
- _ts_param6(1, Optional2()),
3446
- _ts_metadata13("design:type", Function),
3447
- _ts_metadata13("design:paramtypes", [
3211
+ Injectable9(),
3212
+ _ts_param5(1, Optional2()),
3213
+ _ts_metadata14("design:type", Function),
3214
+ _ts_metadata14("design:paramtypes", [
3448
3215
  typeof LoggerService === "undefined" ? Object : LoggerService,
3449
3216
  typeof HttpLoggerOptions === "undefined" ? Object : HttpLoggerOptions
3450
3217
  ])
3451
3218
  ], HttpLoggerInterceptor);
3452
3219
 
3453
3220
  // src/logger/logger.module.ts
3454
- import { Global as Global5, Logger as Logger12, Module as Module6 } from "@nestjs/common";
3221
+ import { Global as Global5, Logger as Logger10, Module as Module6 } from "@nestjs/common";
3455
3222
 
3456
3223
  // src/logger/middleware/correlation-id.middleware.ts
3457
- import { Injectable as Injectable12 } from "@nestjs/common";
3224
+ import { Injectable as Injectable10 } from "@nestjs/common";
3458
3225
  function _ts_decorate21(decorators, target, key, desc2) {
3459
3226
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
3460
3227
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
@@ -3462,10 +3229,10 @@ function _ts_decorate21(decorators, target, key, desc2) {
3462
3229
  return c > 3 && r && Object.defineProperty(target, key, r), r;
3463
3230
  }
3464
3231
  __name(_ts_decorate21, "_ts_decorate");
3465
- function _ts_metadata14(k, v) {
3232
+ function _ts_metadata15(k, v) {
3466
3233
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
3467
3234
  }
3468
- __name(_ts_metadata14, "_ts_metadata");
3235
+ __name(_ts_metadata15, "_ts_metadata");
3469
3236
  var CorrelationIdMiddleware = class {
3470
3237
  static {
3471
3238
  __name(this, "CorrelationIdMiddleware");
@@ -3503,9 +3270,9 @@ var CorrelationIdMiddleware = class {
3503
3270
  }
3504
3271
  };
3505
3272
  CorrelationIdMiddleware = _ts_decorate21([
3506
- Injectable12(),
3507
- _ts_metadata14("design:type", Function),
3508
- _ts_metadata14("design:paramtypes", [
3273
+ Injectable10(),
3274
+ _ts_metadata15("design:type", Function),
3275
+ _ts_metadata15("design:paramtypes", [
3509
3276
  typeof CorrelationIdMiddlewareOptions === "undefined" ? Object : CorrelationIdMiddlewareOptions
3510
3277
  ])
3511
3278
  ], CorrelationIdMiddleware);
@@ -3594,9 +3361,9 @@ function mergeWithDefaults(options = {}) {
3594
3361
  __name(mergeWithDefaults, "mergeWithDefaults");
3595
3362
  function createDefaultLoggerProvider(options) {
3596
3363
  return {
3597
- provide: Logger12,
3364
+ provide: Logger10,
3598
3365
  useFactory: /* @__PURE__ */ __name(() => {
3599
- const logger = new Logger12();
3366
+ const logger = new Logger10();
3600
3367
  if (options.level) {
3601
3368
  const levels = getLevelsUpTo(options.level);
3602
3369
  logger.setLogLevels?.(levels);
@@ -3626,7 +3393,7 @@ function createLoggerProviders(options = {}) {
3626
3393
  inject: [
3627
3394
  LOGGER_MODULE_OPTIONS,
3628
3395
  {
3629
- token: Logger12,
3396
+ token: Logger10,
3630
3397
  optional: true
3631
3398
  }
3632
3399
  ]
@@ -3705,10 +3472,10 @@ var LoggerModule = class _LoggerModule {
3705
3472
  ...asyncProviders,
3706
3473
  // Default logger provider
3707
3474
  {
3708
- provide: Logger12,
3475
+ provide: Logger10,
3709
3476
  useFactory: /* @__PURE__ */ __name((opts) => {
3710
3477
  if (opts.provider === "default") {
3711
- const logger = new Logger12();
3478
+ const logger = new Logger10();
3712
3479
  if (opts.level) {
3713
3480
  const levels = getLevelsUpTo(opts.level);
3714
3481
  logger.setLogLevels?.(levels);
@@ -3730,7 +3497,7 @@ var LoggerModule = class _LoggerModule {
3730
3497
  inject: [
3731
3498
  LOGGER_MODULE_OPTIONS,
3732
3499
  {
3733
- token: Logger12,
3500
+ token: Logger10,
3734
3501
  optional: true
3735
3502
  }
3736
3503
  ]
@@ -3856,7 +3623,7 @@ function ApiHealthCheck() {
3856
3623
  __name(ApiHealthCheck, "ApiHealthCheck");
3857
3624
 
3858
3625
  // src/root/services/app.service.ts
3859
- import { Injectable as Injectable13 } from "@nestjs/common";
3626
+ import { Injectable as Injectable11 } from "@nestjs/common";
3860
3627
  function _ts_decorate23(decorators, target, key, desc2) {
3861
3628
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
3862
3629
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
@@ -3874,7 +3641,7 @@ var AppService = class {
3874
3641
  }
3875
3642
  };
3876
3643
  AppService = _ts_decorate23([
3877
- Injectable13()
3644
+ Injectable11()
3878
3645
  ], AppService);
3879
3646
 
3880
3647
  // src/root/controllers/app.controller.ts
@@ -3885,10 +3652,10 @@ function _ts_decorate24(decorators, target, key, desc2) {
3885
3652
  return c > 3 && r && Object.defineProperty(target, key, r), r;
3886
3653
  }
3887
3654
  __name(_ts_decorate24, "_ts_decorate");
3888
- function _ts_metadata15(k, v) {
3655
+ function _ts_metadata16(k, v) {
3889
3656
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
3890
3657
  }
3891
- __name(_ts_metadata15, "_ts_metadata");
3658
+ __name(_ts_metadata16, "_ts_metadata");
3892
3659
  var AppController = class {
3893
3660
  static {
3894
3661
  __name(this, "AppController");
@@ -3906,15 +3673,15 @@ _ts_decorate24([
3906
3673
  Get(),
3907
3674
  Public(),
3908
3675
  ApiHealthCheck(),
3909
- _ts_metadata15("design:type", Function),
3910
- _ts_metadata15("design:paramtypes", []),
3911
- _ts_metadata15("design:returntype", String)
3676
+ _ts_metadata16("design:type", Function),
3677
+ _ts_metadata16("design:paramtypes", []),
3678
+ _ts_metadata16("design:returntype", String)
3912
3679
  ], AppController.prototype, "getHello", null);
3913
3680
  AppController = _ts_decorate24([
3914
3681
  ApiTags("Health"),
3915
3682
  Controller(),
3916
- _ts_metadata15("design:type", Function),
3917
- _ts_metadata15("design:paramtypes", [
3683
+ _ts_metadata16("design:type", Function),
3684
+ _ts_metadata16("design:paramtypes", [
3918
3685
  typeof AppService === "undefined" ? Object : AppService
3919
3686
  ])
3920
3687
  ], AppController);
@@ -3958,16 +3725,16 @@ function _ts_decorate25(decorators, target, key, desc2) {
3958
3725
  return c > 3 && r && Object.defineProperty(target, key, r), r;
3959
3726
  }
3960
3727
  __name(_ts_decorate25, "_ts_decorate");
3961
- function _ts_metadata16(k, v) {
3728
+ function _ts_metadata17(k, v) {
3962
3729
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
3963
3730
  }
3964
- __name(_ts_metadata16, "_ts_metadata");
3965
- function _ts_param7(paramIndex, decorator) {
3731
+ __name(_ts_metadata17, "_ts_metadata");
3732
+ function _ts_param6(paramIndex, decorator) {
3966
3733
  return function(target, key) {
3967
3734
  decorator(target, key, paramIndex);
3968
3735
  };
3969
3736
  }
3970
- __name(_ts_param7, "_ts_param");
3737
+ __name(_ts_param6, "_ts_param");
3971
3738
  var CsrfController = class {
3972
3739
  static {
3973
3740
  __name(this, "CsrfController");
@@ -3985,14 +3752,14 @@ _ts_decorate25([
3985
3752
  Public(),
3986
3753
  HttpCode(HttpStatus20.OK),
3987
3754
  ApiGetCsrfToken(),
3988
- _ts_param7(0, Res({
3755
+ _ts_param6(0, Res({
3989
3756
  passthrough: true
3990
3757
  })),
3991
- _ts_metadata16("design:type", Function),
3992
- _ts_metadata16("design:paramtypes", [
3758
+ _ts_metadata17("design:type", Function),
3759
+ _ts_metadata17("design:paramtypes", [
3993
3760
  typeof FastifyReply === "undefined" ? Object : FastifyReply
3994
3761
  ]),
3995
- _ts_metadata16("design:returntype", Object)
3762
+ _ts_metadata17("design:returntype", Object)
3996
3763
  ], CsrfController.prototype, "getToken", null);
3997
3764
  CsrfController = _ts_decorate25([
3998
3765
  ApiTags2("CSRF"),
@@ -4233,6 +4000,1067 @@ function normalizePhoneNumber(phone) {
4233
4000
  return phone.startsWith("+") ? phone : `+${phone}`;
4234
4001
  }
4235
4002
  __name(normalizePhoneNumber, "normalizePhoneNumber");
4003
+
4004
+ // src/data-table/data-table.module.ts
4005
+ import { Module as Module8 } from "@nestjs/common";
4006
+ import { ConfigModule as ConfigModule4 } from "@nestjs/config";
4007
+
4008
+ // src/data-table/data-table.constants.ts
4009
+ var DATA_TABLE_VIEWS_TABLE = Symbol("DATA_TABLE_VIEWS_TABLE");
4010
+
4011
+ // src/data-table/state/controllers/data-table-state.controller.ts
4012
+ import { Body, Controller as Controller3, HttpCode as HttpCode2, HttpStatus as HttpStatus21, Logger as Logger12, Post } from "@nestjs/common";
4013
+ import { ApiBearerAuth, ApiTags as ApiTags3 } from "@nestjs/swagger";
4014
+
4015
+ // src/data-table/state/docs/data-table-state.docs.ts
4016
+ import { applyDecorators as applyDecorators3 } from "@nestjs/common";
4017
+ import { ApiBody, ApiOperation as ApiOperation3, ApiResponse as ApiResponse3 } from "@nestjs/swagger";
4018
+
4019
+ // src/data-table/state/dto/request/upsert-data-table-state.dto.ts
4020
+ import { ApiProperty as ApiProperty5, ApiPropertyOptional as ApiPropertyOptional4 } from "@nestjs/swagger";
4021
+ import { IsObject, IsOptional as IsOptional2, IsString as IsString3, IsUUID, MaxLength } from "class-validator";
4022
+ function _ts_decorate27(decorators, target, key, desc2) {
4023
+ var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
4024
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
4025
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4026
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
4027
+ }
4028
+ __name(_ts_decorate27, "_ts_decorate");
4029
+ function _ts_metadata18(k, v) {
4030
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
4031
+ }
4032
+ __name(_ts_metadata18, "_ts_metadata");
4033
+ var UpsertDataTableStateDto = class {
4034
+ static {
4035
+ __name(this, "UpsertDataTableStateDto");
4036
+ }
4037
+ tableSlug;
4038
+ state;
4039
+ activeViewId;
4040
+ };
4041
+ _ts_decorate27([
4042
+ ApiProperty5({
4043
+ description: "Unique slug identifying the table",
4044
+ example: "cloud-providers"
4045
+ }),
4046
+ IsString3(),
4047
+ MaxLength(100),
4048
+ _ts_metadata18("design:type", String)
4049
+ ], UpsertDataTableStateDto.prototype, "tableSlug", void 0);
4050
+ _ts_decorate27([
4051
+ ApiProperty5({
4052
+ description: "Full table view state including filters, sort, and column visibility"
4053
+ }),
4054
+ IsObject(),
4055
+ _ts_metadata18("design:type", typeof TableViewState === "undefined" ? Object : TableViewState)
4056
+ ], UpsertDataTableStateDto.prototype, "state", void 0);
4057
+ _ts_decorate27([
4058
+ ApiPropertyOptional4(),
4059
+ IsOptional2(),
4060
+ IsUUID(),
4061
+ _ts_metadata18("design:type", Object)
4062
+ ], UpsertDataTableStateDto.prototype, "activeViewId", void 0);
4063
+
4064
+ // src/data-table/state/docs/data-table-state.docs.ts
4065
+ function ApiUpsertDataTableState() {
4066
+ return applyDecorators3(ApiOperation3({
4067
+ summary: "Save live table state",
4068
+ description: "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."
4069
+ }), ApiBody({
4070
+ type: UpsertDataTableStateDto
4071
+ }), ApiResponse3({
4072
+ status: 200,
4073
+ description: "Live state cached."
4074
+ }), ApiResponse3({
4075
+ status: 400,
4076
+ description: "Invalid request body."
4077
+ }), ApiResponse3({
4078
+ status: 401,
4079
+ description: "Unauthorized."
4080
+ }));
4081
+ }
4082
+ __name(ApiUpsertDataTableState, "ApiUpsertDataTableState");
4083
+
4084
+ // src/data-table/state/services/data-table-state.service.ts
4085
+ import { Injectable as Injectable12, Logger as Logger11 } from "@nestjs/common";
4086
+ import { ConfigService as ConfigService6 } from "@nestjs/config";
4087
+ function _ts_decorate28(decorators, target, key, desc2) {
4088
+ var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
4089
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
4090
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4091
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
4092
+ }
4093
+ __name(_ts_decorate28, "_ts_decorate");
4094
+ function _ts_metadata19(k, v) {
4095
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
4096
+ }
4097
+ __name(_ts_metadata19, "_ts_metadata");
4098
+ var EMPTY_TABLE_STATE = {
4099
+ filters: [],
4100
+ sort: [],
4101
+ columnVisibility: {},
4102
+ columnOrder: [],
4103
+ columnSizing: {},
4104
+ columnPinning: {
4105
+ left: [],
4106
+ right: []
4107
+ },
4108
+ lockedColumnSizing: false,
4109
+ density: "normal",
4110
+ filterOrder: [],
4111
+ filterVisibility: {},
4112
+ pagination: {
4113
+ limit: 20,
4114
+ offset: 0
4115
+ }
4116
+ };
4117
+ var DataTableStateService = class _DataTableStateService {
4118
+ static {
4119
+ __name(this, "DataTableStateService");
4120
+ }
4121
+ cacheService;
4122
+ configService;
4123
+ logger = new Logger11(_DataTableStateService.name);
4124
+ constructor(cacheService, configService) {
4125
+ this.cacheService = cacheService;
4126
+ this.configService = configService;
4127
+ }
4128
+ // Returns configured TTL for live table state in seconds, defaulting to 3600 (1h)
4129
+ get stateTtl() {
4130
+ return this.configService.get("TABLE_STATE_CACHE_TTL") ?? 3600;
4131
+ }
4132
+ // Saves live table state and active view ID to Redis; DB is not written
4133
+ async upsertCurrentState(userId, dto) {
4134
+ const key = `dt:${userId}:${dto.tableSlug}`;
4135
+ await this.cacheService.set(key, {
4136
+ state: dto.state,
4137
+ activeViewId: dto.activeViewId ?? null
4138
+ }, this.stateTtl);
4139
+ this.logger.log(`Cached live state for user: ${userId}, table: ${dto.tableSlug}`);
4140
+ }
4141
+ // Returns live table state and active view ID from Redis; returns empty state on miss — no DB query
4142
+ async getCurrentState(userId, tableSlug) {
4143
+ const key = `dt:${userId}:${tableSlug}`;
4144
+ const cached = await this.cacheService.get(key);
4145
+ return cached ?? {
4146
+ state: EMPTY_TABLE_STATE,
4147
+ activeViewId: null
4148
+ };
4149
+ }
4150
+ };
4151
+ DataTableStateService = _ts_decorate28([
4152
+ Injectable12(),
4153
+ _ts_metadata19("design:type", Function),
4154
+ _ts_metadata19("design:paramtypes", [
4155
+ typeof CacheService === "undefined" ? Object : CacheService,
4156
+ typeof ConfigService6 === "undefined" ? Object : ConfigService6
4157
+ ])
4158
+ ], DataTableStateService);
4159
+
4160
+ // src/data-table/state/controllers/data-table-state.controller.ts
4161
+ function _ts_decorate29(decorators, target, key, desc2) {
4162
+ var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
4163
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
4164
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4165
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
4166
+ }
4167
+ __name(_ts_decorate29, "_ts_decorate");
4168
+ function _ts_metadata20(k, v) {
4169
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
4170
+ }
4171
+ __name(_ts_metadata20, "_ts_metadata");
4172
+ function _ts_param7(paramIndex, decorator) {
4173
+ return function(target, key) {
4174
+ decorator(target, key, paramIndex);
4175
+ };
4176
+ }
4177
+ __name(_ts_param7, "_ts_param");
4178
+ var DataTableStateController = class _DataTableStateController {
4179
+ static {
4180
+ __name(this, "DataTableStateController");
4181
+ }
4182
+ dataTableStateService;
4183
+ logger = new Logger12(_DataTableStateController.name);
4184
+ constructor(dataTableStateService) {
4185
+ this.dataTableStateService = dataTableStateService;
4186
+ }
4187
+ // Saves live table state to Redis cache for the authenticated user's table
4188
+ upsertCurrentState(userId, dto) {
4189
+ this.logger.log(`POST /table-states - User: ${userId}, table: ${dto.tableSlug}`);
4190
+ return this.dataTableStateService.upsertCurrentState(userId, dto);
4191
+ }
4192
+ };
4193
+ _ts_decorate29([
4194
+ Post(),
4195
+ HttpCode2(HttpStatus21.OK),
4196
+ ApiUpsertDataTableState(),
4197
+ _ts_param7(0, UserId()),
4198
+ _ts_param7(1, Body()),
4199
+ _ts_metadata20("design:type", Function),
4200
+ _ts_metadata20("design:paramtypes", [
4201
+ String,
4202
+ typeof UpsertDataTableStateDto === "undefined" ? Object : UpsertDataTableStateDto
4203
+ ]),
4204
+ _ts_metadata20("design:returntype", typeof Promise === "undefined" ? Object : Promise)
4205
+ ], DataTableStateController.prototype, "upsertCurrentState", null);
4206
+ DataTableStateController = _ts_decorate29([
4207
+ ApiTags3("Table States"),
4208
+ ApiBearerAuth(),
4209
+ RequireSession("CLOUD", "ADMIN"),
4210
+ Controller3("table-states"),
4211
+ _ts_metadata20("design:type", Function),
4212
+ _ts_metadata20("design:paramtypes", [
4213
+ typeof DataTableStateService === "undefined" ? Object : DataTableStateService
4214
+ ])
4215
+ ], DataTableStateController);
4216
+
4217
+ // src/data-table/views/controllers/data-table-views.controller.ts
4218
+ import { Body as Body2, Controller as Controller4, Delete, Get as Get3, HttpCode as HttpCode3, HttpStatus as HttpStatus22, Logger as Logger14, Param, Patch, Post as Post2, Query } from "@nestjs/common";
4219
+ import { ApiBearerAuth as ApiBearerAuth2, ApiTags as ApiTags4 } from "@nestjs/swagger";
4220
+
4221
+ // src/data-table/views/docs/data-table-views.docs.ts
4222
+ import { applyDecorators as applyDecorators4 } from "@nestjs/common";
4223
+ import { ApiBody as ApiBody2, ApiOperation as ApiOperation4, ApiParam, ApiQuery, ApiResponse as ApiResponse4 } from "@nestjs/swagger";
4224
+
4225
+ // src/data-table/views/dto/entity/data-table-view.dto.ts
4226
+ import { ApiProperty as ApiProperty6, ApiPropertyOptional as ApiPropertyOptional5 } from "@nestjs/swagger";
4227
+ function _ts_decorate30(decorators, target, key, desc2) {
4228
+ var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
4229
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
4230
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4231
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
4232
+ }
4233
+ __name(_ts_decorate30, "_ts_decorate");
4234
+ function _ts_metadata21(k, v) {
4235
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
4236
+ }
4237
+ __name(_ts_metadata21, "_ts_metadata");
4238
+ var DataTableViewDto = class _DataTableViewDto {
4239
+ static {
4240
+ __name(this, "DataTableViewDto");
4241
+ }
4242
+ id;
4243
+ name;
4244
+ tableSlug;
4245
+ state;
4246
+ isShared;
4247
+ isOwn;
4248
+ createdAt;
4249
+ updatedAt;
4250
+ // Creates a response DTO from a DataTableView entity, computing isOwn by comparing userId
4251
+ static from(view, userId) {
4252
+ const dto = new _DataTableViewDto();
4253
+ dto.id = view.id;
4254
+ dto.name = view.name ?? null;
4255
+ dto.tableSlug = view.tableSlug;
4256
+ dto.state = view.state;
4257
+ dto.isShared = view.isShared;
4258
+ dto.isOwn = view.userId === userId;
4259
+ dto.createdAt = view.createdAt;
4260
+ dto.updatedAt = view.updatedAt ?? null;
4261
+ return dto;
4262
+ }
4263
+ };
4264
+ _ts_decorate30([
4265
+ ApiProperty6({
4266
+ description: "View unique identifier"
4267
+ }),
4268
+ _ts_metadata21("design:type", String)
4269
+ ], DataTableViewDto.prototype, "id", void 0);
4270
+ _ts_decorate30([
4271
+ ApiPropertyOptional5({
4272
+ description: "Display name of the view",
4273
+ nullable: true
4274
+ }),
4275
+ _ts_metadata21("design:type", Object)
4276
+ ], DataTableViewDto.prototype, "name", void 0);
4277
+ _ts_decorate30([
4278
+ ApiProperty6({
4279
+ description: "Slug of the table this view belongs to",
4280
+ example: "cloud-providers"
4281
+ }),
4282
+ _ts_metadata21("design:type", String)
4283
+ ], DataTableViewDto.prototype, "tableSlug", void 0);
4284
+ _ts_decorate30([
4285
+ ApiProperty6({
4286
+ description: "Stored filter, sort, and column visibility state"
4287
+ }),
4288
+ _ts_metadata21("design:type", typeof TableViewState === "undefined" ? Object : TableViewState)
4289
+ ], DataTableViewDto.prototype, "state", void 0);
4290
+ _ts_decorate30([
4291
+ ApiProperty6({
4292
+ description: "Whether the view is visible to all users",
4293
+ example: false
4294
+ }),
4295
+ _ts_metadata21("design:type", Boolean)
4296
+ ], DataTableViewDto.prototype, "isShared", void 0);
4297
+ _ts_decorate30([
4298
+ ApiProperty6({
4299
+ description: "Whether the requesting user owns this view",
4300
+ example: true
4301
+ }),
4302
+ _ts_metadata21("design:type", Boolean)
4303
+ ], DataTableViewDto.prototype, "isOwn", void 0);
4304
+ _ts_decorate30([
4305
+ ApiProperty6({
4306
+ description: "Creation timestamp"
4307
+ }),
4308
+ _ts_metadata21("design:type", typeof Date === "undefined" ? Object : Date)
4309
+ ], DataTableViewDto.prototype, "createdAt", void 0);
4310
+ _ts_decorate30([
4311
+ ApiPropertyOptional5({
4312
+ description: "Last updated timestamp",
4313
+ nullable: true
4314
+ }),
4315
+ _ts_metadata21("design:type", Object)
4316
+ ], DataTableViewDto.prototype, "updatedAt", void 0);
4317
+
4318
+ // src/data-table/views/dto/request/create-data-table-view.dto.ts
4319
+ import { ApiProperty as ApiProperty7, ApiPropertyOptional as ApiPropertyOptional6 } from "@nestjs/swagger";
4320
+ import { IsBoolean as IsBoolean2, IsObject as IsObject2, IsOptional as IsOptional3, IsString as IsString4, MaxLength as MaxLength2 } from "class-validator";
4321
+ function _ts_decorate31(decorators, target, key, desc2) {
4322
+ var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
4323
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
4324
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4325
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
4326
+ }
4327
+ __name(_ts_decorate31, "_ts_decorate");
4328
+ function _ts_metadata22(k, v) {
4329
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
4330
+ }
4331
+ __name(_ts_metadata22, "_ts_metadata");
4332
+ var CreateDataTableViewDto = class {
4333
+ static {
4334
+ __name(this, "CreateDataTableViewDto");
4335
+ }
4336
+ name;
4337
+ tableSlug;
4338
+ state;
4339
+ isShared;
4340
+ };
4341
+ _ts_decorate31([
4342
+ ApiProperty7({
4343
+ description: "Display name for the saved view",
4344
+ example: "AWS Only"
4345
+ }),
4346
+ IsString4(),
4347
+ MaxLength2(100),
4348
+ _ts_metadata22("design:type", String)
4349
+ ], CreateDataTableViewDto.prototype, "name", void 0);
4350
+ _ts_decorate31([
4351
+ ApiProperty7({
4352
+ description: "Unique slug identifying the table",
4353
+ example: "cloud-providers"
4354
+ }),
4355
+ IsString4(),
4356
+ MaxLength2(100),
4357
+ _ts_metadata22("design:type", String)
4358
+ ], CreateDataTableViewDto.prototype, "tableSlug", void 0);
4359
+ _ts_decorate31([
4360
+ ApiProperty7({
4361
+ description: "Full table view state including filters, sort, and column visibility"
4362
+ }),
4363
+ IsObject2(),
4364
+ _ts_metadata22("design:type", typeof TableViewState === "undefined" ? Object : TableViewState)
4365
+ ], CreateDataTableViewDto.prototype, "state", void 0);
4366
+ _ts_decorate31([
4367
+ ApiPropertyOptional6({
4368
+ description: "Whether this view is visible to all users",
4369
+ example: false
4370
+ }),
4371
+ IsBoolean2(),
4372
+ IsOptional3(),
4373
+ _ts_metadata22("design:type", Boolean)
4374
+ ], CreateDataTableViewDto.prototype, "isShared", void 0);
4375
+
4376
+ // src/data-table/views/dto/request/rename-data-table-view.dto.ts
4377
+ import { ApiProperty as ApiProperty8 } from "@nestjs/swagger";
4378
+ import { IsString as IsString5, MaxLength as MaxLength3, MinLength } from "class-validator";
4379
+ function _ts_decorate32(decorators, target, key, desc2) {
4380
+ var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
4381
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
4382
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4383
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
4384
+ }
4385
+ __name(_ts_decorate32, "_ts_decorate");
4386
+ function _ts_metadata23(k, v) {
4387
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
4388
+ }
4389
+ __name(_ts_metadata23, "_ts_metadata");
4390
+ var RenameDataTableViewDto = class {
4391
+ static {
4392
+ __name(this, "RenameDataTableViewDto");
4393
+ }
4394
+ name;
4395
+ };
4396
+ _ts_decorate32([
4397
+ ApiProperty8({
4398
+ description: "New display name for the view",
4399
+ example: "AWS Only"
4400
+ }),
4401
+ IsString5(),
4402
+ MinLength(1),
4403
+ MaxLength3(100),
4404
+ _ts_metadata23("design:type", String)
4405
+ ], RenameDataTableViewDto.prototype, "name", void 0);
4406
+
4407
+ // src/data-table/views/dto/request/toggle-share-data-table-view.dto.ts
4408
+ import { ApiProperty as ApiProperty9 } from "@nestjs/swagger";
4409
+ import { IsBoolean as IsBoolean3 } from "class-validator";
4410
+ function _ts_decorate33(decorators, target, key, desc2) {
4411
+ var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
4412
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
4413
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4414
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
4415
+ }
4416
+ __name(_ts_decorate33, "_ts_decorate");
4417
+ function _ts_metadata24(k, v) {
4418
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
4419
+ }
4420
+ __name(_ts_metadata24, "_ts_metadata");
4421
+ var ToggleShareDataTableViewDto = class {
4422
+ static {
4423
+ __name(this, "ToggleShareDataTableViewDto");
4424
+ }
4425
+ isShared;
4426
+ };
4427
+ _ts_decorate33([
4428
+ ApiProperty9({
4429
+ description: "Whether the view should be visible to all users",
4430
+ example: true
4431
+ }),
4432
+ IsBoolean3(),
4433
+ _ts_metadata24("design:type", Boolean)
4434
+ ], ToggleShareDataTableViewDto.prototype, "isShared", void 0);
4435
+
4436
+ // src/data-table/views/dto/request/update-data-table-view.dto.ts
4437
+ import { ApiProperty as ApiProperty10 } from "@nestjs/swagger";
4438
+ import { IsObject as IsObject3 } from "class-validator";
4439
+ function _ts_decorate34(decorators, target, key, desc2) {
4440
+ var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
4441
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
4442
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4443
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
4444
+ }
4445
+ __name(_ts_decorate34, "_ts_decorate");
4446
+ function _ts_metadata25(k, v) {
4447
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
4448
+ }
4449
+ __name(_ts_metadata25, "_ts_metadata");
4450
+ var UpdateDataTableViewDto = class {
4451
+ static {
4452
+ __name(this, "UpdateDataTableViewDto");
4453
+ }
4454
+ state;
4455
+ };
4456
+ _ts_decorate34([
4457
+ ApiProperty10({
4458
+ description: "Updated filter, sort, and column visibility state"
4459
+ }),
4460
+ IsObject3(),
4461
+ _ts_metadata25("design:type", typeof TableViewState === "undefined" ? Object : TableViewState)
4462
+ ], UpdateDataTableViewDto.prototype, "state", void 0);
4463
+
4464
+ // src/data-table/views/docs/data-table-views.docs.ts
4465
+ function ApiListDataTableViews() {
4466
+ return applyDecorators4(ApiOperation4({
4467
+ summary: "List named table views",
4468
+ description: "Returns the authenticated user's own named views plus all shared views for the given table slug."
4469
+ }), ApiQuery({
4470
+ name: "tableSlug",
4471
+ description: "Slug of the table to fetch views for",
4472
+ example: "cloud-providers",
4473
+ required: true
4474
+ }), ApiResponse4({
4475
+ status: 200,
4476
+ description: "Named views retrieved.",
4477
+ type: [
4478
+ DataTableViewDto
4479
+ ]
4480
+ }), ApiResponse4({
4481
+ status: 401,
4482
+ description: "Unauthorized."
4483
+ }));
4484
+ }
4485
+ __name(ApiListDataTableViews, "ApiListDataTableViews");
4486
+ function ApiCreateDataTableView() {
4487
+ return applyDecorators4(ApiOperation4({
4488
+ summary: "Create named table view",
4489
+ description: "Saves the current table state as a named view snapshot. The name must be unique per user+table."
4490
+ }), ApiBody2({
4491
+ type: CreateDataTableViewDto
4492
+ }), ApiResponse4({
4493
+ status: 201,
4494
+ description: "Named view created.",
4495
+ type: DataTableViewDto
4496
+ }), ApiResponse4({
4497
+ status: 400,
4498
+ description: "Invalid request body."
4499
+ }), ApiResponse4({
4500
+ status: 401,
4501
+ description: "Unauthorized."
4502
+ }));
4503
+ }
4504
+ __name(ApiCreateDataTableView, "ApiCreateDataTableView");
4505
+ function ApiUpdateDataTableView() {
4506
+ return applyDecorators4(ApiOperation4({
4507
+ summary: "Update named table view",
4508
+ description: "Updates the state of an existing named view. Only the owner can update."
4509
+ }), ApiParam({
4510
+ name: "id",
4511
+ description: "UUID of the table view to update"
4512
+ }), ApiBody2({
4513
+ type: UpdateDataTableViewDto
4514
+ }), ApiResponse4({
4515
+ status: 200,
4516
+ description: "View updated.",
4517
+ type: DataTableViewDto
4518
+ }), ApiResponse4({
4519
+ status: 400,
4520
+ description: "Validation failed or not owned by caller."
4521
+ }), ApiResponse4({
4522
+ status: 401,
4523
+ description: "Unauthorized."
4524
+ }), ApiResponse4({
4525
+ status: 404,
4526
+ description: "View not found."
4527
+ }));
4528
+ }
4529
+ __name(ApiUpdateDataTableView, "ApiUpdateDataTableView");
4530
+ function ApiRenameDataTableView() {
4531
+ return applyDecorators4(ApiOperation4({
4532
+ summary: "Rename a named table view",
4533
+ description: "Updates the display name of an existing view. The new name must be unique per user+table. Only the owner can rename."
4534
+ }), ApiParam({
4535
+ name: "id",
4536
+ description: "UUID of the table view to rename"
4537
+ }), ApiBody2({
4538
+ type: RenameDataTableViewDto
4539
+ }), ApiResponse4({
4540
+ status: 200,
4541
+ description: "View renamed.",
4542
+ type: DataTableViewDto
4543
+ }), ApiResponse4({
4544
+ status: 400,
4545
+ description: "Not owned by caller."
4546
+ }), ApiResponse4({
4547
+ status: 401,
4548
+ description: "Unauthorized."
4549
+ }), ApiResponse4({
4550
+ status: 404,
4551
+ description: "View not found."
4552
+ }), ApiResponse4({
4553
+ status: 409,
4554
+ description: "A view with this name already exists."
4555
+ }));
4556
+ }
4557
+ __name(ApiRenameDataTableView, "ApiRenameDataTableView");
4558
+ function ApiToggleShareDataTableView() {
4559
+ return applyDecorators4(ApiOperation4({
4560
+ summary: "Toggle view sharing",
4561
+ description: "Makes a view visible to all users (shared) or restricts it to the owner only (private). Only the owner can toggle sharing."
4562
+ }), ApiParam({
4563
+ name: "id",
4564
+ description: "UUID of the table view"
4565
+ }), ApiBody2({
4566
+ type: ToggleShareDataTableViewDto
4567
+ }), ApiResponse4({
4568
+ status: 200,
4569
+ description: "Sharing status updated.",
4570
+ type: DataTableViewDto
4571
+ }), ApiResponse4({
4572
+ status: 400,
4573
+ description: "Not owned by caller."
4574
+ }), ApiResponse4({
4575
+ status: 401,
4576
+ description: "Unauthorized."
4577
+ }), ApiResponse4({
4578
+ status: 404,
4579
+ description: "View not found."
4580
+ }));
4581
+ }
4582
+ __name(ApiToggleShareDataTableView, "ApiToggleShareDataTableView");
4583
+ function ApiDeleteDataTableView() {
4584
+ return applyDecorators4(ApiOperation4({
4585
+ summary: "Delete named table view",
4586
+ description: "Permanently deletes a named view. Only the owner can delete their own views."
4587
+ }), ApiParam({
4588
+ name: "id",
4589
+ description: "UUID of the table view to delete"
4590
+ }), ApiResponse4({
4591
+ status: 200,
4592
+ description: "View deleted.",
4593
+ type: DataTableViewDto
4594
+ }), ApiResponse4({
4595
+ status: 400,
4596
+ description: "Not owned by caller."
4597
+ }), ApiResponse4({
4598
+ status: 401,
4599
+ description: "Unauthorized."
4600
+ }), ApiResponse4({
4601
+ status: 404,
4602
+ description: "View not found."
4603
+ }));
4604
+ }
4605
+ __name(ApiDeleteDataTableView, "ApiDeleteDataTableView");
4606
+
4607
+ // src/data-table/views/services/data-table-views.service.ts
4608
+ import { createHash as createHash2 } from "crypto";
4609
+ import { Injectable as Injectable14, Logger as Logger13 } from "@nestjs/common";
4610
+ import { ConfigService as ConfigService7 } from "@nestjs/config";
4611
+
4612
+ // src/data-table/views/repositories/data-table-views.repository.ts
4613
+ import { Inject as Inject4, Injectable as Injectable13 } from "@nestjs/common";
4614
+ import { and as and3, eq as eq3 } from "drizzle-orm";
4615
+ function _ts_decorate35(decorators, target, key, desc2) {
4616
+ var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
4617
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
4618
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4619
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
4620
+ }
4621
+ __name(_ts_decorate35, "_ts_decorate");
4622
+ function _ts_metadata26(k, v) {
4623
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
4624
+ }
4625
+ __name(_ts_metadata26, "_ts_metadata");
4626
+ function _ts_param8(paramIndex, decorator) {
4627
+ return function(target, key) {
4628
+ decorator(target, key, paramIndex);
4629
+ };
4630
+ }
4631
+ __name(_ts_param8, "_ts_param");
4632
+ var NAMED_VIEWS_LIMIT = 100;
4633
+ var DataTableViewsRepository = class extends PrimaryBaseRepository {
4634
+ static {
4635
+ __name(this, "DataTableViewsRepository");
4636
+ }
4637
+ constructor(database, table) {
4638
+ super(database, table);
4639
+ }
4640
+ // Returns personal (non-shared) named views owned by the user for a given table
4641
+ async findPersonalViewsBySlug(userId, tableSlug) {
4642
+ const t = this.table;
4643
+ return this.db.select().from(this.table).where(and3(eq3(t.tableSlug, tableSlug), eq3(t.userId, userId), eq3(t.isShared, false))).orderBy(t.createdAt).limit(NAMED_VIEWS_LIMIT);
4644
+ }
4645
+ // Returns all shared named views for a given table — visible to all users
4646
+ async findSharedViewsBySlug(tableSlug) {
4647
+ const t = this.table;
4648
+ return this.db.select().from(this.table).where(and3(eq3(t.tableSlug, tableSlug), eq3(t.isShared, true))).orderBy(t.createdAt).limit(NAMED_VIEWS_LIMIT);
4649
+ }
4650
+ };
4651
+ DataTableViewsRepository = _ts_decorate35([
4652
+ Injectable13(),
4653
+ _ts_param8(1, Inject4(DATA_TABLE_VIEWS_TABLE)),
4654
+ _ts_metadata26("design:type", Function),
4655
+ _ts_metadata26("design:paramtypes", [
4656
+ typeof PrimaryDatabaseService === "undefined" ? Object : PrimaryDatabaseService,
4657
+ typeof PgTable === "undefined" ? Object : PgTable
4658
+ ])
4659
+ ], DataTableViewsRepository);
4660
+
4661
+ // src/data-table/views/services/data-table-views.service.ts
4662
+ function _ts_decorate36(decorators, target, key, desc2) {
4663
+ var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
4664
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
4665
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4666
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
4667
+ }
4668
+ __name(_ts_decorate36, "_ts_decorate");
4669
+ function _ts_metadata27(k, v) {
4670
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
4671
+ }
4672
+ __name(_ts_metadata27, "_ts_metadata");
4673
+ function computeChecksum(value) {
4674
+ return createHash2("sha256").update(JSON.stringify(value)).digest("hex");
4675
+ }
4676
+ __name(computeChecksum, "computeChecksum");
4677
+ var DataTableViewsService = class _DataTableViewsService {
4678
+ static {
4679
+ __name(this, "DataTableViewsService");
4680
+ }
4681
+ dataTableViewsRepository;
4682
+ cacheService;
4683
+ configService;
4684
+ logger = new Logger13(_DataTableViewsService.name);
4685
+ constructor(dataTableViewsRepository, cacheService, configService) {
4686
+ this.dataTableViewsRepository = dataTableViewsRepository;
4687
+ this.cacheService = cacheService;
4688
+ this.configService = configService;
4689
+ }
4690
+ // Builds the Redis key for a user's personal (non-shared) views for a given table
4691
+ personalViewsKey(userId, tableSlug) {
4692
+ return `views:personal:${userId}:${tableSlug}`;
4693
+ }
4694
+ // Builds the Redis key for all shared views for a given table — same key for all users
4695
+ sharedViewsKey(tableSlug) {
4696
+ return `views:shared:${tableSlug}`;
4697
+ }
4698
+ // Returns configured TTL for named views in seconds, defaulting to 86400 (24h)
4699
+ get viewsTtl() {
4700
+ return this.configService.get("TABLE_VIEWS_CACHE_TTL") ?? 86400;
4701
+ }
4702
+ // Fetches personal views from cache; falls back to DB and warms cache on miss
4703
+ async getOrCachePersonalViews(userId, tableSlug) {
4704
+ const key = this.personalViewsKey(userId, tableSlug);
4705
+ const cached = await this.cacheService.get(key);
4706
+ if (cached) {
4707
+ this.logger.debug(`Cache hit for personal views: user=${userId}, table=${tableSlug}`);
4708
+ return cached;
4709
+ }
4710
+ const rows = await this.dataTableViewsRepository.findPersonalViewsBySlug(userId, tableSlug);
4711
+ await this.cacheService.set(key, rows, this.viewsTtl);
4712
+ return rows;
4713
+ }
4714
+ // Fetches shared views from cache; falls back to DB and warms cache on miss
4715
+ async getOrCacheSharedViews(tableSlug) {
4716
+ const key = this.sharedViewsKey(tableSlug);
4717
+ const cached = await this.cacheService.get(key);
4718
+ if (cached) {
4719
+ this.logger.debug(`Cache hit for shared views: table=${tableSlug}`);
4720
+ return cached;
4721
+ }
4722
+ const rows = await this.dataTableViewsRepository.findSharedViewsBySlug(tableSlug);
4723
+ await this.cacheService.set(key, rows, this.viewsTtl);
4724
+ return rows;
4725
+ }
4726
+ // Deletes personal and/or shared cache keys based on which pools the mutation affects
4727
+ async invalidateViewsCache(userId, tableSlug, affectsPersonal, affectsShared) {
4728
+ const toDelete = [];
4729
+ if (affectsPersonal) toDelete.push(this.personalViewsKey(userId, tableSlug));
4730
+ if (affectsShared) toDelete.push(this.sharedViewsKey(tableSlug));
4731
+ if (toDelete.length > 0) await this.cacheService.del(...toDelete);
4732
+ }
4733
+ // Returns personal + shared named views — each pool fetched from cache or DB in parallel
4734
+ async findViews(userId, tableSlug) {
4735
+ const [personalRows, sharedRows] = await Promise.all([
4736
+ this.getOrCachePersonalViews(userId, tableSlug),
4737
+ this.getOrCacheSharedViews(tableSlug)
4738
+ ]);
4739
+ return [
4740
+ ...personalRows,
4741
+ ...sharedRows
4742
+ ].map((row) => DataTableViewDto.from(row, userId));
4743
+ }
4744
+ // Creates a named snapshot and invalidates the relevant cache pool
4745
+ async createView(userId, dto) {
4746
+ const view = await this.dataTableViewsRepository.create({
4747
+ userId,
4748
+ tableSlug: dto.tableSlug,
4749
+ name: dto.name,
4750
+ state: dto.state,
4751
+ isShared: dto.isShared ?? false
4752
+ });
4753
+ this.logger.log(`Created view "${dto.name}" for user: ${userId}, table: ${dto.tableSlug}`);
4754
+ const isShared = dto.isShared ?? false;
4755
+ await this.invalidateViewsCache(userId, dto.tableSlug, !isShared, isShared);
4756
+ return DataTableViewDto.from(view, userId);
4757
+ }
4758
+ // Updates the state of a named view — skips DB write if state is unchanged
4759
+ async updateView(userId, id, dto) {
4760
+ const view = await this.dataTableViewsRepository.findById(id);
4761
+ if (!view) throw new NotFoundException("Table view not found.");
4762
+ if (view.userId !== userId) throw new BadRequestException("You do not have permission to update this view.");
4763
+ if (computeChecksum(dto.state) === computeChecksum(view.state)) {
4764
+ this.logger.log(`State unchanged for view ${id} \u2014 skipping DB write`);
4765
+ return DataTableViewDto.from(view, userId);
4766
+ }
4767
+ const updated = await this.dataTableViewsRepository.update(id, {
4768
+ state: dto.state
4769
+ });
4770
+ this.logger.log(`Updated state for view ${id}, user: ${userId}`);
4771
+ await this.invalidateViewsCache(userId, view.tableSlug, !view.isShared, view.isShared);
4772
+ return DataTableViewDto.from(updated, userId);
4773
+ }
4774
+ // Toggles the sharing status of a named view — updates both personal and shared cache
4775
+ async toggleShareView(userId, id, isShared) {
4776
+ const view = await this.dataTableViewsRepository.findById(id);
4777
+ if (!view) throw new NotFoundException("Table view not found.");
4778
+ if (view.userId !== userId) throw new BadRequestException("You do not have permission to share this view.");
4779
+ const updated = await this.dataTableViewsRepository.update(id, {
4780
+ isShared
4781
+ });
4782
+ this.logger.log(`Set isShared=${isShared} for view ${id}, user: ${userId}`);
4783
+ await this.invalidateViewsCache(userId, view.tableSlug, true, true);
4784
+ return DataTableViewDto.from(updated, userId);
4785
+ }
4786
+ // Renames a named view — enforces unique name per user+table, invalidates personal cache
4787
+ async renameView(userId, id, name) {
4788
+ const view = await this.dataTableViewsRepository.findById(id);
4789
+ if (!view) throw new NotFoundException("Table view not found.");
4790
+ if (view.userId !== userId) throw new BadRequestException("You do not have permission to rename this view.");
4791
+ const existing = await this.dataTableViewsRepository.findOne({
4792
+ userId,
4793
+ tableSlug: view.tableSlug,
4794
+ name,
4795
+ isShared: false
4796
+ });
4797
+ if (existing && existing.id !== id) {
4798
+ throw new ConflictException({
4799
+ label: "Name Already Taken",
4800
+ detail: "A view with this name already exists for this table.",
4801
+ errors: [
4802
+ {
4803
+ field: "name",
4804
+ message: "Name already taken"
4805
+ }
4806
+ ]
4807
+ });
4808
+ }
4809
+ const updated = await this.dataTableViewsRepository.update(id, {
4810
+ name
4811
+ });
4812
+ this.logger.log(`Renamed view ${id} to "${name}" for user: ${userId}`);
4813
+ await this.invalidateViewsCache(userId, view.tableSlug, !view.isShared, view.isShared);
4814
+ return DataTableViewDto.from(updated, userId);
4815
+ }
4816
+ // Deletes a named view and invalidates the relevant cache pool
4817
+ async deleteView(userId, id) {
4818
+ const view = await this.dataTableViewsRepository.findById(id);
4819
+ if (!view) throw new NotFoundException("Table view not found.");
4820
+ if (view.userId !== userId) throw new BadRequestException("You do not have permission to delete this view.");
4821
+ await this.dataTableViewsRepository.delete(id);
4822
+ this.logger.log(`Deleted view ${id} for user: ${userId}`);
4823
+ await this.invalidateViewsCache(userId, view.tableSlug, !view.isShared, view.isShared);
4824
+ return DataTableViewDto.from(view, userId);
4825
+ }
4826
+ };
4827
+ DataTableViewsService = _ts_decorate36([
4828
+ Injectable14(),
4829
+ _ts_metadata27("design:type", Function),
4830
+ _ts_metadata27("design:paramtypes", [
4831
+ typeof DataTableViewsRepository === "undefined" ? Object : DataTableViewsRepository,
4832
+ typeof CacheService === "undefined" ? Object : CacheService,
4833
+ typeof ConfigService7 === "undefined" ? Object : ConfigService7
4834
+ ])
4835
+ ], DataTableViewsService);
4836
+
4837
+ // src/data-table/views/controllers/data-table-views.controller.ts
4838
+ function _ts_decorate37(decorators, target, key, desc2) {
4839
+ var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
4840
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
4841
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4842
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
4843
+ }
4844
+ __name(_ts_decorate37, "_ts_decorate");
4845
+ function _ts_metadata28(k, v) {
4846
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
4847
+ }
4848
+ __name(_ts_metadata28, "_ts_metadata");
4849
+ function _ts_param9(paramIndex, decorator) {
4850
+ return function(target, key) {
4851
+ decorator(target, key, paramIndex);
4852
+ };
4853
+ }
4854
+ __name(_ts_param9, "_ts_param");
4855
+ var DataTableViewsController = class _DataTableViewsController {
4856
+ static {
4857
+ __name(this, "DataTableViewsController");
4858
+ }
4859
+ dataTableViewsService;
4860
+ logger = new Logger14(_DataTableViewsController.name);
4861
+ constructor(dataTableViewsService) {
4862
+ this.dataTableViewsService = dataTableViewsService;
4863
+ }
4864
+ // Returns all named views for the given table — own plus shared
4865
+ findViews(userId, tableSlug) {
4866
+ this.logger.log(`GET /table-views?tableSlug=${tableSlug} - User: ${userId}`);
4867
+ return this.dataTableViewsService.findViews(userId, tableSlug);
4868
+ }
4869
+ // Creates a named snapshot of the current table state
4870
+ createView(userId, dto) {
4871
+ this.logger.log(`POST /table-views - User: ${userId}, table: ${dto.tableSlug}`);
4872
+ return this.dataTableViewsService.createView(userId, dto);
4873
+ }
4874
+ // Updates state of an existing named view
4875
+ updateView(userId, id, dto) {
4876
+ this.logger.log(`PATCH /table-views/${id} - User: ${userId}`);
4877
+ return this.dataTableViewsService.updateView(userId, id, dto);
4878
+ }
4879
+ // Renames an existing named view — enforces unique name per user+table
4880
+ renameView(userId, id, dto) {
4881
+ this.logger.log(`PATCH /table-views/${id}/rename - User: ${userId}`);
4882
+ return this.dataTableViewsService.renameView(userId, id, dto.name);
4883
+ }
4884
+ // Toggles sharing visibility of a named view
4885
+ toggleShareView(userId, id, dto) {
4886
+ this.logger.log(`PATCH /table-views/${id}/share - User: ${userId}`);
4887
+ return this.dataTableViewsService.toggleShareView(userId, id, dto.isShared);
4888
+ }
4889
+ // Deletes a named view owned by the authenticated user
4890
+ deleteView(userId, id) {
4891
+ this.logger.log(`DELETE /table-views/${id} - User: ${userId}`);
4892
+ return this.dataTableViewsService.deleteView(userId, id);
4893
+ }
4894
+ };
4895
+ _ts_decorate37([
4896
+ Get3(),
4897
+ ApiListDataTableViews(),
4898
+ _ts_param9(0, UserId()),
4899
+ _ts_param9(1, Query("tableSlug")),
4900
+ _ts_metadata28("design:type", Function),
4901
+ _ts_metadata28("design:paramtypes", [
4902
+ String,
4903
+ String
4904
+ ]),
4905
+ _ts_metadata28("design:returntype", typeof Promise === "undefined" ? Object : Promise)
4906
+ ], DataTableViewsController.prototype, "findViews", null);
4907
+ _ts_decorate37([
4908
+ Post2(),
4909
+ HttpCode3(HttpStatus22.CREATED),
4910
+ ApiCreateDataTableView(),
4911
+ _ts_param9(0, UserId()),
4912
+ _ts_param9(1, Body2()),
4913
+ _ts_metadata28("design:type", Function),
4914
+ _ts_metadata28("design:paramtypes", [
4915
+ String,
4916
+ typeof CreateDataTableViewDto === "undefined" ? Object : CreateDataTableViewDto
4917
+ ]),
4918
+ _ts_metadata28("design:returntype", typeof Promise === "undefined" ? Object : Promise)
4919
+ ], DataTableViewsController.prototype, "createView", null);
4920
+ _ts_decorate37([
4921
+ Patch(":id"),
4922
+ ApiUpdateDataTableView(),
4923
+ _ts_param9(0, UserId()),
4924
+ _ts_param9(1, Param("id")),
4925
+ _ts_param9(2, Body2()),
4926
+ _ts_metadata28("design:type", Function),
4927
+ _ts_metadata28("design:paramtypes", [
4928
+ String,
4929
+ String,
4930
+ typeof UpdateDataTableViewDto === "undefined" ? Object : UpdateDataTableViewDto
4931
+ ]),
4932
+ _ts_metadata28("design:returntype", typeof Promise === "undefined" ? Object : Promise)
4933
+ ], DataTableViewsController.prototype, "updateView", null);
4934
+ _ts_decorate37([
4935
+ Patch(":id/rename"),
4936
+ ApiRenameDataTableView(),
4937
+ _ts_param9(0, UserId()),
4938
+ _ts_param9(1, Param("id")),
4939
+ _ts_param9(2, Body2()),
4940
+ _ts_metadata28("design:type", Function),
4941
+ _ts_metadata28("design:paramtypes", [
4942
+ String,
4943
+ String,
4944
+ typeof RenameDataTableViewDto === "undefined" ? Object : RenameDataTableViewDto
4945
+ ]),
4946
+ _ts_metadata28("design:returntype", typeof Promise === "undefined" ? Object : Promise)
4947
+ ], DataTableViewsController.prototype, "renameView", null);
4948
+ _ts_decorate37([
4949
+ Patch(":id/share"),
4950
+ ApiToggleShareDataTableView(),
4951
+ _ts_param9(0, UserId()),
4952
+ _ts_param9(1, Param("id")),
4953
+ _ts_param9(2, Body2()),
4954
+ _ts_metadata28("design:type", Function),
4955
+ _ts_metadata28("design:paramtypes", [
4956
+ String,
4957
+ String,
4958
+ typeof ToggleShareDataTableViewDto === "undefined" ? Object : ToggleShareDataTableViewDto
4959
+ ]),
4960
+ _ts_metadata28("design:returntype", typeof Promise === "undefined" ? Object : Promise)
4961
+ ], DataTableViewsController.prototype, "toggleShareView", null);
4962
+ _ts_decorate37([
4963
+ Delete(":id"),
4964
+ ApiDeleteDataTableView(),
4965
+ _ts_param9(0, UserId()),
4966
+ _ts_param9(1, Param("id")),
4967
+ _ts_metadata28("design:type", Function),
4968
+ _ts_metadata28("design:paramtypes", [
4969
+ String,
4970
+ String
4971
+ ]),
4972
+ _ts_metadata28("design:returntype", typeof Promise === "undefined" ? Object : Promise)
4973
+ ], DataTableViewsController.prototype, "deleteView", null);
4974
+ DataTableViewsController = _ts_decorate37([
4975
+ ApiTags4("Table Views"),
4976
+ ApiBearerAuth2(),
4977
+ RequireSession("CLOUD", "ADMIN"),
4978
+ Controller4("table-views"),
4979
+ _ts_metadata28("design:type", Function),
4980
+ _ts_metadata28("design:paramtypes", [
4981
+ typeof DataTableViewsService === "undefined" ? Object : DataTableViewsService
4982
+ ])
4983
+ ], DataTableViewsController);
4984
+
4985
+ // src/data-table/data-table.module.ts
4986
+ function _ts_decorate38(decorators, target, key, desc2) {
4987
+ var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
4988
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
4989
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4990
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
4991
+ }
4992
+ __name(_ts_decorate38, "_ts_decorate");
4993
+ var DataTableModule = class _DataTableModule {
4994
+ static {
4995
+ __name(this, "DataTableModule");
4996
+ }
4997
+ static forRoot(options) {
4998
+ return {
4999
+ global: true,
5000
+ module: _DataTableModule,
5001
+ imports: [
5002
+ ConfigModule4,
5003
+ CacheModule
5004
+ ],
5005
+ controllers: [
5006
+ DataTableStateController,
5007
+ DataTableViewsController
5008
+ ],
5009
+ providers: [
5010
+ {
5011
+ provide: DATA_TABLE_VIEWS_TABLE,
5012
+ useValue: options.tableViews
5013
+ },
5014
+ DataTableViewsService,
5015
+ DataTableViewsRepository,
5016
+ DataTableStateService
5017
+ ],
5018
+ exports: [
5019
+ DataTableViewsService,
5020
+ DataTableStateService
5021
+ ]
5022
+ };
5023
+ }
5024
+ };
5025
+ DataTableModule = _ts_decorate38([
5026
+ Module8({})
5027
+ ], DataTableModule);
5028
+
5029
+ // src/drizzle-pg-core.ts
5030
+ var drizzle_pg_core_exports = {};
5031
+ __reExport(drizzle_pg_core_exports, pg_core_star);
5032
+ import * as pg_core_star from "drizzle-orm/pg-core";
5033
+
5034
+ // src/data-table/schema/data-table-views.table.ts
5035
+ function dataTableViewsColumns() {
5036
+ return {
5037
+ id: (0, drizzle_pg_core_exports.uuid)("id").primaryKey().defaultRandom(),
5038
+ userId: (0, drizzle_pg_core_exports.uuid)("user_id").notNull(),
5039
+ tableSlug: (0, drizzle_pg_core_exports.varchar)("table_slug", {
5040
+ length: 100
5041
+ }).notNull(),
5042
+ name: (0, drizzle_pg_core_exports.varchar)("name", {
5043
+ length: 100
5044
+ }).notNull(),
5045
+ state: (0, drizzle_pg_core_exports.jsonb)("state").notNull().$type(),
5046
+ isShared: (0, drizzle_pg_core_exports.boolean)("is_shared").notNull().default(false),
5047
+ createdAt: (0, drizzle_pg_core_exports.timestamp)("created_at", {
5048
+ withTimezone: true
5049
+ }).notNull().defaultNow(),
5050
+ updatedAt: (0, drizzle_pg_core_exports.timestamp)("updated_at", {
5051
+ withTimezone: true
5052
+ }).$onUpdate(() => /* @__PURE__ */ new Date())
5053
+ };
5054
+ }
5055
+ __name(dataTableViewsColumns, "dataTableViewsColumns");
5056
+ function dataTableViewsIndexes(table) {
5057
+ return [
5058
+ (0, drizzle_pg_core_exports.index)("table_views_user_table_idx").on(table.userId, table.tableSlug),
5059
+ (0, drizzle_pg_core_exports.index)("table_views_shared_slug_idx").on(table.tableSlug, table.isShared),
5060
+ (0, drizzle_pg_core_exports.uniqueIndex)("table_views_user_table_name_shared_unique").on(table.userId, table.tableSlug, table.name, table.isShared)
5061
+ ];
5062
+ }
5063
+ __name(dataTableViewsIndexes, "dataTableViewsIndexes");
4236
5064
  export {
4237
5065
  AccessToken,
4238
5066
  AuthConfigModule,
@@ -4244,7 +5072,14 @@ export {
4244
5072
  ConflictException,
4245
5073
  CookieDomain,
4246
5074
  CorrelationIdMiddleware,
5075
+ CreateDataTableViewDto,
5076
+ CreateResponseDto,
5077
+ DATA_TABLE_VIEWS_TABLE,
4247
5078
  DEFAULT_CORRELATION_HEADER,
5079
+ DataTableModule,
5080
+ DataTableStateService,
5081
+ DataTableViewDto,
5082
+ DataTableViewsService,
4248
5083
  DatabaseModule,
4249
5084
  EmailModule,
4250
5085
  EmailService,
@@ -4254,6 +5089,8 @@ export {
4254
5089
  HttpExceptionFilter,
4255
5090
  HttpLoggerInterceptor,
4256
5091
  HttpProblemException,
5092
+ ImportResponseDto,
5093
+ ImportSummaryDto,
4257
5094
  InternalServerErrorException,
4258
5095
  JwtAuthService,
4259
5096
  LOGGER_MODULE_OPTIONS,
@@ -4263,40 +5100,44 @@ export {
4263
5100
  NotAcceptableException,
4264
5101
  NotFoundException,
4265
5102
  NotImplementedException,
4266
- Onboarding,
4267
5103
  PayloadTooLargeException,
4268
5104
  PrimaryBaseRepository,
4269
5105
  PrimaryDatabaseService,
4270
5106
  Public,
4271
- RESET_KEY,
5107
+ REQUIRE_SESSION_KEY,
4272
5108
  RedisCacheProvider,
4273
5109
  RefreshCookieOptions,
4274
5110
  RefreshTokenCookie,
5111
+ RenameDataTableViewDto,
4275
5112
  RequestTimeoutException,
4276
- Reset,
5113
+ RequireSession,
4277
5114
  RootModule,
4278
5115
  SKIP_CSRF_KEY,
4279
5116
  SelectOptionsQueryDto,
4280
5117
  ServiceUnavailableException,
4281
5118
  SessionData,
4282
5119
  SkipCsrf,
5120
+ Subdomain,
4283
5121
  SuccessResponseDto,
4284
5122
  TableResponseDto,
4285
- Tenant,
4286
- TenantBaseRepository,
4287
- TenantContextService,
4288
- TenantDatabaseService,
5123
+ ToggleShareDataTableViewDto,
4289
5124
  TokenType,
4290
5125
  TooManyRequestsException,
4291
5126
  UnauthorizedException,
4292
5127
  UnprocessableEntityException,
4293
5128
  UnsupportedMediaTypeException,
5129
+ UpdateDataTableViewDto,
5130
+ UploadedFile,
5131
+ UpsertDataTableStateDto,
4294
5132
  UserId,
5133
+ ValidatedRowDto,
4295
5134
  ValidationException,
4296
5135
  VrittiAuthGuard,
4297
5136
  addCorrelationIdToResponse,
4298
5137
  configureApiSdk,
4299
5138
  correlationStorage,
5139
+ dataTableViewsColumns,
5140
+ dataTableViewsIndexes,
4300
5141
  defineConfig,
4301
5142
  extractCountryFromPhone,
4302
5143
  generateCorrelationId,