bozonx-social-media-posting 1.1.0
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/LICENSE +21 -0
- package/README.md +1003 -0
- package/dist/src/app.constants.d.ts +8 -0
- package/dist/src/app.constants.js +9 -0
- package/dist/src/app.constants.js.map +1 -0
- package/dist/src/common/enums/body-format.enum.d.ts +12 -0
- package/dist/src/common/enums/body-format.enum.js +14 -0
- package/dist/src/common/enums/body-format.enum.js.map +1 -0
- package/dist/src/common/enums/error-code.enum.d.ts +12 -0
- package/dist/src/common/enums/error-code.enum.js +14 -0
- package/dist/src/common/enums/error-code.enum.js.map +1 -0
- package/dist/src/common/enums/index.d.ts +3 -0
- package/dist/src/common/enums/index.js +4 -0
- package/dist/src/common/enums/index.js.map +1 -0
- package/dist/src/common/enums/post-type.enum.d.ts +28 -0
- package/dist/src/common/enums/post-type.enum.js +30 -0
- package/dist/src/common/enums/post-type.enum.js.map +1 -0
- package/dist/src/common/filters/all-exceptions.filter.d.ts +13 -0
- package/dist/src/common/filters/all-exceptions.filter.js +103 -0
- package/dist/src/common/filters/all-exceptions.filter.js.map +1 -0
- package/dist/src/common/helpers/media-input.helper.d.ts +73 -0
- package/dist/src/common/helpers/media-input.helper.js +122 -0
- package/dist/src/common/helpers/media-input.helper.js.map +1 -0
- package/dist/src/common/interceptors/shutdown.interceptor.d.ts +12 -0
- package/dist/src/common/interceptors/shutdown.interceptor.js +41 -0
- package/dist/src/common/interceptors/shutdown.interceptor.js.map +1 -0
- package/dist/src/common/interfaces/logger.interface.d.ts +44 -0
- package/dist/src/common/interfaces/logger.interface.js +44 -0
- package/dist/src/common/interfaces/logger.interface.js.map +1 -0
- package/dist/src/common/services/shutdown.module.d.ts +2 -0
- package/dist/src/common/services/shutdown.module.js +18 -0
- package/dist/src/common/services/shutdown.module.js.map +1 -0
- package/dist/src/common/services/shutdown.service.d.ts +40 -0
- package/dist/src/common/services/shutdown.service.js +122 -0
- package/dist/src/common/services/shutdown.service.js.map +1 -0
- package/dist/src/common/types/index.d.ts +1 -0
- package/dist/src/common/types/index.js +2 -0
- package/dist/src/common/types/index.js.map +1 -0
- package/dist/src/common/types/media-input.type.d.ts +29 -0
- package/dist/src/common/types/media-input.type.js +2 -0
- package/dist/src/common/types/media-input.type.js.map +1 -0
- package/dist/src/common/validators/body-length.validator.d.ts +24 -0
- package/dist/src/common/validators/body-length.validator.js +57 -0
- package/dist/src/common/validators/body-length.validator.js.map +1 -0
- package/dist/src/common/validators/channel-id.validator.d.ts +19 -0
- package/dist/src/common/validators/channel-id.validator.js +58 -0
- package/dist/src/common/validators/channel-id.validator.js.map +1 -0
- package/dist/src/common/validators/has-content.validator.d.ts +23 -0
- package/dist/src/common/validators/has-content.validator.js +57 -0
- package/dist/src/common/validators/has-content.validator.js.map +1 -0
- package/dist/src/common/validators/media-input.validator.d.ts +44 -0
- package/dist/src/common/validators/media-input.validator.js +112 -0
- package/dist/src/common/validators/media-input.validator.js.map +1 -0
- package/dist/src/common/validators/media-priority.validator.d.ts +19 -0
- package/dist/src/common/validators/media-priority.validator.js +38 -0
- package/dist/src/common/validators/media-priority.validator.js.map +1 -0
- package/dist/src/config/app.config.d.ts +33 -0
- package/dist/src/config/app.config.js +83 -0
- package/dist/src/config/app.config.js.map +1 -0
- package/dist/src/config/library.config.d.ts +51 -0
- package/dist/src/config/library.config.js +197 -0
- package/dist/src/config/library.config.js.map +1 -0
- package/dist/src/config/yaml-config.dto.d.ts +37 -0
- package/dist/src/config/yaml-config.dto.js +152 -0
- package/dist/src/config/yaml-config.dto.js.map +1 -0
- package/dist/src/config/yaml.config.d.ts +14 -0
- package/dist/src/config/yaml.config.js +72 -0
- package/dist/src/config/yaml.config.js.map +1 -0
- package/dist/src/index.d.ts +19 -0
- package/dist/src/index.js +17 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/library.d.ts +57 -0
- package/dist/src/library.js +92 -0
- package/dist/src/library.js.map +1 -0
- package/dist/src/modules/app-config/app-config.module.d.ts +2 -0
- package/dist/src/modules/app-config/app-config.module.js +26 -0
- package/dist/src/modules/app-config/app-config.module.js.map +1 -0
- package/dist/src/modules/app-config/app-config.service.d.ts +14 -0
- package/dist/src/modules/app-config/app-config.service.js +18 -0
- package/dist/src/modules/app-config/app-config.service.js.map +1 -0
- package/dist/src/modules/app-config/interfaces/app-config.interface.d.ts +31 -0
- package/dist/src/modules/app-config/interfaces/app-config.interface.js +2 -0
- package/dist/src/modules/app-config/interfaces/app-config.interface.js.map +1 -0
- package/dist/src/modules/app-config/nest-config.service.d.ts +41 -0
- package/dist/src/modules/app-config/nest-config.service.js +91 -0
- package/dist/src/modules/app-config/nest-config.service.js.map +1 -0
- package/dist/src/modules/health/health.controller.d.ts +12 -0
- package/dist/src/modules/health/health.controller.js +33 -0
- package/dist/src/modules/health/health.controller.js.map +1 -0
- package/dist/src/modules/health/health.module.d.ts +2 -0
- package/dist/src/modules/health/health.module.js +17 -0
- package/dist/src/modules/health/health.module.js.map +1 -0
- package/dist/src/modules/media/media.module.d.ts +2 -0
- package/dist/src/modules/media/media.module.js +18 -0
- package/dist/src/modules/media/media.module.js.map +1 -0
- package/dist/src/modules/media/media.service.d.ts +15 -0
- package/dist/src/modules/media/media.service.js +49 -0
- package/dist/src/modules/media/media.service.js.map +1 -0
- package/dist/src/modules/platforms/base/auth-validator-registry.service.d.ts +25 -0
- package/dist/src/modules/platforms/base/auth-validator-registry.service.js +50 -0
- package/dist/src/modules/platforms/base/auth-validator-registry.service.js.map +1 -0
- package/dist/src/modules/platforms/base/auth-validator.interface.d.ts +16 -0
- package/dist/src/modules/platforms/base/auth-validator.interface.js +2 -0
- package/dist/src/modules/platforms/base/auth-validator.interface.js.map +1 -0
- package/dist/src/modules/platforms/base/index.d.ts +4 -0
- package/dist/src/modules/platforms/base/index.js +5 -0
- package/dist/src/modules/platforms/base/index.js.map +1 -0
- package/dist/src/modules/platforms/base/platform-registry.service.d.ts +31 -0
- package/dist/src/modules/platforms/base/platform-registry.service.js +54 -0
- package/dist/src/modules/platforms/base/platform-registry.service.js.map +1 -0
- package/dist/src/modules/platforms/base/platform.interface.d.ts +39 -0
- package/dist/src/modules/platforms/base/platform.interface.js +2 -0
- package/dist/src/modules/platforms/base/platform.interface.js.map +1 -0
- package/dist/src/modules/platforms/platforms.module.d.ts +13 -0
- package/dist/src/modules/platforms/platforms.module.js +59 -0
- package/dist/src/modules/platforms/platforms.module.js.map +1 -0
- package/dist/src/modules/platforms/telegram/telegram-auth.validator.d.ts +19 -0
- package/dist/src/modules/platforms/telegram/telegram-auth.validator.js +51 -0
- package/dist/src/modules/platforms/telegram/telegram-auth.validator.js.map +1 -0
- package/dist/src/modules/platforms/telegram/telegram-type-detector.service.d.ts +18 -0
- package/dist/src/modules/platforms/telegram/telegram-type-detector.service.js +47 -0
- package/dist/src/modules/platforms/telegram/telegram-type-detector.service.js.map +1 -0
- package/dist/src/modules/platforms/telegram/telegram.platform.d.ts +58 -0
- package/dist/src/modules/platforms/telegram/telegram.platform.js +434 -0
- package/dist/src/modules/platforms/telegram/telegram.platform.js.map +1 -0
- package/dist/src/modules/post/base-post.service.d.ts +64 -0
- package/dist/src/modules/post/base-post.service.js +99 -0
- package/dist/src/modules/post/base-post.service.js.map +1 -0
- package/dist/src/modules/post/dto/index.d.ts +3 -0
- package/dist/src/modules/post/dto/index.js +4 -0
- package/dist/src/modules/post/dto/index.js.map +1 -0
- package/dist/src/modules/post/dto/post-request.dto.d.ts +56 -0
- package/dist/src/modules/post/dto/post-request.dto.js +195 -0
- package/dist/src/modules/post/dto/post-request.dto.js.map +1 -0
- package/dist/src/modules/post/dto/post-response.dto.d.ts +41 -0
- package/dist/src/modules/post/dto/post-response.dto.js +2 -0
- package/dist/src/modules/post/dto/post-response.dto.js.map +1 -0
- package/dist/src/modules/post/dto/preview-response.dto.d.ts +33 -0
- package/dist/src/modules/post/dto/preview-response.dto.js +2 -0
- package/dist/src/modules/post/dto/preview-response.dto.js.map +1 -0
- package/dist/src/modules/post/idempotency.service.d.ts +95 -0
- package/dist/src/modules/post/idempotency.service.js +229 -0
- package/dist/src/modules/post/idempotency.service.js.map +1 -0
- package/dist/src/modules/post/post.controller.d.ts +13 -0
- package/dist/src/modules/post/post.controller.js +97 -0
- package/dist/src/modules/post/post.controller.js.map +1 -0
- package/dist/src/modules/post/post.module.d.ts +2 -0
- package/dist/src/modules/post/post.module.js +25 -0
- package/dist/src/modules/post/post.module.js.map +1 -0
- package/dist/src/modules/post/post.service.d.ts +62 -0
- package/dist/src/modules/post/post.service.js +325 -0
- package/dist/src/modules/post/post.service.js.map +1 -0
- package/dist/src/modules/post/preview.service.d.ts +23 -0
- package/dist/src/modules/post/preview.service.js +69 -0
- package/dist/src/modules/post/preview.service.js.map +1 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -0
- package/package.json +102 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
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;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { Module } from '@nestjs/common';
|
|
8
|
+
import { ShutdownService } from './shutdown.service.js';
|
|
9
|
+
let ShutdownModule = class ShutdownModule {
|
|
10
|
+
};
|
|
11
|
+
ShutdownModule = __decorate([
|
|
12
|
+
Module({
|
|
13
|
+
providers: [ShutdownService],
|
|
14
|
+
exports: [ShutdownService],
|
|
15
|
+
})
|
|
16
|
+
], ShutdownModule);
|
|
17
|
+
export { ShutdownModule };
|
|
18
|
+
//# sourceMappingURL=shutdown.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shutdown.module.js","sourceRoot":"","sources":["../../../../src/common/services/shutdown.module.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAMjD,IAAM,cAAc,GAApB,MAAM,cAAc;CAAG,CAAA;AAAjB,cAAc;IAJ1B,MAAM,CAAC;QACN,SAAS,EAAE,CAAC,eAAe,CAAC;QAC5B,OAAO,EAAE,CAAC,eAAe,CAAC;KAC3B,CAAC;GACW,cAAc,CAAG"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { OnApplicationShutdown, OnModuleDestroy } from '@nestjs/common';
|
|
2
|
+
/**
|
|
3
|
+
* Service to manage graceful shutdown
|
|
4
|
+
* Tracks in-flight requests and signals shutdown state to the application
|
|
5
|
+
* Thread-safe implementation to prevent race conditions
|
|
6
|
+
*/
|
|
7
|
+
export declare class ShutdownService implements OnApplicationShutdown, OnModuleDestroy {
|
|
8
|
+
private readonly logger;
|
|
9
|
+
private isShuttingDown;
|
|
10
|
+
private inFlightRequests;
|
|
11
|
+
private shutdownResolve?;
|
|
12
|
+
private operationLock;
|
|
13
|
+
constructor();
|
|
14
|
+
/**
|
|
15
|
+
* Check if the application is shutting down
|
|
16
|
+
*/
|
|
17
|
+
get shuttingDown(): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Increment in-flight request counter atomically
|
|
20
|
+
*/
|
|
21
|
+
trackRequest(): void;
|
|
22
|
+
/**
|
|
23
|
+
* Decrement in-flight request counter atomically and resolve shutdown if no requests remain
|
|
24
|
+
*/
|
|
25
|
+
untrackRequest(): void;
|
|
26
|
+
/**
|
|
27
|
+
* Get the current count of in-flight requests
|
|
28
|
+
*/
|
|
29
|
+
getInFlightRequestsCount(): number;
|
|
30
|
+
/**
|
|
31
|
+
* Called by NestJS when shutdown signal is received
|
|
32
|
+
* Waits for all in-flight requests to complete with timeout
|
|
33
|
+
*/
|
|
34
|
+
onApplicationShutdown(signal?: string): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Called by NestJS when module is being destroyed
|
|
37
|
+
* Cleanup internal state
|
|
38
|
+
*/
|
|
39
|
+
onModuleDestroy(): void;
|
|
40
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
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;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var ShutdownService_1;
|
|
11
|
+
import { Injectable, Logger } from '@nestjs/common';
|
|
12
|
+
import { GRACEFUL_SHUTDOWN_TIMEOUT_MS } from '../../app.constants.js';
|
|
13
|
+
/**
|
|
14
|
+
* Service to manage graceful shutdown
|
|
15
|
+
* Tracks in-flight requests and signals shutdown state to the application
|
|
16
|
+
* Thread-safe implementation to prevent race conditions
|
|
17
|
+
*/
|
|
18
|
+
let ShutdownService = ShutdownService_1 = class ShutdownService {
|
|
19
|
+
logger = new Logger(ShutdownService_1.name);
|
|
20
|
+
isShuttingDown = false;
|
|
21
|
+
inFlightRequests = 0;
|
|
22
|
+
shutdownResolve;
|
|
23
|
+
operationLock = false;
|
|
24
|
+
constructor() { }
|
|
25
|
+
/**
|
|
26
|
+
* Check if the application is shutting down
|
|
27
|
+
*/
|
|
28
|
+
get shuttingDown() {
|
|
29
|
+
return this.isShuttingDown;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Increment in-flight request counter atomically
|
|
33
|
+
*/
|
|
34
|
+
trackRequest() {
|
|
35
|
+
// Wait for any ongoing operation to complete
|
|
36
|
+
while (this.operationLock) {
|
|
37
|
+
// Busy wait (acceptable for very short operations)
|
|
38
|
+
}
|
|
39
|
+
this.operationLock = true;
|
|
40
|
+
try {
|
|
41
|
+
this.inFlightRequests++;
|
|
42
|
+
this.logger.debug(`Request tracked. In-flight requests: ${this.inFlightRequests}`, 'ShutdownService');
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
this.operationLock = false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Decrement in-flight request counter atomically and resolve shutdown if no requests remain
|
|
50
|
+
*/
|
|
51
|
+
untrackRequest() {
|
|
52
|
+
// Wait for any ongoing operation to complete
|
|
53
|
+
while (this.operationLock) {
|
|
54
|
+
// Busy wait (acceptable for very short operations)
|
|
55
|
+
}
|
|
56
|
+
this.operationLock = true;
|
|
57
|
+
try {
|
|
58
|
+
this.inFlightRequests--;
|
|
59
|
+
this.logger.debug(`Request untracked. In-flight requests: ${this.inFlightRequests}`, 'ShutdownService');
|
|
60
|
+
// Check if we should resolve shutdown
|
|
61
|
+
if (this.isShuttingDown && this.inFlightRequests <= 0 && this.shutdownResolve) {
|
|
62
|
+
this.logger.log('All in-flight requests completed during shutdown', 'ShutdownService');
|
|
63
|
+
this.shutdownResolve();
|
|
64
|
+
this.shutdownResolve = undefined;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
this.operationLock = false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Get the current count of in-flight requests
|
|
73
|
+
*/
|
|
74
|
+
getInFlightRequestsCount() {
|
|
75
|
+
return this.inFlightRequests;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Called by NestJS when shutdown signal is received
|
|
79
|
+
* Waits for all in-flight requests to complete with timeout
|
|
80
|
+
*/
|
|
81
|
+
async onApplicationShutdown(signal) {
|
|
82
|
+
this.logger.log(`Received shutdown signal: ${signal ?? 'unknown'}. In-flight requests: ${this.inFlightRequests}`, 'ShutdownService');
|
|
83
|
+
this.isShuttingDown = true;
|
|
84
|
+
if (this.inFlightRequests > 0) {
|
|
85
|
+
this.logger.log(`Waiting for ${this.inFlightRequests} in-flight requests to complete...`, 'ShutdownService');
|
|
86
|
+
const startTime = Date.now();
|
|
87
|
+
// Wait for requests to complete with timeout
|
|
88
|
+
await Promise.race([
|
|
89
|
+
new Promise(resolve => {
|
|
90
|
+
this.shutdownResolve = resolve;
|
|
91
|
+
}),
|
|
92
|
+
new Promise(resolve => {
|
|
93
|
+
setTimeout(() => {
|
|
94
|
+
this.logger.warn(`Shutdown timeout reached. Remaining in-flight requests: ${this.inFlightRequests}`, 'ShutdownService');
|
|
95
|
+
resolve();
|
|
96
|
+
}, GRACEFUL_SHUTDOWN_TIMEOUT_MS);
|
|
97
|
+
}),
|
|
98
|
+
]);
|
|
99
|
+
const duration = Date.now() - startTime;
|
|
100
|
+
this.logger.log(`Shutdown wait completed in ${duration}ms. Remaining requests: ${this.inFlightRequests}`, 'ShutdownService');
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
this.logger.log('No in-flight requests, shutting down immediately', 'ShutdownService');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Called by NestJS when module is being destroyed
|
|
108
|
+
* Cleanup internal state
|
|
109
|
+
*/
|
|
110
|
+
onModuleDestroy() {
|
|
111
|
+
this.logger.debug('ShutdownService module destroyed', 'ShutdownService');
|
|
112
|
+
this.shutdownResolve = undefined;
|
|
113
|
+
this.inFlightRequests = 0;
|
|
114
|
+
this.isShuttingDown = false;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
ShutdownService = ShutdownService_1 = __decorate([
|
|
118
|
+
Injectable(),
|
|
119
|
+
__metadata("design:paramtypes", [])
|
|
120
|
+
], ShutdownService);
|
|
121
|
+
export { ShutdownService };
|
|
122
|
+
//# sourceMappingURL=shutdown.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shutdown.service.js","sourceRoot":"","sources":["../../../../src/common/services/shutdown.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { MediaInput, MediaInputObject } from './media-input.type.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/common/types/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Media type for explicit type specification in media arrays
|
|
3
|
+
* Used in albums to avoid auto-detection by URL extension
|
|
4
|
+
*/
|
|
5
|
+
export type MediaType = 'image' | 'video' | 'audio' | 'document';
|
|
6
|
+
/**
|
|
7
|
+
* MediaInput type
|
|
8
|
+
* Always an object with src and optional parameters
|
|
9
|
+
* For single media fields (cover, video, audio, document): hasSpoiler is optional
|
|
10
|
+
* For media arrays: type should be specified to override auto-detection
|
|
11
|
+
*/
|
|
12
|
+
export type MediaInput = MediaInputObject;
|
|
13
|
+
export interface MediaInputObject {
|
|
14
|
+
/**
|
|
15
|
+
* Media source (URL or Telegram file_id)
|
|
16
|
+
*/
|
|
17
|
+
src: string;
|
|
18
|
+
/**
|
|
19
|
+
* Hide media with spoiler animation (for shocking content)
|
|
20
|
+
* Supported by Telegram Bot API 5.6+
|
|
21
|
+
*/
|
|
22
|
+
hasSpoiler?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Explicit media type specification
|
|
25
|
+
* For single media fields (cover, video, audio, document) this is ignored
|
|
26
|
+
* For media[] arrays this overrides auto-detection by URL extension
|
|
27
|
+
*/
|
|
28
|
+
type?: MediaType;
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-input.type.js","sourceRoot":"","sources":["../../../../src/common/types/media-input.type.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ValidationOptions, ValidationArguments, ValidatorConstraintInterface } from 'class-validator';
|
|
2
|
+
/** Absolute maximum body length limit in characters (cannot be exceeded) */
|
|
3
|
+
export declare const MAX_BODY_LIMIT = 500000;
|
|
4
|
+
/**
|
|
5
|
+
* Validator constraint for body field with dynamic max length
|
|
6
|
+
* Uses maxBody from request (capped at MAX_BODY_LIMIT)
|
|
7
|
+
*/
|
|
8
|
+
export declare class IsValidBodyLengthConstraint implements ValidatorConstraintInterface {
|
|
9
|
+
/**
|
|
10
|
+
* Validates body length against maxBody or MAX_BODY_LIMIT
|
|
11
|
+
* @param value - Body string to validate
|
|
12
|
+
* @param args - Validation arguments containing the object
|
|
13
|
+
* @returns True if valid, false otherwise
|
|
14
|
+
*/
|
|
15
|
+
validate(value: any, args: ValidationArguments): boolean;
|
|
16
|
+
defaultMessage(args: ValidationArguments): string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Decorator factory for body length validation
|
|
20
|
+
* Validates body against maxBody parameter or default max length
|
|
21
|
+
* @param validationOptions - Optional validation options
|
|
22
|
+
* @returns Property decorator
|
|
23
|
+
*/
|
|
24
|
+
export declare function IsValidBodyLength(validationOptions?: ValidationOptions): (object: Object, propertyName: string) => void;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
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;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { registerDecorator, ValidatorConstraint, } from 'class-validator';
|
|
8
|
+
/** Absolute maximum body length limit in characters (cannot be exceeded) */
|
|
9
|
+
export const MAX_BODY_LIMIT = 500_000;
|
|
10
|
+
/**
|
|
11
|
+
* Validator constraint for body field with dynamic max length
|
|
12
|
+
* Uses maxBody from request (capped at MAX_BODY_LIMIT)
|
|
13
|
+
*/
|
|
14
|
+
let IsValidBodyLengthConstraint = class IsValidBodyLengthConstraint {
|
|
15
|
+
/**
|
|
16
|
+
* Validates body length against maxBody or MAX_BODY_LIMIT
|
|
17
|
+
* @param value - Body string to validate
|
|
18
|
+
* @param args - Validation arguments containing the object
|
|
19
|
+
* @returns True if valid, false otherwise
|
|
20
|
+
*/
|
|
21
|
+
validate(value, args) {
|
|
22
|
+
if (typeof value !== 'string') {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
const obj = args.object;
|
|
26
|
+
// Use maxBody from request if provided, otherwise use absolute limit
|
|
27
|
+
const maxLength = Math.min(obj.maxBody || MAX_BODY_LIMIT, MAX_BODY_LIMIT);
|
|
28
|
+
return value.length <= maxLength;
|
|
29
|
+
}
|
|
30
|
+
defaultMessage(args) {
|
|
31
|
+
const obj = args.object;
|
|
32
|
+
const maxLength = Math.min(obj.maxBody || MAX_BODY_LIMIT, MAX_BODY_LIMIT);
|
|
33
|
+
return `Body length must not exceed ${maxLength} characters`;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
IsValidBodyLengthConstraint = __decorate([
|
|
37
|
+
ValidatorConstraint({ name: 'isValidBodyLength', async: false })
|
|
38
|
+
], IsValidBodyLengthConstraint);
|
|
39
|
+
export { IsValidBodyLengthConstraint };
|
|
40
|
+
/**
|
|
41
|
+
* Decorator factory for body length validation
|
|
42
|
+
* Validates body against maxBody parameter or default max length
|
|
43
|
+
* @param validationOptions - Optional validation options
|
|
44
|
+
* @returns Property decorator
|
|
45
|
+
*/
|
|
46
|
+
export function IsValidBodyLength(validationOptions) {
|
|
47
|
+
return function (object, propertyName) {
|
|
48
|
+
registerDecorator({
|
|
49
|
+
target: object.constructor,
|
|
50
|
+
propertyName: propertyName,
|
|
51
|
+
options: validationOptions,
|
|
52
|
+
constraints: [],
|
|
53
|
+
validator: IsValidBodyLengthConstraint,
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=body-length.validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"body-length.validator.js","sourceRoot":"","sources":["../../../../src/common/validators/body-length.validator.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EACL,iBAAiB,EAGjB,mBAAmB,GAEpB,MAAM,iBAAiB,CAAC;AAEzB,4EAA4E;AAC5E,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AAEtC;;;GAGG;AAEI,IAAM,2BAA2B,GAAjC,MAAM,2BAA2B;IACtC;;;;;OAKG;IACH,QAAQ,CAAC,KAAU,EAAE,IAAyB;QAC5C,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,MAAa,CAAC;QAC/B,qEAAqE;QACrE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,cAAc,EAAE,cAAc,CAAC,CAAC;QAE1E,OAAO,KAAK,CAAC,MAAM,IAAI,SAAS,CAAC;IACnC,CAAC;IAED,cAAc,CAAC,IAAyB;QACtC,MAAM,GAAG,GAAG,IAAI,CAAC,MAAa,CAAC;QAC/B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,cAAc,EAAE,cAAc,CAAC,CAAC;QAC1E,OAAO,+BAA+B,SAAS,aAAa,CAAC;IAC/D,CAAC;CACF,CAAA;AAxBY,2BAA2B;IADvC,mBAAmB,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;GACpD,2BAA2B,CAwBvC;;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,iBAAqC;IACrE,OAAO,UAAU,MAAc,EAAE,YAAoB;QACnD,iBAAiB,CAAC;YAChB,MAAM,EAAE,MAAM,CAAC,WAAW;YAC1B,YAAY,EAAE,YAAY;YAC1B,OAAO,EAAE,iBAAiB;YAC1B,WAAW,EAAE,EAAE;YACf,SAAS,EAAE,2BAA2B;SACvC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ValidationOptions, ValidationArguments, ValidatorConstraintInterface } from 'class-validator';
|
|
2
|
+
/**
|
|
3
|
+
* Validator constraint for channelId field
|
|
4
|
+
* Validates that channelId is either a string or a number
|
|
5
|
+
* Allows formats like:
|
|
6
|
+
* - String: "@mychannel", "-100123456789", "123456789"
|
|
7
|
+
* - Number: 123456789, -100123456789
|
|
8
|
+
*/
|
|
9
|
+
export declare class IsChannelIdConstraint implements ValidatorConstraintInterface {
|
|
10
|
+
validate(value: any, args: ValidationArguments): boolean;
|
|
11
|
+
defaultMessage(args: ValidationArguments): string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Decorator factory for channelId validation
|
|
15
|
+
* Use on DTO properties that accept channelId
|
|
16
|
+
* @param validationOptions - Optional validation options
|
|
17
|
+
* @returns Property decorator
|
|
18
|
+
*/
|
|
19
|
+
export declare function IsChannelId(validationOptions?: ValidationOptions): (object: object, propertyName: string) => void;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
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;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { registerDecorator, ValidatorConstraint, } from 'class-validator';
|
|
8
|
+
/**
|
|
9
|
+
* Validator constraint for channelId field
|
|
10
|
+
* Validates that channelId is either a string or a number
|
|
11
|
+
* Allows formats like:
|
|
12
|
+
* - String: "@mychannel", "-100123456789", "123456789"
|
|
13
|
+
* - Number: 123456789, -100123456789
|
|
14
|
+
*/
|
|
15
|
+
let IsChannelIdConstraint = class IsChannelIdConstraint {
|
|
16
|
+
validate(value, args) {
|
|
17
|
+
// Allow undefined/null for optional fields
|
|
18
|
+
if (value === undefined || value === null) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
// Check if it's a string or number
|
|
22
|
+
if (typeof value === 'string') {
|
|
23
|
+
// String must not be empty
|
|
24
|
+
return value.trim().length > 0;
|
|
25
|
+
}
|
|
26
|
+
if (typeof value === 'number') {
|
|
27
|
+
// Number must be a valid integer
|
|
28
|
+
return Number.isInteger(value);
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
defaultMessage(args) {
|
|
33
|
+
return 'channelId must be a non-empty string or an integer number';
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
IsChannelIdConstraint = __decorate([
|
|
37
|
+
ValidatorConstraint({ name: 'isChannelId', async: false })
|
|
38
|
+
], IsChannelIdConstraint);
|
|
39
|
+
export { IsChannelIdConstraint };
|
|
40
|
+
/**
|
|
41
|
+
* Decorator factory for channelId validation
|
|
42
|
+
* Use on DTO properties that accept channelId
|
|
43
|
+
* @param validationOptions - Optional validation options
|
|
44
|
+
* @returns Property decorator
|
|
45
|
+
*/
|
|
46
|
+
export function IsChannelId(validationOptions) {
|
|
47
|
+
return function (object, propertyName) {
|
|
48
|
+
registerDecorator({
|
|
49
|
+
name: 'isChannelId',
|
|
50
|
+
target: object.constructor,
|
|
51
|
+
propertyName: propertyName,
|
|
52
|
+
options: validationOptions,
|
|
53
|
+
constraints: [],
|
|
54
|
+
validator: IsChannelIdConstraint,
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=channel-id.validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel-id.validator.js","sourceRoot":"","sources":["../../../../src/common/validators/channel-id.validator.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EACH,iBAAiB,EAGjB,mBAAmB,GAEtB,MAAM,iBAAiB,CAAC;AAEzB;;;;;;GAMG;AAEI,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;IAC9B,QAAQ,CAAC,KAAU,EAAE,IAAyB;QAC1C,2CAA2C;QAC3C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACxC,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,mCAAmC;QACnC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC5B,2BAA2B;YAC3B,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;QACnC,CAAC;QAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC5B,iCAAiC;YACjC,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;QAED,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,cAAc,CAAC,IAAyB;QACpC,OAAO,2DAA2D,CAAC;IACvE,CAAC;CACJ,CAAA;AAxBY,qBAAqB;IADjC,mBAAmB,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;GAC9C,qBAAqB,CAwBjC;;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,iBAAqC;IAC7D,OAAO,UAAU,MAAc,EAAE,YAAoB;QACjD,iBAAiB,CAAC;YACd,IAAI,EAAE,aAAa;YACnB,MAAM,EAAE,MAAM,CAAC,WAAW;YAC1B,YAAY,EAAE,YAAY;YAC1B,OAAO,EAAE,iBAAiB;YAC1B,WAAW,EAAE,EAAE;YACf,SAAS,EAAE,qBAAqB;SACnC,CAAC,CAAC;IACP,CAAC,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ValidationOptions, ValidationArguments, ValidatorConstraintInterface } from 'class-validator';
|
|
2
|
+
/**
|
|
3
|
+
* Validator constraint for ensuring post has content
|
|
4
|
+
* Checks that either body or at least one media field is provided
|
|
5
|
+
*/
|
|
6
|
+
export declare class HasContentConstraint implements ValidatorConstraintInterface {
|
|
7
|
+
/**
|
|
8
|
+
* Validates that post has either body or media content
|
|
9
|
+
* @param _value - Not used (class-level validator)
|
|
10
|
+
* @param args - Validation arguments containing the object
|
|
11
|
+
* @returns True if valid, false otherwise
|
|
12
|
+
*/
|
|
13
|
+
validate(_value: any, args: ValidationArguments): any;
|
|
14
|
+
defaultMessage(_args: ValidationArguments): string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Decorator factory for content validation
|
|
18
|
+
* Validates that post has either body or media content
|
|
19
|
+
* This is a class-level decorator
|
|
20
|
+
* @param validationOptions - Optional validation options
|
|
21
|
+
* @returns Class decorator
|
|
22
|
+
*/
|
|
23
|
+
export declare function HasContent(validationOptions?: ValidationOptions): (object: Function) => void;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
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;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { registerDecorator, ValidatorConstraint, } from 'class-validator';
|
|
8
|
+
/**
|
|
9
|
+
* Validator constraint for ensuring post has content
|
|
10
|
+
* Checks that either body or at least one media field is provided
|
|
11
|
+
*/
|
|
12
|
+
let HasContentConstraint = class HasContentConstraint {
|
|
13
|
+
/**
|
|
14
|
+
* Validates that post has either body or media content
|
|
15
|
+
* @param _value - Not used (class-level validator)
|
|
16
|
+
* @param args - Validation arguments containing the object
|
|
17
|
+
* @returns True if valid, false otherwise
|
|
18
|
+
*/
|
|
19
|
+
validate(_value, args) {
|
|
20
|
+
const obj = args.object;
|
|
21
|
+
// Check if body is a non-empty string
|
|
22
|
+
const hasBody = typeof obj.body === 'string' && obj.body.trim().length > 0;
|
|
23
|
+
// Check if at least one media field is provided (ignore falsy values like false, null, undefined, '')
|
|
24
|
+
const hasMedia = (obj.cover && typeof obj.cover === 'object') ||
|
|
25
|
+
(obj.video && typeof obj.video === 'object') ||
|
|
26
|
+
(obj.audio && typeof obj.audio === 'object') ||
|
|
27
|
+
(obj.document && typeof obj.document === 'object') ||
|
|
28
|
+
(Array.isArray(obj.media) && obj.media.length > 0);
|
|
29
|
+
return hasBody || hasMedia;
|
|
30
|
+
}
|
|
31
|
+
defaultMessage(_args) {
|
|
32
|
+
return 'Post must have either body text or at least one media field (cover, video, audio, document, or media)';
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
HasContentConstraint = __decorate([
|
|
36
|
+
ValidatorConstraint({ name: 'hasContent', async: false })
|
|
37
|
+
], HasContentConstraint);
|
|
38
|
+
export { HasContentConstraint };
|
|
39
|
+
/**
|
|
40
|
+
* Decorator factory for content validation
|
|
41
|
+
* Validates that post has either body or media content
|
|
42
|
+
* This is a class-level decorator
|
|
43
|
+
* @param validationOptions - Optional validation options
|
|
44
|
+
* @returns Class decorator
|
|
45
|
+
*/
|
|
46
|
+
export function HasContent(validationOptions) {
|
|
47
|
+
return function (object) {
|
|
48
|
+
registerDecorator({
|
|
49
|
+
target: object,
|
|
50
|
+
propertyName: '',
|
|
51
|
+
options: validationOptions,
|
|
52
|
+
constraints: [],
|
|
53
|
+
validator: HasContentConstraint,
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=has-content.validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"has-content.validator.js","sourceRoot":"","sources":["../../../../src/common/validators/has-content.validator.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EACH,iBAAiB,EAGjB,mBAAmB,GAEtB,MAAM,iBAAiB,CAAC;AAEzB;;;GAGG;AAEI,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,MAAW,EAAE,IAAyB;QAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,MAAa,CAAC;QAE/B,sCAAsC;QACtC,MAAM,OAAO,GAAG,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;QAE3E,sGAAsG;QACtG,MAAM,QAAQ,GACV,CAAC,GAAG,CAAC,KAAK,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,CAAC;YAC5C,CAAC,GAAG,CAAC,KAAK,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,CAAC;YAC5C,CAAC,GAAG,CAAC,KAAK,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,CAAC;YAC5C,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;YAClD,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAEvD,OAAO,OAAO,IAAI,QAAQ,CAAC;IAC/B,CAAC;IAED,cAAc,CAAC,KAA0B;QACrC,OAAO,uGAAuG,CAAC;IACnH,CAAC;CACJ,CAAA;AA3BY,oBAAoB;IADhC,mBAAmB,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;GAC7C,oBAAoB,CA2BhC;;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,iBAAqC;IAC5D,OAAO,UAAU,MAAgB;QAC7B,iBAAiB,CAAC;YACd,MAAM,EAAE,MAAM;YACd,YAAY,EAAE,EAAE;YAChB,OAAO,EAAE,iBAAiB;YAC1B,WAAW,EAAE,EAAE;YACf,SAAS,EAAE,oBAAoB;SAClC,CAAC,CAAC;IACP,CAAC,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ValidationOptions, ValidationArguments, ValidatorConstraintInterface } from 'class-validator';
|
|
2
|
+
/**
|
|
3
|
+
* Validator constraint for MediaInput type
|
|
4
|
+
* Validates that a value is an object with src property
|
|
5
|
+
*/
|
|
6
|
+
export declare class IsMediaInputConstraint implements ValidatorConstraintInterface {
|
|
7
|
+
/**
|
|
8
|
+
* Validates MediaInput value
|
|
9
|
+
* Accepts only an object with src property (max 500 characters)
|
|
10
|
+
* @param value - Value to validate
|
|
11
|
+
* @param args - Validation arguments
|
|
12
|
+
* @returns True if valid, false otherwise
|
|
13
|
+
*/
|
|
14
|
+
validate(value: any, args: ValidationArguments): boolean;
|
|
15
|
+
defaultMessage(args: ValidationArguments): string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Decorator factory for MediaInput validation
|
|
19
|
+
* Use on DTO properties that accept MediaInput type
|
|
20
|
+
* @param validationOptions - Optional validation options
|
|
21
|
+
* @returns Property decorator
|
|
22
|
+
*/
|
|
23
|
+
export declare function IsMediaInput(validationOptions?: ValidationOptions): (object: Object, propertyName: string) => void;
|
|
24
|
+
/**
|
|
25
|
+
* Validator constraint for MediaInput array type
|
|
26
|
+
* Validates that each item in the array is a valid MediaInput
|
|
27
|
+
*/
|
|
28
|
+
export declare class IsMediaInputArrayConstraint implements ValidatorConstraintInterface {
|
|
29
|
+
/**
|
|
30
|
+
* Validates array of MediaInput values
|
|
31
|
+
* @param value - Array to validate
|
|
32
|
+
* @param args - Validation arguments
|
|
33
|
+
* @returns True if all items are valid MediaInput, false otherwise
|
|
34
|
+
*/
|
|
35
|
+
validate(value: any, args: ValidationArguments): boolean;
|
|
36
|
+
defaultMessage(args: ValidationArguments): string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Decorator factory for MediaInput array validation
|
|
40
|
+
* Use on DTO properties that accept MediaInput[] type
|
|
41
|
+
* @param validationOptions - Optional validation options
|
|
42
|
+
* @returns Property decorator
|
|
43
|
+
*/
|
|
44
|
+
export declare function IsMediaInputArray(validationOptions?: ValidationOptions): (object: Object, propertyName: string) => void;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
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;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { registerDecorator, ValidatorConstraint, } from 'class-validator';
|
|
8
|
+
/** Maximum length for URL and fileId strings */
|
|
9
|
+
const MAX_MEDIA_STRING_LENGTH = 500;
|
|
10
|
+
/**
|
|
11
|
+
* Validator constraint for MediaInput type
|
|
12
|
+
* Validates that a value is an object with src property
|
|
13
|
+
*/
|
|
14
|
+
let IsMediaInputConstraint = class IsMediaInputConstraint {
|
|
15
|
+
/**
|
|
16
|
+
* Validates MediaInput value
|
|
17
|
+
* Accepts only an object with src property (max 500 characters)
|
|
18
|
+
* @param value - Value to validate
|
|
19
|
+
* @param args - Validation arguments
|
|
20
|
+
* @returns True if valid, false otherwise
|
|
21
|
+
*/
|
|
22
|
+
validate(value, args) {
|
|
23
|
+
// Optional field - allow null/undefined/false
|
|
24
|
+
if (value === null || value === undefined || value === false) {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
// Must be an object with src property
|
|
28
|
+
if (typeof value === 'object' && value !== null) {
|
|
29
|
+
const hasSrc = typeof value.src === 'string';
|
|
30
|
+
const hasSpoiler = value.hasSpoiler === undefined || typeof value.hasSpoiler === 'boolean';
|
|
31
|
+
const hasType = value.type === undefined || typeof value.type === 'string';
|
|
32
|
+
// Validate string length
|
|
33
|
+
if (hasSrc && value.src.length > MAX_MEDIA_STRING_LENGTH) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
// Must have src, and hasSpoiler/type must be correct types if present
|
|
37
|
+
return hasSrc && value.src.length > 0 && hasSpoiler && hasType;
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
defaultMessage(args) {
|
|
42
|
+
return `MediaInput must be an object with src (max ${MAX_MEDIA_STRING_LENGTH} characters), optional hasSpoiler boolean, and optional type string`;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
IsMediaInputConstraint = __decorate([
|
|
46
|
+
ValidatorConstraint({ name: 'isMediaInput', async: false })
|
|
47
|
+
], IsMediaInputConstraint);
|
|
48
|
+
export { IsMediaInputConstraint };
|
|
49
|
+
/**
|
|
50
|
+
* Decorator factory for MediaInput validation
|
|
51
|
+
* Use on DTO properties that accept MediaInput type
|
|
52
|
+
* @param validationOptions - Optional validation options
|
|
53
|
+
* @returns Property decorator
|
|
54
|
+
*/
|
|
55
|
+
export function IsMediaInput(validationOptions) {
|
|
56
|
+
return function (object, propertyName) {
|
|
57
|
+
registerDecorator({
|
|
58
|
+
target: object.constructor,
|
|
59
|
+
propertyName: propertyName,
|
|
60
|
+
options: validationOptions,
|
|
61
|
+
constraints: [],
|
|
62
|
+
validator: IsMediaInputConstraint,
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Validator constraint for MediaInput array type
|
|
68
|
+
* Validates that each item in the array is a valid MediaInput
|
|
69
|
+
*/
|
|
70
|
+
let IsMediaInputArrayConstraint = class IsMediaInputArrayConstraint {
|
|
71
|
+
/**
|
|
72
|
+
* Validates array of MediaInput values
|
|
73
|
+
* @param value - Array to validate
|
|
74
|
+
* @param args - Validation arguments
|
|
75
|
+
* @returns True if all items are valid MediaInput, false otherwise
|
|
76
|
+
*/
|
|
77
|
+
validate(value, args) {
|
|
78
|
+
if (!value) {
|
|
79
|
+
return true; // Optional field
|
|
80
|
+
}
|
|
81
|
+
if (!Array.isArray(value)) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
const validator = new IsMediaInputConstraint();
|
|
85
|
+
return value.every(item => validator.validate(item, args));
|
|
86
|
+
}
|
|
87
|
+
defaultMessage(args) {
|
|
88
|
+
return `Property "media" must be an array of objects. Example: [{"src": "https://example.com/image.jpg", "type": "image"}]. Each item must have src (max ${MAX_MEDIA_STRING_LENGTH} characters), optional hasSpoiler boolean, and optional type string`;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
IsMediaInputArrayConstraint = __decorate([
|
|
92
|
+
ValidatorConstraint({ name: 'isMediaInputArray', async: false })
|
|
93
|
+
], IsMediaInputArrayConstraint);
|
|
94
|
+
export { IsMediaInputArrayConstraint };
|
|
95
|
+
/**
|
|
96
|
+
* Decorator factory for MediaInput array validation
|
|
97
|
+
* Use on DTO properties that accept MediaInput[] type
|
|
98
|
+
* @param validationOptions - Optional validation options
|
|
99
|
+
* @returns Property decorator
|
|
100
|
+
*/
|
|
101
|
+
export function IsMediaInputArray(validationOptions) {
|
|
102
|
+
return function (object, propertyName) {
|
|
103
|
+
registerDecorator({
|
|
104
|
+
target: object.constructor,
|
|
105
|
+
propertyName: propertyName,
|
|
106
|
+
options: validationOptions,
|
|
107
|
+
constraints: [],
|
|
108
|
+
validator: IsMediaInputArrayConstraint,
|
|
109
|
+
});
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=media-input.validator.js.map
|