@arcaelas/dynamite 1.0.17 → 1.0.19
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/package.json +40 -2
- package/src/@types/index.d.ts +116 -75
- package/src/core/client.d.ts +36 -0
- package/src/core/client.js +80 -27
- package/src/core/decorator.d.ts +44 -0
- package/src/core/decorator.js +133 -0
- package/src/core/method.d.ts +73 -0
- package/src/core/method.js +140 -0
- package/src/core/table.d.ts +44 -86
- package/src/core/table.js +510 -310
- package/src/decorators/indexes.d.ts +38 -0
- package/src/decorators/indexes.js +67 -0
- package/src/decorators/relations.d.ts +55 -0
- package/src/decorators/relations.js +84 -0
- package/src/decorators/timestamps.d.ts +54 -0
- package/src/decorators/timestamps.js +67 -0
- package/src/decorators/transforms.d.ts +86 -0
- package/src/decorators/transforms.js +154 -0
- package/src/index.d.ts +10 -16
- package/src/index.js +50 -32
- package/src/index.test.d.ts +13 -0
- package/src/index.test.js +1992 -0
- package/src/utils/relations.d.ts +34 -12
- package/src/utils/relations.js +109 -133
- package/src/@types/index.js +0 -9
- package/src/core/wrapper.d.ts +0 -17
- package/src/core/wrapper.js +0 -46
- package/src/decorators/belongs_to.d.ts +0 -1
- package/src/decorators/belongs_to.js +0 -24
- package/src/decorators/created_at.d.ts +0 -1
- package/src/decorators/created_at.js +0 -11
- package/src/decorators/default.d.ts +0 -1
- package/src/decorators/default.js +0 -47
- package/src/decorators/has_many.d.ts +0 -1
- package/src/decorators/has_many.js +0 -24
- package/src/decorators/index.d.ts +0 -11
- package/src/decorators/index.js +0 -36
- package/src/decorators/index_sort.d.ts +0 -12
- package/src/decorators/index_sort.js +0 -43
- package/src/decorators/mutate.d.ts +0 -2
- package/src/decorators/mutate.js +0 -51
- package/src/decorators/name.d.ts +0 -1
- package/src/decorators/name.js +0 -28
- package/src/decorators/not_null.d.ts +0 -1
- package/src/decorators/not_null.js +0 -13
- package/src/decorators/primary_key.d.ts +0 -6
- package/src/decorators/primary_key.js +0 -30
- package/src/decorators/updated_at.d.ts +0 -12
- package/src/decorators/updated_at.js +0 -26
- package/src/decorators/validate.d.ts +0 -1
- package/src/decorators/validate.js +0 -53
- package/src/utils/batch-relations.d.ts +0 -14
- package/src/utils/batch-relations.js +0 -131
- package/src/utils/circular-detector.d.ts +0 -82
- package/src/utils/circular-detector.js +0 -212
- package/src/utils/memory-manager.d.ts +0 -42
- package/src/utils/memory-manager.js +0 -107
- package/src/utils/naming.d.ts +0 -8
- package/src/utils/naming.js +0 -18
- package/src/utils/projection.d.ts +0 -12
- package/src/utils/projection.js +0 -51
- package/src/utils/security-validator.d.ts +0 -49
- package/src/utils/security-validator.js +0 -163
- package/src/utils/throttle-manager.d.ts +0 -78
- package/src/utils/throttle-manager.js +0 -201
- package/src/utils/transaction-manager.d.ts +0 -88
- package/src/utils/transaction-manager.js +0 -300
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file memory-manager.ts
|
|
3
|
-
* @description Memory management and leak prevention
|
|
4
|
-
* @author Miguel Alejandro
|
|
5
|
-
* @fecha 2025-08-31
|
|
6
|
-
*/
|
|
7
|
-
declare class MemoryManager {
|
|
8
|
-
private static instance;
|
|
9
|
-
private cleanupTasks;
|
|
10
|
-
private maxCacheSize;
|
|
11
|
-
private maxCacheAge;
|
|
12
|
-
static getInstance(): MemoryManager;
|
|
13
|
-
/**
|
|
14
|
-
* Registrar una tarea de limpieza
|
|
15
|
-
*/
|
|
16
|
-
registerCleanup(id: string, cleanup: () => void, intervalMs?: number): void;
|
|
17
|
-
/**
|
|
18
|
-
* Desregistrar y limpiar tarea
|
|
19
|
-
*/
|
|
20
|
-
unregisterCleanup(id: string): void;
|
|
21
|
-
/**
|
|
22
|
-
* Limpiar cache con límites de tamaño y edad
|
|
23
|
-
*/
|
|
24
|
-
cleanCache<T>(cache: Map<string, {
|
|
25
|
-
data: T;
|
|
26
|
-
expires: number;
|
|
27
|
-
created: number;
|
|
28
|
-
}>, maxSize?: number): void;
|
|
29
|
-
/**
|
|
30
|
-
* Monitorear uso de memoria
|
|
31
|
-
*/
|
|
32
|
-
getMemoryUsage(): NodeJS.MemoryUsage;
|
|
33
|
-
/**
|
|
34
|
-
* Forzar garbage collection si está disponible
|
|
35
|
-
*/
|
|
36
|
-
forceGC(): void;
|
|
37
|
-
/**
|
|
38
|
-
* Cleanup completo al shutdown
|
|
39
|
-
*/
|
|
40
|
-
shutdown(): void;
|
|
41
|
-
}
|
|
42
|
-
export default MemoryManager;
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* @file memory-manager.ts
|
|
4
|
-
* @description Memory management and leak prevention
|
|
5
|
-
* @author Miguel Alejandro
|
|
6
|
-
* @fecha 2025-08-31
|
|
7
|
-
*/
|
|
8
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
class MemoryManager {
|
|
10
|
-
constructor() {
|
|
11
|
-
this.cleanupTasks = new Map();
|
|
12
|
-
this.maxCacheSize = 1000;
|
|
13
|
-
this.maxCacheAge = 300000; // 5 minutos
|
|
14
|
-
}
|
|
15
|
-
static getInstance() {
|
|
16
|
-
if (!MemoryManager.instance) {
|
|
17
|
-
MemoryManager.instance = new MemoryManager();
|
|
18
|
-
}
|
|
19
|
-
return MemoryManager.instance;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Registrar una tarea de limpieza
|
|
23
|
-
*/
|
|
24
|
-
registerCleanup(id, cleanup, intervalMs) {
|
|
25
|
-
// Limpiar tarea previa si existe
|
|
26
|
-
this.unregisterCleanup(id);
|
|
27
|
-
const task = { id, cleanup };
|
|
28
|
-
if (intervalMs) {
|
|
29
|
-
task.interval = setInterval(() => {
|
|
30
|
-
try {
|
|
31
|
-
cleanup();
|
|
32
|
-
}
|
|
33
|
-
catch (error) {
|
|
34
|
-
console.warn(`Cleanup task ${id} failed:`, error);
|
|
35
|
-
}
|
|
36
|
-
}, intervalMs);
|
|
37
|
-
}
|
|
38
|
-
this.cleanupTasks.set(id, task);
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Desregistrar y limpiar tarea
|
|
42
|
-
*/
|
|
43
|
-
unregisterCleanup(id) {
|
|
44
|
-
const task = this.cleanupTasks.get(id);
|
|
45
|
-
if (task) {
|
|
46
|
-
if (task.interval) {
|
|
47
|
-
clearInterval(task.interval);
|
|
48
|
-
}
|
|
49
|
-
task.cleanup();
|
|
50
|
-
this.cleanupTasks.delete(id);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Limpiar cache con límites de tamaño y edad
|
|
55
|
-
*/
|
|
56
|
-
cleanCache(cache, maxSize = this.maxCacheSize) {
|
|
57
|
-
const now = Date.now();
|
|
58
|
-
// Remover entradas expiradas
|
|
59
|
-
for (const [key, entry] of cache.entries()) {
|
|
60
|
-
if (entry.expires <= now || now - entry.created > this.maxCacheAge) {
|
|
61
|
-
cache.delete(key);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
// Si aún excede el tamaño, remover las más antiguas
|
|
65
|
-
if (cache.size > maxSize) {
|
|
66
|
-
const entries = Array.from(cache.entries()).sort((a, b) => a[1].created - b[1].created);
|
|
67
|
-
const toRemove = entries.slice(0, cache.size - maxSize);
|
|
68
|
-
toRemove.forEach(([key]) => cache.delete(key));
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Monitorear uso de memoria
|
|
73
|
-
*/
|
|
74
|
-
getMemoryUsage() {
|
|
75
|
-
return process.memoryUsage();
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Forzar garbage collection si está disponible
|
|
79
|
-
*/
|
|
80
|
-
forceGC() {
|
|
81
|
-
if (global.gc) {
|
|
82
|
-
global.gc();
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Cleanup completo al shutdown
|
|
87
|
-
*/
|
|
88
|
-
shutdown() {
|
|
89
|
-
console.log("MemoryManager: Iniciando cleanup completo...");
|
|
90
|
-
for (const [id, task] of this.cleanupTasks.entries()) {
|
|
91
|
-
try {
|
|
92
|
-
this.unregisterCleanup(id);
|
|
93
|
-
}
|
|
94
|
-
catch (error) {
|
|
95
|
-
console.warn(`Error cleaning up task ${id}:`, error);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
this.cleanupTasks.clear();
|
|
99
|
-
this.forceGC();
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
// Cleanup automático en shutdown
|
|
103
|
-
process.on("SIGTERM", () => MemoryManager.getInstance().shutdown());
|
|
104
|
-
process.on("SIGINT", () => MemoryManager.getInstance().shutdown());
|
|
105
|
-
process.on("uncaughtException", () => MemoryManager.getInstance().shutdown());
|
|
106
|
-
exports.default = MemoryManager;
|
|
107
|
-
//# sourceMappingURL=memory-manager.js.map
|
package/src/utils/naming.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file naming.ts
|
|
3
|
-
* @descripcion Utilidades de conversión de nombres
|
|
4
|
-
* @autor Miguel Alejandro
|
|
5
|
-
* @fecha 2025-01-27
|
|
6
|
-
*/
|
|
7
|
-
/** Convierte nombre de clase a formato snake_case plural para tablas */
|
|
8
|
-
export declare function toSnakePlural(input: string): string;
|
package/src/utils/naming.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* @file naming.ts
|
|
4
|
-
* @descripcion Utilidades de conversión de nombres
|
|
5
|
-
* @autor Miguel Alejandro
|
|
6
|
-
* @fecha 2025-01-27
|
|
7
|
-
*/
|
|
8
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.toSnakePlural = toSnakePlural;
|
|
13
|
-
const pluralize_1 = __importDefault(require("pluralize"));
|
|
14
|
-
/** Convierte nombre de clase a formato snake_case plural para tablas */
|
|
15
|
-
function toSnakePlural(input) {
|
|
16
|
-
return (0, pluralize_1.default)(input.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase());
|
|
17
|
-
}
|
|
18
|
-
//# sourceMappingURL=naming.js.map
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file projection.ts
|
|
3
|
-
* @description Selective field loading and projection optimization
|
|
4
|
-
* @autor Miguel Alejandro
|
|
5
|
-
* @fecha 2025-01-27
|
|
6
|
-
*/
|
|
7
|
-
/** Build DynamoDB ProjectionExpression */
|
|
8
|
-
export declare const buildProjection: (attributes?: string[], meta?: any) => string | undefined;
|
|
9
|
-
/** Optimize attributes loading for relations */
|
|
10
|
-
export declare const optimizeRelationAttributes: (include: any, baseAttributes?: string[]) => string[];
|
|
11
|
-
/** Smart attribute selection for common patterns */
|
|
12
|
-
export declare const getSmartAttributes: (Model: any, scenario: "list" | "detail" | "minimal") => string[];
|
package/src/utils/projection.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* @file projection.ts
|
|
4
|
-
* @description Selective field loading and projection optimization
|
|
5
|
-
* @autor Miguel Alejandro
|
|
6
|
-
* @fecha 2025-01-27
|
|
7
|
-
*/
|
|
8
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.getSmartAttributes = exports.optimizeRelationAttributes = exports.buildProjection = void 0;
|
|
10
|
-
const wrapper_1 = require("../core/wrapper");
|
|
11
|
-
/** Build DynamoDB ProjectionExpression */
|
|
12
|
-
const buildProjection = (attributes, meta) => {
|
|
13
|
-
if (!attributes?.length || !meta)
|
|
14
|
-
return undefined;
|
|
15
|
-
// Validate attributes exist in model
|
|
16
|
-
const validAttributes = attributes.filter((attr) => meta.columns.has(attr) || meta.relations.has(attr));
|
|
17
|
-
return validAttributes.length ? validAttributes.join(", ") : undefined;
|
|
18
|
-
};
|
|
19
|
-
exports.buildProjection = buildProjection;
|
|
20
|
-
/** Optimize attributes loading for relations */
|
|
21
|
-
const optimizeRelationAttributes = (include, baseAttributes) => {
|
|
22
|
-
const attributes = new Set(baseAttributes || []);
|
|
23
|
-
// Add foreign keys needed for relations
|
|
24
|
-
Object.entries(include || {}).forEach(([relationKey, options]) => {
|
|
25
|
-
attributes.add(relationKey);
|
|
26
|
-
// Add foreign key fields
|
|
27
|
-
if (options?.foreignKey)
|
|
28
|
-
attributes.add(options.foreignKey);
|
|
29
|
-
if (options?.localKey)
|
|
30
|
-
attributes.add(options.localKey);
|
|
31
|
-
});
|
|
32
|
-
return Array.from(attributes);
|
|
33
|
-
};
|
|
34
|
-
exports.optimizeRelationAttributes = optimizeRelationAttributes;
|
|
35
|
-
/** Smart attribute selection for common patterns */
|
|
36
|
-
const getSmartAttributes = (Model, scenario) => {
|
|
37
|
-
const meta = (0, wrapper_1.mustMeta)(Model);
|
|
38
|
-
const columns = Array.from(meta.columns.keys());
|
|
39
|
-
switch (scenario) {
|
|
40
|
-
case "minimal":
|
|
41
|
-
return columns.filter((col) => meta.columns.get(col)?.primaryKey ||
|
|
42
|
-
["id", "name", "title", "email"].includes(col));
|
|
43
|
-
case "list":
|
|
44
|
-
return columns.filter((col) => !["description", "content", "body", "metadata"].includes(col));
|
|
45
|
-
case "detail":
|
|
46
|
-
default:
|
|
47
|
-
return columns;
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
exports.getSmartAttributes = getSmartAttributes;
|
|
51
|
-
//# sourceMappingURL=projection.js.map
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file security-validator.ts
|
|
3
|
-
* @description Security validation and NoSQL injection prevention
|
|
4
|
-
* @author Miguel Alejandro
|
|
5
|
-
* @fecha 2025-08-31
|
|
6
|
-
*/
|
|
7
|
-
import { QueryOperator } from "../@types/index";
|
|
8
|
-
interface SecurityConfig {
|
|
9
|
-
maxStringLength: number;
|
|
10
|
-
maxArrayLength: number;
|
|
11
|
-
maxNestedDepth: number;
|
|
12
|
-
allowedOperators: QueryOperator[];
|
|
13
|
-
blockedPatterns: RegExp[];
|
|
14
|
-
}
|
|
15
|
-
declare class SecurityValidator {
|
|
16
|
-
private static readonly DEFAULT_CONFIG;
|
|
17
|
-
private config;
|
|
18
|
-
constructor(config?: Partial<SecurityConfig>);
|
|
19
|
-
/**
|
|
20
|
-
* Validar nombre de atributo/tabla
|
|
21
|
-
*/
|
|
22
|
-
validateAttributeName(name: string): void;
|
|
23
|
-
/**
|
|
24
|
-
* Validar operador de query
|
|
25
|
-
*/
|
|
26
|
-
validateOperator(operator: string): QueryOperator;
|
|
27
|
-
/**
|
|
28
|
-
* Validar valor de campo
|
|
29
|
-
*/
|
|
30
|
-
validateValue(value: any, depth?: number): any;
|
|
31
|
-
/**
|
|
32
|
-
* Validar filtros de query completos
|
|
33
|
-
*/
|
|
34
|
-
validateQueryFilters(filters: Record<string, any>): Record<string, any>;
|
|
35
|
-
/**
|
|
36
|
-
* Sanitizar string para DynamoDB
|
|
37
|
-
*/
|
|
38
|
-
sanitizeString(input: string): string;
|
|
39
|
-
/**
|
|
40
|
-
* Validar tamaño de item para DynamoDB (límite 400KB)
|
|
41
|
-
*/
|
|
42
|
-
validateItemSize(item: any): void;
|
|
43
|
-
}
|
|
44
|
-
declare class SecurityError extends Error {
|
|
45
|
-
constructor(message: string);
|
|
46
|
-
}
|
|
47
|
-
declare const securityValidator: SecurityValidator;
|
|
48
|
-
export { SecurityError, SecurityValidator, securityValidator };
|
|
49
|
-
export default securityValidator;
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* @file security-validator.ts
|
|
4
|
-
* @description Security validation and NoSQL injection prevention
|
|
5
|
-
* @author Miguel Alejandro
|
|
6
|
-
* @fecha 2025-08-31
|
|
7
|
-
*/
|
|
8
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.securityValidator = exports.SecurityValidator = exports.SecurityError = void 0;
|
|
10
|
-
class SecurityValidator {
|
|
11
|
-
static { this.DEFAULT_CONFIG = {
|
|
12
|
-
maxStringLength: 10000,
|
|
13
|
-
maxArrayLength: 1000,
|
|
14
|
-
maxNestedDepth: 10,
|
|
15
|
-
allowedOperators: [
|
|
16
|
-
"=",
|
|
17
|
-
"!=",
|
|
18
|
-
"<",
|
|
19
|
-
"<=",
|
|
20
|
-
">",
|
|
21
|
-
">=",
|
|
22
|
-
"in",
|
|
23
|
-
"not-in",
|
|
24
|
-
"contains",
|
|
25
|
-
"begins-with",
|
|
26
|
-
],
|
|
27
|
-
blockedPatterns: [
|
|
28
|
-
/\$\w+/g, // MongoDB operators
|
|
29
|
-
/javascript:/gi, // JavaScript injection
|
|
30
|
-
/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, // Script tags
|
|
31
|
-
/eval\s*\(/gi, // eval() calls
|
|
32
|
-
/function\s*\(/gi, // function declarations
|
|
33
|
-
/\{\s*\$\w+/g, // NoSQL operators
|
|
34
|
-
/\.\.\//g, // Path traversal
|
|
35
|
-
/union\s+select/gi, // SQL injection patterns
|
|
36
|
-
/drop\s+table/gi, // Destructive SQL
|
|
37
|
-
],
|
|
38
|
-
}; }
|
|
39
|
-
constructor(config) {
|
|
40
|
-
this.config = { ...SecurityValidator.DEFAULT_CONFIG, ...config };
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Validar nombre de atributo/tabla
|
|
44
|
-
*/
|
|
45
|
-
validateAttributeName(name) {
|
|
46
|
-
if (!name || typeof name !== "string") {
|
|
47
|
-
throw new SecurityError("Nombre de atributo inválido");
|
|
48
|
-
}
|
|
49
|
-
if (name.length > 255) {
|
|
50
|
-
throw new SecurityError("Nombre de atributo muy largo");
|
|
51
|
-
}
|
|
52
|
-
// Solo permitir caracteres alfanuméricos, guiones y guiones bajos
|
|
53
|
-
if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name)) {
|
|
54
|
-
throw new SecurityError("Nombre de atributo contiene caracteres inválidos");
|
|
55
|
-
}
|
|
56
|
-
// Verificar patrones bloqueados
|
|
57
|
-
for (const pattern of this.config.blockedPatterns) {
|
|
58
|
-
if (pattern.test(name)) {
|
|
59
|
-
throw new SecurityError("Nombre de atributo contiene patrones peligrosos");
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Validar operador de query
|
|
65
|
-
*/
|
|
66
|
-
validateOperator(operator) {
|
|
67
|
-
if (!this.config.allowedOperators.includes(operator)) {
|
|
68
|
-
throw new SecurityError(`Operador no permitido: ${operator}`);
|
|
69
|
-
}
|
|
70
|
-
return operator;
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Validar valor de campo
|
|
74
|
-
*/
|
|
75
|
-
validateValue(value, depth = 0) {
|
|
76
|
-
if (depth > this.config.maxNestedDepth) {
|
|
77
|
-
throw new SecurityError("Estructura de datos anidada muy profunda");
|
|
78
|
-
}
|
|
79
|
-
// Valores null/undefined son válidos
|
|
80
|
-
if (value === null || value === undefined) {
|
|
81
|
-
return value;
|
|
82
|
-
}
|
|
83
|
-
// Validar strings
|
|
84
|
-
if (typeof value === "string") {
|
|
85
|
-
if (value.length > this.config.maxStringLength) {
|
|
86
|
-
throw new SecurityError("String muy largo");
|
|
87
|
-
}
|
|
88
|
-
for (const pattern of this.config.blockedPatterns) {
|
|
89
|
-
if (pattern.test(value)) {
|
|
90
|
-
throw new SecurityError("Valor contiene patrones peligrosos");
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
return value;
|
|
94
|
-
}
|
|
95
|
-
// Validar arrays
|
|
96
|
-
if (Array.isArray(value)) {
|
|
97
|
-
if (value.length > this.config.maxArrayLength) {
|
|
98
|
-
throw new SecurityError("Array muy largo");
|
|
99
|
-
}
|
|
100
|
-
return value.map((item) => this.validateValue(item, depth + 1));
|
|
101
|
-
}
|
|
102
|
-
// Validar objetos
|
|
103
|
-
if (typeof value === "object") {
|
|
104
|
-
const validated = {};
|
|
105
|
-
for (const [key, val] of Object.entries(value)) {
|
|
106
|
-
this.validateAttributeName(key);
|
|
107
|
-
validated[key] = this.validateValue(val, depth + 1);
|
|
108
|
-
}
|
|
109
|
-
return validated;
|
|
110
|
-
}
|
|
111
|
-
// Números, booleans son válidos
|
|
112
|
-
if (typeof value === "number" || typeof value === "boolean") {
|
|
113
|
-
return value;
|
|
114
|
-
}
|
|
115
|
-
throw new SecurityError(`Tipo de valor no permitido: ${typeof value}`);
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Validar filtros de query completos
|
|
119
|
-
*/
|
|
120
|
-
validateQueryFilters(filters) {
|
|
121
|
-
const validated = {};
|
|
122
|
-
for (const [key, value] of Object.entries(filters)) {
|
|
123
|
-
this.validateAttributeName(key);
|
|
124
|
-
validated[key] = this.validateValue(value);
|
|
125
|
-
}
|
|
126
|
-
return validated;
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Sanitizar string para DynamoDB
|
|
130
|
-
*/
|
|
131
|
-
sanitizeString(input) {
|
|
132
|
-
if (typeof input !== "string") {
|
|
133
|
-
return String(input);
|
|
134
|
-
}
|
|
135
|
-
return input
|
|
136
|
-
.replace(/[\x00-\x1F\x7F]/g, "") // Remover caracteres de control
|
|
137
|
-
.trim()
|
|
138
|
-
.slice(0, this.config.maxStringLength);
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* Validar tamaño de item para DynamoDB (límite 400KB)
|
|
142
|
-
*/
|
|
143
|
-
validateItemSize(item) {
|
|
144
|
-
const size = JSON.stringify(item).length;
|
|
145
|
-
const maxSize = 400 * 1024; // 400KB en bytes
|
|
146
|
-
if (size > maxSize) {
|
|
147
|
-
throw new SecurityError(`Item muy grande: ${size} bytes (máximo: ${maxSize} bytes)`);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
exports.SecurityValidator = SecurityValidator;
|
|
152
|
-
class SecurityError extends Error {
|
|
153
|
-
constructor(message) {
|
|
154
|
-
super(message);
|
|
155
|
-
this.name = "SecurityError";
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
exports.SecurityError = SecurityError;
|
|
159
|
-
// Instancia singleton
|
|
160
|
-
const securityValidator = new SecurityValidator();
|
|
161
|
-
exports.securityValidator = securityValidator;
|
|
162
|
-
exports.default = securityValidator;
|
|
163
|
-
//# sourceMappingURL=security-validator.js.map
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file throttle-manager.ts
|
|
3
|
-
* @description AWS DynamoDB throttling and retry management
|
|
4
|
-
* @author Miguel Alejandro
|
|
5
|
-
* @fecha 2025-08-31
|
|
6
|
-
*/
|
|
7
|
-
interface RetryConfig {
|
|
8
|
-
maxRetries: number;
|
|
9
|
-
baseDelay: number;
|
|
10
|
-
maxDelay: number;
|
|
11
|
-
backoffMultiplier: number;
|
|
12
|
-
jitterFactor: number;
|
|
13
|
-
}
|
|
14
|
-
interface ThrottleStats {
|
|
15
|
-
totalRequests: number;
|
|
16
|
-
throttledRequests: number;
|
|
17
|
-
retriedRequests: number;
|
|
18
|
-
averageLatency: number;
|
|
19
|
-
}
|
|
20
|
-
declare class ThrottleManager {
|
|
21
|
-
private static readonly DEFAULT_CONFIG;
|
|
22
|
-
private config;
|
|
23
|
-
private stats;
|
|
24
|
-
private requestQueue;
|
|
25
|
-
private isProcessingQueue;
|
|
26
|
-
private concurrentRequests;
|
|
27
|
-
private maxConcurrentRequests;
|
|
28
|
-
constructor(config?: Partial<RetryConfig>);
|
|
29
|
-
/**
|
|
30
|
-
* Ejecutar operación con retry automático
|
|
31
|
-
*/
|
|
32
|
-
executeWithRetry<T>(operation: () => Promise<T>, operationName?: string): Promise<T>;
|
|
33
|
-
/**
|
|
34
|
-
* Verificar si el error es reintentable
|
|
35
|
-
*/
|
|
36
|
-
private isRetryableError;
|
|
37
|
-
/**
|
|
38
|
-
* Calcular delay con exponential backoff + jitter
|
|
39
|
-
*/
|
|
40
|
-
private calculateDelay;
|
|
41
|
-
/**
|
|
42
|
-
* Controlar concurrencia de requests
|
|
43
|
-
*/
|
|
44
|
-
private acquireConcurrencySlot;
|
|
45
|
-
private releaseConcurrencySlot;
|
|
46
|
-
/**
|
|
47
|
-
* Queue para operaciones batch con rate limiting
|
|
48
|
-
*/
|
|
49
|
-
queueOperation<T>(operation: () => Promise<T>): Promise<T>;
|
|
50
|
-
private processQueue;
|
|
51
|
-
/**
|
|
52
|
-
* Obtener estadísticas de throttling
|
|
53
|
-
*/
|
|
54
|
-
getStats(): ThrottleStats;
|
|
55
|
-
/**
|
|
56
|
-
* Resetear estadísticas
|
|
57
|
-
*/
|
|
58
|
-
resetStats(): void;
|
|
59
|
-
private updateLatencyStats;
|
|
60
|
-
private sleep;
|
|
61
|
-
/**
|
|
62
|
-
* Configurar límites de concurrencia dinámicamente
|
|
63
|
-
*/
|
|
64
|
-
setConcurrencyLimit(limit: number): void;
|
|
65
|
-
/**
|
|
66
|
-
* Obtener métricas de salud del throttling
|
|
67
|
-
*/
|
|
68
|
-
getHealthMetrics(): {
|
|
69
|
-
throttleRate: number;
|
|
70
|
-
retryRate: number;
|
|
71
|
-
avgLatency: number;
|
|
72
|
-
concurrentRequests: number;
|
|
73
|
-
queueSize: number;
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
declare const throttleManager: ThrottleManager;
|
|
77
|
-
export { RetryConfig, ThrottleManager, ThrottleStats, throttleManager };
|
|
78
|
-
export default throttleManager;
|