@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.cjs +1692 -850
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +189 -109
- package/dist/index.d.ts +189 -109
- package/dist/index.js +1634 -793
- package/dist/index.js.map +1 -1
- package/dist/xlsx.cjs +88 -0
- package/dist/xlsx.cjs.map +1 -0
- package/dist/xlsx.d.cts +6 -0
- package/dist/xlsx.d.ts +6 -0
- package/dist/xlsx.js +61 -0
- package/dist/xlsx.js.map +1 -0
- package/package.json +15 -4
package/dist/index.cjs
CHANGED
|
@@ -18,6 +18,7 @@ var __copyProps = (to, from, except, desc2) => {
|
|
|
18
18
|
}
|
|
19
19
|
return to;
|
|
20
20
|
};
|
|
21
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
21
22
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
23
|
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
24
|
// file that has been converted to a CommonJS file using a Babel-
|
|
@@ -41,7 +42,14 @@ __export(index_exports, {
|
|
|
41
42
|
ConflictException: () => ConflictException,
|
|
42
43
|
CookieDomain: () => CookieDomain,
|
|
43
44
|
CorrelationIdMiddleware: () => CorrelationIdMiddleware,
|
|
45
|
+
CreateDataTableViewDto: () => CreateDataTableViewDto,
|
|
46
|
+
CreateResponseDto: () => CreateResponseDto,
|
|
47
|
+
DATA_TABLE_VIEWS_TABLE: () => DATA_TABLE_VIEWS_TABLE,
|
|
44
48
|
DEFAULT_CORRELATION_HEADER: () => DEFAULT_CORRELATION_HEADER,
|
|
49
|
+
DataTableModule: () => DataTableModule,
|
|
50
|
+
DataTableStateService: () => DataTableStateService,
|
|
51
|
+
DataTableViewDto: () => DataTableViewDto,
|
|
52
|
+
DataTableViewsService: () => DataTableViewsService,
|
|
45
53
|
DatabaseModule: () => DatabaseModule,
|
|
46
54
|
EmailModule: () => EmailModule,
|
|
47
55
|
EmailService: () => EmailService,
|
|
@@ -51,6 +59,8 @@ __export(index_exports, {
|
|
|
51
59
|
HttpExceptionFilter: () => HttpExceptionFilter,
|
|
52
60
|
HttpLoggerInterceptor: () => HttpLoggerInterceptor,
|
|
53
61
|
HttpProblemException: () => HttpProblemException,
|
|
62
|
+
ImportResponseDto: () => ImportResponseDto,
|
|
63
|
+
ImportSummaryDto: () => ImportSummaryDto,
|
|
54
64
|
InternalServerErrorException: () => InternalServerErrorException,
|
|
55
65
|
JwtAuthService: () => JwtAuthService,
|
|
56
66
|
LOGGER_MODULE_OPTIONS: () => LOGGER_MODULE_OPTIONS,
|
|
@@ -60,40 +70,44 @@ __export(index_exports, {
|
|
|
60
70
|
NotAcceptableException: () => NotAcceptableException,
|
|
61
71
|
NotFoundException: () => NotFoundException,
|
|
62
72
|
NotImplementedException: () => NotImplementedException,
|
|
63
|
-
Onboarding: () => Onboarding,
|
|
64
73
|
PayloadTooLargeException: () => PayloadTooLargeException,
|
|
65
74
|
PrimaryBaseRepository: () => PrimaryBaseRepository,
|
|
66
75
|
PrimaryDatabaseService: () => PrimaryDatabaseService,
|
|
67
76
|
Public: () => Public,
|
|
68
|
-
|
|
77
|
+
REQUIRE_SESSION_KEY: () => REQUIRE_SESSION_KEY,
|
|
69
78
|
RedisCacheProvider: () => RedisCacheProvider,
|
|
70
79
|
RefreshCookieOptions: () => RefreshCookieOptions,
|
|
71
80
|
RefreshTokenCookie: () => RefreshTokenCookie,
|
|
81
|
+
RenameDataTableViewDto: () => RenameDataTableViewDto,
|
|
72
82
|
RequestTimeoutException: () => RequestTimeoutException,
|
|
73
|
-
|
|
83
|
+
RequireSession: () => RequireSession,
|
|
74
84
|
RootModule: () => RootModule,
|
|
75
85
|
SKIP_CSRF_KEY: () => SKIP_CSRF_KEY,
|
|
76
86
|
SelectOptionsQueryDto: () => SelectOptionsQueryDto,
|
|
77
87
|
ServiceUnavailableException: () => ServiceUnavailableException,
|
|
78
88
|
SessionData: () => SessionData,
|
|
79
89
|
SkipCsrf: () => SkipCsrf,
|
|
90
|
+
Subdomain: () => Subdomain,
|
|
80
91
|
SuccessResponseDto: () => SuccessResponseDto,
|
|
81
92
|
TableResponseDto: () => TableResponseDto,
|
|
82
|
-
|
|
83
|
-
TenantBaseRepository: () => TenantBaseRepository,
|
|
84
|
-
TenantContextService: () => TenantContextService,
|
|
85
|
-
TenantDatabaseService: () => TenantDatabaseService,
|
|
93
|
+
ToggleShareDataTableViewDto: () => ToggleShareDataTableViewDto,
|
|
86
94
|
TokenType: () => TokenType,
|
|
87
95
|
TooManyRequestsException: () => TooManyRequestsException,
|
|
88
96
|
UnauthorizedException: () => UnauthorizedException,
|
|
89
97
|
UnprocessableEntityException: () => UnprocessableEntityException,
|
|
90
98
|
UnsupportedMediaTypeException: () => UnsupportedMediaTypeException,
|
|
99
|
+
UpdateDataTableViewDto: () => UpdateDataTableViewDto,
|
|
100
|
+
UploadedFile: () => UploadedFile,
|
|
101
|
+
UpsertDataTableStateDto: () => UpsertDataTableStateDto,
|
|
91
102
|
UserId: () => UserId,
|
|
103
|
+
ValidatedRowDto: () => ValidatedRowDto,
|
|
92
104
|
ValidationException: () => ValidationException,
|
|
93
105
|
VrittiAuthGuard: () => VrittiAuthGuard,
|
|
94
106
|
addCorrelationIdToResponse: () => addCorrelationIdToResponse,
|
|
95
107
|
configureApiSdk: () => configureApiSdk,
|
|
96
108
|
correlationStorage: () => correlationStorage,
|
|
109
|
+
dataTableViewsColumns: () => dataTableViewsColumns,
|
|
110
|
+
dataTableViewsIndexes: () => dataTableViewsIndexes,
|
|
97
111
|
defineConfig: () => defineConfig,
|
|
98
112
|
extractCountryFromPhone: () => extractCountryFromPhone,
|
|
99
113
|
generateCorrelationId: () => generateCorrelationId,
|
|
@@ -117,7 +131,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
117
131
|
|
|
118
132
|
// src/auth/auth-config.module.ts
|
|
119
133
|
var import_common26 = require("@nestjs/common");
|
|
120
|
-
var
|
|
134
|
+
var import_config5 = require("@nestjs/config");
|
|
121
135
|
var import_core3 = require("@nestjs/core");
|
|
122
136
|
var import_jwt4 = require("@nestjs/jwt");
|
|
123
137
|
|
|
@@ -365,7 +379,10 @@ var defaultConfig = {
|
|
|
365
379
|
guard: {
|
|
366
380
|
tenantHeaderName: "x-tenant-id",
|
|
367
381
|
authHeaderName: "authorization",
|
|
368
|
-
tokenPrefix: "Bearer"
|
|
382
|
+
tokenPrefix: "Bearer",
|
|
383
|
+
defaultSessionTypes: [
|
|
384
|
+
"CLOUD"
|
|
385
|
+
]
|
|
369
386
|
}
|
|
370
387
|
};
|
|
371
388
|
var currentConfig = {
|
|
@@ -553,10 +570,10 @@ var import_config2 = require("@nestjs/config");
|
|
|
553
570
|
var import_core2 = require("@nestjs/core");
|
|
554
571
|
var import_jwt = require("@nestjs/jwt");
|
|
555
572
|
|
|
556
|
-
// src/auth/decorators/
|
|
573
|
+
// src/auth/decorators/require-session.decorator.ts
|
|
557
574
|
var import_common22 = require("@nestjs/common");
|
|
558
|
-
var
|
|
559
|
-
var
|
|
575
|
+
var REQUIRE_SESSION_KEY = "requiredSessionTypes";
|
|
576
|
+
var RequireSession = /* @__PURE__ */ __name((...types) => (0, import_common22.SetMetadata)(REQUIRE_SESSION_KEY, types), "RequireSession");
|
|
560
577
|
|
|
561
578
|
// src/auth/decorators/skip-csrf.decorator.ts
|
|
562
579
|
var import_common23 = require("@nestjs/common");
|
|
@@ -620,17 +637,13 @@ var VrittiAuthGuard = class _VrittiAuthGuard {
|
|
|
620
637
|
if (isPublic) {
|
|
621
638
|
return true;
|
|
622
639
|
}
|
|
623
|
-
const
|
|
624
|
-
context.getHandler(),
|
|
625
|
-
context.getClass()
|
|
626
|
-
]);
|
|
627
|
-
const isReset = this.reflector.getAllAndOverride(RESET_KEY, [
|
|
640
|
+
const requiredSessionTypes = this.reflector.getAllAndOverride(REQUIRE_SESSION_KEY, [
|
|
628
641
|
context.getHandler(),
|
|
629
642
|
context.getClass()
|
|
630
643
|
]);
|
|
631
644
|
const isSseEndpoint = this.reflector.get(import_constants.SSE_METADATA, context.getHandler());
|
|
632
645
|
if (isSseEndpoint) {
|
|
633
|
-
return this.handleSseAuth(request,
|
|
646
|
+
return this.handleSseAuth(request, requiredSessionTypes);
|
|
634
647
|
}
|
|
635
648
|
try {
|
|
636
649
|
const accessToken = this.requestService.getAccessToken();
|
|
@@ -642,14 +655,10 @@ var VrittiAuthGuard = class _VrittiAuthGuard {
|
|
|
642
655
|
throw new import_common24.UnauthorizedException("Invalid token type");
|
|
643
656
|
}
|
|
644
657
|
this.validateRefreshTokenBinding(decodedAccessToken);
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
throw new import_common24.UnauthorizedException("This endpoint requires a reset session");
|
|
650
|
-
}
|
|
651
|
-
if (!isOnboarding && !isReset && (decodedAccessToken.sessionType === "ONBOARDING" || decodedAccessToken.sessionType === "RESET")) {
|
|
652
|
-
throw new import_common24.UnauthorizedException(`${decodedAccessToken.sessionType} sessions cannot access this endpoint`);
|
|
658
|
+
const sessionType = decodedAccessToken.sessionType;
|
|
659
|
+
const allowed = requiredSessionTypes ?? getConfig().guard.defaultSessionTypes;
|
|
660
|
+
if (!allowed.includes(sessionType)) {
|
|
661
|
+
throw new import_common24.UnauthorizedException(`${sessionType} sessions cannot access this endpoint`);
|
|
653
662
|
}
|
|
654
663
|
request.sessionInfo = {
|
|
655
664
|
userId: decodedAccessToken.userId,
|
|
@@ -698,7 +707,7 @@ var VrittiAuthGuard = class _VrittiAuthGuard {
|
|
|
698
707
|
}
|
|
699
708
|
}
|
|
700
709
|
// Authenticates SSE connections using the refresh token httpOnly cookie
|
|
701
|
-
handleSseAuth(request,
|
|
710
|
+
handleSseAuth(request, requiredSessionTypes) {
|
|
702
711
|
const refreshToken = this.requestService.getRefreshToken();
|
|
703
712
|
if (!refreshToken) {
|
|
704
713
|
throw new import_common24.UnauthorizedException("Authentication required");
|
|
@@ -712,8 +721,9 @@ var VrittiAuthGuard = class _VrittiAuthGuard {
|
|
|
712
721
|
if (decoded.tokenType !== "refresh") {
|
|
713
722
|
throw new import_common24.UnauthorizedException("Invalid token type");
|
|
714
723
|
}
|
|
715
|
-
|
|
716
|
-
|
|
724
|
+
const allowed = requiredSessionTypes ?? getConfig().guard.defaultSessionTypes;
|
|
725
|
+
if (!allowed.includes(decoded.sessionType)) {
|
|
726
|
+
throw new import_common24.UnauthorizedException(`${decoded.sessionType} sessions cannot access this endpoint`);
|
|
717
727
|
}
|
|
718
728
|
request.sessionInfo = {
|
|
719
729
|
userId: decoded.userId,
|
|
@@ -777,7 +787,7 @@ VrittiAuthGuard = _ts_decorate3([
|
|
|
777
787
|
|
|
778
788
|
// src/auth/services/jwt-auth.service.ts
|
|
779
789
|
var import_common25 = require("@nestjs/common");
|
|
780
|
-
var
|
|
790
|
+
var import_config4 = require("@nestjs/config");
|
|
781
791
|
var import_jwt2 = require("@nestjs/jwt");
|
|
782
792
|
|
|
783
793
|
// src/utils/time.utils.ts
|
|
@@ -893,7 +903,7 @@ JwtAuthService = _ts_decorate4([
|
|
|
893
903
|
_ts_metadata3("design:type", Function),
|
|
894
904
|
_ts_metadata3("design:paramtypes", [
|
|
895
905
|
typeof import_jwt2.JwtService === "undefined" ? Object : import_jwt2.JwtService,
|
|
896
|
-
typeof
|
|
906
|
+
typeof import_config4.ConfigService === "undefined" ? Object : import_config4.ConfigService
|
|
897
907
|
])
|
|
898
908
|
], JwtAuthService);
|
|
899
909
|
|
|
@@ -914,14 +924,14 @@ var AuthConfigModule = class _AuthConfigModule {
|
|
|
914
924
|
return {
|
|
915
925
|
module: _AuthConfigModule,
|
|
916
926
|
imports: [
|
|
917
|
-
|
|
927
|
+
import_config5.ConfigModule,
|
|
918
928
|
RequestModule,
|
|
919
929
|
import_jwt4.JwtModule.registerAsync({
|
|
920
930
|
imports: [
|
|
921
|
-
|
|
931
|
+
import_config5.ConfigModule
|
|
922
932
|
],
|
|
923
933
|
inject: [
|
|
924
|
-
|
|
934
|
+
import_config5.ConfigService
|
|
925
935
|
],
|
|
926
936
|
useFactory: /* @__PURE__ */ __name((config) => ({
|
|
927
937
|
secret: config.get("JWT_SECRET"),
|
|
@@ -975,17 +985,13 @@ var CookieDomain = (0, import_common28.createParamDecorator)((_data, ctx) => {
|
|
|
975
985
|
return domain.endsWith(`.${baseDomain}`) ? domain : baseDomain;
|
|
976
986
|
});
|
|
977
987
|
|
|
978
|
-
// src/auth/decorators/onboarding.decorator.ts
|
|
979
|
-
var import_common29 = require("@nestjs/common");
|
|
980
|
-
var Onboarding = /* @__PURE__ */ __name(() => (0, import_common29.SetMetadata)("isOnboarding", true), "Onboarding");
|
|
981
|
-
|
|
982
988
|
// src/auth/decorators/public.decorator.ts
|
|
983
|
-
var
|
|
984
|
-
var Public = /* @__PURE__ */ __name(() => (0,
|
|
989
|
+
var import_common29 = require("@nestjs/common");
|
|
990
|
+
var Public = /* @__PURE__ */ __name(() => (0, import_common29.SetMetadata)("isPublic", true), "Public");
|
|
985
991
|
|
|
986
992
|
// src/auth/decorators/refresh-cookie-options.decorator.ts
|
|
987
|
-
var
|
|
988
|
-
var RefreshCookieOptions = (0,
|
|
993
|
+
var import_common30 = require("@nestjs/common");
|
|
994
|
+
var RefreshCookieOptions = (0, import_common30.createParamDecorator)((_data, ctx) => {
|
|
989
995
|
const request = ctx.switchToHttp().getRequest();
|
|
990
996
|
const forwarded = request.headers["x-forwarded-host"];
|
|
991
997
|
const raw = Array.isArray(forwarded) ? forwarded[0] : forwarded;
|
|
@@ -995,14 +1001,32 @@ var RefreshCookieOptions = (0, import_common31.createParamDecorator)((_data, ctx
|
|
|
995
1001
|
});
|
|
996
1002
|
|
|
997
1003
|
// src/auth/decorators/refresh-token-cookie.decorator.ts
|
|
998
|
-
var
|
|
999
|
-
var RefreshTokenCookie = (0,
|
|
1004
|
+
var import_common31 = require("@nestjs/common");
|
|
1005
|
+
var RefreshTokenCookie = (0, import_common31.createParamDecorator)((_data, ctx) => {
|
|
1000
1006
|
const request = ctx.switchToHttp().getRequest();
|
|
1001
1007
|
const cookies = request.cookies ?? {};
|
|
1002
1008
|
const config = getConfig();
|
|
1003
1009
|
return cookies[config.cookie.refreshCookieName];
|
|
1004
1010
|
});
|
|
1005
1011
|
|
|
1012
|
+
// src/auth/decorators/subdomain.decorator.ts
|
|
1013
|
+
var import_common32 = require("@nestjs/common");
|
|
1014
|
+
var Subdomain = (0, import_common32.createParamDecorator)((_data, ctx) => {
|
|
1015
|
+
const request = ctx.switchToHttp().getRequest();
|
|
1016
|
+
const origin = request.headers.origin;
|
|
1017
|
+
if (origin) {
|
|
1018
|
+
try {
|
|
1019
|
+
const url = new URL(origin);
|
|
1020
|
+
return url.hostname.split(".")[0];
|
|
1021
|
+
} catch {
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
const forwarded = request.headers["x-forwarded-host"];
|
|
1025
|
+
const host = Array.isArray(forwarded) ? forwarded[0] : forwarded;
|
|
1026
|
+
if (host) return host.split(".")[0];
|
|
1027
|
+
return void 0;
|
|
1028
|
+
});
|
|
1029
|
+
|
|
1006
1030
|
// src/auth/decorators/session-data.decorator.ts
|
|
1007
1031
|
var import_common33 = require("@nestjs/common");
|
|
1008
1032
|
var SessionData = (0, import_common33.createParamDecorator)((_data, ctx) => {
|
|
@@ -1031,7 +1055,7 @@ var UserId = (0, import_common34.createParamDecorator)((_data, ctx) => {
|
|
|
1031
1055
|
|
|
1032
1056
|
// src/cache/cache.module.ts
|
|
1033
1057
|
var import_common37 = require("@nestjs/common");
|
|
1034
|
-
var
|
|
1058
|
+
var import_config10 = require("@nestjs/config");
|
|
1035
1059
|
|
|
1036
1060
|
// src/cache/cache.service.ts
|
|
1037
1061
|
var import_common35 = require("@nestjs/common");
|
|
@@ -1121,7 +1145,7 @@ CacheService = _ts_decorate6([
|
|
|
1121
1145
|
|
|
1122
1146
|
// src/cache/providers/redis.provider.ts
|
|
1123
1147
|
var import_common36 = require("@nestjs/common");
|
|
1124
|
-
var
|
|
1148
|
+
var import_config9 = require("@nestjs/config");
|
|
1125
1149
|
var import_ioredis = __toESM(require("ioredis"), 1);
|
|
1126
1150
|
function _ts_decorate7(decorators, target, key, desc2) {
|
|
1127
1151
|
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
@@ -1196,7 +1220,7 @@ RedisCacheProvider = _ts_decorate7([
|
|
|
1196
1220
|
(0, import_common36.Injectable)(),
|
|
1197
1221
|
_ts_metadata5("design:type", Function),
|
|
1198
1222
|
_ts_metadata5("design:paramtypes", [
|
|
1199
|
-
typeof
|
|
1223
|
+
typeof import_config9.ConfigService === "undefined" ? Object : import_config9.ConfigService
|
|
1200
1224
|
])
|
|
1201
1225
|
], RedisCacheProvider);
|
|
1202
1226
|
|
|
@@ -1216,7 +1240,7 @@ var CacheModule = class {
|
|
|
1216
1240
|
CacheModule = _ts_decorate8([
|
|
1217
1241
|
(0, import_common37.Module)({
|
|
1218
1242
|
imports: [
|
|
1219
|
-
|
|
1243
|
+
import_config10.ConfigModule
|
|
1220
1244
|
],
|
|
1221
1245
|
providers: [
|
|
1222
1246
|
RedisCacheProvider,
|
|
@@ -1235,7 +1259,7 @@ CacheModule = _ts_decorate8([
|
|
|
1235
1259
|
], CacheModule);
|
|
1236
1260
|
|
|
1237
1261
|
// src/database/database.module.ts
|
|
1238
|
-
var
|
|
1262
|
+
var import_common39 = require("@nestjs/common");
|
|
1239
1263
|
var import_core4 = require("@nestjs/core");
|
|
1240
1264
|
|
|
1241
1265
|
// src/database/constants.ts
|
|
@@ -1243,7 +1267,6 @@ var DATABASE_MODULE_OPTIONS = Symbol("DATABASE_MODULE_OPTIONS");
|
|
|
1243
1267
|
|
|
1244
1268
|
// src/database/services/primary-database.service.ts
|
|
1245
1269
|
var import_common38 = require("@nestjs/common");
|
|
1246
|
-
var import_drizzle_orm = require("drizzle-orm");
|
|
1247
1270
|
var import_node_postgres = require("drizzle-orm/node-postgres");
|
|
1248
1271
|
var import_pg = require("pg");
|
|
1249
1272
|
function _ts_decorate9(decorators, target, key, desc2) {
|
|
@@ -1271,11 +1294,8 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
|
|
|
1271
1294
|
logger = new import_common38.Logger(_PrimaryDatabaseService.name);
|
|
1272
1295
|
pool = null;
|
|
1273
1296
|
db = null;
|
|
1274
|
-
tenantConfigCache = /* @__PURE__ */ new Map();
|
|
1275
|
-
cacheTTL;
|
|
1276
1297
|
constructor(options) {
|
|
1277
1298
|
this.options = options;
|
|
1278
|
-
this.cacheTTL = options.connectionCacheTTL || 3e5;
|
|
1279
1299
|
}
|
|
1280
1300
|
async onModuleInit() {
|
|
1281
1301
|
if (this.options.primaryDb) {
|
|
@@ -1285,10 +1305,20 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
|
|
|
1285
1305
|
// Initializes connection to primary database using Drizzle
|
|
1286
1306
|
async initializeDrizzleClient() {
|
|
1287
1307
|
try {
|
|
1288
|
-
const
|
|
1308
|
+
const { host, port = 5432, username, password, database, schema, sslMode = "require" } = this.options.primaryDb;
|
|
1289
1309
|
this.pool = new import_pg.Pool({
|
|
1290
|
-
|
|
1291
|
-
|
|
1310
|
+
host,
|
|
1311
|
+
port,
|
|
1312
|
+
user: username,
|
|
1313
|
+
password,
|
|
1314
|
+
database,
|
|
1315
|
+
max: this.options.maxConnections || 10,
|
|
1316
|
+
ssl: sslMode === "disable" ? false : {
|
|
1317
|
+
rejectUnauthorized: sslMode !== "no-verify"
|
|
1318
|
+
},
|
|
1319
|
+
...schema && {
|
|
1320
|
+
options: `-csearch_path=${schema}`
|
|
1321
|
+
}
|
|
1292
1322
|
});
|
|
1293
1323
|
this.logger.debug(`Schema keys passed to drizzle: [${Object.keys(this.options.drizzleSchema || {}).join(", ")}]`);
|
|
1294
1324
|
this.logger.debug(`Relations keys passed to drizzle: [${Object.keys(this.options.drizzleRelations || {}).join(", ")}]`);
|
|
@@ -1299,110 +1329,13 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
|
|
|
1299
1329
|
});
|
|
1300
1330
|
this.logger.debug(`Drizzle query keys after init: [${Object.keys(this.db.query || {}).join(", ")}]`);
|
|
1301
1331
|
await this.pool.query("SELECT 1");
|
|
1302
|
-
this.logger.log(
|
|
1332
|
+
this.logger.log(`Connected to primary database (schema: ${schema ?? "public"})`);
|
|
1303
1333
|
} catch (error) {
|
|
1304
1334
|
this.logger.error("Failed to connect to primary database", error);
|
|
1305
|
-
throw new import_common38.InternalServerErrorException("Failed to initialize
|
|
1306
|
-
}
|
|
1307
|
-
}
|
|
1308
|
-
// Builds the PostgreSQL connection URL from primary database config properties
|
|
1309
|
-
buildPrimaryDbUrl() {
|
|
1310
|
-
if (!this.options.primaryDb) {
|
|
1311
|
-
throw new Error("Primary database configuration not provided");
|
|
1312
|
-
}
|
|
1313
|
-
const { host, port = 5432, username, password, database, schema = "public", sslMode = "require" } = this.options.primaryDb;
|
|
1314
|
-
let url = `postgresql://${username}:${encodeURIComponent(password)}@${host}:${port}/${database}`;
|
|
1315
|
-
const params = new URLSearchParams();
|
|
1316
|
-
if (schema) {
|
|
1317
|
-
params.set("schema", schema);
|
|
1318
|
-
}
|
|
1319
|
-
params.set("sslmode", sslMode);
|
|
1320
|
-
const queryString = params.toString();
|
|
1321
|
-
if (queryString) {
|
|
1322
|
-
url += `?${queryString}`;
|
|
1323
|
-
}
|
|
1324
|
-
this.logger.debug(`Primary DB connection URL: ${this.maskPassword(url)}`);
|
|
1325
|
-
return url;
|
|
1326
|
-
}
|
|
1327
|
-
// Masks password in connection URL for safe logging
|
|
1328
|
-
maskPassword(url) {
|
|
1329
|
-
return url.replace(/:([^@]+)@/, ":****@");
|
|
1330
|
-
}
|
|
1331
|
-
// Retrieves tenant configuration by ID or subdomain, with in-memory caching
|
|
1332
|
-
async getTenantInfo(tenantIdentifier) {
|
|
1333
|
-
const cached = this.tenantConfigCache.get(tenantIdentifier);
|
|
1334
|
-
if (cached) {
|
|
1335
|
-
this.logger.debug(`Cache hit for tenant: ${tenantIdentifier}`);
|
|
1336
|
-
return cached;
|
|
1337
|
-
}
|
|
1338
|
-
try {
|
|
1339
|
-
if (!this.db) {
|
|
1340
|
-
throw new Error("Primary database client not initialized");
|
|
1341
|
-
}
|
|
1342
|
-
this.logger.debug(`Querying primary database for tenant: ${tenantIdentifier}`);
|
|
1343
|
-
const schema = this.options.drizzleSchema;
|
|
1344
|
-
const { tenants, tenantDatabaseConfigs } = schema;
|
|
1345
|
-
const result = await this.db.select().from(tenants).leftJoin(tenantDatabaseConfigs, (0, import_drizzle_orm.eq)(tenants.id, tenantDatabaseConfigs.tenantId)).where((0, import_drizzle_orm.or)((0, import_drizzle_orm.eq)(tenants.id, tenantIdentifier), (0, import_drizzle_orm.eq)(tenants.subdomain, tenantIdentifier))).limit(1);
|
|
1346
|
-
if (!result.length) {
|
|
1347
|
-
this.logger.warn(`Tenant not found: ${tenantIdentifier}`);
|
|
1348
|
-
return null;
|
|
1349
|
-
}
|
|
1350
|
-
const row = result[0];
|
|
1351
|
-
const tenant = row.tenants;
|
|
1352
|
-
const config = row.tenant_database_configs;
|
|
1353
|
-
if (tenant.status !== "ACTIVE") {
|
|
1354
|
-
this.logger.warn(`Tenant not active: ${tenantIdentifier}`);
|
|
1355
|
-
return null;
|
|
1356
|
-
}
|
|
1357
|
-
const info = {
|
|
1358
|
-
id: tenant.id,
|
|
1359
|
-
subdomain: tenant.subdomain,
|
|
1360
|
-
type: tenant.dbType,
|
|
1361
|
-
status: tenant.status,
|
|
1362
|
-
// For SHARED tenants: schema name
|
|
1363
|
-
schemaName: config?.dbSchema || void 0,
|
|
1364
|
-
// For DEDICATED tenants: database configuration from TenantDatabaseConfig table
|
|
1365
|
-
databaseName: config?.dbName || void 0,
|
|
1366
|
-
databaseHost: config?.dbHost || void 0,
|
|
1367
|
-
databasePort: config?.dbPort || void 0,
|
|
1368
|
-
databaseUsername: config?.dbUsername ? this.decrypt(config.dbUsername) : void 0,
|
|
1369
|
-
databasePassword: config?.dbPassword ? this.decrypt(config.dbPassword) : void 0,
|
|
1370
|
-
databaseSslMode: config?.dbSslMode || void 0,
|
|
1371
|
-
connectionPoolSize: config?.connectionPoolSize || void 0
|
|
1372
|
-
};
|
|
1373
|
-
this.cacheInfo(info);
|
|
1374
|
-
return info;
|
|
1375
|
-
} catch (error) {
|
|
1376
|
-
this.logger.error(`Failed to fetch tenant info: ${tenantIdentifier}`, error);
|
|
1377
|
-
throw new import_common38.InternalServerErrorException("Failed to resolve tenant");
|
|
1378
|
-
}
|
|
1379
|
-
}
|
|
1380
|
-
// Caches tenant info by both ID and subdomain with TTL expiration
|
|
1381
|
-
cacheInfo(info) {
|
|
1382
|
-
this.tenantConfigCache.set(info.id, info);
|
|
1383
|
-
this.tenantConfigCache.set(info.subdomain, info);
|
|
1384
|
-
setTimeout(() => {
|
|
1385
|
-
this.tenantConfigCache.delete(info.id);
|
|
1386
|
-
this.tenantConfigCache.delete(info.subdomain);
|
|
1387
|
-
this.logger.debug(`Cache expired for tenant: ${info.subdomain}`);
|
|
1388
|
-
}, this.cacheTTL);
|
|
1389
|
-
}
|
|
1390
|
-
// Clears cached tenant info for the given ID or subdomain
|
|
1391
|
-
clearTenantCache(tenantIdentifier) {
|
|
1392
|
-
const config = this.tenantConfigCache.get(tenantIdentifier);
|
|
1393
|
-
if (config) {
|
|
1394
|
-
this.tenantConfigCache.delete(config.id);
|
|
1395
|
-
this.tenantConfigCache.delete(config.subdomain);
|
|
1396
|
-
this.logger.log(`Cleared cache for tenant: ${tenantIdentifier}`);
|
|
1335
|
+
throw new import_common38.InternalServerErrorException("Failed to initialize database connection");
|
|
1397
1336
|
}
|
|
1398
1337
|
}
|
|
1399
|
-
//
|
|
1400
|
-
clearAllCaches() {
|
|
1401
|
-
const size = this.tenantConfigCache.size;
|
|
1402
|
-
this.tenantConfigCache.clear();
|
|
1403
|
-
this.logger.log(`Cleared ${size} cached tenant configs`);
|
|
1404
|
-
}
|
|
1405
|
-
// Returns the initialized Drizzle client, throwing if not yet initialized
|
|
1338
|
+
// Returns the initialized Drizzle client
|
|
1406
1339
|
get drizzleClient() {
|
|
1407
1340
|
if (!this.db) {
|
|
1408
1341
|
throw new Error("Primary database client not initialized");
|
|
@@ -1413,10 +1346,6 @@ var PrimaryDatabaseService = class _PrimaryDatabaseService {
|
|
|
1413
1346
|
get schema() {
|
|
1414
1347
|
return this.options.drizzleSchema;
|
|
1415
1348
|
}
|
|
1416
|
-
// Decrypts a database credential value (placeholder for actual decryption)
|
|
1417
|
-
decrypt(encrypted) {
|
|
1418
|
-
return encrypted;
|
|
1419
|
-
}
|
|
1420
1349
|
async onModuleDestroy() {
|
|
1421
1350
|
if (this.pool) {
|
|
1422
1351
|
await this.pool.end();
|
|
@@ -1433,8 +1362,7 @@ PrimaryDatabaseService = _ts_decorate9([
|
|
|
1433
1362
|
])
|
|
1434
1363
|
], PrimaryDatabaseService);
|
|
1435
1364
|
|
|
1436
|
-
// src/database/
|
|
1437
|
-
var import_common39 = require("@nestjs/common");
|
|
1365
|
+
// src/database/database.module.ts
|
|
1438
1366
|
function _ts_decorate10(decorators, target, key, desc2) {
|
|
1439
1367
|
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
1440
1368
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
|
|
@@ -1442,52 +1370,63 @@ function _ts_decorate10(decorators, target, key, desc2) {
|
|
|
1442
1370
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1443
1371
|
}
|
|
1444
1372
|
__name(_ts_decorate10, "_ts_decorate");
|
|
1445
|
-
var
|
|
1373
|
+
var DatabaseModule = class _DatabaseModule {
|
|
1446
1374
|
static {
|
|
1447
|
-
__name(this, "
|
|
1448
|
-
}
|
|
1449
|
-
tenantInfo = null;
|
|
1450
|
-
// Sets tenant info for this request, throwing if already set to prevent overwrites
|
|
1451
|
-
setTenant(tenantInfo) {
|
|
1452
|
-
if (this.tenantInfo) {
|
|
1453
|
-
throw new Error("Tenant context already set for this request");
|
|
1454
|
-
}
|
|
1455
|
-
this.tenantInfo = tenantInfo;
|
|
1456
|
-
}
|
|
1457
|
-
// Returns the tenant info for this request, throwing if context is not set
|
|
1458
|
-
getTenant() {
|
|
1459
|
-
if (!this.tenantInfo) {
|
|
1460
|
-
throw new import_common39.UnauthorizedException("Tenant context not set");
|
|
1461
|
-
}
|
|
1462
|
-
return this.tenantInfo;
|
|
1463
|
-
}
|
|
1464
|
-
// Returns true if tenant context has been set for this request
|
|
1465
|
-
hasTenant() {
|
|
1466
|
-
return this.tenantInfo !== null;
|
|
1467
|
-
}
|
|
1468
|
-
// Clears the tenant context (useful for RabbitMQ message handler cleanup)
|
|
1469
|
-
clearTenant() {
|
|
1470
|
-
this.tenantInfo = null;
|
|
1471
|
-
}
|
|
1472
|
-
// Returns the tenant ID or null if context is not set
|
|
1473
|
-
getTenantIdSafe() {
|
|
1474
|
-
return this.tenantInfo?.id ?? null;
|
|
1375
|
+
__name(this, "DatabaseModule");
|
|
1475
1376
|
}
|
|
1476
|
-
//
|
|
1477
|
-
|
|
1478
|
-
|
|
1377
|
+
// Configures the database module with a single primary connection
|
|
1378
|
+
static forServer(options) {
|
|
1379
|
+
const asyncProvider = {
|
|
1380
|
+
provide: DATABASE_MODULE_OPTIONS,
|
|
1381
|
+
useFactory: options.useFactory,
|
|
1382
|
+
inject: options.inject || []
|
|
1383
|
+
};
|
|
1384
|
+
return {
|
|
1385
|
+
module: _DatabaseModule,
|
|
1386
|
+
imports: [
|
|
1387
|
+
RequestModule
|
|
1388
|
+
],
|
|
1389
|
+
providers: [
|
|
1390
|
+
{
|
|
1391
|
+
provide: import_core4.Reflector,
|
|
1392
|
+
useClass: import_core4.Reflector
|
|
1393
|
+
},
|
|
1394
|
+
asyncProvider,
|
|
1395
|
+
PrimaryDatabaseService
|
|
1396
|
+
],
|
|
1397
|
+
exports: [
|
|
1398
|
+
PrimaryDatabaseService,
|
|
1399
|
+
asyncProvider
|
|
1400
|
+
]
|
|
1401
|
+
};
|
|
1479
1402
|
}
|
|
1480
1403
|
};
|
|
1481
|
-
|
|
1482
|
-
(0, import_common39.
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
], TenantContextService);
|
|
1404
|
+
DatabaseModule = _ts_decorate10([
|
|
1405
|
+
(0, import_common39.Global)(),
|
|
1406
|
+
(0, import_common39.Module)({})
|
|
1407
|
+
], DatabaseModule);
|
|
1486
1408
|
|
|
1487
|
-
// src/
|
|
1409
|
+
// src/decorators/uploaded-file.decorator.ts
|
|
1488
1410
|
var import_common40 = require("@nestjs/common");
|
|
1489
|
-
var
|
|
1490
|
-
|
|
1411
|
+
var UploadedFile = (0, import_common40.createParamDecorator)(async (_data, ctx) => {
|
|
1412
|
+
const request = ctx.switchToHttp().getRequest();
|
|
1413
|
+
const file = await request.file();
|
|
1414
|
+
if (!file) {
|
|
1415
|
+
throw new BadRequestException({
|
|
1416
|
+
label: "File Required",
|
|
1417
|
+
detail: "Please attach a file to your request."
|
|
1418
|
+
});
|
|
1419
|
+
}
|
|
1420
|
+
const buffer = await file.toBuffer();
|
|
1421
|
+
return {
|
|
1422
|
+
buffer,
|
|
1423
|
+
filename: file.filename,
|
|
1424
|
+
mimetype: file.mimetype
|
|
1425
|
+
};
|
|
1426
|
+
});
|
|
1427
|
+
|
|
1428
|
+
// src/database/dto/create-response.dto.ts
|
|
1429
|
+
var import_swagger = require("@nestjs/swagger");
|
|
1491
1430
|
function _ts_decorate11(decorators, target, key, desc2) {
|
|
1492
1431
|
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
1493
1432
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
|
|
@@ -1499,161 +1438,33 @@ function _ts_metadata7(k, v) {
|
|
|
1499
1438
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1500
1439
|
}
|
|
1501
1440
|
__name(_ts_metadata7, "_ts_metadata");
|
|
1502
|
-
|
|
1503
|
-
return function(target, key) {
|
|
1504
|
-
decorator(target, key, paramIndex);
|
|
1505
|
-
};
|
|
1506
|
-
}
|
|
1507
|
-
__name(_ts_param4, "_ts_param");
|
|
1508
|
-
var TenantDatabaseService = class _TenantDatabaseService {
|
|
1441
|
+
var CreateResponseDto = class {
|
|
1509
1442
|
static {
|
|
1510
|
-
__name(this, "
|
|
1511
|
-
}
|
|
1512
|
-
options;
|
|
1513
|
-
tenantContext;
|
|
1514
|
-
logger = new import_common40.Logger(_TenantDatabaseService.name);
|
|
1515
|
-
clients = /* @__PURE__ */ new Map();
|
|
1516
|
-
clientLastUsed = /* @__PURE__ */ new Map();
|
|
1517
|
-
cleanupInterval;
|
|
1518
|
-
constructor(options, tenantContext) {
|
|
1519
|
-
this.options = options;
|
|
1520
|
-
this.tenantContext = tenantContext;
|
|
1521
|
-
this.startConnectionCleaner();
|
|
1522
|
-
}
|
|
1523
|
-
// Returns the Drizzle client scoped to the current tenant's database
|
|
1524
|
-
get drizzleClient() {
|
|
1525
|
-
return this.getDbClient();
|
|
1526
|
-
}
|
|
1527
|
-
// Returns the Drizzle schema passed in module options
|
|
1528
|
-
get schema() {
|
|
1529
|
-
return this.options.drizzleSchema;
|
|
1530
|
-
}
|
|
1531
|
-
// Returns a cached or new Drizzle client for the current tenant context
|
|
1532
|
-
getDbClient() {
|
|
1533
|
-
const tenant = this.tenantContext.getTenant();
|
|
1534
|
-
const cacheKey = this.buildCacheKey(tenant);
|
|
1535
|
-
const existing = this.clients.get(cacheKey);
|
|
1536
|
-
if (existing) {
|
|
1537
|
-
this.clientLastUsed.set(cacheKey, Date.now());
|
|
1538
|
-
this.logger.debug(`Reusing cached connection: ${cacheKey}`);
|
|
1539
|
-
return existing.db;
|
|
1540
|
-
}
|
|
1541
|
-
this.logger.log(`Creating new database connection: ${cacheKey}`);
|
|
1542
|
-
const connection = this.createDbClientSync(tenant);
|
|
1543
|
-
this.clients.set(cacheKey, connection);
|
|
1544
|
-
this.clientLastUsed.set(cacheKey, Date.now());
|
|
1545
|
-
return connection.db;
|
|
1546
|
-
}
|
|
1547
|
-
// Creates a new pool and Drizzle client for the given tenant
|
|
1548
|
-
createDbClientSync(tenant) {
|
|
1549
|
-
try {
|
|
1550
|
-
const databaseUrl = this.buildTenantDbUrl(tenant);
|
|
1551
|
-
const pool = new import_pg2.Pool({
|
|
1552
|
-
connectionString: databaseUrl,
|
|
1553
|
-
max: tenant.connectionPoolSize || this.options.maxConnections || 10
|
|
1554
|
-
});
|
|
1555
|
-
const db = (0, import_node_postgres2.drizzle)({
|
|
1556
|
-
client: pool,
|
|
1557
|
-
schema: this.options.drizzleSchema
|
|
1558
|
-
});
|
|
1559
|
-
this.logger.log(`Connected to database for tenant: ${tenant.subdomain}`);
|
|
1560
|
-
return {
|
|
1561
|
-
pool,
|
|
1562
|
-
db
|
|
1563
|
-
};
|
|
1564
|
-
} catch (error) {
|
|
1565
|
-
this.logger.error(`Failed to create database connection for tenant: ${tenant.subdomain}`, error);
|
|
1566
|
-
throw new import_common40.InternalServerErrorException("Failed to connect to tenant database");
|
|
1567
|
-
}
|
|
1568
|
-
}
|
|
1569
|
-
// Builds the PostgreSQL connection URL for a dedicated tenant database
|
|
1570
|
-
buildTenantDbUrl(tenant) {
|
|
1571
|
-
const { databaseHost, databasePort, databaseName, databaseUsername, databasePassword, databaseSslMode } = tenant;
|
|
1572
|
-
if (!databaseHost || !databaseName || !databaseUsername) {
|
|
1573
|
-
throw new Error(`Tenant ${tenant.subdomain} missing database configuration`);
|
|
1574
|
-
}
|
|
1575
|
-
const port = databasePort || 5432;
|
|
1576
|
-
const sslMode = databaseSslMode || "require";
|
|
1577
|
-
const connectionUrl = `postgresql://${databaseUsername}:${encodeURIComponent(databasePassword || "")}@${databaseHost}:${port}/${databaseName}?sslmode=${sslMode}`;
|
|
1578
|
-
this.logger.debug(`Tenant connection URL: ${this.maskPassword(connectionUrl)}`);
|
|
1579
|
-
return connectionUrl;
|
|
1580
|
-
}
|
|
1581
|
-
// Builds a cache key for connection pooling from tenant database coordinates
|
|
1582
|
-
buildCacheKey(tenant) {
|
|
1583
|
-
return `${tenant.type}:${tenant.databaseName}@${tenant.databaseHost}`;
|
|
1584
|
-
}
|
|
1585
|
-
// Starts a periodic interval to close idle database connections
|
|
1586
|
-
startConnectionCleaner() {
|
|
1587
|
-
const interval = this.options.connectionCacheTTL || 3e5;
|
|
1588
|
-
this.cleanupInterval = setInterval(() => {
|
|
1589
|
-
this.cleanupIdleConnections();
|
|
1590
|
-
}, interval);
|
|
1591
|
-
this.logger.log(`Connection cleanup scheduled every ${interval / 1e3} seconds`);
|
|
1592
|
-
}
|
|
1593
|
-
// Closes and removes connections that have been idle beyond the TTL
|
|
1594
|
-
async cleanupIdleConnections() {
|
|
1595
|
-
const now = Date.now();
|
|
1596
|
-
const maxIdle = this.options.connectionCacheTTL || 3e5;
|
|
1597
|
-
let cleaned = 0;
|
|
1598
|
-
for (const [key, lastUsed] of this.clientLastUsed.entries()) {
|
|
1599
|
-
if (now - lastUsed > maxIdle) {
|
|
1600
|
-
const connection = this.clients.get(key);
|
|
1601
|
-
if (connection) {
|
|
1602
|
-
try {
|
|
1603
|
-
await connection.pool.end();
|
|
1604
|
-
this.logger.debug(`Cleaned up idle connection: ${key}`);
|
|
1605
|
-
} catch (error) {
|
|
1606
|
-
this.logger.error(`Error disconnecting idle client: ${key}`, error);
|
|
1607
|
-
}
|
|
1608
|
-
this.clients.delete(key);
|
|
1609
|
-
this.clientLastUsed.delete(key);
|
|
1610
|
-
cleaned++;
|
|
1611
|
-
}
|
|
1612
|
-
}
|
|
1613
|
-
}
|
|
1614
|
-
if (cleaned > 0) {
|
|
1615
|
-
this.logger.log(`Cleaned up ${cleaned} idle connections`);
|
|
1616
|
-
}
|
|
1617
|
-
}
|
|
1618
|
-
// Returns the current number of active pooled connections and their tenant keys
|
|
1619
|
-
getPoolStats() {
|
|
1620
|
-
return {
|
|
1621
|
-
activeConnections: this.clients.size,
|
|
1622
|
-
tenants: Array.from(this.clients.keys())
|
|
1623
|
-
};
|
|
1624
|
-
}
|
|
1625
|
-
// Masks password in connection URL for safe logging
|
|
1626
|
-
maskPassword(url) {
|
|
1627
|
-
return url.replace(/:([^@]+)@/, ":****@");
|
|
1628
|
-
}
|
|
1629
|
-
async onModuleDestroy() {
|
|
1630
|
-
if (this.cleanupInterval) {
|
|
1631
|
-
clearInterval(this.cleanupInterval);
|
|
1632
|
-
}
|
|
1633
|
-
this.logger.log(`Disconnecting ${this.clients.size} database connections`);
|
|
1634
|
-
const disconnectPromises = Array.from(this.clients.entries()).map(async ([key, connection]) => {
|
|
1635
|
-
try {
|
|
1636
|
-
await connection.pool.end();
|
|
1637
|
-
this.logger.debug(`Disconnected: ${key}`);
|
|
1638
|
-
} catch (error) {
|
|
1639
|
-
this.logger.error(`Error disconnecting client: ${key}`, error);
|
|
1640
|
-
}
|
|
1641
|
-
});
|
|
1642
|
-
await Promise.all(disconnectPromises);
|
|
1643
|
-
this.logger.log("All database connections closed");
|
|
1443
|
+
__name(this, "CreateResponseDto");
|
|
1644
1444
|
}
|
|
1445
|
+
success;
|
|
1446
|
+
message;
|
|
1447
|
+
data;
|
|
1645
1448
|
};
|
|
1646
|
-
|
|
1647
|
-
(0,
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
_ts_metadata7("design:
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1449
|
+
_ts_decorate11([
|
|
1450
|
+
(0, import_swagger.ApiProperty)({
|
|
1451
|
+
example: true
|
|
1452
|
+
}),
|
|
1453
|
+
_ts_metadata7("design:type", Boolean)
|
|
1454
|
+
], CreateResponseDto.prototype, "success", void 0);
|
|
1455
|
+
_ts_decorate11([
|
|
1456
|
+
(0, import_swagger.ApiProperty)({
|
|
1457
|
+
example: "Resource created successfully"
|
|
1458
|
+
}),
|
|
1459
|
+
_ts_metadata7("design:type", String)
|
|
1460
|
+
], CreateResponseDto.prototype, "message", void 0);
|
|
1461
|
+
_ts_decorate11([
|
|
1462
|
+
(0, import_swagger.ApiProperty)(),
|
|
1463
|
+
_ts_metadata7("design:type", typeof T === "undefined" ? Object : T)
|
|
1464
|
+
], CreateResponseDto.prototype, "data", void 0);
|
|
1655
1465
|
|
|
1656
|
-
// src/database/
|
|
1466
|
+
// src/database/dto/import-response.dto.ts
|
|
1467
|
+
var import_swagger2 = require("@nestjs/swagger");
|
|
1657
1468
|
function _ts_decorate12(decorators, target, key, desc2) {
|
|
1658
1469
|
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
1659
1470
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
|
|
@@ -1661,69 +1472,133 @@ function _ts_decorate12(decorators, target, key, desc2) {
|
|
|
1661
1472
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1662
1473
|
}
|
|
1663
1474
|
__name(_ts_decorate12, "_ts_decorate");
|
|
1664
|
-
|
|
1475
|
+
function _ts_metadata8(k, v) {
|
|
1476
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1477
|
+
}
|
|
1478
|
+
__name(_ts_metadata8, "_ts_metadata");
|
|
1479
|
+
var ValidatedRowDto = class {
|
|
1665
1480
|
static {
|
|
1666
|
-
__name(this, "
|
|
1667
|
-
}
|
|
1668
|
-
// Configures the module for gateway/HTTP mode with TenantContextInterceptor
|
|
1669
|
-
static forServer(options) {
|
|
1670
|
-
return _DatabaseModule.createDynamicModule(options, "server");
|
|
1481
|
+
__name(this, "ValidatedRowDto");
|
|
1671
1482
|
}
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1483
|
+
index;
|
|
1484
|
+
data;
|
|
1485
|
+
valid;
|
|
1486
|
+
errors;
|
|
1487
|
+
};
|
|
1488
|
+
_ts_decorate12([
|
|
1489
|
+
(0, import_swagger2.ApiProperty)({
|
|
1490
|
+
example: 1
|
|
1491
|
+
}),
|
|
1492
|
+
_ts_metadata8("design:type", Number)
|
|
1493
|
+
], ValidatedRowDto.prototype, "index", void 0);
|
|
1494
|
+
_ts_decorate12([
|
|
1495
|
+
(0, import_swagger2.ApiProperty)({
|
|
1496
|
+
example: {
|
|
1497
|
+
code: "products",
|
|
1498
|
+
name: "Products"
|
|
1499
|
+
}
|
|
1500
|
+
}),
|
|
1501
|
+
_ts_metadata8("design:type", typeof Record === "undefined" ? Object : Record)
|
|
1502
|
+
], ValidatedRowDto.prototype, "data", void 0);
|
|
1503
|
+
_ts_decorate12([
|
|
1504
|
+
(0, import_swagger2.ApiProperty)({
|
|
1505
|
+
example: true
|
|
1506
|
+
}),
|
|
1507
|
+
_ts_metadata8("design:type", Boolean)
|
|
1508
|
+
], ValidatedRowDto.prototype, "valid", void 0);
|
|
1509
|
+
_ts_decorate12([
|
|
1510
|
+
(0, import_swagger2.ApiProperty)({
|
|
1511
|
+
example: [
|
|
1512
|
+
"Code already exists"
|
|
1513
|
+
]
|
|
1514
|
+
}),
|
|
1515
|
+
_ts_metadata8("design:type", Array)
|
|
1516
|
+
], ValidatedRowDto.prototype, "errors", void 0);
|
|
1517
|
+
var ImportSummaryDto = class {
|
|
1518
|
+
static {
|
|
1519
|
+
__name(this, "ImportSummaryDto");
|
|
1707
1520
|
}
|
|
1521
|
+
total;
|
|
1522
|
+
valid;
|
|
1523
|
+
invalid;
|
|
1708
1524
|
};
|
|
1709
|
-
|
|
1710
|
-
(0,
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1525
|
+
_ts_decorate12([
|
|
1526
|
+
(0, import_swagger2.ApiProperty)({
|
|
1527
|
+
example: 10
|
|
1528
|
+
}),
|
|
1529
|
+
_ts_metadata8("design:type", Number)
|
|
1530
|
+
], ImportSummaryDto.prototype, "total", void 0);
|
|
1531
|
+
_ts_decorate12([
|
|
1532
|
+
(0, import_swagger2.ApiProperty)({
|
|
1533
|
+
example: 8
|
|
1534
|
+
}),
|
|
1535
|
+
_ts_metadata8("design:type", Number)
|
|
1536
|
+
], ImportSummaryDto.prototype, "valid", void 0);
|
|
1537
|
+
_ts_decorate12([
|
|
1538
|
+
(0, import_swagger2.ApiProperty)({
|
|
1539
|
+
example: 2
|
|
1540
|
+
}),
|
|
1541
|
+
_ts_metadata8("design:type", Number)
|
|
1542
|
+
], ImportSummaryDto.prototype, "invalid", void 0);
|
|
1543
|
+
var ImportResponseDto = class {
|
|
1544
|
+
static {
|
|
1545
|
+
__name(this, "ImportResponseDto");
|
|
1721
1546
|
}
|
|
1722
|
-
|
|
1723
|
-
|
|
1547
|
+
success;
|
|
1548
|
+
message;
|
|
1549
|
+
created;
|
|
1550
|
+
updated;
|
|
1551
|
+
skipped;
|
|
1552
|
+
rows;
|
|
1553
|
+
summary;
|
|
1554
|
+
};
|
|
1555
|
+
_ts_decorate12([
|
|
1556
|
+
(0, import_swagger2.ApiProperty)({
|
|
1557
|
+
example: true
|
|
1558
|
+
}),
|
|
1559
|
+
_ts_metadata8("design:type", Boolean)
|
|
1560
|
+
], ImportResponseDto.prototype, "success", void 0);
|
|
1561
|
+
_ts_decorate12([
|
|
1562
|
+
(0, import_swagger2.ApiProperty)({
|
|
1563
|
+
example: "Import complete."
|
|
1564
|
+
}),
|
|
1565
|
+
_ts_metadata8("design:type", String)
|
|
1566
|
+
], ImportResponseDto.prototype, "message", void 0);
|
|
1567
|
+
_ts_decorate12([
|
|
1568
|
+
(0, import_swagger2.ApiPropertyOptional)({
|
|
1569
|
+
example: 3
|
|
1570
|
+
}),
|
|
1571
|
+
_ts_metadata8("design:type", Number)
|
|
1572
|
+
], ImportResponseDto.prototype, "created", void 0);
|
|
1573
|
+
_ts_decorate12([
|
|
1574
|
+
(0, import_swagger2.ApiPropertyOptional)({
|
|
1575
|
+
example: 2
|
|
1576
|
+
}),
|
|
1577
|
+
_ts_metadata8("design:type", Number)
|
|
1578
|
+
], ImportResponseDto.prototype, "updated", void 0);
|
|
1579
|
+
_ts_decorate12([
|
|
1580
|
+
(0, import_swagger2.ApiPropertyOptional)({
|
|
1581
|
+
example: 1
|
|
1582
|
+
}),
|
|
1583
|
+
_ts_metadata8("design:type", Number)
|
|
1584
|
+
], ImportResponseDto.prototype, "skipped", void 0);
|
|
1585
|
+
_ts_decorate12([
|
|
1586
|
+
(0, import_swagger2.ApiPropertyOptional)({
|
|
1587
|
+
type: [
|
|
1588
|
+
ValidatedRowDto
|
|
1589
|
+
]
|
|
1590
|
+
}),
|
|
1591
|
+
_ts_metadata8("design:type", Array)
|
|
1592
|
+
], ImportResponseDto.prototype, "rows", void 0);
|
|
1593
|
+
_ts_decorate12([
|
|
1594
|
+
(0, import_swagger2.ApiPropertyOptional)({
|
|
1595
|
+
type: ImportSummaryDto
|
|
1596
|
+
}),
|
|
1597
|
+
_ts_metadata8("design:type", typeof ImportSummaryDto === "undefined" ? Object : ImportSummaryDto)
|
|
1598
|
+
], ImportResponseDto.prototype, "summary", void 0);
|
|
1724
1599
|
|
|
1725
1600
|
// src/database/dto/select-options-query.dto.ts
|
|
1726
|
-
var
|
|
1601
|
+
var import_swagger3 = require("@nestjs/swagger");
|
|
1727
1602
|
var import_class_transformer = require("class-transformer");
|
|
1728
1603
|
var import_class_validator = require("class-validator");
|
|
1729
1604
|
function _ts_decorate13(decorators, target, key, desc2) {
|
|
@@ -1733,10 +1608,10 @@ function _ts_decorate13(decorators, target, key, desc2) {
|
|
|
1733
1608
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1734
1609
|
}
|
|
1735
1610
|
__name(_ts_decorate13, "_ts_decorate");
|
|
1736
|
-
function
|
|
1611
|
+
function _ts_metadata9(k, v) {
|
|
1737
1612
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1738
1613
|
}
|
|
1739
|
-
__name(
|
|
1614
|
+
__name(_ts_metadata9, "_ts_metadata");
|
|
1740
1615
|
var SelectOptionsQueryDto = class {
|
|
1741
1616
|
static {
|
|
1742
1617
|
__name(this, "SelectOptionsQueryDto");
|
|
@@ -1752,16 +1627,16 @@ var SelectOptionsQueryDto = class {
|
|
|
1752
1627
|
groupIdKey;
|
|
1753
1628
|
};
|
|
1754
1629
|
_ts_decorate13([
|
|
1755
|
-
(0,
|
|
1630
|
+
(0, import_swagger3.ApiPropertyOptional)({
|
|
1756
1631
|
description: "Search term to filter by label",
|
|
1757
1632
|
example: "united"
|
|
1758
1633
|
}),
|
|
1759
1634
|
(0, import_class_validator.IsOptional)(),
|
|
1760
1635
|
(0, import_class_validator.IsString)(),
|
|
1761
|
-
|
|
1636
|
+
_ts_metadata9("design:type", String)
|
|
1762
1637
|
], SelectOptionsQueryDto.prototype, "search", void 0);
|
|
1763
1638
|
_ts_decorate13([
|
|
1764
|
-
(0,
|
|
1639
|
+
(0, import_swagger3.ApiPropertyOptional)({
|
|
1765
1640
|
description: "Maximum number of results",
|
|
1766
1641
|
example: 20,
|
|
1767
1642
|
default: 20
|
|
@@ -1770,10 +1645,10 @@ _ts_decorate13([
|
|
|
1770
1645
|
(0, import_class_transformer.Type)(() => Number),
|
|
1771
1646
|
(0, import_class_validator.IsInt)(),
|
|
1772
1647
|
(0, import_class_validator.Min)(1),
|
|
1773
|
-
|
|
1648
|
+
_ts_metadata9("design:type", Number)
|
|
1774
1649
|
], SelectOptionsQueryDto.prototype, "limit", void 0);
|
|
1775
1650
|
_ts_decorate13([
|
|
1776
|
-
(0,
|
|
1651
|
+
(0, import_swagger3.ApiPropertyOptional)({
|
|
1777
1652
|
description: "Number of results to skip",
|
|
1778
1653
|
example: 0,
|
|
1779
1654
|
default: 0
|
|
@@ -1782,67 +1657,67 @@ _ts_decorate13([
|
|
|
1782
1657
|
(0, import_class_transformer.Type)(() => Number),
|
|
1783
1658
|
(0, import_class_validator.IsInt)(),
|
|
1784
1659
|
(0, import_class_validator.Min)(0),
|
|
1785
|
-
|
|
1660
|
+
_ts_metadata9("design:type", Number)
|
|
1786
1661
|
], SelectOptionsQueryDto.prototype, "offset", void 0);
|
|
1787
1662
|
_ts_decorate13([
|
|
1788
|
-
(0,
|
|
1663
|
+
(0, import_swagger3.ApiPropertyOptional)({
|
|
1789
1664
|
description: "Comma-separated values to fetch specific options",
|
|
1790
1665
|
example: "1,2,3"
|
|
1791
1666
|
}),
|
|
1792
1667
|
(0, import_class_validator.IsOptional)(),
|
|
1793
1668
|
(0, import_class_validator.IsString)(),
|
|
1794
|
-
|
|
1669
|
+
_ts_metadata9("design:type", String)
|
|
1795
1670
|
], SelectOptionsQueryDto.prototype, "values", void 0);
|
|
1796
1671
|
_ts_decorate13([
|
|
1797
|
-
(0,
|
|
1672
|
+
(0, import_swagger3.ApiPropertyOptional)({
|
|
1798
1673
|
description: "Comma-separated IDs to exclude from results (already selected)",
|
|
1799
1674
|
example: "5,10"
|
|
1800
1675
|
}),
|
|
1801
1676
|
(0, import_class_validator.IsOptional)(),
|
|
1802
1677
|
(0, import_class_validator.IsString)(),
|
|
1803
|
-
|
|
1678
|
+
_ts_metadata9("design:type", String)
|
|
1804
1679
|
], SelectOptionsQueryDto.prototype, "excludeIds", void 0);
|
|
1805
1680
|
_ts_decorate13([
|
|
1806
|
-
(0,
|
|
1681
|
+
(0, import_swagger3.ApiPropertyOptional)({
|
|
1807
1682
|
description: "Column name for option value",
|
|
1808
1683
|
example: "id",
|
|
1809
1684
|
default: "id"
|
|
1810
1685
|
}),
|
|
1811
1686
|
(0, import_class_validator.IsOptional)(),
|
|
1812
1687
|
(0, import_class_validator.IsString)(),
|
|
1813
|
-
|
|
1688
|
+
_ts_metadata9("design:type", String)
|
|
1814
1689
|
], SelectOptionsQueryDto.prototype, "valueKey", void 0);
|
|
1815
1690
|
_ts_decorate13([
|
|
1816
|
-
(0,
|
|
1691
|
+
(0, import_swagger3.ApiPropertyOptional)({
|
|
1817
1692
|
description: "Column name for option label",
|
|
1818
1693
|
example: "name",
|
|
1819
1694
|
default: "name"
|
|
1820
1695
|
}),
|
|
1821
1696
|
(0, import_class_validator.IsOptional)(),
|
|
1822
1697
|
(0, import_class_validator.IsString)(),
|
|
1823
|
-
|
|
1698
|
+
_ts_metadata9("design:type", String)
|
|
1824
1699
|
], SelectOptionsQueryDto.prototype, "labelKey", void 0);
|
|
1825
1700
|
_ts_decorate13([
|
|
1826
|
-
(0,
|
|
1701
|
+
(0, import_swagger3.ApiPropertyOptional)({
|
|
1827
1702
|
description: "Column name for option description",
|
|
1828
1703
|
example: "description"
|
|
1829
1704
|
}),
|
|
1830
1705
|
(0, import_class_validator.IsOptional)(),
|
|
1831
1706
|
(0, import_class_validator.IsString)(),
|
|
1832
|
-
|
|
1707
|
+
_ts_metadata9("design:type", String)
|
|
1833
1708
|
], SelectOptionsQueryDto.prototype, "descriptionKey", void 0);
|
|
1834
1709
|
_ts_decorate13([
|
|
1835
|
-
(0,
|
|
1710
|
+
(0, import_swagger3.ApiPropertyOptional)({
|
|
1836
1711
|
description: "Column name for group ID",
|
|
1837
1712
|
example: "regionId"
|
|
1838
1713
|
}),
|
|
1839
1714
|
(0, import_class_validator.IsOptional)(),
|
|
1840
1715
|
(0, import_class_validator.IsString)(),
|
|
1841
|
-
|
|
1716
|
+
_ts_metadata9("design:type", String)
|
|
1842
1717
|
], SelectOptionsQueryDto.prototype, "groupIdKey", void 0);
|
|
1843
1718
|
|
|
1844
1719
|
// src/database/dto/success-response.dto.ts
|
|
1845
|
-
var
|
|
1720
|
+
var import_swagger4 = require("@nestjs/swagger");
|
|
1846
1721
|
var import_class_validator2 = require("class-validator");
|
|
1847
1722
|
function _ts_decorate14(decorators, target, key, desc2) {
|
|
1848
1723
|
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
@@ -1851,10 +1726,10 @@ function _ts_decorate14(decorators, target, key, desc2) {
|
|
|
1851
1726
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1852
1727
|
}
|
|
1853
1728
|
__name(_ts_decorate14, "_ts_decorate");
|
|
1854
|
-
function
|
|
1729
|
+
function _ts_metadata10(k, v) {
|
|
1855
1730
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1856
1731
|
}
|
|
1857
|
-
__name(
|
|
1732
|
+
__name(_ts_metadata10, "_ts_metadata");
|
|
1858
1733
|
var SuccessResponseDto = class {
|
|
1859
1734
|
static {
|
|
1860
1735
|
__name(this, "SuccessResponseDto");
|
|
@@ -1863,24 +1738,24 @@ var SuccessResponseDto = class {
|
|
|
1863
1738
|
message;
|
|
1864
1739
|
};
|
|
1865
1740
|
_ts_decorate14([
|
|
1866
|
-
(0,
|
|
1741
|
+
(0, import_swagger4.ApiProperty)({
|
|
1867
1742
|
example: true
|
|
1868
1743
|
}),
|
|
1869
1744
|
(0, import_class_validator2.IsNotEmpty)(),
|
|
1870
1745
|
(0, import_class_validator2.IsBoolean)(),
|
|
1871
|
-
|
|
1746
|
+
_ts_metadata10("design:type", Boolean)
|
|
1872
1747
|
], SuccessResponseDto.prototype, "success", void 0);
|
|
1873
1748
|
_ts_decorate14([
|
|
1874
|
-
(0,
|
|
1749
|
+
(0, import_swagger4.ApiProperty)({
|
|
1875
1750
|
example: "Operation completed successfully"
|
|
1876
1751
|
}),
|
|
1877
1752
|
(0, import_class_validator2.IsNotEmpty)(),
|
|
1878
1753
|
(0, import_class_validator2.IsString)(),
|
|
1879
|
-
|
|
1754
|
+
_ts_metadata10("design:type", String)
|
|
1880
1755
|
], SuccessResponseDto.prototype, "message", void 0);
|
|
1881
1756
|
|
|
1882
1757
|
// src/database/dto/table-response.dto.ts
|
|
1883
|
-
var
|
|
1758
|
+
var import_swagger5 = require("@nestjs/swagger");
|
|
1884
1759
|
function _ts_decorate15(decorators, target, key, desc2) {
|
|
1885
1760
|
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
1886
1761
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
|
|
@@ -1888,10 +1763,10 @@ function _ts_decorate15(decorators, target, key, desc2) {
|
|
|
1888
1763
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1889
1764
|
}
|
|
1890
1765
|
__name(_ts_decorate15, "_ts_decorate");
|
|
1891
|
-
function
|
|
1766
|
+
function _ts_metadata11(k, v) {
|
|
1892
1767
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1893
1768
|
}
|
|
1894
|
-
__name(
|
|
1769
|
+
__name(_ts_metadata11, "_ts_metadata");
|
|
1895
1770
|
var TableResponseDto = class {
|
|
1896
1771
|
static {
|
|
1897
1772
|
__name(this, "TableResponseDto");
|
|
@@ -1902,26 +1777,26 @@ var TableResponseDto = class {
|
|
|
1902
1777
|
activeViewId;
|
|
1903
1778
|
};
|
|
1904
1779
|
_ts_decorate15([
|
|
1905
|
-
(0,
|
|
1906
|
-
|
|
1780
|
+
(0, import_swagger5.ApiProperty)(),
|
|
1781
|
+
_ts_metadata11("design:type", Array)
|
|
1907
1782
|
], TableResponseDto.prototype, "result", void 0);
|
|
1908
1783
|
_ts_decorate15([
|
|
1909
|
-
(0,
|
|
1910
|
-
|
|
1784
|
+
(0, import_swagger5.ApiProperty)(),
|
|
1785
|
+
_ts_metadata11("design:type", Number)
|
|
1911
1786
|
], TableResponseDto.prototype, "count", void 0);
|
|
1912
1787
|
_ts_decorate15([
|
|
1913
|
-
(0,
|
|
1914
|
-
|
|
1788
|
+
(0, import_swagger5.ApiProperty)(),
|
|
1789
|
+
_ts_metadata11("design:type", typeof TableViewState === "undefined" ? Object : TableViewState)
|
|
1915
1790
|
], TableResponseDto.prototype, "state", void 0);
|
|
1916
1791
|
_ts_decorate15([
|
|
1917
|
-
(0,
|
|
1792
|
+
(0, import_swagger5.ApiPropertyOptional)({
|
|
1918
1793
|
nullable: true
|
|
1919
1794
|
}),
|
|
1920
|
-
|
|
1795
|
+
_ts_metadata11("design:type", Object)
|
|
1921
1796
|
], TableResponseDto.prototype, "activeViewId", void 0);
|
|
1922
1797
|
|
|
1923
1798
|
// src/database/filter/filter.processor.ts
|
|
1924
|
-
var
|
|
1799
|
+
var import_drizzle_orm = require("drizzle-orm");
|
|
1925
1800
|
var FilterProcessor = class {
|
|
1926
1801
|
static {
|
|
1927
1802
|
__name(this, "FilterProcessor");
|
|
@@ -1939,58 +1814,58 @@ var FilterProcessor = class {
|
|
|
1939
1814
|
switch (f.operator) {
|
|
1940
1815
|
case "equals":
|
|
1941
1816
|
if (def.type === "boolean") return [
|
|
1942
|
-
(0,
|
|
1817
|
+
(0, import_drizzle_orm.eq)(col, val === "true" || val === 1)
|
|
1943
1818
|
];
|
|
1944
1819
|
return [
|
|
1945
|
-
(0,
|
|
1820
|
+
(0, import_drizzle_orm.eq)(col, val)
|
|
1946
1821
|
];
|
|
1947
1822
|
case "notEquals":
|
|
1948
1823
|
if (def.type === "boolean") return [
|
|
1949
|
-
(0,
|
|
1824
|
+
(0, import_drizzle_orm.ne)(col, val === "true" || val === 1)
|
|
1950
1825
|
];
|
|
1951
1826
|
return [
|
|
1952
|
-
(0,
|
|
1827
|
+
(0, import_drizzle_orm.ne)(col, val)
|
|
1953
1828
|
];
|
|
1954
1829
|
case "contains":
|
|
1955
1830
|
return [
|
|
1956
|
-
(0,
|
|
1831
|
+
(0, import_drizzle_orm.ilike)(col, `%${val}%`)
|
|
1957
1832
|
];
|
|
1958
1833
|
case "notContains":
|
|
1959
1834
|
return [
|
|
1960
|
-
(0,
|
|
1835
|
+
(0, import_drizzle_orm.notIlike)(col, `%${val}%`)
|
|
1961
1836
|
];
|
|
1962
1837
|
case "gt":
|
|
1963
1838
|
return [
|
|
1964
|
-
(0,
|
|
1839
|
+
(0, import_drizzle_orm.gt)(col, val)
|
|
1965
1840
|
];
|
|
1966
1841
|
case "gte":
|
|
1967
1842
|
return [
|
|
1968
|
-
(0,
|
|
1843
|
+
(0, import_drizzle_orm.gte)(col, val)
|
|
1969
1844
|
];
|
|
1970
1845
|
case "lt":
|
|
1971
1846
|
return [
|
|
1972
|
-
(0,
|
|
1847
|
+
(0, import_drizzle_orm.lt)(col, val)
|
|
1973
1848
|
];
|
|
1974
1849
|
case "lte":
|
|
1975
1850
|
return [
|
|
1976
|
-
(0,
|
|
1851
|
+
(0, import_drizzle_orm.lte)(col, val)
|
|
1977
1852
|
];
|
|
1978
1853
|
default:
|
|
1979
1854
|
return [];
|
|
1980
1855
|
}
|
|
1981
1856
|
});
|
|
1982
|
-
return conditions.length ? (0,
|
|
1857
|
+
return conditions.length ? (0, import_drizzle_orm.and)(...conditions) : void 0;
|
|
1983
1858
|
}
|
|
1984
1859
|
// Builds a search WHERE — OR across all string fields when columnId is 'all', otherwise a single ilike
|
|
1985
1860
|
static buildSearch(search, fieldMap) {
|
|
1986
1861
|
if (!search?.value) return void 0;
|
|
1987
1862
|
if (search.columnId === "all") {
|
|
1988
|
-
const conditions = Object.values(fieldMap).filter((def2) => "column" in def2 && def2.type === "string").map((def2) => (0,
|
|
1989
|
-
return conditions.length ? (0,
|
|
1863
|
+
const conditions = Object.values(fieldMap).filter((def2) => "column" in def2 && def2.type === "string").map((def2) => (0, import_drizzle_orm.ilike)(def2.column, `%${search.value}%`));
|
|
1864
|
+
return conditions.length ? (0, import_drizzle_orm.or)(...conditions) : void 0;
|
|
1990
1865
|
}
|
|
1991
1866
|
const def = fieldMap[search.columnId];
|
|
1992
1867
|
if (!def || !("column" in def)) return void 0;
|
|
1993
|
-
return (0,
|
|
1868
|
+
return (0, import_drizzle_orm.ilike)(def.column, `%${search.value}%`);
|
|
1994
1869
|
}
|
|
1995
1870
|
// Maps each SortCondition to an asc/desc SQL expression
|
|
1996
1871
|
static buildOrderBy(sort = [], fieldMap) {
|
|
@@ -1998,15 +1873,15 @@ var FilterProcessor = class {
|
|
|
1998
1873
|
const def = fieldMap[s.field];
|
|
1999
1874
|
if (!def || !("column" in def)) return [];
|
|
2000
1875
|
return [
|
|
2001
|
-
s.direction === "asc" ? (0,
|
|
1876
|
+
s.direction === "asc" ? (0, import_drizzle_orm.asc)(def.column) : (0, import_drizzle_orm.desc)(def.column)
|
|
2002
1877
|
];
|
|
2003
1878
|
});
|
|
2004
1879
|
}
|
|
2005
1880
|
};
|
|
2006
1881
|
|
|
2007
1882
|
// src/database/repositories/primary-base.repository.ts
|
|
2008
|
-
var
|
|
2009
|
-
var
|
|
1883
|
+
var import_common41 = require("@nestjs/common");
|
|
1884
|
+
var import_drizzle_orm2 = require("drizzle-orm");
|
|
2010
1885
|
function snakeToCamel(str) {
|
|
2011
1886
|
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
2012
1887
|
}
|
|
@@ -2035,16 +1910,17 @@ var PrimaryBaseRepository = class {
|
|
|
2035
1910
|
constructor(database, table) {
|
|
2036
1911
|
this.database = database;
|
|
2037
1912
|
this.table = table;
|
|
2038
|
-
const dbTableName = (0,
|
|
1913
|
+
const dbTableName = (0, import_drizzle_orm2.getTableName)(table);
|
|
2039
1914
|
this.tableName = snakeToCamel(dbTableName);
|
|
2040
|
-
this.logger = new
|
|
1915
|
+
this.logger = new import_common41.Logger(this.constructor.name);
|
|
2041
1916
|
this.logger.debug(`Initialized ${this.constructor.name}`);
|
|
2042
1917
|
this.logger.debug(`Table name: '${dbTableName}' -> query key: '${this.tableName}'`);
|
|
2043
1918
|
}
|
|
2044
1919
|
// Creates a new record and returns it
|
|
2045
|
-
async create(data) {
|
|
1920
|
+
async create(data, tx) {
|
|
2046
1921
|
this.logger.log("Creating record");
|
|
2047
|
-
const
|
|
1922
|
+
const db = tx ?? this.db;
|
|
1923
|
+
const results = await db.insert(this.table).values(data).returning();
|
|
2048
1924
|
const record = results[0];
|
|
2049
1925
|
if (!record) throw new Error(`${this.tableName}: database operation returned no record`);
|
|
2050
1926
|
return record;
|
|
@@ -2070,16 +1946,35 @@ var PrimaryBaseRepository = class {
|
|
|
2070
1946
|
this.logger.debug("Finding multiple records");
|
|
2071
1947
|
return this.model.findMany(options);
|
|
2072
1948
|
}
|
|
2073
|
-
// Builds a select query with optional custom fields,
|
|
1949
|
+
// Builds a select query with optional custom fields, joins, filter, grouping, ordering, and pagination
|
|
2074
1950
|
buildSelectQuery(options) {
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
1951
|
+
let query = (options?.select ? this.db.select(options.select).from(this.table) : this.db.select().from(this.table)).$dynamic();
|
|
1952
|
+
if (options?.leftJoin) {
|
|
1953
|
+
query = query.leftJoin(options.leftJoin.table, options.leftJoin.on);
|
|
1954
|
+
}
|
|
1955
|
+
if (options?.leftJoins) {
|
|
1956
|
+
for (const join of options.leftJoins) {
|
|
1957
|
+
query = query.leftJoin(join.table, join.on);
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
if (options?.where) {
|
|
1961
|
+
query = query.where(options.where);
|
|
1962
|
+
}
|
|
1963
|
+
if (options?.groupBy?.length) {
|
|
1964
|
+
query = query.groupBy(...options.groupBy);
|
|
1965
|
+
}
|
|
1966
|
+
if (options?.orderBy?.length) {
|
|
1967
|
+
query = query.orderBy(...options.orderBy);
|
|
1968
|
+
}
|
|
1969
|
+
if (options?.limit) {
|
|
1970
|
+
query = query.limit(options.limit);
|
|
1971
|
+
}
|
|
1972
|
+
if (options?.offset) {
|
|
1973
|
+
query = query.offset(options.offset);
|
|
1974
|
+
}
|
|
1975
|
+
return query;
|
|
1976
|
+
}
|
|
1977
|
+
// Returns paginated result and total count, with optional custom select, LEFT JOINs, GROUP BY, and ordering
|
|
2083
1978
|
async findAllAndCount(options) {
|
|
2084
1979
|
const [count, result] = await Promise.all([
|
|
2085
1980
|
this.count(options?.where),
|
|
@@ -2091,37 +1986,41 @@ var PrimaryBaseRepository = class {
|
|
|
2091
1986
|
};
|
|
2092
1987
|
}
|
|
2093
1988
|
// Updates a record by ID and returns the updated record
|
|
2094
|
-
async update(id, data) {
|
|
1989
|
+
async update(id, data, tx) {
|
|
2095
1990
|
this.logger.log(`Updating record with ID: ${id}`);
|
|
1991
|
+
const db = tx ?? this.db;
|
|
2096
1992
|
const idColumn = this.table.id;
|
|
2097
1993
|
if (!idColumn) throw new Error(`Table '${this.tableName}' has no 'id' column`);
|
|
2098
|
-
const results = await
|
|
1994
|
+
const results = await db.update(this.table).set(data).where((0, import_drizzle_orm2.eq)(idColumn, id)).returning();
|
|
2099
1995
|
const record = results[0];
|
|
2100
1996
|
if (!record) throw new Error(`${this.tableName}: database operation returned no record`);
|
|
2101
1997
|
return record;
|
|
2102
1998
|
}
|
|
2103
1999
|
// Updates all records matching the SQL condition and returns the affected count
|
|
2104
|
-
async updateMany(where, data) {
|
|
2000
|
+
async updateMany(where, data, tx) {
|
|
2105
2001
|
this.logger.log("Updating multiple records");
|
|
2106
|
-
const
|
|
2002
|
+
const db = tx ?? this.db;
|
|
2003
|
+
const result = await db.update(this.table).set(data).where(where);
|
|
2107
2004
|
return {
|
|
2108
2005
|
count: result.rowCount ?? 0
|
|
2109
2006
|
};
|
|
2110
2007
|
}
|
|
2111
2008
|
// Deletes a record by ID and returns the deleted record
|
|
2112
|
-
async delete(id) {
|
|
2009
|
+
async delete(id, tx) {
|
|
2113
2010
|
this.logger.log(`Deleting record with ID: ${id}`);
|
|
2011
|
+
const db = tx ?? this.db;
|
|
2114
2012
|
const idColumn = this.table.id;
|
|
2115
2013
|
if (!idColumn) throw new Error(`Table '${this.tableName}' has no 'id' column`);
|
|
2116
|
-
const results = await
|
|
2014
|
+
const results = await db.delete(this.table).where((0, import_drizzle_orm2.eq)(idColumn, id)).returning();
|
|
2117
2015
|
const record = results[0];
|
|
2118
2016
|
if (!record) throw new Error(`${this.tableName}: database operation returned no record`);
|
|
2119
2017
|
return record;
|
|
2120
2018
|
}
|
|
2121
2019
|
// Deletes all records matching the SQL condition and returns the affected count
|
|
2122
|
-
async deleteMany(where) {
|
|
2020
|
+
async deleteMany(where, tx) {
|
|
2123
2021
|
this.logger.log("Deleting multiple records");
|
|
2124
|
-
const
|
|
2022
|
+
const db = tx ?? this.db;
|
|
2023
|
+
const result = await db.delete(this.table).where(where);
|
|
2125
2024
|
return {
|
|
2126
2025
|
count: result.rowCount ?? 0
|
|
2127
2026
|
};
|
|
@@ -2130,7 +2029,7 @@ var PrimaryBaseRepository = class {
|
|
|
2130
2029
|
async count(where) {
|
|
2131
2030
|
this.logger.debug("Counting records");
|
|
2132
2031
|
let query = this.db.select({
|
|
2133
|
-
count:
|
|
2032
|
+
count: import_drizzle_orm2.sql`count(*)::int`
|
|
2134
2033
|
}).from(this.table).$dynamic();
|
|
2135
2034
|
if (where) {
|
|
2136
2035
|
query = query.where(where);
|
|
@@ -2143,9 +2042,14 @@ var PrimaryBaseRepository = class {
|
|
|
2143
2042
|
const count = await this.count(where);
|
|
2144
2043
|
return count > 0;
|
|
2145
2044
|
}
|
|
2045
|
+
// Executes the callback within a database transaction
|
|
2046
|
+
async transaction(callback) {
|
|
2047
|
+
return this.db.transaction(callback);
|
|
2048
|
+
}
|
|
2146
2049
|
// Finds records formatted as select dropdown options with optional search, pagination, and grouping
|
|
2147
2050
|
async findForSelect(config) {
|
|
2148
2051
|
this.logger.debug("Finding records for select dropdown");
|
|
2052
|
+
const selectFn = config.distinct ? this.db.selectDistinct.bind(this.db) : this.db.select.bind(this.db);
|
|
2149
2053
|
const parsedValues = typeof config.values === "string" ? config.values.split(",").map((v) => v.trim()).filter(Boolean) : config.values;
|
|
2150
2054
|
const parsedExcludeIds = typeof config.excludeIds === "string" ? config.excludeIds.split(",").map((v) => v.trim()).filter(Boolean) : config.excludeIds ?? [];
|
|
2151
2055
|
const tableColumns = this.table;
|
|
@@ -2173,7 +2077,7 @@ var PrimaryBaseRepository = class {
|
|
|
2173
2077
|
const groupIdCol = tableColumns[config.groupId];
|
|
2174
2078
|
if (groupIdCol) selectCols.groupId = groupIdCol;
|
|
2175
2079
|
}
|
|
2176
|
-
let valuesQuery =
|
|
2080
|
+
let valuesQuery = selectFn(selectCols).from(this.table).$dynamic();
|
|
2177
2081
|
if (config.joins) {
|
|
2178
2082
|
for (const join of config.joins) {
|
|
2179
2083
|
if (join.type === "inner") {
|
|
@@ -2183,7 +2087,7 @@ var PrimaryBaseRepository = class {
|
|
|
2183
2087
|
}
|
|
2184
2088
|
}
|
|
2185
2089
|
}
|
|
2186
|
-
const rows2 = await valuesQuery.where((0,
|
|
2090
|
+
const rows2 = await valuesQuery.where((0, import_drizzle_orm2.inArray)(valueCol, parsedValues));
|
|
2187
2091
|
return {
|
|
2188
2092
|
options: rows2.map((row) => ({
|
|
2189
2093
|
value: row.value,
|
|
@@ -2204,7 +2108,7 @@ var PrimaryBaseRepository = class {
|
|
|
2204
2108
|
const selectFields = {
|
|
2205
2109
|
value: valueCol,
|
|
2206
2110
|
label: labelCol,
|
|
2207
|
-
totalCount:
|
|
2111
|
+
totalCount: import_drizzle_orm2.sql`count(*) over()`.mapWith(Number)
|
|
2208
2112
|
};
|
|
2209
2113
|
if (descriptionCol) selectFields.description = descriptionCol;
|
|
2210
2114
|
if (config.groupId) {
|
|
@@ -2213,16 +2117,16 @@ var PrimaryBaseRepository = class {
|
|
|
2213
2117
|
}
|
|
2214
2118
|
const conditions = [];
|
|
2215
2119
|
if (config.search) {
|
|
2216
|
-
conditions.push((0,
|
|
2120
|
+
conditions.push((0, import_drizzle_orm2.ilike)(labelCol, `%${config.search}%`));
|
|
2217
2121
|
}
|
|
2218
2122
|
if (parsedExcludeIds.length > 0) {
|
|
2219
|
-
conditions.push((0,
|
|
2123
|
+
conditions.push((0, import_drizzle_orm2.notInArray)(valueCol, parsedExcludeIds));
|
|
2220
2124
|
}
|
|
2221
2125
|
if (config.where) {
|
|
2222
2126
|
for (const [field, val] of Object.entries(config.where)) {
|
|
2223
2127
|
const column = tableColumns[field];
|
|
2224
2128
|
if (column) {
|
|
2225
|
-
conditions.push((0,
|
|
2129
|
+
conditions.push((0, import_drizzle_orm2.eq)(column, val));
|
|
2226
2130
|
}
|
|
2227
2131
|
}
|
|
2228
2132
|
}
|
|
@@ -2233,7 +2137,7 @@ var PrimaryBaseRepository = class {
|
|
|
2233
2137
|
const orderByCol = orderByKey ? tableColumns[orderByKey] ?? labelCol : labelCol;
|
|
2234
2138
|
const limit = Number(config.limit) || 20;
|
|
2235
2139
|
const offset = Number(config.offset) || 0;
|
|
2236
|
-
let query =
|
|
2140
|
+
let query = selectFn(selectFields).from(this.table).$dynamic();
|
|
2237
2141
|
if (config.joins) {
|
|
2238
2142
|
for (const join of config.joins) {
|
|
2239
2143
|
if (join.type === "inner") {
|
|
@@ -2244,14 +2148,14 @@ var PrimaryBaseRepository = class {
|
|
|
2244
2148
|
}
|
|
2245
2149
|
}
|
|
2246
2150
|
if (conditions.length > 0) {
|
|
2247
|
-
query = query.where(conditions.length === 1 ? conditions[0] : (0,
|
|
2151
|
+
query = query.where(conditions.length === 1 ? conditions[0] : (0, import_drizzle_orm2.and)(...conditions));
|
|
2248
2152
|
}
|
|
2249
2153
|
const orderClauses = [];
|
|
2250
2154
|
if (config.groupId) {
|
|
2251
2155
|
const groupIdCol = tableColumns[config.groupId];
|
|
2252
|
-
if (groupIdCol) orderClauses.push((0,
|
|
2156
|
+
if (groupIdCol) orderClauses.push((0, import_drizzle_orm2.asc)(groupIdCol));
|
|
2253
2157
|
}
|
|
2254
|
-
orderClauses.push((0,
|
|
2158
|
+
orderClauses.push((0, import_drizzle_orm2.asc)(orderByCol));
|
|
2255
2159
|
query = query.orderBy(...orderClauses).limit(limit).offset(offset);
|
|
2256
2160
|
const rows = await query;
|
|
2257
2161
|
const totalCount = rows.length > 0 ? rows[0].totalCount : 0;
|
|
@@ -2277,235 +2181,7 @@ var PrimaryBaseRepository = class {
|
|
|
2277
2181
|
const groupRows = await this.db.select({
|
|
2278
2182
|
id: groupIdCol,
|
|
2279
2183
|
name: groupNameCol
|
|
2280
|
-
}).from(config.groupTable).orderBy((0,
|
|
2281
|
-
resolvedGroups = groupRows.map((r) => ({
|
|
2282
|
-
id: r.id,
|
|
2283
|
-
name: String(r.name)
|
|
2284
|
-
}));
|
|
2285
|
-
}
|
|
2286
|
-
return {
|
|
2287
|
-
options,
|
|
2288
|
-
hasMore: offset + limit < totalCount,
|
|
2289
|
-
totalCount,
|
|
2290
|
-
...resolvedGroups ? {
|
|
2291
|
-
groups: resolvedGroups
|
|
2292
|
-
} : {}
|
|
2293
|
-
};
|
|
2294
|
-
}
|
|
2295
|
-
};
|
|
2296
|
-
|
|
2297
|
-
// src/database/repositories/tenant-base.repository.ts
|
|
2298
|
-
var import_common44 = require("@nestjs/common");
|
|
2299
|
-
var import_drizzle_orm4 = require("drizzle-orm");
|
|
2300
|
-
var TenantBaseRepository = class {
|
|
2301
|
-
static {
|
|
2302
|
-
__name(this, "TenantBaseRepository");
|
|
2303
|
-
}
|
|
2304
|
-
database;
|
|
2305
|
-
table;
|
|
2306
|
-
logger;
|
|
2307
|
-
tableName;
|
|
2308
|
-
get db() {
|
|
2309
|
-
return this.database.drizzleClient;
|
|
2310
|
-
}
|
|
2311
|
-
get model() {
|
|
2312
|
-
return this.database.drizzleClient.query[this.tableName];
|
|
2313
|
-
}
|
|
2314
|
-
constructor(database, table) {
|
|
2315
|
-
this.database = database;
|
|
2316
|
-
this.table = table;
|
|
2317
|
-
this.tableName = (0, import_drizzle_orm4.getTableName)(table);
|
|
2318
|
-
this.logger = new import_common44.Logger(this.constructor.name);
|
|
2319
|
-
this.logger.debug(`Initialized ${this.constructor.name}`);
|
|
2320
|
-
}
|
|
2321
|
-
// Creates a new record and returns it
|
|
2322
|
-
async create(data) {
|
|
2323
|
-
this.logger.log("Creating record");
|
|
2324
|
-
const results = await this.db.insert(this.table).values(data).returning();
|
|
2325
|
-
const record = results[0];
|
|
2326
|
-
if (!record) throw new Error(`${this.tableName}: database operation returned no record`);
|
|
2327
|
-
return record;
|
|
2328
|
-
}
|
|
2329
|
-
// Finds a single record by primary key ID
|
|
2330
|
-
async findById(id) {
|
|
2331
|
-
this.logger.debug(`Finding record by ID: ${id}`);
|
|
2332
|
-
const idColumn = this.table.id;
|
|
2333
|
-
if (!idColumn) throw new Error(`Table '${this.tableName}' has no 'id' column`);
|
|
2334
|
-
const results = await this.db.select().from(this.table).where((0, import_drizzle_orm4.eq)(idColumn, id)).limit(1);
|
|
2335
|
-
return results[0] ?? null;
|
|
2336
|
-
}
|
|
2337
|
-
// Finds a single record matching the given SQL condition
|
|
2338
|
-
async findOne(where) {
|
|
2339
|
-
this.logger.debug("Finding record with custom query");
|
|
2340
|
-
const results = await this.db.select().from(this.table).where(where).limit(1);
|
|
2341
|
-
return results[0] ?? null;
|
|
2342
|
-
}
|
|
2343
|
-
// Finds multiple records with optional SQL filtering, ordering, and pagination
|
|
2344
|
-
async findMany(options) {
|
|
2345
|
-
this.logger.debug("Finding multiple records");
|
|
2346
|
-
let query = this.db.select().from(this.table).$dynamic();
|
|
2347
|
-
if (options?.where) {
|
|
2348
|
-
query = query.where(options.where);
|
|
2349
|
-
}
|
|
2350
|
-
if (options?.orderBy) {
|
|
2351
|
-
query = query.orderBy(options.orderBy);
|
|
2352
|
-
}
|
|
2353
|
-
if (options?.limit) {
|
|
2354
|
-
query = query.limit(options.limit);
|
|
2355
|
-
}
|
|
2356
|
-
if (options?.offset) {
|
|
2357
|
-
query = query.offset(options.offset);
|
|
2358
|
-
}
|
|
2359
|
-
return await query;
|
|
2360
|
-
}
|
|
2361
|
-
// Updates a record by ID and returns the updated record
|
|
2362
|
-
async update(id, data) {
|
|
2363
|
-
this.logger.log(`Updating record with ID: ${id}`);
|
|
2364
|
-
const idColumn = this.table.id;
|
|
2365
|
-
if (!idColumn) throw new Error(`Table '${this.tableName}' has no 'id' column`);
|
|
2366
|
-
const results = await this.db.update(this.table).set(data).where((0, import_drizzle_orm4.eq)(idColumn, id)).returning();
|
|
2367
|
-
const record = results[0];
|
|
2368
|
-
if (!record) throw new Error(`${this.tableName}: database operation returned no record`);
|
|
2369
|
-
return record;
|
|
2370
|
-
}
|
|
2371
|
-
// Updates all records matching the SQL condition and returns the affected count
|
|
2372
|
-
async updateMany(where, data) {
|
|
2373
|
-
this.logger.log("Updating multiple records");
|
|
2374
|
-
const result = await this.db.update(this.table).set(data).where(where);
|
|
2375
|
-
return {
|
|
2376
|
-
count: result.rowCount ?? 0
|
|
2377
|
-
};
|
|
2378
|
-
}
|
|
2379
|
-
// Deletes a record by ID and returns the deleted record
|
|
2380
|
-
async delete(id) {
|
|
2381
|
-
this.logger.log(`Deleting record with ID: ${id}`);
|
|
2382
|
-
const idColumn = this.table.id;
|
|
2383
|
-
if (!idColumn) throw new Error(`Table '${this.tableName}' has no 'id' column`);
|
|
2384
|
-
const results = await this.db.delete(this.table).where((0, import_drizzle_orm4.eq)(idColumn, id)).returning();
|
|
2385
|
-
const record = results[0];
|
|
2386
|
-
if (!record) throw new Error(`${this.tableName}: database operation returned no record`);
|
|
2387
|
-
return record;
|
|
2388
|
-
}
|
|
2389
|
-
// Deletes all records matching the SQL condition and returns the affected count
|
|
2390
|
-
async deleteMany(where) {
|
|
2391
|
-
this.logger.log("Deleting multiple records");
|
|
2392
|
-
const result = await this.db.delete(this.table).where(where);
|
|
2393
|
-
return {
|
|
2394
|
-
count: result.rowCount ?? 0
|
|
2395
|
-
};
|
|
2396
|
-
}
|
|
2397
|
-
// Counts records matching the optional SQL condition
|
|
2398
|
-
async count(where) {
|
|
2399
|
-
this.logger.debug("Counting records");
|
|
2400
|
-
let query = this.db.select({
|
|
2401
|
-
count: import_drizzle_orm4.sql`count(*)::int`
|
|
2402
|
-
}).from(this.table).$dynamic();
|
|
2403
|
-
if (where) {
|
|
2404
|
-
query = query.where(where);
|
|
2405
|
-
}
|
|
2406
|
-
const results = await query;
|
|
2407
|
-
return results[0].count;
|
|
2408
|
-
}
|
|
2409
|
-
// Returns true if at least one record matches the SQL condition
|
|
2410
|
-
async exists(where) {
|
|
2411
|
-
const count = await this.count(where);
|
|
2412
|
-
return count > 0;
|
|
2413
|
-
}
|
|
2414
|
-
// Finds records formatted as select dropdown options with optional search, pagination, and grouping
|
|
2415
|
-
async findForSelect(config) {
|
|
2416
|
-
this.logger.debug("Finding records for select dropdown");
|
|
2417
|
-
const parsedValues = typeof config.values === "string" ? config.values.split(",").map((v) => v.trim()).filter(Boolean) : config.values;
|
|
2418
|
-
const parsedExcludeIds = typeof config.excludeIds === "string" ? config.excludeIds.split(",").map((v) => v.trim()).filter(Boolean) : config.excludeIds ?? [];
|
|
2419
|
-
const tableColumns = this.table;
|
|
2420
|
-
const valueCol = tableColumns[config.value];
|
|
2421
|
-
if (!valueCol) throw new Error(`Column '${config.value}' not found in table '${this.tableName}'`);
|
|
2422
|
-
const labelCol = tableColumns[config.label];
|
|
2423
|
-
if (!labelCol) throw new Error(`Column '${config.label}' not found in table '${this.tableName}'`);
|
|
2424
|
-
if (parsedValues && parsedValues.length > 0) {
|
|
2425
|
-
const selectCols = {
|
|
2426
|
-
value: valueCol,
|
|
2427
|
-
label: labelCol
|
|
2428
|
-
};
|
|
2429
|
-
if (config.groupId) {
|
|
2430
|
-
const groupIdCol = tableColumns[config.groupId];
|
|
2431
|
-
if (groupIdCol) selectCols.groupId = groupIdCol;
|
|
2432
|
-
}
|
|
2433
|
-
const rows2 = await this.db.select(selectCols).from(this.table).where((0, import_drizzle_orm4.inArray)(valueCol, parsedValues));
|
|
2434
|
-
return {
|
|
2435
|
-
options: rows2.map((row) => ({
|
|
2436
|
-
value: row.value,
|
|
2437
|
-
label: String(row.label),
|
|
2438
|
-
...config.groupId && row.groupId != null ? {
|
|
2439
|
-
groupId: row.groupId
|
|
2440
|
-
} : {}
|
|
2441
|
-
})),
|
|
2442
|
-
hasMore: false,
|
|
2443
|
-
...config.groups ? {
|
|
2444
|
-
groups: config.groups
|
|
2445
|
-
} : {}
|
|
2446
|
-
};
|
|
2447
|
-
}
|
|
2448
|
-
const selectFields = {
|
|
2449
|
-
value: valueCol,
|
|
2450
|
-
label: labelCol,
|
|
2451
|
-
totalCount: import_drizzle_orm4.sql`count(*) over()`.mapWith(Number)
|
|
2452
|
-
};
|
|
2453
|
-
if (config.groupId) {
|
|
2454
|
-
const groupIdCol = tableColumns[config.groupId];
|
|
2455
|
-
if (groupIdCol) selectFields.groupId = groupIdCol;
|
|
2456
|
-
}
|
|
2457
|
-
const conditions = [];
|
|
2458
|
-
if (config.search) {
|
|
2459
|
-
conditions.push((0, import_drizzle_orm4.ilike)(labelCol, `%${config.search}%`));
|
|
2460
|
-
}
|
|
2461
|
-
if (parsedExcludeIds.length > 0) {
|
|
2462
|
-
conditions.push((0, import_drizzle_orm4.notInArray)(valueCol, parsedExcludeIds));
|
|
2463
|
-
}
|
|
2464
|
-
if (config.where) {
|
|
2465
|
-
for (const [field, val] of Object.entries(config.where)) {
|
|
2466
|
-
const column = tableColumns[field];
|
|
2467
|
-
if (column) {
|
|
2468
|
-
conditions.push((0, import_drizzle_orm4.eq)(column, val));
|
|
2469
|
-
}
|
|
2470
|
-
}
|
|
2471
|
-
}
|
|
2472
|
-
const orderByKey = config.orderBy ? Object.keys(config.orderBy)[0] : void 0;
|
|
2473
|
-
const orderByCol = orderByKey ? tableColumns[orderByKey] ?? labelCol : labelCol;
|
|
2474
|
-
const limit = Number(config.limit) || 20;
|
|
2475
|
-
const offset = Number(config.offset) || 0;
|
|
2476
|
-
let query = this.db.select(selectFields).from(this.table).$dynamic();
|
|
2477
|
-
if (conditions.length > 0) {
|
|
2478
|
-
query = query.where(conditions.length === 1 ? conditions[0] : (0, import_drizzle_orm4.and)(...conditions));
|
|
2479
|
-
}
|
|
2480
|
-
const orderClauses = [];
|
|
2481
|
-
if (config.groupId) {
|
|
2482
|
-
const groupIdCol = tableColumns[config.groupId];
|
|
2483
|
-
if (groupIdCol) orderClauses.push((0, import_drizzle_orm4.asc)(groupIdCol));
|
|
2484
|
-
}
|
|
2485
|
-
orderClauses.push((0, import_drizzle_orm4.asc)(orderByCol));
|
|
2486
|
-
query = query.orderBy(...orderClauses).limit(limit).offset(offset);
|
|
2487
|
-
const rows = await query;
|
|
2488
|
-
const totalCount = rows.length > 0 ? rows[0].totalCount : 0;
|
|
2489
|
-
const options = rows.map((row) => ({
|
|
2490
|
-
value: row.value,
|
|
2491
|
-
label: String(row.label),
|
|
2492
|
-
...config.groupId && row.groupId != null ? {
|
|
2493
|
-
groupId: row.groupId
|
|
2494
|
-
} : {}
|
|
2495
|
-
}));
|
|
2496
|
-
let resolvedGroups = config.groups;
|
|
2497
|
-
if (config.groupTable && config.groupId) {
|
|
2498
|
-
const groupTableColumns = config.groupTable;
|
|
2499
|
-
const groupIdKey = config.groupIdKey ?? "id";
|
|
2500
|
-
const groupNameKey = config.groupLabelKey ?? "name";
|
|
2501
|
-
const groupIdCol = groupTableColumns[groupIdKey];
|
|
2502
|
-
if (!groupIdCol) throw new Error(`Column '${groupIdKey}' not found in group table`);
|
|
2503
|
-
const groupNameCol = groupTableColumns[groupNameKey];
|
|
2504
|
-
if (!groupNameCol) throw new Error(`Column '${groupNameKey}' not found in group table`);
|
|
2505
|
-
const groupRows = await this.db.select({
|
|
2506
|
-
id: groupIdCol,
|
|
2507
|
-
name: groupNameCol
|
|
2508
|
-
}).from(config.groupTable).orderBy((0, import_drizzle_orm4.asc)(groupNameCol));
|
|
2184
|
+
}).from(config.groupTable).orderBy((0, import_drizzle_orm2.asc)(groupNameCol));
|
|
2509
2185
|
resolvedGroups = groupRows.map((r) => ({
|
|
2510
2186
|
id: r.id,
|
|
2511
2187
|
name: String(r.name)
|
|
@@ -2523,13 +2199,13 @@ var TenantBaseRepository = class {
|
|
|
2523
2199
|
};
|
|
2524
2200
|
|
|
2525
2201
|
// src/email/email.module.ts
|
|
2526
|
-
var
|
|
2527
|
-
var
|
|
2202
|
+
var import_common43 = require("@nestjs/common");
|
|
2203
|
+
var import_config12 = require("@nestjs/config");
|
|
2528
2204
|
|
|
2529
2205
|
// src/email/email.service.ts
|
|
2530
2206
|
var import_brevo = require("@getbrevo/brevo");
|
|
2531
|
-
var
|
|
2532
|
-
var
|
|
2207
|
+
var import_common42 = require("@nestjs/common");
|
|
2208
|
+
var import_config11 = require("@nestjs/config");
|
|
2533
2209
|
function _ts_decorate16(decorators, target, key, desc2) {
|
|
2534
2210
|
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
2535
2211
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
|
|
@@ -2537,16 +2213,16 @@ function _ts_decorate16(decorators, target, key, desc2) {
|
|
|
2537
2213
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2538
2214
|
}
|
|
2539
2215
|
__name(_ts_decorate16, "_ts_decorate");
|
|
2540
|
-
function
|
|
2216
|
+
function _ts_metadata12(k, v) {
|
|
2541
2217
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
2542
2218
|
}
|
|
2543
|
-
__name(
|
|
2219
|
+
__name(_ts_metadata12, "_ts_metadata");
|
|
2544
2220
|
var EmailService = class _EmailService {
|
|
2545
2221
|
static {
|
|
2546
2222
|
__name(this, "EmailService");
|
|
2547
2223
|
}
|
|
2548
2224
|
configService;
|
|
2549
|
-
logger = new
|
|
2225
|
+
logger = new import_common42.Logger(_EmailService.name);
|
|
2550
2226
|
brevoClient;
|
|
2551
2227
|
senderEmail;
|
|
2552
2228
|
senderName;
|
|
@@ -2979,28 +2655,117 @@ This is an automated message, please do not reply.
|
|
|
2979
2655
|
});
|
|
2980
2656
|
this.logger.log(`Email revert confirmation sent to ${email}`);
|
|
2981
2657
|
}
|
|
2982
|
-
//
|
|
2983
|
-
async
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
2658
|
+
// Sends an invite email to a new portal user with their set-password link
|
|
2659
|
+
async sendInviteEmail(params) {
|
|
2660
|
+
const { to, name, inviteUrl } = params;
|
|
2661
|
+
const subject = "You have been invited to Vritti AI";
|
|
2662
|
+
const htmlContent = `
|
|
2663
|
+
<!DOCTYPE html>
|
|
2664
|
+
<html>
|
|
2665
|
+
<head>
|
|
2666
|
+
<meta charset="UTF-8">
|
|
2667
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
2668
|
+
</head>
|
|
2669
|
+
<body style="margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background-color: #f5f5f5;">
|
|
2670
|
+
<table role="presentation" style="width: 100%; border-collapse: collapse;">
|
|
2671
|
+
<tr>
|
|
2672
|
+
<td style="padding: 40px 20px;">
|
|
2673
|
+
<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);">
|
|
2674
|
+
<!-- Header -->
|
|
2675
|
+
<tr>
|
|
2676
|
+
<td style="padding: 40px 40px 20px; text-align: center; border-bottom: 1px solid #e0e0e0;">
|
|
2677
|
+
<h1 style="margin: 0; color: #1a1a1a; font-size: 24px; font-weight: 600;">You're Invited</h1>
|
|
2678
|
+
</td>
|
|
2679
|
+
</tr>
|
|
2680
|
+
|
|
2681
|
+
<!-- Content -->
|
|
2682
|
+
<tr>
|
|
2683
|
+
<td style="padding: 40px;">
|
|
2684
|
+
<p style="margin: 0 0 20px; color: #333333; font-size: 16px; line-height: 1.6;">
|
|
2685
|
+
Hello <strong>${name}</strong>,
|
|
2686
|
+
</p>
|
|
2687
|
+
<p style="margin: 0 0 30px; color: #333333; font-size: 16px; line-height: 1.6;">
|
|
2688
|
+
You have been invited to join Vritti AI. Click the button below to set your password and get started.
|
|
2689
|
+
</p>
|
|
2690
|
+
|
|
2691
|
+
<div style="text-align: center; margin: 30px 0;">
|
|
2692
|
+
<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;">
|
|
2693
|
+
Set Your Password
|
|
2694
|
+
</a>
|
|
2695
|
+
</div>
|
|
2696
|
+
|
|
2697
|
+
<p style="margin: 30px 0 0; color: #666666; font-size: 14px; line-height: 1.6;">
|
|
2698
|
+
If you did not expect this invitation, you can safely ignore this email.
|
|
2699
|
+
</p>
|
|
2700
|
+
</td>
|
|
2701
|
+
</tr>
|
|
2702
|
+
|
|
2703
|
+
<!-- Footer -->
|
|
2704
|
+
<tr>
|
|
2705
|
+
<td style="padding: 30px 40px; border-top: 1px solid #e0e0e0; text-align: center;">
|
|
2706
|
+
<p style="margin: 0; color: #999999; font-size: 12px; line-height: 1.5;">
|
|
2707
|
+
Vritti AI Cloud - Cloud Management Platform
|
|
2708
|
+
</p>
|
|
2709
|
+
<p style="margin: 8px 0 0; color: #999999; font-size: 12px; line-height: 1.5;">
|
|
2710
|
+
This is an automated message, please do not reply.
|
|
2711
|
+
</p>
|
|
2712
|
+
</td>
|
|
2713
|
+
</tr>
|
|
2714
|
+
</table>
|
|
2715
|
+
</td>
|
|
2716
|
+
</tr>
|
|
2717
|
+
</table>
|
|
2718
|
+
</body>
|
|
2719
|
+
</html>
|
|
2720
|
+
`;
|
|
2721
|
+
const textContent = `
|
|
2722
|
+
Hello ${name},
|
|
2723
|
+
|
|
2724
|
+
You have been invited to join Vritti AI. Visit the link below to set your password and get started:
|
|
2725
|
+
|
|
2726
|
+
${inviteUrl}
|
|
2727
|
+
|
|
2728
|
+
If you did not expect this invitation, you can safely ignore this email.
|
|
2729
|
+
|
|
2730
|
+
---
|
|
2731
|
+
Vritti AI Cloud - Cloud Management Platform
|
|
2732
|
+
This is an automated message, please do not reply.
|
|
2733
|
+
`.trim();
|
|
2734
|
+
await this.sendEmail({
|
|
2735
|
+
to: [
|
|
2736
|
+
{
|
|
2737
|
+
email: to,
|
|
2738
|
+
name
|
|
2739
|
+
}
|
|
2740
|
+
],
|
|
2741
|
+
subject,
|
|
2742
|
+
htmlContent,
|
|
2743
|
+
textContent
|
|
2744
|
+
});
|
|
2745
|
+
this.logger.log(`Invite email sent to ${to}`);
|
|
2746
|
+
}
|
|
2747
|
+
// Verifies Brevo API connectivity — a 400 response means the API is reachable
|
|
2748
|
+
async verifyConnection() {
|
|
2749
|
+
try {
|
|
2750
|
+
await this.brevoClient.transactionalEmails.sendTransacEmail({
|
|
2751
|
+
sender: {
|
|
2752
|
+
email: this.senderEmail,
|
|
2753
|
+
name: this.senderName
|
|
2754
|
+
},
|
|
2755
|
+
to: [
|
|
2756
|
+
{
|
|
2757
|
+
email: this.senderEmail
|
|
2758
|
+
}
|
|
2759
|
+
],
|
|
2760
|
+
subject: "Connection Test",
|
|
2761
|
+
htmlContent: "<p>Test</p>"
|
|
2762
|
+
});
|
|
2763
|
+
return true;
|
|
2764
|
+
} catch (err) {
|
|
2765
|
+
if (err instanceof import_brevo.BrevoError && err.statusCode === 400) {
|
|
2766
|
+
return true;
|
|
2767
|
+
}
|
|
2768
|
+
this.logger.error("Brevo connection verification failed:", err);
|
|
3004
2769
|
return false;
|
|
3005
2770
|
}
|
|
3006
2771
|
}
|
|
@@ -3044,10 +2809,10 @@ This is an automated message, please do not reply.
|
|
|
3044
2809
|
}
|
|
3045
2810
|
};
|
|
3046
2811
|
EmailService = _ts_decorate16([
|
|
3047
|
-
(0,
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
typeof
|
|
2812
|
+
(0, import_common42.Injectable)(),
|
|
2813
|
+
_ts_metadata12("design:type", Function),
|
|
2814
|
+
_ts_metadata12("design:paramtypes", [
|
|
2815
|
+
typeof import_config11.ConfigService === "undefined" ? Object : import_config11.ConfigService
|
|
3051
2816
|
])
|
|
3052
2817
|
], EmailService);
|
|
3053
2818
|
|
|
@@ -3065,10 +2830,10 @@ var EmailModule = class {
|
|
|
3065
2830
|
}
|
|
3066
2831
|
};
|
|
3067
2832
|
EmailModule = _ts_decorate17([
|
|
3068
|
-
(0,
|
|
3069
|
-
(0,
|
|
2833
|
+
(0, import_common43.Global)(),
|
|
2834
|
+
(0, import_common43.Module)({
|
|
3070
2835
|
imports: [
|
|
3071
|
-
|
|
2836
|
+
import_config12.ConfigModule
|
|
3072
2837
|
],
|
|
3073
2838
|
providers: [
|
|
3074
2839
|
EmailService
|
|
@@ -3080,7 +2845,7 @@ EmailModule = _ts_decorate17([
|
|
|
3080
2845
|
], EmailModule);
|
|
3081
2846
|
|
|
3082
2847
|
// src/filters/http-exception.filter.ts
|
|
3083
|
-
var
|
|
2848
|
+
var import_common44 = require("@nestjs/common");
|
|
3084
2849
|
function _ts_decorate18(decorators, target, key, desc2) {
|
|
3085
2850
|
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
3086
2851
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
|
|
@@ -3089,7 +2854,7 @@ function _ts_decorate18(decorators, target, key, desc2) {
|
|
|
3089
2854
|
}
|
|
3090
2855
|
__name(_ts_decorate18, "_ts_decorate");
|
|
3091
2856
|
function getHttpStatusTitle(status) {
|
|
3092
|
-
const enumKey = Object.entries(
|
|
2857
|
+
const enumKey = Object.entries(import_common44.HttpStatus).find(([key, value]) => value === status && Number.isNaN(Number(key)))?.[0];
|
|
3093
2858
|
if (!enumKey) {
|
|
3094
2859
|
return "Error";
|
|
3095
2860
|
}
|
|
@@ -3100,17 +2865,17 @@ var HttpExceptionFilter = class _HttpExceptionFilter {
|
|
|
3100
2865
|
static {
|
|
3101
2866
|
__name(this, "HttpExceptionFilter");
|
|
3102
2867
|
}
|
|
3103
|
-
logger = new
|
|
2868
|
+
logger = new import_common44.Logger(_HttpExceptionFilter.name);
|
|
3104
2869
|
catch(exception, host) {
|
|
3105
2870
|
const ctx = host.switchToHttp();
|
|
3106
2871
|
const response = ctx.getResponse();
|
|
3107
2872
|
const request = ctx.getRequest();
|
|
3108
|
-
let status =
|
|
2873
|
+
let status = import_common44.HttpStatus.INTERNAL_SERVER_ERROR;
|
|
3109
2874
|
let type = "about:blank";
|
|
3110
2875
|
let label;
|
|
3111
2876
|
let detail = "Internal server error";
|
|
3112
2877
|
let errors = [];
|
|
3113
|
-
if (exception
|
|
2878
|
+
if (this.isHttpException(exception)) {
|
|
3114
2879
|
status = exception.getStatus();
|
|
3115
2880
|
const exceptionResponse = exception.getResponse();
|
|
3116
2881
|
if (typeof exceptionResponse === "object" && exceptionResponse !== null) {
|
|
@@ -3144,7 +2909,7 @@ var HttpExceptionFilter = class _HttpExceptionFilter {
|
|
|
3144
2909
|
const axiosStatus = exception.response?.status;
|
|
3145
2910
|
const axiosDetail = exception.response?.data?.message || exception.response?.data?.detail || exception.message;
|
|
3146
2911
|
const url = exception.config?.url;
|
|
3147
|
-
status =
|
|
2912
|
+
status = import_common44.HttpStatus.BAD_GATEWAY;
|
|
3148
2913
|
detail = `Upstream service error${axiosStatus ? ` (${axiosStatus})` : ""}: ${axiosDetail}`;
|
|
3149
2914
|
this.logger.error(`Upstream API error [${axiosStatus}]: ${axiosDetail} \u2014 URL: ${url}`, exception.stack);
|
|
3150
2915
|
} else {
|
|
@@ -3163,21 +2928,25 @@ var HttpExceptionFilter = class _HttpExceptionFilter {
|
|
|
3163
2928
|
};
|
|
3164
2929
|
response.header("Content-Type", "application/problem+json").status(status).send(problemDetails);
|
|
3165
2930
|
}
|
|
2931
|
+
// Duck-type check for HttpException — avoids instanceof failing across pnpm package instances
|
|
2932
|
+
isHttpException(error) {
|
|
2933
|
+
return error instanceof Error && typeof error.getStatus === "function" && typeof error.getResponse === "function";
|
|
2934
|
+
}
|
|
3166
2935
|
// Duck-type check for AxiosError without importing axios
|
|
3167
2936
|
isAxiosError(error) {
|
|
3168
2937
|
return error instanceof Error && error.isAxiosError === true;
|
|
3169
2938
|
}
|
|
3170
2939
|
};
|
|
3171
2940
|
HttpExceptionFilter = _ts_decorate18([
|
|
3172
|
-
(0,
|
|
2941
|
+
(0, import_common44.Catch)()
|
|
3173
2942
|
], HttpExceptionFilter);
|
|
3174
2943
|
|
|
3175
2944
|
// src/logger/interceptors/http-logger.interceptor.ts
|
|
3176
|
-
var
|
|
2945
|
+
var import_common46 = require("@nestjs/common");
|
|
3177
2946
|
var import_operators = require("rxjs/operators");
|
|
3178
2947
|
|
|
3179
2948
|
// src/logger/services/logger.service.ts
|
|
3180
|
-
var
|
|
2949
|
+
var import_common45 = require("@nestjs/common");
|
|
3181
2950
|
var import_winston = require("winston");
|
|
3182
2951
|
var import_winston_daily_rotate_file = __toESM(require("winston-daily-rotate-file"), 1);
|
|
3183
2952
|
|
|
@@ -3222,16 +2991,16 @@ function _ts_decorate19(decorators, target, key, desc2) {
|
|
|
3222
2991
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
3223
2992
|
}
|
|
3224
2993
|
__name(_ts_decorate19, "_ts_decorate");
|
|
3225
|
-
function
|
|
2994
|
+
function _ts_metadata13(k, v) {
|
|
3226
2995
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
3227
2996
|
}
|
|
3228
|
-
__name(
|
|
3229
|
-
function
|
|
2997
|
+
__name(_ts_metadata13, "_ts_metadata");
|
|
2998
|
+
function _ts_param4(paramIndex, decorator) {
|
|
3230
2999
|
return function(target, key) {
|
|
3231
3000
|
decorator(target, key, paramIndex);
|
|
3232
3001
|
};
|
|
3233
3002
|
}
|
|
3234
|
-
__name(
|
|
3003
|
+
__name(_ts_param4, "_ts_param");
|
|
3235
3004
|
var LoggerService = class _LoggerService {
|
|
3236
3005
|
static {
|
|
3237
3006
|
__name(this, "LoggerService");
|
|
@@ -3271,9 +3040,9 @@ var LoggerService = class _LoggerService {
|
|
|
3271
3040
|
}) : new import_winston.transports.Console({
|
|
3272
3041
|
level,
|
|
3273
3042
|
format: import_winston.format.combine(...baseFormatters, import_winston.format.printf((info) => {
|
|
3274
|
-
const { timestamp, level: level2, message, context, correlationId, trace } = info;
|
|
3043
|
+
const { timestamp: timestamp2, level: level2, message, context, correlationId, trace } = info;
|
|
3275
3044
|
const parts = [
|
|
3276
|
-
|
|
3045
|
+
timestamp2,
|
|
3277
3046
|
level2.toUpperCase().padEnd(7),
|
|
3278
3047
|
correlationId ? `[${correlationId.toString().slice(-6)}]` : "",
|
|
3279
3048
|
context ? `[${context}]` : "",
|
|
@@ -3424,11 +3193,11 @@ ${trace}`;
|
|
|
3424
3193
|
}
|
|
3425
3194
|
};
|
|
3426
3195
|
LoggerService = _ts_decorate19([
|
|
3427
|
-
(0,
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3196
|
+
(0, import_common45.Injectable)(),
|
|
3197
|
+
_ts_param4(0, (0, import_common45.Optional)()),
|
|
3198
|
+
_ts_param4(1, (0, import_common45.Optional)()),
|
|
3199
|
+
_ts_metadata13("design:type", Function),
|
|
3200
|
+
_ts_metadata13("design:paramtypes", [
|
|
3432
3201
|
typeof LoggerModuleOptions === "undefined" ? Object : LoggerModuleOptions,
|
|
3433
3202
|
typeof Logger === "undefined" ? Object : Logger
|
|
3434
3203
|
])
|
|
@@ -3442,16 +3211,16 @@ function _ts_decorate20(decorators, target, key, desc2) {
|
|
|
3442
3211
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
3443
3212
|
}
|
|
3444
3213
|
__name(_ts_decorate20, "_ts_decorate");
|
|
3445
|
-
function
|
|
3214
|
+
function _ts_metadata14(k, v) {
|
|
3446
3215
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
3447
3216
|
}
|
|
3448
|
-
__name(
|
|
3449
|
-
function
|
|
3217
|
+
__name(_ts_metadata14, "_ts_metadata");
|
|
3218
|
+
function _ts_param5(paramIndex, decorator) {
|
|
3450
3219
|
return function(target, key) {
|
|
3451
3220
|
decorator(target, key, paramIndex);
|
|
3452
3221
|
};
|
|
3453
3222
|
}
|
|
3454
|
-
__name(
|
|
3223
|
+
__name(_ts_param5, "_ts_param");
|
|
3455
3224
|
var HttpLoggerInterceptor = class {
|
|
3456
3225
|
static {
|
|
3457
3226
|
__name(this, "HttpLoggerInterceptor");
|
|
@@ -3555,20 +3324,20 @@ var HttpLoggerInterceptor = class {
|
|
|
3555
3324
|
}
|
|
3556
3325
|
};
|
|
3557
3326
|
HttpLoggerInterceptor = _ts_decorate20([
|
|
3558
|
-
(0,
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3327
|
+
(0, import_common46.Injectable)(),
|
|
3328
|
+
_ts_param5(1, (0, import_common46.Optional)()),
|
|
3329
|
+
_ts_metadata14("design:type", Function),
|
|
3330
|
+
_ts_metadata14("design:paramtypes", [
|
|
3562
3331
|
typeof LoggerService === "undefined" ? Object : LoggerService,
|
|
3563
3332
|
typeof HttpLoggerOptions === "undefined" ? Object : HttpLoggerOptions
|
|
3564
3333
|
])
|
|
3565
3334
|
], HttpLoggerInterceptor);
|
|
3566
3335
|
|
|
3567
3336
|
// src/logger/logger.module.ts
|
|
3568
|
-
var
|
|
3337
|
+
var import_common48 = require("@nestjs/common");
|
|
3569
3338
|
|
|
3570
3339
|
// src/logger/middleware/correlation-id.middleware.ts
|
|
3571
|
-
var
|
|
3340
|
+
var import_common47 = require("@nestjs/common");
|
|
3572
3341
|
function _ts_decorate21(decorators, target, key, desc2) {
|
|
3573
3342
|
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
3574
3343
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
|
|
@@ -3576,10 +3345,10 @@ function _ts_decorate21(decorators, target, key, desc2) {
|
|
|
3576
3345
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
3577
3346
|
}
|
|
3578
3347
|
__name(_ts_decorate21, "_ts_decorate");
|
|
3579
|
-
function
|
|
3348
|
+
function _ts_metadata15(k, v) {
|
|
3580
3349
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
3581
3350
|
}
|
|
3582
|
-
__name(
|
|
3351
|
+
__name(_ts_metadata15, "_ts_metadata");
|
|
3583
3352
|
var CorrelationIdMiddleware = class {
|
|
3584
3353
|
static {
|
|
3585
3354
|
__name(this, "CorrelationIdMiddleware");
|
|
@@ -3617,9 +3386,9 @@ var CorrelationIdMiddleware = class {
|
|
|
3617
3386
|
}
|
|
3618
3387
|
};
|
|
3619
3388
|
CorrelationIdMiddleware = _ts_decorate21([
|
|
3620
|
-
(0,
|
|
3621
|
-
|
|
3622
|
-
|
|
3389
|
+
(0, import_common47.Injectable)(),
|
|
3390
|
+
_ts_metadata15("design:type", Function),
|
|
3391
|
+
_ts_metadata15("design:paramtypes", [
|
|
3623
3392
|
typeof CorrelationIdMiddlewareOptions === "undefined" ? Object : CorrelationIdMiddlewareOptions
|
|
3624
3393
|
])
|
|
3625
3394
|
], CorrelationIdMiddleware);
|
|
@@ -3708,9 +3477,9 @@ function mergeWithDefaults(options = {}) {
|
|
|
3708
3477
|
__name(mergeWithDefaults, "mergeWithDefaults");
|
|
3709
3478
|
function createDefaultLoggerProvider(options) {
|
|
3710
3479
|
return {
|
|
3711
|
-
provide:
|
|
3480
|
+
provide: import_common48.Logger,
|
|
3712
3481
|
useFactory: /* @__PURE__ */ __name(() => {
|
|
3713
|
-
const logger = new
|
|
3482
|
+
const logger = new import_common48.Logger();
|
|
3714
3483
|
if (options.level) {
|
|
3715
3484
|
const levels = getLevelsUpTo(options.level);
|
|
3716
3485
|
logger.setLogLevels?.(levels);
|
|
@@ -3740,7 +3509,7 @@ function createLoggerProviders(options = {}) {
|
|
|
3740
3509
|
inject: [
|
|
3741
3510
|
LOGGER_MODULE_OPTIONS,
|
|
3742
3511
|
{
|
|
3743
|
-
token:
|
|
3512
|
+
token: import_common48.Logger,
|
|
3744
3513
|
optional: true
|
|
3745
3514
|
}
|
|
3746
3515
|
]
|
|
@@ -3819,10 +3588,10 @@ var LoggerModule = class _LoggerModule {
|
|
|
3819
3588
|
...asyncProviders,
|
|
3820
3589
|
// Default logger provider
|
|
3821
3590
|
{
|
|
3822
|
-
provide:
|
|
3591
|
+
provide: import_common48.Logger,
|
|
3823
3592
|
useFactory: /* @__PURE__ */ __name((opts) => {
|
|
3824
3593
|
if (opts.provider === "default") {
|
|
3825
|
-
const logger = new
|
|
3594
|
+
const logger = new import_common48.Logger();
|
|
3826
3595
|
if (opts.level) {
|
|
3827
3596
|
const levels = getLevelsUpTo(opts.level);
|
|
3828
3597
|
logger.setLogLevels?.(levels);
|
|
@@ -3844,7 +3613,7 @@ var LoggerModule = class _LoggerModule {
|
|
|
3844
3613
|
inject: [
|
|
3845
3614
|
LOGGER_MODULE_OPTIONS,
|
|
3846
3615
|
{
|
|
3847
|
-
token:
|
|
3616
|
+
token: import_common48.Logger,
|
|
3848
3617
|
optional: true
|
|
3849
3618
|
}
|
|
3850
3619
|
]
|
|
@@ -3944,24 +3713,24 @@ var LoggerModule = class _LoggerModule {
|
|
|
3944
3713
|
}
|
|
3945
3714
|
};
|
|
3946
3715
|
LoggerModule = _ts_decorate22([
|
|
3947
|
-
(0,
|
|
3948
|
-
(0,
|
|
3716
|
+
(0, import_common48.Global)(),
|
|
3717
|
+
(0, import_common48.Module)({})
|
|
3949
3718
|
], LoggerModule);
|
|
3950
3719
|
|
|
3951
3720
|
// src/root/root.module.ts
|
|
3952
|
-
var
|
|
3721
|
+
var import_common54 = require("@nestjs/common");
|
|
3953
3722
|
|
|
3954
3723
|
// src/root/controllers/app.controller.ts
|
|
3955
|
-
var
|
|
3956
|
-
var
|
|
3724
|
+
var import_common51 = require("@nestjs/common");
|
|
3725
|
+
var import_swagger7 = require("@nestjs/swagger");
|
|
3957
3726
|
|
|
3958
3727
|
// src/root/docs/app.docs.ts
|
|
3959
|
-
var
|
|
3960
|
-
var
|
|
3728
|
+
var import_common49 = require("@nestjs/common");
|
|
3729
|
+
var import_swagger6 = require("@nestjs/swagger");
|
|
3961
3730
|
function ApiHealthCheck() {
|
|
3962
|
-
return (0,
|
|
3731
|
+
return (0, import_common49.applyDecorators)((0, import_swagger6.ApiOperation)({
|
|
3963
3732
|
summary: "Health check endpoint"
|
|
3964
|
-
}), (0,
|
|
3733
|
+
}), (0, import_swagger6.ApiResponse)({
|
|
3965
3734
|
status: 200,
|
|
3966
3735
|
description: "Returns a welcome message indicating the API is running",
|
|
3967
3736
|
type: String
|
|
@@ -3970,7 +3739,7 @@ function ApiHealthCheck() {
|
|
|
3970
3739
|
__name(ApiHealthCheck, "ApiHealthCheck");
|
|
3971
3740
|
|
|
3972
3741
|
// src/root/services/app.service.ts
|
|
3973
|
-
var
|
|
3742
|
+
var import_common50 = require("@nestjs/common");
|
|
3974
3743
|
function _ts_decorate23(decorators, target, key, desc2) {
|
|
3975
3744
|
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
3976
3745
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
|
|
@@ -3988,7 +3757,7 @@ var AppService = class {
|
|
|
3988
3757
|
}
|
|
3989
3758
|
};
|
|
3990
3759
|
AppService = _ts_decorate23([
|
|
3991
|
-
(0,
|
|
3760
|
+
(0, import_common50.Injectable)()
|
|
3992
3761
|
], AppService);
|
|
3993
3762
|
|
|
3994
3763
|
// src/root/controllers/app.controller.ts
|
|
@@ -3999,10 +3768,10 @@ function _ts_decorate24(decorators, target, key, desc2) {
|
|
|
3999
3768
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
4000
3769
|
}
|
|
4001
3770
|
__name(_ts_decorate24, "_ts_decorate");
|
|
4002
|
-
function
|
|
3771
|
+
function _ts_metadata16(k, v) {
|
|
4003
3772
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
4004
3773
|
}
|
|
4005
|
-
__name(
|
|
3774
|
+
__name(_ts_metadata16, "_ts_metadata");
|
|
4006
3775
|
var AppController = class {
|
|
4007
3776
|
static {
|
|
4008
3777
|
__name(this, "AppController");
|
|
@@ -4017,34 +3786,34 @@ var AppController = class {
|
|
|
4017
3786
|
}
|
|
4018
3787
|
};
|
|
4019
3788
|
_ts_decorate24([
|
|
4020
|
-
(0,
|
|
3789
|
+
(0, import_common51.Get)(),
|
|
4021
3790
|
Public(),
|
|
4022
3791
|
ApiHealthCheck(),
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
3792
|
+
_ts_metadata16("design:type", Function),
|
|
3793
|
+
_ts_metadata16("design:paramtypes", []),
|
|
3794
|
+
_ts_metadata16("design:returntype", String)
|
|
4026
3795
|
], AppController.prototype, "getHello", null);
|
|
4027
3796
|
AppController = _ts_decorate24([
|
|
4028
|
-
(0,
|
|
4029
|
-
(0,
|
|
4030
|
-
|
|
4031
|
-
|
|
3797
|
+
(0, import_swagger7.ApiTags)("Health"),
|
|
3798
|
+
(0, import_common51.Controller)(),
|
|
3799
|
+
_ts_metadata16("design:type", Function),
|
|
3800
|
+
_ts_metadata16("design:paramtypes", [
|
|
4032
3801
|
typeof AppService === "undefined" ? Object : AppService
|
|
4033
3802
|
])
|
|
4034
3803
|
], AppController);
|
|
4035
3804
|
|
|
4036
3805
|
// src/root/controllers/csrf.controller.ts
|
|
4037
|
-
var
|
|
4038
|
-
var
|
|
3806
|
+
var import_common53 = require("@nestjs/common");
|
|
3807
|
+
var import_swagger9 = require("@nestjs/swagger");
|
|
4039
3808
|
|
|
4040
3809
|
// src/root/docs/csrf.docs.ts
|
|
4041
|
-
var
|
|
4042
|
-
var
|
|
3810
|
+
var import_common52 = require("@nestjs/common");
|
|
3811
|
+
var import_swagger8 = require("@nestjs/swagger");
|
|
4043
3812
|
function ApiGetCsrfToken() {
|
|
4044
|
-
return (0,
|
|
3813
|
+
return (0, import_common52.applyDecorators)((0, import_swagger8.ApiOperation)({
|
|
4045
3814
|
summary: "Get CSRF token",
|
|
4046
3815
|
description: "Generates and returns a CSRF token that must be included in all state-changing requests (POST, PUT, PATCH, DELETE). The token should be sent in the X-CSRF-Token header."
|
|
4047
|
-
}), (0,
|
|
3816
|
+
}), (0, import_swagger8.ApiResponse)({
|
|
4048
3817
|
status: 200,
|
|
4049
3818
|
description: "CSRF token generated successfully",
|
|
4050
3819
|
schema: {
|
|
@@ -4072,16 +3841,16 @@ function _ts_decorate25(decorators, target, key, desc2) {
|
|
|
4072
3841
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
4073
3842
|
}
|
|
4074
3843
|
__name(_ts_decorate25, "_ts_decorate");
|
|
4075
|
-
function
|
|
3844
|
+
function _ts_metadata17(k, v) {
|
|
4076
3845
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
4077
3846
|
}
|
|
4078
|
-
__name(
|
|
4079
|
-
function
|
|
3847
|
+
__name(_ts_metadata17, "_ts_metadata");
|
|
3848
|
+
function _ts_param6(paramIndex, decorator) {
|
|
4080
3849
|
return function(target, key) {
|
|
4081
3850
|
decorator(target, key, paramIndex);
|
|
4082
3851
|
};
|
|
4083
3852
|
}
|
|
4084
|
-
__name(
|
|
3853
|
+
__name(_ts_param6, "_ts_param");
|
|
4085
3854
|
var CsrfController = class {
|
|
4086
3855
|
static {
|
|
4087
3856
|
__name(this, "CsrfController");
|
|
@@ -4095,22 +3864,22 @@ var CsrfController = class {
|
|
|
4095
3864
|
}
|
|
4096
3865
|
};
|
|
4097
3866
|
_ts_decorate25([
|
|
4098
|
-
(0,
|
|
3867
|
+
(0, import_common53.Get)("token"),
|
|
4099
3868
|
Public(),
|
|
4100
|
-
(0,
|
|
3869
|
+
(0, import_common53.HttpCode)(import_common53.HttpStatus.OK),
|
|
4101
3870
|
ApiGetCsrfToken(),
|
|
4102
|
-
|
|
3871
|
+
_ts_param6(0, (0, import_common53.Res)({
|
|
4103
3872
|
passthrough: true
|
|
4104
3873
|
})),
|
|
4105
|
-
|
|
4106
|
-
|
|
3874
|
+
_ts_metadata17("design:type", Function),
|
|
3875
|
+
_ts_metadata17("design:paramtypes", [
|
|
4107
3876
|
typeof FastifyReply === "undefined" ? Object : FastifyReply
|
|
4108
3877
|
]),
|
|
4109
|
-
|
|
3878
|
+
_ts_metadata17("design:returntype", Object)
|
|
4110
3879
|
], CsrfController.prototype, "getToken", null);
|
|
4111
3880
|
CsrfController = _ts_decorate25([
|
|
4112
|
-
(0,
|
|
4113
|
-
(0,
|
|
3881
|
+
(0, import_swagger9.ApiTags)("CSRF"),
|
|
3882
|
+
(0, import_common53.Controller)("csrf")
|
|
4114
3883
|
], CsrfController);
|
|
4115
3884
|
|
|
4116
3885
|
// src/root/root.module.ts
|
|
@@ -4127,7 +3896,7 @@ var RootModule = class {
|
|
|
4127
3896
|
}
|
|
4128
3897
|
};
|
|
4129
3898
|
RootModule = _ts_decorate26([
|
|
4130
|
-
(0,
|
|
3899
|
+
(0, import_common54.Module)({
|
|
4131
3900
|
controllers: [
|
|
4132
3901
|
AppController,
|
|
4133
3902
|
CsrfController
|
|
@@ -4347,6 +4116,1066 @@ function normalizePhoneNumber(phone) {
|
|
|
4347
4116
|
return phone.startsWith("+") ? phone : `+${phone}`;
|
|
4348
4117
|
}
|
|
4349
4118
|
__name(normalizePhoneNumber, "normalizePhoneNumber");
|
|
4119
|
+
|
|
4120
|
+
// src/data-table/data-table.module.ts
|
|
4121
|
+
var import_common62 = require("@nestjs/common");
|
|
4122
|
+
var import_config15 = require("@nestjs/config");
|
|
4123
|
+
|
|
4124
|
+
// src/data-table/data-table.constants.ts
|
|
4125
|
+
var DATA_TABLE_VIEWS_TABLE = Symbol("DATA_TABLE_VIEWS_TABLE");
|
|
4126
|
+
|
|
4127
|
+
// src/data-table/state/controllers/data-table-state.controller.ts
|
|
4128
|
+
var import_common57 = require("@nestjs/common");
|
|
4129
|
+
var import_swagger12 = require("@nestjs/swagger");
|
|
4130
|
+
|
|
4131
|
+
// src/data-table/state/docs/data-table-state.docs.ts
|
|
4132
|
+
var import_common55 = require("@nestjs/common");
|
|
4133
|
+
var import_swagger11 = require("@nestjs/swagger");
|
|
4134
|
+
|
|
4135
|
+
// src/data-table/state/dto/request/upsert-data-table-state.dto.ts
|
|
4136
|
+
var import_swagger10 = require("@nestjs/swagger");
|
|
4137
|
+
var import_class_validator3 = require("class-validator");
|
|
4138
|
+
function _ts_decorate27(decorators, target, key, desc2) {
|
|
4139
|
+
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
4140
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
|
|
4141
|
+
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;
|
|
4142
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
4143
|
+
}
|
|
4144
|
+
__name(_ts_decorate27, "_ts_decorate");
|
|
4145
|
+
function _ts_metadata18(k, v) {
|
|
4146
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
4147
|
+
}
|
|
4148
|
+
__name(_ts_metadata18, "_ts_metadata");
|
|
4149
|
+
var UpsertDataTableStateDto = class {
|
|
4150
|
+
static {
|
|
4151
|
+
__name(this, "UpsertDataTableStateDto");
|
|
4152
|
+
}
|
|
4153
|
+
tableSlug;
|
|
4154
|
+
state;
|
|
4155
|
+
activeViewId;
|
|
4156
|
+
};
|
|
4157
|
+
_ts_decorate27([
|
|
4158
|
+
(0, import_swagger10.ApiProperty)({
|
|
4159
|
+
description: "Unique slug identifying the table",
|
|
4160
|
+
example: "cloud-providers"
|
|
4161
|
+
}),
|
|
4162
|
+
(0, import_class_validator3.IsString)(),
|
|
4163
|
+
(0, import_class_validator3.MaxLength)(100),
|
|
4164
|
+
_ts_metadata18("design:type", String)
|
|
4165
|
+
], UpsertDataTableStateDto.prototype, "tableSlug", void 0);
|
|
4166
|
+
_ts_decorate27([
|
|
4167
|
+
(0, import_swagger10.ApiProperty)({
|
|
4168
|
+
description: "Full table view state including filters, sort, and column visibility"
|
|
4169
|
+
}),
|
|
4170
|
+
(0, import_class_validator3.IsObject)(),
|
|
4171
|
+
_ts_metadata18("design:type", typeof TableViewState === "undefined" ? Object : TableViewState)
|
|
4172
|
+
], UpsertDataTableStateDto.prototype, "state", void 0);
|
|
4173
|
+
_ts_decorate27([
|
|
4174
|
+
(0, import_swagger10.ApiPropertyOptional)(),
|
|
4175
|
+
(0, import_class_validator3.IsOptional)(),
|
|
4176
|
+
(0, import_class_validator3.IsUUID)(),
|
|
4177
|
+
_ts_metadata18("design:type", Object)
|
|
4178
|
+
], UpsertDataTableStateDto.prototype, "activeViewId", void 0);
|
|
4179
|
+
|
|
4180
|
+
// src/data-table/state/docs/data-table-state.docs.ts
|
|
4181
|
+
function ApiUpsertDataTableState() {
|
|
4182
|
+
return (0, import_common55.applyDecorators)((0, import_swagger11.ApiOperation)({
|
|
4183
|
+
summary: "Save live table state",
|
|
4184
|
+
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."
|
|
4185
|
+
}), (0, import_swagger11.ApiBody)({
|
|
4186
|
+
type: UpsertDataTableStateDto
|
|
4187
|
+
}), (0, import_swagger11.ApiResponse)({
|
|
4188
|
+
status: 200,
|
|
4189
|
+
description: "Live state cached."
|
|
4190
|
+
}), (0, import_swagger11.ApiResponse)({
|
|
4191
|
+
status: 400,
|
|
4192
|
+
description: "Invalid request body."
|
|
4193
|
+
}), (0, import_swagger11.ApiResponse)({
|
|
4194
|
+
status: 401,
|
|
4195
|
+
description: "Unauthorized."
|
|
4196
|
+
}));
|
|
4197
|
+
}
|
|
4198
|
+
__name(ApiUpsertDataTableState, "ApiUpsertDataTableState");
|
|
4199
|
+
|
|
4200
|
+
// src/data-table/state/services/data-table-state.service.ts
|
|
4201
|
+
var import_common56 = require("@nestjs/common");
|
|
4202
|
+
var import_config13 = require("@nestjs/config");
|
|
4203
|
+
function _ts_decorate28(decorators, target, key, desc2) {
|
|
4204
|
+
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
4205
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
|
|
4206
|
+
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;
|
|
4207
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
4208
|
+
}
|
|
4209
|
+
__name(_ts_decorate28, "_ts_decorate");
|
|
4210
|
+
function _ts_metadata19(k, v) {
|
|
4211
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
4212
|
+
}
|
|
4213
|
+
__name(_ts_metadata19, "_ts_metadata");
|
|
4214
|
+
var EMPTY_TABLE_STATE = {
|
|
4215
|
+
filters: [],
|
|
4216
|
+
sort: [],
|
|
4217
|
+
columnVisibility: {},
|
|
4218
|
+
columnOrder: [],
|
|
4219
|
+
columnSizing: {},
|
|
4220
|
+
columnPinning: {
|
|
4221
|
+
left: [],
|
|
4222
|
+
right: []
|
|
4223
|
+
},
|
|
4224
|
+
lockedColumnSizing: false,
|
|
4225
|
+
density: "normal",
|
|
4226
|
+
filterOrder: [],
|
|
4227
|
+
filterVisibility: {},
|
|
4228
|
+
pagination: {
|
|
4229
|
+
limit: 20,
|
|
4230
|
+
offset: 0
|
|
4231
|
+
}
|
|
4232
|
+
};
|
|
4233
|
+
var DataTableStateService = class _DataTableStateService {
|
|
4234
|
+
static {
|
|
4235
|
+
__name(this, "DataTableStateService");
|
|
4236
|
+
}
|
|
4237
|
+
cacheService;
|
|
4238
|
+
configService;
|
|
4239
|
+
logger = new import_common56.Logger(_DataTableStateService.name);
|
|
4240
|
+
constructor(cacheService, configService) {
|
|
4241
|
+
this.cacheService = cacheService;
|
|
4242
|
+
this.configService = configService;
|
|
4243
|
+
}
|
|
4244
|
+
// Returns configured TTL for live table state in seconds, defaulting to 3600 (1h)
|
|
4245
|
+
get stateTtl() {
|
|
4246
|
+
return this.configService.get("TABLE_STATE_CACHE_TTL") ?? 3600;
|
|
4247
|
+
}
|
|
4248
|
+
// Saves live table state and active view ID to Redis; DB is not written
|
|
4249
|
+
async upsertCurrentState(userId, dto) {
|
|
4250
|
+
const key = `dt:${userId}:${dto.tableSlug}`;
|
|
4251
|
+
await this.cacheService.set(key, {
|
|
4252
|
+
state: dto.state,
|
|
4253
|
+
activeViewId: dto.activeViewId ?? null
|
|
4254
|
+
}, this.stateTtl);
|
|
4255
|
+
this.logger.log(`Cached live state for user: ${userId}, table: ${dto.tableSlug}`);
|
|
4256
|
+
}
|
|
4257
|
+
// Returns live table state and active view ID from Redis; returns empty state on miss — no DB query
|
|
4258
|
+
async getCurrentState(userId, tableSlug) {
|
|
4259
|
+
const key = `dt:${userId}:${tableSlug}`;
|
|
4260
|
+
const cached = await this.cacheService.get(key);
|
|
4261
|
+
return cached ?? {
|
|
4262
|
+
state: EMPTY_TABLE_STATE,
|
|
4263
|
+
activeViewId: null
|
|
4264
|
+
};
|
|
4265
|
+
}
|
|
4266
|
+
};
|
|
4267
|
+
DataTableStateService = _ts_decorate28([
|
|
4268
|
+
(0, import_common56.Injectable)(),
|
|
4269
|
+
_ts_metadata19("design:type", Function),
|
|
4270
|
+
_ts_metadata19("design:paramtypes", [
|
|
4271
|
+
typeof CacheService === "undefined" ? Object : CacheService,
|
|
4272
|
+
typeof import_config13.ConfigService === "undefined" ? Object : import_config13.ConfigService
|
|
4273
|
+
])
|
|
4274
|
+
], DataTableStateService);
|
|
4275
|
+
|
|
4276
|
+
// src/data-table/state/controllers/data-table-state.controller.ts
|
|
4277
|
+
function _ts_decorate29(decorators, target, key, desc2) {
|
|
4278
|
+
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
4279
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
|
|
4280
|
+
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;
|
|
4281
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
4282
|
+
}
|
|
4283
|
+
__name(_ts_decorate29, "_ts_decorate");
|
|
4284
|
+
function _ts_metadata20(k, v) {
|
|
4285
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
4286
|
+
}
|
|
4287
|
+
__name(_ts_metadata20, "_ts_metadata");
|
|
4288
|
+
function _ts_param7(paramIndex, decorator) {
|
|
4289
|
+
return function(target, key) {
|
|
4290
|
+
decorator(target, key, paramIndex);
|
|
4291
|
+
};
|
|
4292
|
+
}
|
|
4293
|
+
__name(_ts_param7, "_ts_param");
|
|
4294
|
+
var DataTableStateController = class _DataTableStateController {
|
|
4295
|
+
static {
|
|
4296
|
+
__name(this, "DataTableStateController");
|
|
4297
|
+
}
|
|
4298
|
+
dataTableStateService;
|
|
4299
|
+
logger = new import_common57.Logger(_DataTableStateController.name);
|
|
4300
|
+
constructor(dataTableStateService) {
|
|
4301
|
+
this.dataTableStateService = dataTableStateService;
|
|
4302
|
+
}
|
|
4303
|
+
// Saves live table state to Redis cache for the authenticated user's table
|
|
4304
|
+
upsertCurrentState(userId, dto) {
|
|
4305
|
+
this.logger.log(`POST /table-states - User: ${userId}, table: ${dto.tableSlug}`);
|
|
4306
|
+
return this.dataTableStateService.upsertCurrentState(userId, dto);
|
|
4307
|
+
}
|
|
4308
|
+
};
|
|
4309
|
+
_ts_decorate29([
|
|
4310
|
+
(0, import_common57.Post)(),
|
|
4311
|
+
(0, import_common57.HttpCode)(import_common57.HttpStatus.OK),
|
|
4312
|
+
ApiUpsertDataTableState(),
|
|
4313
|
+
_ts_param7(0, UserId()),
|
|
4314
|
+
_ts_param7(1, (0, import_common57.Body)()),
|
|
4315
|
+
_ts_metadata20("design:type", Function),
|
|
4316
|
+
_ts_metadata20("design:paramtypes", [
|
|
4317
|
+
String,
|
|
4318
|
+
typeof UpsertDataTableStateDto === "undefined" ? Object : UpsertDataTableStateDto
|
|
4319
|
+
]),
|
|
4320
|
+
_ts_metadata20("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
4321
|
+
], DataTableStateController.prototype, "upsertCurrentState", null);
|
|
4322
|
+
DataTableStateController = _ts_decorate29([
|
|
4323
|
+
(0, import_swagger12.ApiTags)("Table States"),
|
|
4324
|
+
(0, import_swagger12.ApiBearerAuth)(),
|
|
4325
|
+
RequireSession("CLOUD", "ADMIN"),
|
|
4326
|
+
(0, import_common57.Controller)("table-states"),
|
|
4327
|
+
_ts_metadata20("design:type", Function),
|
|
4328
|
+
_ts_metadata20("design:paramtypes", [
|
|
4329
|
+
typeof DataTableStateService === "undefined" ? Object : DataTableStateService
|
|
4330
|
+
])
|
|
4331
|
+
], DataTableStateController);
|
|
4332
|
+
|
|
4333
|
+
// src/data-table/views/controllers/data-table-views.controller.ts
|
|
4334
|
+
var import_common61 = require("@nestjs/common");
|
|
4335
|
+
var import_swagger19 = require("@nestjs/swagger");
|
|
4336
|
+
|
|
4337
|
+
// src/data-table/views/docs/data-table-views.docs.ts
|
|
4338
|
+
var import_common58 = require("@nestjs/common");
|
|
4339
|
+
var import_swagger18 = require("@nestjs/swagger");
|
|
4340
|
+
|
|
4341
|
+
// src/data-table/views/dto/entity/data-table-view.dto.ts
|
|
4342
|
+
var import_swagger13 = require("@nestjs/swagger");
|
|
4343
|
+
function _ts_decorate30(decorators, target, key, desc2) {
|
|
4344
|
+
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
4345
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
|
|
4346
|
+
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;
|
|
4347
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
4348
|
+
}
|
|
4349
|
+
__name(_ts_decorate30, "_ts_decorate");
|
|
4350
|
+
function _ts_metadata21(k, v) {
|
|
4351
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
4352
|
+
}
|
|
4353
|
+
__name(_ts_metadata21, "_ts_metadata");
|
|
4354
|
+
var DataTableViewDto = class _DataTableViewDto {
|
|
4355
|
+
static {
|
|
4356
|
+
__name(this, "DataTableViewDto");
|
|
4357
|
+
}
|
|
4358
|
+
id;
|
|
4359
|
+
name;
|
|
4360
|
+
tableSlug;
|
|
4361
|
+
state;
|
|
4362
|
+
isShared;
|
|
4363
|
+
isOwn;
|
|
4364
|
+
createdAt;
|
|
4365
|
+
updatedAt;
|
|
4366
|
+
// Creates a response DTO from a DataTableView entity, computing isOwn by comparing userId
|
|
4367
|
+
static from(view, userId) {
|
|
4368
|
+
const dto = new _DataTableViewDto();
|
|
4369
|
+
dto.id = view.id;
|
|
4370
|
+
dto.name = view.name ?? null;
|
|
4371
|
+
dto.tableSlug = view.tableSlug;
|
|
4372
|
+
dto.state = view.state;
|
|
4373
|
+
dto.isShared = view.isShared;
|
|
4374
|
+
dto.isOwn = view.userId === userId;
|
|
4375
|
+
dto.createdAt = view.createdAt;
|
|
4376
|
+
dto.updatedAt = view.updatedAt ?? null;
|
|
4377
|
+
return dto;
|
|
4378
|
+
}
|
|
4379
|
+
};
|
|
4380
|
+
_ts_decorate30([
|
|
4381
|
+
(0, import_swagger13.ApiProperty)({
|
|
4382
|
+
description: "View unique identifier"
|
|
4383
|
+
}),
|
|
4384
|
+
_ts_metadata21("design:type", String)
|
|
4385
|
+
], DataTableViewDto.prototype, "id", void 0);
|
|
4386
|
+
_ts_decorate30([
|
|
4387
|
+
(0, import_swagger13.ApiPropertyOptional)({
|
|
4388
|
+
description: "Display name of the view",
|
|
4389
|
+
nullable: true
|
|
4390
|
+
}),
|
|
4391
|
+
_ts_metadata21("design:type", Object)
|
|
4392
|
+
], DataTableViewDto.prototype, "name", void 0);
|
|
4393
|
+
_ts_decorate30([
|
|
4394
|
+
(0, import_swagger13.ApiProperty)({
|
|
4395
|
+
description: "Slug of the table this view belongs to",
|
|
4396
|
+
example: "cloud-providers"
|
|
4397
|
+
}),
|
|
4398
|
+
_ts_metadata21("design:type", String)
|
|
4399
|
+
], DataTableViewDto.prototype, "tableSlug", void 0);
|
|
4400
|
+
_ts_decorate30([
|
|
4401
|
+
(0, import_swagger13.ApiProperty)({
|
|
4402
|
+
description: "Stored filter, sort, and column visibility state"
|
|
4403
|
+
}),
|
|
4404
|
+
_ts_metadata21("design:type", typeof TableViewState === "undefined" ? Object : TableViewState)
|
|
4405
|
+
], DataTableViewDto.prototype, "state", void 0);
|
|
4406
|
+
_ts_decorate30([
|
|
4407
|
+
(0, import_swagger13.ApiProperty)({
|
|
4408
|
+
description: "Whether the view is visible to all users",
|
|
4409
|
+
example: false
|
|
4410
|
+
}),
|
|
4411
|
+
_ts_metadata21("design:type", Boolean)
|
|
4412
|
+
], DataTableViewDto.prototype, "isShared", void 0);
|
|
4413
|
+
_ts_decorate30([
|
|
4414
|
+
(0, import_swagger13.ApiProperty)({
|
|
4415
|
+
description: "Whether the requesting user owns this view",
|
|
4416
|
+
example: true
|
|
4417
|
+
}),
|
|
4418
|
+
_ts_metadata21("design:type", Boolean)
|
|
4419
|
+
], DataTableViewDto.prototype, "isOwn", void 0);
|
|
4420
|
+
_ts_decorate30([
|
|
4421
|
+
(0, import_swagger13.ApiProperty)({
|
|
4422
|
+
description: "Creation timestamp"
|
|
4423
|
+
}),
|
|
4424
|
+
_ts_metadata21("design:type", typeof Date === "undefined" ? Object : Date)
|
|
4425
|
+
], DataTableViewDto.prototype, "createdAt", void 0);
|
|
4426
|
+
_ts_decorate30([
|
|
4427
|
+
(0, import_swagger13.ApiPropertyOptional)({
|
|
4428
|
+
description: "Last updated timestamp",
|
|
4429
|
+
nullable: true
|
|
4430
|
+
}),
|
|
4431
|
+
_ts_metadata21("design:type", Object)
|
|
4432
|
+
], DataTableViewDto.prototype, "updatedAt", void 0);
|
|
4433
|
+
|
|
4434
|
+
// src/data-table/views/dto/request/create-data-table-view.dto.ts
|
|
4435
|
+
var import_swagger14 = require("@nestjs/swagger");
|
|
4436
|
+
var import_class_validator4 = require("class-validator");
|
|
4437
|
+
function _ts_decorate31(decorators, target, key, desc2) {
|
|
4438
|
+
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
4439
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
|
|
4440
|
+
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;
|
|
4441
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
4442
|
+
}
|
|
4443
|
+
__name(_ts_decorate31, "_ts_decorate");
|
|
4444
|
+
function _ts_metadata22(k, v) {
|
|
4445
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
4446
|
+
}
|
|
4447
|
+
__name(_ts_metadata22, "_ts_metadata");
|
|
4448
|
+
var CreateDataTableViewDto = class {
|
|
4449
|
+
static {
|
|
4450
|
+
__name(this, "CreateDataTableViewDto");
|
|
4451
|
+
}
|
|
4452
|
+
name;
|
|
4453
|
+
tableSlug;
|
|
4454
|
+
state;
|
|
4455
|
+
isShared;
|
|
4456
|
+
};
|
|
4457
|
+
_ts_decorate31([
|
|
4458
|
+
(0, import_swagger14.ApiProperty)({
|
|
4459
|
+
description: "Display name for the saved view",
|
|
4460
|
+
example: "AWS Only"
|
|
4461
|
+
}),
|
|
4462
|
+
(0, import_class_validator4.IsString)(),
|
|
4463
|
+
(0, import_class_validator4.MaxLength)(100),
|
|
4464
|
+
_ts_metadata22("design:type", String)
|
|
4465
|
+
], CreateDataTableViewDto.prototype, "name", void 0);
|
|
4466
|
+
_ts_decorate31([
|
|
4467
|
+
(0, import_swagger14.ApiProperty)({
|
|
4468
|
+
description: "Unique slug identifying the table",
|
|
4469
|
+
example: "cloud-providers"
|
|
4470
|
+
}),
|
|
4471
|
+
(0, import_class_validator4.IsString)(),
|
|
4472
|
+
(0, import_class_validator4.MaxLength)(100),
|
|
4473
|
+
_ts_metadata22("design:type", String)
|
|
4474
|
+
], CreateDataTableViewDto.prototype, "tableSlug", void 0);
|
|
4475
|
+
_ts_decorate31([
|
|
4476
|
+
(0, import_swagger14.ApiProperty)({
|
|
4477
|
+
description: "Full table view state including filters, sort, and column visibility"
|
|
4478
|
+
}),
|
|
4479
|
+
(0, import_class_validator4.IsObject)(),
|
|
4480
|
+
_ts_metadata22("design:type", typeof TableViewState === "undefined" ? Object : TableViewState)
|
|
4481
|
+
], CreateDataTableViewDto.prototype, "state", void 0);
|
|
4482
|
+
_ts_decorate31([
|
|
4483
|
+
(0, import_swagger14.ApiPropertyOptional)({
|
|
4484
|
+
description: "Whether this view is visible to all users",
|
|
4485
|
+
example: false
|
|
4486
|
+
}),
|
|
4487
|
+
(0, import_class_validator4.IsBoolean)(),
|
|
4488
|
+
(0, import_class_validator4.IsOptional)(),
|
|
4489
|
+
_ts_metadata22("design:type", Boolean)
|
|
4490
|
+
], CreateDataTableViewDto.prototype, "isShared", void 0);
|
|
4491
|
+
|
|
4492
|
+
// src/data-table/views/dto/request/rename-data-table-view.dto.ts
|
|
4493
|
+
var import_swagger15 = require("@nestjs/swagger");
|
|
4494
|
+
var import_class_validator5 = require("class-validator");
|
|
4495
|
+
function _ts_decorate32(decorators, target, key, desc2) {
|
|
4496
|
+
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
4497
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
|
|
4498
|
+
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;
|
|
4499
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
4500
|
+
}
|
|
4501
|
+
__name(_ts_decorate32, "_ts_decorate");
|
|
4502
|
+
function _ts_metadata23(k, v) {
|
|
4503
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
4504
|
+
}
|
|
4505
|
+
__name(_ts_metadata23, "_ts_metadata");
|
|
4506
|
+
var RenameDataTableViewDto = class {
|
|
4507
|
+
static {
|
|
4508
|
+
__name(this, "RenameDataTableViewDto");
|
|
4509
|
+
}
|
|
4510
|
+
name;
|
|
4511
|
+
};
|
|
4512
|
+
_ts_decorate32([
|
|
4513
|
+
(0, import_swagger15.ApiProperty)({
|
|
4514
|
+
description: "New display name for the view",
|
|
4515
|
+
example: "AWS Only"
|
|
4516
|
+
}),
|
|
4517
|
+
(0, import_class_validator5.IsString)(),
|
|
4518
|
+
(0, import_class_validator5.MinLength)(1),
|
|
4519
|
+
(0, import_class_validator5.MaxLength)(100),
|
|
4520
|
+
_ts_metadata23("design:type", String)
|
|
4521
|
+
], RenameDataTableViewDto.prototype, "name", void 0);
|
|
4522
|
+
|
|
4523
|
+
// src/data-table/views/dto/request/toggle-share-data-table-view.dto.ts
|
|
4524
|
+
var import_swagger16 = require("@nestjs/swagger");
|
|
4525
|
+
var import_class_validator6 = require("class-validator");
|
|
4526
|
+
function _ts_decorate33(decorators, target, key, desc2) {
|
|
4527
|
+
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
4528
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
|
|
4529
|
+
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;
|
|
4530
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
4531
|
+
}
|
|
4532
|
+
__name(_ts_decorate33, "_ts_decorate");
|
|
4533
|
+
function _ts_metadata24(k, v) {
|
|
4534
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
4535
|
+
}
|
|
4536
|
+
__name(_ts_metadata24, "_ts_metadata");
|
|
4537
|
+
var ToggleShareDataTableViewDto = class {
|
|
4538
|
+
static {
|
|
4539
|
+
__name(this, "ToggleShareDataTableViewDto");
|
|
4540
|
+
}
|
|
4541
|
+
isShared;
|
|
4542
|
+
};
|
|
4543
|
+
_ts_decorate33([
|
|
4544
|
+
(0, import_swagger16.ApiProperty)({
|
|
4545
|
+
description: "Whether the view should be visible to all users",
|
|
4546
|
+
example: true
|
|
4547
|
+
}),
|
|
4548
|
+
(0, import_class_validator6.IsBoolean)(),
|
|
4549
|
+
_ts_metadata24("design:type", Boolean)
|
|
4550
|
+
], ToggleShareDataTableViewDto.prototype, "isShared", void 0);
|
|
4551
|
+
|
|
4552
|
+
// src/data-table/views/dto/request/update-data-table-view.dto.ts
|
|
4553
|
+
var import_swagger17 = require("@nestjs/swagger");
|
|
4554
|
+
var import_class_validator7 = require("class-validator");
|
|
4555
|
+
function _ts_decorate34(decorators, target, key, desc2) {
|
|
4556
|
+
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
4557
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
|
|
4558
|
+
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;
|
|
4559
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
4560
|
+
}
|
|
4561
|
+
__name(_ts_decorate34, "_ts_decorate");
|
|
4562
|
+
function _ts_metadata25(k, v) {
|
|
4563
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
4564
|
+
}
|
|
4565
|
+
__name(_ts_metadata25, "_ts_metadata");
|
|
4566
|
+
var UpdateDataTableViewDto = class {
|
|
4567
|
+
static {
|
|
4568
|
+
__name(this, "UpdateDataTableViewDto");
|
|
4569
|
+
}
|
|
4570
|
+
state;
|
|
4571
|
+
};
|
|
4572
|
+
_ts_decorate34([
|
|
4573
|
+
(0, import_swagger17.ApiProperty)({
|
|
4574
|
+
description: "Updated filter, sort, and column visibility state"
|
|
4575
|
+
}),
|
|
4576
|
+
(0, import_class_validator7.IsObject)(),
|
|
4577
|
+
_ts_metadata25("design:type", typeof TableViewState === "undefined" ? Object : TableViewState)
|
|
4578
|
+
], UpdateDataTableViewDto.prototype, "state", void 0);
|
|
4579
|
+
|
|
4580
|
+
// src/data-table/views/docs/data-table-views.docs.ts
|
|
4581
|
+
function ApiListDataTableViews() {
|
|
4582
|
+
return (0, import_common58.applyDecorators)((0, import_swagger18.ApiOperation)({
|
|
4583
|
+
summary: "List named table views",
|
|
4584
|
+
description: "Returns the authenticated user's own named views plus all shared views for the given table slug."
|
|
4585
|
+
}), (0, import_swagger18.ApiQuery)({
|
|
4586
|
+
name: "tableSlug",
|
|
4587
|
+
description: "Slug of the table to fetch views for",
|
|
4588
|
+
example: "cloud-providers",
|
|
4589
|
+
required: true
|
|
4590
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4591
|
+
status: 200,
|
|
4592
|
+
description: "Named views retrieved.",
|
|
4593
|
+
type: [
|
|
4594
|
+
DataTableViewDto
|
|
4595
|
+
]
|
|
4596
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4597
|
+
status: 401,
|
|
4598
|
+
description: "Unauthorized."
|
|
4599
|
+
}));
|
|
4600
|
+
}
|
|
4601
|
+
__name(ApiListDataTableViews, "ApiListDataTableViews");
|
|
4602
|
+
function ApiCreateDataTableView() {
|
|
4603
|
+
return (0, import_common58.applyDecorators)((0, import_swagger18.ApiOperation)({
|
|
4604
|
+
summary: "Create named table view",
|
|
4605
|
+
description: "Saves the current table state as a named view snapshot. The name must be unique per user+table."
|
|
4606
|
+
}), (0, import_swagger18.ApiBody)({
|
|
4607
|
+
type: CreateDataTableViewDto
|
|
4608
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4609
|
+
status: 201,
|
|
4610
|
+
description: "Named view created.",
|
|
4611
|
+
type: DataTableViewDto
|
|
4612
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4613
|
+
status: 400,
|
|
4614
|
+
description: "Invalid request body."
|
|
4615
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4616
|
+
status: 401,
|
|
4617
|
+
description: "Unauthorized."
|
|
4618
|
+
}));
|
|
4619
|
+
}
|
|
4620
|
+
__name(ApiCreateDataTableView, "ApiCreateDataTableView");
|
|
4621
|
+
function ApiUpdateDataTableView() {
|
|
4622
|
+
return (0, import_common58.applyDecorators)((0, import_swagger18.ApiOperation)({
|
|
4623
|
+
summary: "Update named table view",
|
|
4624
|
+
description: "Updates the state of an existing named view. Only the owner can update."
|
|
4625
|
+
}), (0, import_swagger18.ApiParam)({
|
|
4626
|
+
name: "id",
|
|
4627
|
+
description: "UUID of the table view to update"
|
|
4628
|
+
}), (0, import_swagger18.ApiBody)({
|
|
4629
|
+
type: UpdateDataTableViewDto
|
|
4630
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4631
|
+
status: 200,
|
|
4632
|
+
description: "View updated.",
|
|
4633
|
+
type: DataTableViewDto
|
|
4634
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4635
|
+
status: 400,
|
|
4636
|
+
description: "Validation failed or not owned by caller."
|
|
4637
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4638
|
+
status: 401,
|
|
4639
|
+
description: "Unauthorized."
|
|
4640
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4641
|
+
status: 404,
|
|
4642
|
+
description: "View not found."
|
|
4643
|
+
}));
|
|
4644
|
+
}
|
|
4645
|
+
__name(ApiUpdateDataTableView, "ApiUpdateDataTableView");
|
|
4646
|
+
function ApiRenameDataTableView() {
|
|
4647
|
+
return (0, import_common58.applyDecorators)((0, import_swagger18.ApiOperation)({
|
|
4648
|
+
summary: "Rename a named table view",
|
|
4649
|
+
description: "Updates the display name of an existing view. The new name must be unique per user+table. Only the owner can rename."
|
|
4650
|
+
}), (0, import_swagger18.ApiParam)({
|
|
4651
|
+
name: "id",
|
|
4652
|
+
description: "UUID of the table view to rename"
|
|
4653
|
+
}), (0, import_swagger18.ApiBody)({
|
|
4654
|
+
type: RenameDataTableViewDto
|
|
4655
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4656
|
+
status: 200,
|
|
4657
|
+
description: "View renamed.",
|
|
4658
|
+
type: DataTableViewDto
|
|
4659
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4660
|
+
status: 400,
|
|
4661
|
+
description: "Not owned by caller."
|
|
4662
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4663
|
+
status: 401,
|
|
4664
|
+
description: "Unauthorized."
|
|
4665
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4666
|
+
status: 404,
|
|
4667
|
+
description: "View not found."
|
|
4668
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4669
|
+
status: 409,
|
|
4670
|
+
description: "A view with this name already exists."
|
|
4671
|
+
}));
|
|
4672
|
+
}
|
|
4673
|
+
__name(ApiRenameDataTableView, "ApiRenameDataTableView");
|
|
4674
|
+
function ApiToggleShareDataTableView() {
|
|
4675
|
+
return (0, import_common58.applyDecorators)((0, import_swagger18.ApiOperation)({
|
|
4676
|
+
summary: "Toggle view sharing",
|
|
4677
|
+
description: "Makes a view visible to all users (shared) or restricts it to the owner only (private). Only the owner can toggle sharing."
|
|
4678
|
+
}), (0, import_swagger18.ApiParam)({
|
|
4679
|
+
name: "id",
|
|
4680
|
+
description: "UUID of the table view"
|
|
4681
|
+
}), (0, import_swagger18.ApiBody)({
|
|
4682
|
+
type: ToggleShareDataTableViewDto
|
|
4683
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4684
|
+
status: 200,
|
|
4685
|
+
description: "Sharing status updated.",
|
|
4686
|
+
type: DataTableViewDto
|
|
4687
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4688
|
+
status: 400,
|
|
4689
|
+
description: "Not owned by caller."
|
|
4690
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4691
|
+
status: 401,
|
|
4692
|
+
description: "Unauthorized."
|
|
4693
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4694
|
+
status: 404,
|
|
4695
|
+
description: "View not found."
|
|
4696
|
+
}));
|
|
4697
|
+
}
|
|
4698
|
+
__name(ApiToggleShareDataTableView, "ApiToggleShareDataTableView");
|
|
4699
|
+
function ApiDeleteDataTableView() {
|
|
4700
|
+
return (0, import_common58.applyDecorators)((0, import_swagger18.ApiOperation)({
|
|
4701
|
+
summary: "Delete named table view",
|
|
4702
|
+
description: "Permanently deletes a named view. Only the owner can delete their own views."
|
|
4703
|
+
}), (0, import_swagger18.ApiParam)({
|
|
4704
|
+
name: "id",
|
|
4705
|
+
description: "UUID of the table view to delete"
|
|
4706
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4707
|
+
status: 200,
|
|
4708
|
+
description: "View deleted.",
|
|
4709
|
+
type: DataTableViewDto
|
|
4710
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4711
|
+
status: 400,
|
|
4712
|
+
description: "Not owned by caller."
|
|
4713
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4714
|
+
status: 401,
|
|
4715
|
+
description: "Unauthorized."
|
|
4716
|
+
}), (0, import_swagger18.ApiResponse)({
|
|
4717
|
+
status: 404,
|
|
4718
|
+
description: "View not found."
|
|
4719
|
+
}));
|
|
4720
|
+
}
|
|
4721
|
+
__name(ApiDeleteDataTableView, "ApiDeleteDataTableView");
|
|
4722
|
+
|
|
4723
|
+
// src/data-table/views/services/data-table-views.service.ts
|
|
4724
|
+
var import_node_crypto2 = require("crypto");
|
|
4725
|
+
var import_common60 = require("@nestjs/common");
|
|
4726
|
+
var import_config14 = require("@nestjs/config");
|
|
4727
|
+
|
|
4728
|
+
// src/data-table/views/repositories/data-table-views.repository.ts
|
|
4729
|
+
var import_common59 = require("@nestjs/common");
|
|
4730
|
+
var import_drizzle_orm3 = require("drizzle-orm");
|
|
4731
|
+
function _ts_decorate35(decorators, target, key, desc2) {
|
|
4732
|
+
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
4733
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
|
|
4734
|
+
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;
|
|
4735
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
4736
|
+
}
|
|
4737
|
+
__name(_ts_decorate35, "_ts_decorate");
|
|
4738
|
+
function _ts_metadata26(k, v) {
|
|
4739
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
4740
|
+
}
|
|
4741
|
+
__name(_ts_metadata26, "_ts_metadata");
|
|
4742
|
+
function _ts_param8(paramIndex, decorator) {
|
|
4743
|
+
return function(target, key) {
|
|
4744
|
+
decorator(target, key, paramIndex);
|
|
4745
|
+
};
|
|
4746
|
+
}
|
|
4747
|
+
__name(_ts_param8, "_ts_param");
|
|
4748
|
+
var NAMED_VIEWS_LIMIT = 100;
|
|
4749
|
+
var DataTableViewsRepository = class extends PrimaryBaseRepository {
|
|
4750
|
+
static {
|
|
4751
|
+
__name(this, "DataTableViewsRepository");
|
|
4752
|
+
}
|
|
4753
|
+
constructor(database, table) {
|
|
4754
|
+
super(database, table);
|
|
4755
|
+
}
|
|
4756
|
+
// Returns personal (non-shared) named views owned by the user for a given table
|
|
4757
|
+
async findPersonalViewsBySlug(userId, tableSlug) {
|
|
4758
|
+
const t = this.table;
|
|
4759
|
+
return this.db.select().from(this.table).where((0, import_drizzle_orm3.and)((0, import_drizzle_orm3.eq)(t.tableSlug, tableSlug), (0, import_drizzle_orm3.eq)(t.userId, userId), (0, import_drizzle_orm3.eq)(t.isShared, false))).orderBy(t.createdAt).limit(NAMED_VIEWS_LIMIT);
|
|
4760
|
+
}
|
|
4761
|
+
// Returns all shared named views for a given table — visible to all users
|
|
4762
|
+
async findSharedViewsBySlug(tableSlug) {
|
|
4763
|
+
const t = this.table;
|
|
4764
|
+
return this.db.select().from(this.table).where((0, import_drizzle_orm3.and)((0, import_drizzle_orm3.eq)(t.tableSlug, tableSlug), (0, import_drizzle_orm3.eq)(t.isShared, true))).orderBy(t.createdAt).limit(NAMED_VIEWS_LIMIT);
|
|
4765
|
+
}
|
|
4766
|
+
};
|
|
4767
|
+
DataTableViewsRepository = _ts_decorate35([
|
|
4768
|
+
(0, import_common59.Injectable)(),
|
|
4769
|
+
_ts_param8(1, (0, import_common59.Inject)(DATA_TABLE_VIEWS_TABLE)),
|
|
4770
|
+
_ts_metadata26("design:type", Function),
|
|
4771
|
+
_ts_metadata26("design:paramtypes", [
|
|
4772
|
+
typeof PrimaryDatabaseService === "undefined" ? Object : PrimaryDatabaseService,
|
|
4773
|
+
typeof PgTable === "undefined" ? Object : PgTable
|
|
4774
|
+
])
|
|
4775
|
+
], DataTableViewsRepository);
|
|
4776
|
+
|
|
4777
|
+
// src/data-table/views/services/data-table-views.service.ts
|
|
4778
|
+
function _ts_decorate36(decorators, target, key, desc2) {
|
|
4779
|
+
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
4780
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
|
|
4781
|
+
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;
|
|
4782
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
4783
|
+
}
|
|
4784
|
+
__name(_ts_decorate36, "_ts_decorate");
|
|
4785
|
+
function _ts_metadata27(k, v) {
|
|
4786
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
4787
|
+
}
|
|
4788
|
+
__name(_ts_metadata27, "_ts_metadata");
|
|
4789
|
+
function computeChecksum(value) {
|
|
4790
|
+
return (0, import_node_crypto2.createHash)("sha256").update(JSON.stringify(value)).digest("hex");
|
|
4791
|
+
}
|
|
4792
|
+
__name(computeChecksum, "computeChecksum");
|
|
4793
|
+
var DataTableViewsService = class _DataTableViewsService {
|
|
4794
|
+
static {
|
|
4795
|
+
__name(this, "DataTableViewsService");
|
|
4796
|
+
}
|
|
4797
|
+
dataTableViewsRepository;
|
|
4798
|
+
cacheService;
|
|
4799
|
+
configService;
|
|
4800
|
+
logger = new import_common60.Logger(_DataTableViewsService.name);
|
|
4801
|
+
constructor(dataTableViewsRepository, cacheService, configService) {
|
|
4802
|
+
this.dataTableViewsRepository = dataTableViewsRepository;
|
|
4803
|
+
this.cacheService = cacheService;
|
|
4804
|
+
this.configService = configService;
|
|
4805
|
+
}
|
|
4806
|
+
// Builds the Redis key for a user's personal (non-shared) views for a given table
|
|
4807
|
+
personalViewsKey(userId, tableSlug) {
|
|
4808
|
+
return `views:personal:${userId}:${tableSlug}`;
|
|
4809
|
+
}
|
|
4810
|
+
// Builds the Redis key for all shared views for a given table — same key for all users
|
|
4811
|
+
sharedViewsKey(tableSlug) {
|
|
4812
|
+
return `views:shared:${tableSlug}`;
|
|
4813
|
+
}
|
|
4814
|
+
// Returns configured TTL for named views in seconds, defaulting to 86400 (24h)
|
|
4815
|
+
get viewsTtl() {
|
|
4816
|
+
return this.configService.get("TABLE_VIEWS_CACHE_TTL") ?? 86400;
|
|
4817
|
+
}
|
|
4818
|
+
// Fetches personal views from cache; falls back to DB and warms cache on miss
|
|
4819
|
+
async getOrCachePersonalViews(userId, tableSlug) {
|
|
4820
|
+
const key = this.personalViewsKey(userId, tableSlug);
|
|
4821
|
+
const cached = await this.cacheService.get(key);
|
|
4822
|
+
if (cached) {
|
|
4823
|
+
this.logger.debug(`Cache hit for personal views: user=${userId}, table=${tableSlug}`);
|
|
4824
|
+
return cached;
|
|
4825
|
+
}
|
|
4826
|
+
const rows = await this.dataTableViewsRepository.findPersonalViewsBySlug(userId, tableSlug);
|
|
4827
|
+
await this.cacheService.set(key, rows, this.viewsTtl);
|
|
4828
|
+
return rows;
|
|
4829
|
+
}
|
|
4830
|
+
// Fetches shared views from cache; falls back to DB and warms cache on miss
|
|
4831
|
+
async getOrCacheSharedViews(tableSlug) {
|
|
4832
|
+
const key = this.sharedViewsKey(tableSlug);
|
|
4833
|
+
const cached = await this.cacheService.get(key);
|
|
4834
|
+
if (cached) {
|
|
4835
|
+
this.logger.debug(`Cache hit for shared views: table=${tableSlug}`);
|
|
4836
|
+
return cached;
|
|
4837
|
+
}
|
|
4838
|
+
const rows = await this.dataTableViewsRepository.findSharedViewsBySlug(tableSlug);
|
|
4839
|
+
await this.cacheService.set(key, rows, this.viewsTtl);
|
|
4840
|
+
return rows;
|
|
4841
|
+
}
|
|
4842
|
+
// Deletes personal and/or shared cache keys based on which pools the mutation affects
|
|
4843
|
+
async invalidateViewsCache(userId, tableSlug, affectsPersonal, affectsShared) {
|
|
4844
|
+
const toDelete = [];
|
|
4845
|
+
if (affectsPersonal) toDelete.push(this.personalViewsKey(userId, tableSlug));
|
|
4846
|
+
if (affectsShared) toDelete.push(this.sharedViewsKey(tableSlug));
|
|
4847
|
+
if (toDelete.length > 0) await this.cacheService.del(...toDelete);
|
|
4848
|
+
}
|
|
4849
|
+
// Returns personal + shared named views — each pool fetched from cache or DB in parallel
|
|
4850
|
+
async findViews(userId, tableSlug) {
|
|
4851
|
+
const [personalRows, sharedRows] = await Promise.all([
|
|
4852
|
+
this.getOrCachePersonalViews(userId, tableSlug),
|
|
4853
|
+
this.getOrCacheSharedViews(tableSlug)
|
|
4854
|
+
]);
|
|
4855
|
+
return [
|
|
4856
|
+
...personalRows,
|
|
4857
|
+
...sharedRows
|
|
4858
|
+
].map((row) => DataTableViewDto.from(row, userId));
|
|
4859
|
+
}
|
|
4860
|
+
// Creates a named snapshot and invalidates the relevant cache pool
|
|
4861
|
+
async createView(userId, dto) {
|
|
4862
|
+
const view = await this.dataTableViewsRepository.create({
|
|
4863
|
+
userId,
|
|
4864
|
+
tableSlug: dto.tableSlug,
|
|
4865
|
+
name: dto.name,
|
|
4866
|
+
state: dto.state,
|
|
4867
|
+
isShared: dto.isShared ?? false
|
|
4868
|
+
});
|
|
4869
|
+
this.logger.log(`Created view "${dto.name}" for user: ${userId}, table: ${dto.tableSlug}`);
|
|
4870
|
+
const isShared = dto.isShared ?? false;
|
|
4871
|
+
await this.invalidateViewsCache(userId, dto.tableSlug, !isShared, isShared);
|
|
4872
|
+
return DataTableViewDto.from(view, userId);
|
|
4873
|
+
}
|
|
4874
|
+
// Updates the state of a named view — skips DB write if state is unchanged
|
|
4875
|
+
async updateView(userId, id, dto) {
|
|
4876
|
+
const view = await this.dataTableViewsRepository.findById(id);
|
|
4877
|
+
if (!view) throw new NotFoundException("Table view not found.");
|
|
4878
|
+
if (view.userId !== userId) throw new BadRequestException("You do not have permission to update this view.");
|
|
4879
|
+
if (computeChecksum(dto.state) === computeChecksum(view.state)) {
|
|
4880
|
+
this.logger.log(`State unchanged for view ${id} \u2014 skipping DB write`);
|
|
4881
|
+
return DataTableViewDto.from(view, userId);
|
|
4882
|
+
}
|
|
4883
|
+
const updated = await this.dataTableViewsRepository.update(id, {
|
|
4884
|
+
state: dto.state
|
|
4885
|
+
});
|
|
4886
|
+
this.logger.log(`Updated state for view ${id}, user: ${userId}`);
|
|
4887
|
+
await this.invalidateViewsCache(userId, view.tableSlug, !view.isShared, view.isShared);
|
|
4888
|
+
return DataTableViewDto.from(updated, userId);
|
|
4889
|
+
}
|
|
4890
|
+
// Toggles the sharing status of a named view — updates both personal and shared cache
|
|
4891
|
+
async toggleShareView(userId, id, isShared) {
|
|
4892
|
+
const view = await this.dataTableViewsRepository.findById(id);
|
|
4893
|
+
if (!view) throw new NotFoundException("Table view not found.");
|
|
4894
|
+
if (view.userId !== userId) throw new BadRequestException("You do not have permission to share this view.");
|
|
4895
|
+
const updated = await this.dataTableViewsRepository.update(id, {
|
|
4896
|
+
isShared
|
|
4897
|
+
});
|
|
4898
|
+
this.logger.log(`Set isShared=${isShared} for view ${id}, user: ${userId}`);
|
|
4899
|
+
await this.invalidateViewsCache(userId, view.tableSlug, true, true);
|
|
4900
|
+
return DataTableViewDto.from(updated, userId);
|
|
4901
|
+
}
|
|
4902
|
+
// Renames a named view — enforces unique name per user+table, invalidates personal cache
|
|
4903
|
+
async renameView(userId, id, name) {
|
|
4904
|
+
const view = await this.dataTableViewsRepository.findById(id);
|
|
4905
|
+
if (!view) throw new NotFoundException("Table view not found.");
|
|
4906
|
+
if (view.userId !== userId) throw new BadRequestException("You do not have permission to rename this view.");
|
|
4907
|
+
const existing = await this.dataTableViewsRepository.findOne({
|
|
4908
|
+
userId,
|
|
4909
|
+
tableSlug: view.tableSlug,
|
|
4910
|
+
name,
|
|
4911
|
+
isShared: false
|
|
4912
|
+
});
|
|
4913
|
+
if (existing && existing.id !== id) {
|
|
4914
|
+
throw new ConflictException({
|
|
4915
|
+
label: "Name Already Taken",
|
|
4916
|
+
detail: "A view with this name already exists for this table.",
|
|
4917
|
+
errors: [
|
|
4918
|
+
{
|
|
4919
|
+
field: "name",
|
|
4920
|
+
message: "Name already taken"
|
|
4921
|
+
}
|
|
4922
|
+
]
|
|
4923
|
+
});
|
|
4924
|
+
}
|
|
4925
|
+
const updated = await this.dataTableViewsRepository.update(id, {
|
|
4926
|
+
name
|
|
4927
|
+
});
|
|
4928
|
+
this.logger.log(`Renamed view ${id} to "${name}" for user: ${userId}`);
|
|
4929
|
+
await this.invalidateViewsCache(userId, view.tableSlug, !view.isShared, view.isShared);
|
|
4930
|
+
return DataTableViewDto.from(updated, userId);
|
|
4931
|
+
}
|
|
4932
|
+
// Deletes a named view and invalidates the relevant cache pool
|
|
4933
|
+
async deleteView(userId, id) {
|
|
4934
|
+
const view = await this.dataTableViewsRepository.findById(id);
|
|
4935
|
+
if (!view) throw new NotFoundException("Table view not found.");
|
|
4936
|
+
if (view.userId !== userId) throw new BadRequestException("You do not have permission to delete this view.");
|
|
4937
|
+
await this.dataTableViewsRepository.delete(id);
|
|
4938
|
+
this.logger.log(`Deleted view ${id} for user: ${userId}`);
|
|
4939
|
+
await this.invalidateViewsCache(userId, view.tableSlug, !view.isShared, view.isShared);
|
|
4940
|
+
return DataTableViewDto.from(view, userId);
|
|
4941
|
+
}
|
|
4942
|
+
};
|
|
4943
|
+
DataTableViewsService = _ts_decorate36([
|
|
4944
|
+
(0, import_common60.Injectable)(),
|
|
4945
|
+
_ts_metadata27("design:type", Function),
|
|
4946
|
+
_ts_metadata27("design:paramtypes", [
|
|
4947
|
+
typeof DataTableViewsRepository === "undefined" ? Object : DataTableViewsRepository,
|
|
4948
|
+
typeof CacheService === "undefined" ? Object : CacheService,
|
|
4949
|
+
typeof import_config14.ConfigService === "undefined" ? Object : import_config14.ConfigService
|
|
4950
|
+
])
|
|
4951
|
+
], DataTableViewsService);
|
|
4952
|
+
|
|
4953
|
+
// src/data-table/views/controllers/data-table-views.controller.ts
|
|
4954
|
+
function _ts_decorate37(decorators, target, key, desc2) {
|
|
4955
|
+
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
4956
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
|
|
4957
|
+
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;
|
|
4958
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
4959
|
+
}
|
|
4960
|
+
__name(_ts_decorate37, "_ts_decorate");
|
|
4961
|
+
function _ts_metadata28(k, v) {
|
|
4962
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
4963
|
+
}
|
|
4964
|
+
__name(_ts_metadata28, "_ts_metadata");
|
|
4965
|
+
function _ts_param9(paramIndex, decorator) {
|
|
4966
|
+
return function(target, key) {
|
|
4967
|
+
decorator(target, key, paramIndex);
|
|
4968
|
+
};
|
|
4969
|
+
}
|
|
4970
|
+
__name(_ts_param9, "_ts_param");
|
|
4971
|
+
var DataTableViewsController = class _DataTableViewsController {
|
|
4972
|
+
static {
|
|
4973
|
+
__name(this, "DataTableViewsController");
|
|
4974
|
+
}
|
|
4975
|
+
dataTableViewsService;
|
|
4976
|
+
logger = new import_common61.Logger(_DataTableViewsController.name);
|
|
4977
|
+
constructor(dataTableViewsService) {
|
|
4978
|
+
this.dataTableViewsService = dataTableViewsService;
|
|
4979
|
+
}
|
|
4980
|
+
// Returns all named views for the given table — own plus shared
|
|
4981
|
+
findViews(userId, tableSlug) {
|
|
4982
|
+
this.logger.log(`GET /table-views?tableSlug=${tableSlug} - User: ${userId}`);
|
|
4983
|
+
return this.dataTableViewsService.findViews(userId, tableSlug);
|
|
4984
|
+
}
|
|
4985
|
+
// Creates a named snapshot of the current table state
|
|
4986
|
+
createView(userId, dto) {
|
|
4987
|
+
this.logger.log(`POST /table-views - User: ${userId}, table: ${dto.tableSlug}`);
|
|
4988
|
+
return this.dataTableViewsService.createView(userId, dto);
|
|
4989
|
+
}
|
|
4990
|
+
// Updates state of an existing named view
|
|
4991
|
+
updateView(userId, id, dto) {
|
|
4992
|
+
this.logger.log(`PATCH /table-views/${id} - User: ${userId}`);
|
|
4993
|
+
return this.dataTableViewsService.updateView(userId, id, dto);
|
|
4994
|
+
}
|
|
4995
|
+
// Renames an existing named view — enforces unique name per user+table
|
|
4996
|
+
renameView(userId, id, dto) {
|
|
4997
|
+
this.logger.log(`PATCH /table-views/${id}/rename - User: ${userId}`);
|
|
4998
|
+
return this.dataTableViewsService.renameView(userId, id, dto.name);
|
|
4999
|
+
}
|
|
5000
|
+
// Toggles sharing visibility of a named view
|
|
5001
|
+
toggleShareView(userId, id, dto) {
|
|
5002
|
+
this.logger.log(`PATCH /table-views/${id}/share - User: ${userId}`);
|
|
5003
|
+
return this.dataTableViewsService.toggleShareView(userId, id, dto.isShared);
|
|
5004
|
+
}
|
|
5005
|
+
// Deletes a named view owned by the authenticated user
|
|
5006
|
+
deleteView(userId, id) {
|
|
5007
|
+
this.logger.log(`DELETE /table-views/${id} - User: ${userId}`);
|
|
5008
|
+
return this.dataTableViewsService.deleteView(userId, id);
|
|
5009
|
+
}
|
|
5010
|
+
};
|
|
5011
|
+
_ts_decorate37([
|
|
5012
|
+
(0, import_common61.Get)(),
|
|
5013
|
+
ApiListDataTableViews(),
|
|
5014
|
+
_ts_param9(0, UserId()),
|
|
5015
|
+
_ts_param9(1, (0, import_common61.Query)("tableSlug")),
|
|
5016
|
+
_ts_metadata28("design:type", Function),
|
|
5017
|
+
_ts_metadata28("design:paramtypes", [
|
|
5018
|
+
String,
|
|
5019
|
+
String
|
|
5020
|
+
]),
|
|
5021
|
+
_ts_metadata28("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
5022
|
+
], DataTableViewsController.prototype, "findViews", null);
|
|
5023
|
+
_ts_decorate37([
|
|
5024
|
+
(0, import_common61.Post)(),
|
|
5025
|
+
(0, import_common61.HttpCode)(import_common61.HttpStatus.CREATED),
|
|
5026
|
+
ApiCreateDataTableView(),
|
|
5027
|
+
_ts_param9(0, UserId()),
|
|
5028
|
+
_ts_param9(1, (0, import_common61.Body)()),
|
|
5029
|
+
_ts_metadata28("design:type", Function),
|
|
5030
|
+
_ts_metadata28("design:paramtypes", [
|
|
5031
|
+
String,
|
|
5032
|
+
typeof CreateDataTableViewDto === "undefined" ? Object : CreateDataTableViewDto
|
|
5033
|
+
]),
|
|
5034
|
+
_ts_metadata28("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
5035
|
+
], DataTableViewsController.prototype, "createView", null);
|
|
5036
|
+
_ts_decorate37([
|
|
5037
|
+
(0, import_common61.Patch)(":id"),
|
|
5038
|
+
ApiUpdateDataTableView(),
|
|
5039
|
+
_ts_param9(0, UserId()),
|
|
5040
|
+
_ts_param9(1, (0, import_common61.Param)("id")),
|
|
5041
|
+
_ts_param9(2, (0, import_common61.Body)()),
|
|
5042
|
+
_ts_metadata28("design:type", Function),
|
|
5043
|
+
_ts_metadata28("design:paramtypes", [
|
|
5044
|
+
String,
|
|
5045
|
+
String,
|
|
5046
|
+
typeof UpdateDataTableViewDto === "undefined" ? Object : UpdateDataTableViewDto
|
|
5047
|
+
]),
|
|
5048
|
+
_ts_metadata28("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
5049
|
+
], DataTableViewsController.prototype, "updateView", null);
|
|
5050
|
+
_ts_decorate37([
|
|
5051
|
+
(0, import_common61.Patch)(":id/rename"),
|
|
5052
|
+
ApiRenameDataTableView(),
|
|
5053
|
+
_ts_param9(0, UserId()),
|
|
5054
|
+
_ts_param9(1, (0, import_common61.Param)("id")),
|
|
5055
|
+
_ts_param9(2, (0, import_common61.Body)()),
|
|
5056
|
+
_ts_metadata28("design:type", Function),
|
|
5057
|
+
_ts_metadata28("design:paramtypes", [
|
|
5058
|
+
String,
|
|
5059
|
+
String,
|
|
5060
|
+
typeof RenameDataTableViewDto === "undefined" ? Object : RenameDataTableViewDto
|
|
5061
|
+
]),
|
|
5062
|
+
_ts_metadata28("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
5063
|
+
], DataTableViewsController.prototype, "renameView", null);
|
|
5064
|
+
_ts_decorate37([
|
|
5065
|
+
(0, import_common61.Patch)(":id/share"),
|
|
5066
|
+
ApiToggleShareDataTableView(),
|
|
5067
|
+
_ts_param9(0, UserId()),
|
|
5068
|
+
_ts_param9(1, (0, import_common61.Param)("id")),
|
|
5069
|
+
_ts_param9(2, (0, import_common61.Body)()),
|
|
5070
|
+
_ts_metadata28("design:type", Function),
|
|
5071
|
+
_ts_metadata28("design:paramtypes", [
|
|
5072
|
+
String,
|
|
5073
|
+
String,
|
|
5074
|
+
typeof ToggleShareDataTableViewDto === "undefined" ? Object : ToggleShareDataTableViewDto
|
|
5075
|
+
]),
|
|
5076
|
+
_ts_metadata28("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
5077
|
+
], DataTableViewsController.prototype, "toggleShareView", null);
|
|
5078
|
+
_ts_decorate37([
|
|
5079
|
+
(0, import_common61.Delete)(":id"),
|
|
5080
|
+
ApiDeleteDataTableView(),
|
|
5081
|
+
_ts_param9(0, UserId()),
|
|
5082
|
+
_ts_param9(1, (0, import_common61.Param)("id")),
|
|
5083
|
+
_ts_metadata28("design:type", Function),
|
|
5084
|
+
_ts_metadata28("design:paramtypes", [
|
|
5085
|
+
String,
|
|
5086
|
+
String
|
|
5087
|
+
]),
|
|
5088
|
+
_ts_metadata28("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
5089
|
+
], DataTableViewsController.prototype, "deleteView", null);
|
|
5090
|
+
DataTableViewsController = _ts_decorate37([
|
|
5091
|
+
(0, import_swagger19.ApiTags)("Table Views"),
|
|
5092
|
+
(0, import_swagger19.ApiBearerAuth)(),
|
|
5093
|
+
RequireSession("CLOUD", "ADMIN"),
|
|
5094
|
+
(0, import_common61.Controller)("table-views"),
|
|
5095
|
+
_ts_metadata28("design:type", Function),
|
|
5096
|
+
_ts_metadata28("design:paramtypes", [
|
|
5097
|
+
typeof DataTableViewsService === "undefined" ? Object : DataTableViewsService
|
|
5098
|
+
])
|
|
5099
|
+
], DataTableViewsController);
|
|
5100
|
+
|
|
5101
|
+
// src/data-table/data-table.module.ts
|
|
5102
|
+
function _ts_decorate38(decorators, target, key, desc2) {
|
|
5103
|
+
var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
|
|
5104
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
|
|
5105
|
+
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;
|
|
5106
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
5107
|
+
}
|
|
5108
|
+
__name(_ts_decorate38, "_ts_decorate");
|
|
5109
|
+
var DataTableModule = class _DataTableModule {
|
|
5110
|
+
static {
|
|
5111
|
+
__name(this, "DataTableModule");
|
|
5112
|
+
}
|
|
5113
|
+
static forRoot(options) {
|
|
5114
|
+
return {
|
|
5115
|
+
global: true,
|
|
5116
|
+
module: _DataTableModule,
|
|
5117
|
+
imports: [
|
|
5118
|
+
import_config15.ConfigModule,
|
|
5119
|
+
CacheModule
|
|
5120
|
+
],
|
|
5121
|
+
controllers: [
|
|
5122
|
+
DataTableStateController,
|
|
5123
|
+
DataTableViewsController
|
|
5124
|
+
],
|
|
5125
|
+
providers: [
|
|
5126
|
+
{
|
|
5127
|
+
provide: DATA_TABLE_VIEWS_TABLE,
|
|
5128
|
+
useValue: options.tableViews
|
|
5129
|
+
},
|
|
5130
|
+
DataTableViewsService,
|
|
5131
|
+
DataTableViewsRepository,
|
|
5132
|
+
DataTableStateService
|
|
5133
|
+
],
|
|
5134
|
+
exports: [
|
|
5135
|
+
DataTableViewsService,
|
|
5136
|
+
DataTableStateService
|
|
5137
|
+
]
|
|
5138
|
+
};
|
|
5139
|
+
}
|
|
5140
|
+
};
|
|
5141
|
+
DataTableModule = _ts_decorate38([
|
|
5142
|
+
(0, import_common62.Module)({})
|
|
5143
|
+
], DataTableModule);
|
|
5144
|
+
|
|
5145
|
+
// src/drizzle-pg-core.ts
|
|
5146
|
+
var drizzle_pg_core_exports = {};
|
|
5147
|
+
__reExport(drizzle_pg_core_exports, require("drizzle-orm/pg-core"));
|
|
5148
|
+
|
|
5149
|
+
// src/data-table/schema/data-table-views.table.ts
|
|
5150
|
+
function dataTableViewsColumns() {
|
|
5151
|
+
return {
|
|
5152
|
+
id: (0, drizzle_pg_core_exports.uuid)("id").primaryKey().defaultRandom(),
|
|
5153
|
+
userId: (0, drizzle_pg_core_exports.uuid)("user_id").notNull(),
|
|
5154
|
+
tableSlug: (0, drizzle_pg_core_exports.varchar)("table_slug", {
|
|
5155
|
+
length: 100
|
|
5156
|
+
}).notNull(),
|
|
5157
|
+
name: (0, drizzle_pg_core_exports.varchar)("name", {
|
|
5158
|
+
length: 100
|
|
5159
|
+
}).notNull(),
|
|
5160
|
+
state: (0, drizzle_pg_core_exports.jsonb)("state").notNull().$type(),
|
|
5161
|
+
isShared: (0, drizzle_pg_core_exports.boolean)("is_shared").notNull().default(false),
|
|
5162
|
+
createdAt: (0, drizzle_pg_core_exports.timestamp)("created_at", {
|
|
5163
|
+
withTimezone: true
|
|
5164
|
+
}).notNull().defaultNow(),
|
|
5165
|
+
updatedAt: (0, drizzle_pg_core_exports.timestamp)("updated_at", {
|
|
5166
|
+
withTimezone: true
|
|
5167
|
+
}).$onUpdate(() => /* @__PURE__ */ new Date())
|
|
5168
|
+
};
|
|
5169
|
+
}
|
|
5170
|
+
__name(dataTableViewsColumns, "dataTableViewsColumns");
|
|
5171
|
+
function dataTableViewsIndexes(table) {
|
|
5172
|
+
return [
|
|
5173
|
+
(0, drizzle_pg_core_exports.index)("table_views_user_table_idx").on(table.userId, table.tableSlug),
|
|
5174
|
+
(0, drizzle_pg_core_exports.index)("table_views_shared_slug_idx").on(table.tableSlug, table.isShared),
|
|
5175
|
+
(0, drizzle_pg_core_exports.uniqueIndex)("table_views_user_table_name_shared_unique").on(table.userId, table.tableSlug, table.name, table.isShared)
|
|
5176
|
+
];
|
|
5177
|
+
}
|
|
5178
|
+
__name(dataTableViewsIndexes, "dataTableViewsIndexes");
|
|
4350
5179
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4351
5180
|
0 && (module.exports = {
|
|
4352
5181
|
AccessToken,
|
|
@@ -4359,7 +5188,14 @@ __name(normalizePhoneNumber, "normalizePhoneNumber");
|
|
|
4359
5188
|
ConflictException,
|
|
4360
5189
|
CookieDomain,
|
|
4361
5190
|
CorrelationIdMiddleware,
|
|
5191
|
+
CreateDataTableViewDto,
|
|
5192
|
+
CreateResponseDto,
|
|
5193
|
+
DATA_TABLE_VIEWS_TABLE,
|
|
4362
5194
|
DEFAULT_CORRELATION_HEADER,
|
|
5195
|
+
DataTableModule,
|
|
5196
|
+
DataTableStateService,
|
|
5197
|
+
DataTableViewDto,
|
|
5198
|
+
DataTableViewsService,
|
|
4363
5199
|
DatabaseModule,
|
|
4364
5200
|
EmailModule,
|
|
4365
5201
|
EmailService,
|
|
@@ -4369,6 +5205,8 @@ __name(normalizePhoneNumber, "normalizePhoneNumber");
|
|
|
4369
5205
|
HttpExceptionFilter,
|
|
4370
5206
|
HttpLoggerInterceptor,
|
|
4371
5207
|
HttpProblemException,
|
|
5208
|
+
ImportResponseDto,
|
|
5209
|
+
ImportSummaryDto,
|
|
4372
5210
|
InternalServerErrorException,
|
|
4373
5211
|
JwtAuthService,
|
|
4374
5212
|
LOGGER_MODULE_OPTIONS,
|
|
@@ -4378,40 +5216,44 @@ __name(normalizePhoneNumber, "normalizePhoneNumber");
|
|
|
4378
5216
|
NotAcceptableException,
|
|
4379
5217
|
NotFoundException,
|
|
4380
5218
|
NotImplementedException,
|
|
4381
|
-
Onboarding,
|
|
4382
5219
|
PayloadTooLargeException,
|
|
4383
5220
|
PrimaryBaseRepository,
|
|
4384
5221
|
PrimaryDatabaseService,
|
|
4385
5222
|
Public,
|
|
4386
|
-
|
|
5223
|
+
REQUIRE_SESSION_KEY,
|
|
4387
5224
|
RedisCacheProvider,
|
|
4388
5225
|
RefreshCookieOptions,
|
|
4389
5226
|
RefreshTokenCookie,
|
|
5227
|
+
RenameDataTableViewDto,
|
|
4390
5228
|
RequestTimeoutException,
|
|
4391
|
-
|
|
5229
|
+
RequireSession,
|
|
4392
5230
|
RootModule,
|
|
4393
5231
|
SKIP_CSRF_KEY,
|
|
4394
5232
|
SelectOptionsQueryDto,
|
|
4395
5233
|
ServiceUnavailableException,
|
|
4396
5234
|
SessionData,
|
|
4397
5235
|
SkipCsrf,
|
|
5236
|
+
Subdomain,
|
|
4398
5237
|
SuccessResponseDto,
|
|
4399
5238
|
TableResponseDto,
|
|
4400
|
-
|
|
4401
|
-
TenantBaseRepository,
|
|
4402
|
-
TenantContextService,
|
|
4403
|
-
TenantDatabaseService,
|
|
5239
|
+
ToggleShareDataTableViewDto,
|
|
4404
5240
|
TokenType,
|
|
4405
5241
|
TooManyRequestsException,
|
|
4406
5242
|
UnauthorizedException,
|
|
4407
5243
|
UnprocessableEntityException,
|
|
4408
5244
|
UnsupportedMediaTypeException,
|
|
5245
|
+
UpdateDataTableViewDto,
|
|
5246
|
+
UploadedFile,
|
|
5247
|
+
UpsertDataTableStateDto,
|
|
4409
5248
|
UserId,
|
|
5249
|
+
ValidatedRowDto,
|
|
4410
5250
|
ValidationException,
|
|
4411
5251
|
VrittiAuthGuard,
|
|
4412
5252
|
addCorrelationIdToResponse,
|
|
4413
5253
|
configureApiSdk,
|
|
4414
5254
|
correlationStorage,
|
|
5255
|
+
dataTableViewsColumns,
|
|
5256
|
+
dataTableViewsIndexes,
|
|
4415
5257
|
defineConfig,
|
|
4416
5258
|
extractCountryFromPhone,
|
|
4417
5259
|
generateCorrelationId,
|