@groundbrick/service-base 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +713 -0
  2. package/dist/core/BaseService.d.ts +55 -0
  3. package/dist/core/BaseService.d.ts.map +1 -0
  4. package/dist/core/BaseService.js +123 -0
  5. package/dist/core/BaseService.js.map +1 -0
  6. package/dist/email/EmailConfigurationService.d.ts +14 -0
  7. package/dist/email/EmailConfigurationService.d.ts.map +1 -0
  8. package/dist/email/EmailConfigurationService.js +60 -0
  9. package/dist/email/EmailConfigurationService.js.map +1 -0
  10. package/dist/email/EmailService.d.ts +15 -0
  11. package/dist/email/EmailService.d.ts.map +1 -0
  12. package/dist/email/EmailService.js +96 -0
  13. package/dist/email/EmailService.js.map +1 -0
  14. package/dist/email/interfaces/EmailInterfaces.d.ts +45 -0
  15. package/dist/email/interfaces/EmailInterfaces.d.ts.map +1 -0
  16. package/dist/email/interfaces/EmailInterfaces.js +2 -0
  17. package/dist/email/interfaces/EmailInterfaces.js.map +1 -0
  18. package/dist/email/providers/SmtpEmailProvider.d.ts +14 -0
  19. package/dist/email/providers/SmtpEmailProvider.d.ts.map +1 -0
  20. package/dist/email/providers/SmtpEmailProvider.js +88 -0
  21. package/dist/email/providers/SmtpEmailProvider.js.map +1 -0
  22. package/dist/index.d.ts +14 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +22 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/types/BusinessError.d.ts +31 -0
  27. package/dist/types/BusinessError.d.ts.map +1 -0
  28. package/dist/types/BusinessError.js +57 -0
  29. package/dist/types/BusinessError.js.map +1 -0
  30. package/dist/types/ServiceOptions.d.ts +14 -0
  31. package/dist/types/ServiceOptions.d.ts.map +1 -0
  32. package/dist/types/ServiceOptions.js +2 -0
  33. package/dist/types/ServiceOptions.js.map +1 -0
  34. package/dist/types/ServiceResult.d.ts +31 -0
  35. package/dist/types/ServiceResult.d.ts.map +1 -0
  36. package/dist/types/ServiceResult.js +61 -0
  37. package/dist/types/ServiceResult.js.map +1 -0
  38. package/dist/validation/ValidationError.d.ts +14 -0
  39. package/dist/validation/ValidationError.d.ts.map +1 -0
  40. package/dist/validation/ValidationError.js +2 -0
  41. package/dist/validation/ValidationError.js.map +1 -0
  42. package/dist/validation/ValidationHelper.d.ts +70 -0
  43. package/dist/validation/ValidationHelper.d.ts.map +1 -0
  44. package/dist/validation/ValidationHelper.js +169 -0
  45. package/dist/validation/ValidationHelper.js.map +1 -0
  46. package/dist/validation/ValidationResult.d.ts +12 -0
  47. package/dist/validation/ValidationResult.d.ts.map +1 -0
  48. package/dist/validation/ValidationResult.js +2 -0
  49. package/dist/validation/ValidationResult.js.map +1 -0
  50. package/dist/validation/Validator.d.ts +35 -0
  51. package/dist/validation/Validator.d.ts.map +1 -0
  52. package/dist/validation/Validator.js +52 -0
  53. package/dist/validation/Validator.js.map +1 -0
  54. package/package.json +60 -0
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Business logic error with structured information
3
+ */
4
+ export declare class BusinessError extends Error {
5
+ readonly code: string;
6
+ readonly originalError?: Error;
7
+ readonly context?: Record<string, any>;
8
+ readonly timestamp: Date;
9
+ constructor(message: string, code: string, originalError?: Error, context?: Record<string, any>);
10
+ /**
11
+ * Convert to JSON for logging/API responses
12
+ */
13
+ toJSON(): Record<string, any>;
14
+ /**
15
+ * Create user-friendly error response
16
+ */
17
+ toUserResponse(): {
18
+ error: string;
19
+ code: string;
20
+ timestamp: string;
21
+ };
22
+ /**
23
+ * Check if error is of specific business type
24
+ */
25
+ static isBusinessError(error: any): error is BusinessError;
26
+ /**
27
+ * Check if error has specific code
28
+ */
29
+ hasCode(code: string): boolean;
30
+ }
31
+ //# sourceMappingURL=BusinessError.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BusinessError.d.ts","sourceRoot":"","sources":["../../src/types/BusinessError.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACpC,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,SAAgB,aAAa,CAAC,EAAE,KAAK,CAAC;IACtC,SAAgB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9C,SAAgB,SAAS,EAAE,IAAI,CAAC;gBAG5B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,aAAa,CAAC,EAAE,KAAK,EACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAejC;;OAEG;IACH,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAW7B;;OAEG;IACH,cAAc,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;IAQpE;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,GAAG,GAAG,KAAK,IAAI,aAAa;IAI1D;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;CAGjC"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Business logic error with structured information
3
+ */
4
+ export class BusinessError extends Error {
5
+ code;
6
+ originalError;
7
+ context;
8
+ timestamp;
9
+ constructor(message, code, originalError, context) {
10
+ super(message);
11
+ this.name = 'BusinessError';
12
+ this.code = code;
13
+ this.originalError = originalError;
14
+ this.context = context;
15
+ this.timestamp = new Date();
16
+ // Maintain stack trace
17
+ if (Error.captureStackTrace) {
18
+ Error.captureStackTrace(this, BusinessError);
19
+ }
20
+ }
21
+ /**
22
+ * Convert to JSON for logging/API responses
23
+ */
24
+ toJSON() {
25
+ return {
26
+ name: this.name,
27
+ message: this.message,
28
+ code: this.code,
29
+ timestamp: this.timestamp.toISOString(),
30
+ context: this.context,
31
+ stack: this.stack
32
+ };
33
+ }
34
+ /**
35
+ * Create user-friendly error response
36
+ */
37
+ toUserResponse() {
38
+ return {
39
+ error: this.message,
40
+ code: this.code,
41
+ timestamp: this.timestamp.toISOString()
42
+ };
43
+ }
44
+ /**
45
+ * Check if error is of specific business type
46
+ */
47
+ static isBusinessError(error) {
48
+ return error instanceof BusinessError;
49
+ }
50
+ /**
51
+ * Check if error has specific code
52
+ */
53
+ hasCode(code) {
54
+ return this.code === code;
55
+ }
56
+ }
57
+ //# sourceMappingURL=BusinessError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BusinessError.js","sourceRoot":"","sources":["../../src/types/BusinessError.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IACpB,IAAI,CAAS;IACb,aAAa,CAAS;IACtB,OAAO,CAAuB;IAC9B,SAAS,CAAO;IAEhC,YACI,OAAe,EACf,IAAY,EACZ,aAAqB,EACrB,OAA6B;QAE7B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;QAE5B,uBAAuB;QACvB,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;YAC1B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;QACjD,CAAC;IACL,CAAC;IAED;;OAEG;IACH,MAAM;QACF,OAAO;YACH,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE;YACvC,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,KAAK,EAAE,IAAI,CAAC,KAAK;SACpB,CAAC;IACN,CAAC;IAED;;OAEG;IACH,cAAc;QACV,OAAO;YACH,KAAK,EAAE,IAAI,CAAC,OAAO;YACnB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE;SAC1C,CAAC;IACN,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,KAAU;QAC7B,OAAO,KAAK,YAAY,aAAa,CAAC;IAC1C,CAAC;IAED;;OAEG;IACH,OAAO,CAAC,IAAY;QAChB,OAAO,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC;IAC9B,CAAC;CACJ"}
@@ -0,0 +1,14 @@
1
+ import { DatabaseClient } from '@groundbrick/db-core';
2
+ import { Validator } from '../validation/Validator.js';
3
+ /**
4
+ * Configuration options for service instances
5
+ */
6
+ export interface ServiceOptions {
7
+ /** Database client for transaction support */
8
+ database?: DatabaseClient;
9
+ /** Custom validator instance */
10
+ validator?: Validator;
11
+ /** Additional service-specific configuration */
12
+ config?: Record<string, any>;
13
+ }
14
+ //# sourceMappingURL=ServiceOptions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServiceOptions.d.ts","sourceRoot":"","sources":["../../src/types/ServiceOptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC3B,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,cAAc,CAAC;IAE1B,gCAAgC;IAChC,SAAS,CAAC,EAAE,SAAS,CAAC;IAEtB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ServiceOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServiceOptions.js","sourceRoot":"","sources":["../../src/types/ServiceOptions.ts"],"names":[],"mappings":""}
@@ -0,0 +1,31 @@
1
+ import { BusinessError } from "./BusinessError.js";
2
+ /**
3
+ * Standardized service operation result
4
+ */
5
+ export interface ServiceResult<T = any> {
6
+ /** Whether operation succeeded */
7
+ success: boolean;
8
+ /** Result data (if successful) */
9
+ data?: T;
10
+ /** Error information (if failed) */
11
+ error?: {
12
+ message: string;
13
+ code: string;
14
+ details?: Record<string, any>;
15
+ };
16
+ /** Operation metadata */
17
+ metadata?: {
18
+ duration?: number;
19
+ timestamp: string;
20
+ operation?: string;
21
+ };
22
+ }
23
+ /**
24
+ * Helper to create successful result
25
+ */
26
+ export declare function createSuccessResult<T>(data: T, metadata?: any): ServiceResult<T>;
27
+ /**
28
+ * Helper to create error result
29
+ */
30
+ export declare function createErrorResult(error: BusinessError | Error | any): ServiceResult;
31
+ //# sourceMappingURL=ServiceResult.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServiceResult.d.ts","sourceRoot":"","sources":["../../src/types/ServiceResult.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,GAAG;IAClC,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;IAEjB,kCAAkC;IAClC,IAAI,CAAC,EAAE,CAAC,CAAC;IAET,oCAAoC;IACpC,KAAK,CAAC,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KACjC,CAAC;IAEF,yBAAyB;IACzB,QAAQ,CAAC,EAAE;QACP,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACL;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,CAAC,EAAE,GAAG,GAAG,aAAa,CAAC,CAAC,CAAC,CAShF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,KAAK,GAAG,GAAG,GAAG,aAAa,CAkBnF"}
@@ -0,0 +1,61 @@
1
+ import { BusinessError } from "./BusinessError.js";
2
+ /**
3
+ * Helper to create successful result
4
+ */
5
+ export function createSuccessResult(data, metadata) {
6
+ return {
7
+ success: true,
8
+ data,
9
+ metadata: {
10
+ timestamp: new Date().toISOString(),
11
+ ...metadata
12
+ }
13
+ };
14
+ }
15
+ /**
16
+ * Helper to create error result
17
+ */
18
+ export function createErrorResult(error) {
19
+ const isBusinessError = BusinessError.isBusinessError(error);
20
+ if (!isBusinessError) {
21
+ handleRepositoryError(error);
22
+ }
23
+ return {
24
+ success: false,
25
+ error: {
26
+ message: error.message,
27
+ code: isBusinessError ? error.code : 'UNKNOWN_ERROR',
28
+ details: isBusinessError ? error.context : undefined
29
+ },
30
+ metadata: {
31
+ timestamp: new Date().toISOString()
32
+ }
33
+ };
34
+ }
35
+ /**
36
+ * Transform repository errors into business errors
37
+ * @param error - Original error from repository layer
38
+ * @returns BusinessError with appropriate context
39
+ */
40
+ function handleRepositoryError(error) {
41
+ // Handle query errors
42
+ if (error.code === 'QUERY_ERROR' || error.message.includes('query failed') || error.message.includes('syntax error')) {
43
+ return new BusinessError('Execução inválida na base de dados.', 'QUERY_ERROR', error);
44
+ }
45
+ // Handle common database constraint violations
46
+ if (error.message.includes('duplicate') || error.message.includes('unique')) {
47
+ return new BusinessError('Recurso já existe', 'DUPLICATE_RESOURCE', error);
48
+ }
49
+ if (error.message.includes('not found') || error.message.includes('does not exist')) {
50
+ return new BusinessError('Recurso não encontrado', 'RESOURCE_NOT_FOUND', error);
51
+ }
52
+ if (error.message.includes('foreign key') || error.message.includes('constraint')) {
53
+ return new BusinessError('Referência inválida ou violação de restrição', 'CONSTRAINT_VIOLATION', error);
54
+ }
55
+ if (error.message.includes('ETIMEDOUT') || error.message.includes('deadlock')) {
56
+ return new BusinessError('Operação no banco de dados expirou ou ficou bloqueada', 'DATABASE_TIMEOUT', error);
57
+ }
58
+ // Default: wrap as generic business error
59
+ return new BusinessError('Operação falhou', 'OPERATION_FAILED', error);
60
+ }
61
+ //# sourceMappingURL=ServiceResult.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServiceResult.js","sourceRoot":"","sources":["../../src/types/ServiceResult.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AA2BnD;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAI,IAAO,EAAE,QAAc;IAC1D,OAAO;QACH,OAAO,EAAE,IAAI;QACb,IAAI;QACJ,QAAQ,EAAE;YACN,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,GAAG,QAAQ;SACd;KACJ,CAAC;AACN,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAkC;IAChE,MAAM,eAAe,GAAG,aAAa,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAE7D,IAAI,CAAC,eAAe,EAAE,CAAC;QACnB,qBAAqB,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAED,OAAO;QACH,OAAO,EAAE,KAAK;QACd,KAAK,EAAE;YACH,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe;YACpD,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;SACvD;QACD,QAAQ,EAAE;YACN,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACtC;KACJ,CAAC;AACN,CAAC;AAED;;;;GAIG;AACH,SAAS,qBAAqB,CAAC,KAAU;IAErC,sBAAsB;IACtB,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;QACnH,OAAO,IAAI,aAAa,CACpB,qCAAqC,EACrC,aAAa,EACb,KAAK,CACR,CAAC;IACN,CAAC;IAED,+CAA+C;IAC/C,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1E,OAAO,IAAI,aAAa,CACpB,mBAAmB,EACnB,oBAAoB,EACpB,KAAK,CACR,CAAC;IACN,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAClF,OAAO,IAAI,aAAa,CACpB,wBAAwB,EACxB,oBAAoB,EACpB,KAAK,CACR,CAAC;IACN,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QAChF,OAAO,IAAI,aAAa,CACpB,8CAA8C,EAC9C,sBAAsB,EACtB,KAAK,CACR,CAAC;IACN,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5E,OAAO,IAAI,aAAa,CACpB,uDAAuD,EACvD,kBAAkB,EAClB,KAAK,CACR,CAAC;IACN,CAAC;IAED,0CAA0C;IAC1C,OAAO,IAAI,aAAa,CACpB,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,CACR,CAAC;AACN,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Individual validation error
3
+ */
4
+ export interface ValidationError {
5
+ /** Field that failed validation */
6
+ field: string;
7
+ /** Error message */
8
+ message: string;
9
+ /** Validation rule that failed */
10
+ rule: string;
11
+ /** Current value that failed */
12
+ value?: any;
13
+ }
14
+ //# sourceMappingURL=ValidationError.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ValidationError.d.ts","sourceRoot":"","sources":["../../src/validation/ValidationError.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,eAAe;IAC5B,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IAEd,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;IAEhB,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IAEb,gCAAgC;IAChC,KAAK,CAAC,EAAE,GAAG,CAAC;CACf"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ValidationError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ValidationError.js","sourceRoot":"","sources":["../../src/validation/ValidationError.ts"],"names":[],"mappings":""}
@@ -0,0 +1,70 @@
1
+ import { ValidationRule } from "./Validator.js";
2
+ /**
3
+ * Common validation rules and helpers
4
+ */
5
+ export declare class ValidationHelper {
6
+ /**
7
+ * Rule: Field is required (not null, undefined, or empty string)
8
+ */
9
+ static required(): ValidationRule;
10
+ /**
11
+ * Rule: String minimum length
12
+ */
13
+ static minLength(min: number): ValidationRule;
14
+ /**
15
+ * Rule: String maximum length
16
+ */
17
+ static maxLength(max: number): ValidationRule;
18
+ /**
19
+ * Rule: Valid email format
20
+ */
21
+ static email(): ValidationRule;
22
+ /**
23
+ * Rule: Numeric value within range
24
+ */
25
+ static numberRange(min?: number, max?: number): ValidationRule;
26
+ /**
27
+ * Rule: Value matches regex pattern
28
+ */
29
+ static pattern(regex: RegExp, message: string): ValidationRule;
30
+ /**
31
+ * Rule: Value is one of allowed options
32
+ */
33
+ static oneOf(options: any[], message?: string): ValidationRule;
34
+ /**
35
+ * Rule: Array has minimum length
36
+ */
37
+ static arrayMinLength(min: number): ValidationRule;
38
+ /**
39
+ * Rule: Custom validation with context
40
+ */
41
+ static custom(validator: (value: any, data?: any) => string | null): ValidationRule;
42
+ /**
43
+ * Rule: Conditional validation
44
+ */
45
+ static when(condition: (data: any) => boolean, rule: ValidationRule): ValidationRule;
46
+ /**
47
+ * Combine multiple validation rules
48
+ */
49
+ static combine(...rules: ValidationRule[]): ValidationRule[];
50
+ /**
51
+ * Create validation rules for common entity patterns
52
+ */
53
+ static entityId(): ValidationRule[];
54
+ /**
55
+ * Create validation rules for user creation
56
+ */
57
+ static userCreation(): {
58
+ name: ValidationRule[];
59
+ email: ValidationRule[];
60
+ password: ValidationRule[];
61
+ };
62
+ /**
63
+ * Create validation rules for pagination
64
+ */
65
+ static pagination(): {
66
+ limit: ValidationRule[];
67
+ offset: ValidationRule[];
68
+ };
69
+ }
70
+ //# sourceMappingURL=ValidationHelper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ValidationHelper.d.ts","sourceRoot":"","sources":["../../src/validation/ValidationHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD;;GAEG;AACH,qBAAa,gBAAgB;IACzB;;OAEG;IACH,MAAM,CAAC,QAAQ,IAAI,cAAc;IASjC;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc;IAU7C;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc;IAU7C;;OAEG;IACH,MAAM,CAAC,KAAK,IAAI,cAAc;IAW9B;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,cAAc;IAgB9D;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc;IAU9D;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,cAAc;IAS9D;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc;IAUlD;;OAEG;IACH,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,GAAG,KAAK,MAAM,GAAG,IAAI,GAAG,cAAc;IAInF;;OAEG;IACH,MAAM,CAAC,IAAI,CACP,SAAS,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,EACjC,IAAI,EAAE,cAAc,GACrB,cAAc;IASjB;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,GAAG,KAAK,EAAE,cAAc,EAAE,GAAG,cAAc,EAAE;IAI5D;;OAEG;IACH,MAAM,CAAC,QAAQ,IAAI,cAAc,EAAE;IAanC;;OAEG;IACH,MAAM,CAAC,YAAY;;;;;IAQnB;;OAEG;IACH,MAAM,CAAC,UAAU;;;;CAMpB"}
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Common validation rules and helpers
3
+ */
4
+ export class ValidationHelper {
5
+ /**
6
+ * Rule: Field is required (not null, undefined, or empty string)
7
+ */
8
+ static required() {
9
+ return (value) => {
10
+ if (value === null || value === undefined || value === '') {
11
+ return 'This field is required';
12
+ }
13
+ return null;
14
+ };
15
+ }
16
+ /**
17
+ * Rule: String minimum length
18
+ */
19
+ static minLength(min) {
20
+ return (value) => {
21
+ if (typeof value !== 'string')
22
+ return null;
23
+ if (value.length < min) {
24
+ return `Must be at least ${min} characters long`;
25
+ }
26
+ return null;
27
+ };
28
+ }
29
+ /**
30
+ * Rule: String maximum length
31
+ */
32
+ static maxLength(max) {
33
+ return (value) => {
34
+ if (typeof value !== 'string')
35
+ return null;
36
+ if (value.length > max) {
37
+ return `Must be no more than ${max} characters long`;
38
+ }
39
+ return null;
40
+ };
41
+ }
42
+ /**
43
+ * Rule: Valid email format
44
+ */
45
+ static email() {
46
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
47
+ return (value) => {
48
+ if (typeof value !== 'string')
49
+ return null;
50
+ if (!emailRegex.test(value)) {
51
+ return 'Must be a valid email address';
52
+ }
53
+ return null;
54
+ };
55
+ }
56
+ /**
57
+ * Rule: Numeric value within range
58
+ */
59
+ static numberRange(min, max) {
60
+ return (value) => {
61
+ const num = Number(value);
62
+ if (isNaN(num)) {
63
+ return 'Must be a valid number';
64
+ }
65
+ if (min !== undefined && num < min) {
66
+ return `Must be at least ${min}`;
67
+ }
68
+ if (max !== undefined && num > max) {
69
+ return `Must be no more than ${max}`;
70
+ }
71
+ return null;
72
+ };
73
+ }
74
+ /**
75
+ * Rule: Value matches regex pattern
76
+ */
77
+ static pattern(regex, message) {
78
+ return (value) => {
79
+ if (typeof value !== 'string')
80
+ return null;
81
+ if (!regex.test(value)) {
82
+ return message;
83
+ }
84
+ return null;
85
+ };
86
+ }
87
+ /**
88
+ * Rule: Value is one of allowed options
89
+ */
90
+ static oneOf(options, message) {
91
+ return (value) => {
92
+ if (!options.includes(value)) {
93
+ return message || `Must be one of: ${options.join(', ')}`;
94
+ }
95
+ return null;
96
+ };
97
+ }
98
+ /**
99
+ * Rule: Array has minimum length
100
+ */
101
+ static arrayMinLength(min) {
102
+ return (value) => {
103
+ if (!Array.isArray(value))
104
+ return null;
105
+ if (value.length < min) {
106
+ return `Must contain at least ${min} items`;
107
+ }
108
+ return null;
109
+ };
110
+ }
111
+ /**
112
+ * Rule: Custom validation with context
113
+ */
114
+ static custom(validator) {
115
+ return validator;
116
+ }
117
+ /**
118
+ * Rule: Conditional validation
119
+ */
120
+ static when(condition, rule) {
121
+ return (value, data) => {
122
+ if (condition(data || {})) {
123
+ return rule(value, data);
124
+ }
125
+ return null;
126
+ };
127
+ }
128
+ /**
129
+ * Combine multiple validation rules
130
+ */
131
+ static combine(...rules) {
132
+ return rules;
133
+ }
134
+ /**
135
+ * Create validation rules for common entity patterns
136
+ */
137
+ static entityId() {
138
+ return [
139
+ this.required(),
140
+ this.custom((value) => {
141
+ const id = Number(value);
142
+ if (isNaN(id) || id <= 0) {
143
+ return 'Must be a valid positive ID';
144
+ }
145
+ return null;
146
+ })
147
+ ];
148
+ }
149
+ /**
150
+ * Create validation rules for user creation
151
+ */
152
+ static userCreation() {
153
+ return {
154
+ name: [this.required(), this.minLength(2), this.maxLength(100)],
155
+ email: [this.required(), this.email()],
156
+ password: [this.required(), this.minLength(8)]
157
+ };
158
+ }
159
+ /**
160
+ * Create validation rules for pagination
161
+ */
162
+ static pagination() {
163
+ return {
164
+ limit: [this.numberRange(1, 100)],
165
+ offset: [this.numberRange(0)]
166
+ };
167
+ }
168
+ }
169
+ //# sourceMappingURL=ValidationHelper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ValidationHelper.js","sourceRoot":"","sources":["../../src/validation/ValidationHelper.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Result of input validation
3
+ */
4
+ export interface ValidationResult {
5
+ /** Whether validation passed */
6
+ isValid: boolean;
7
+ /** Validation errors by field name */
8
+ errors: Record<string, string[]>;
9
+ /** Total number of errors */
10
+ errorCount: number;
11
+ }
12
+ //# sourceMappingURL=ValidationResult.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ValidationResult.d.ts","sourceRoot":"","sources":["../../src/validation/ValidationResult.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,gCAAgC;IAChC,OAAO,EAAE,OAAO,CAAC;IAEjB,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAEjC,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAC;CACtB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ValidationResult.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ValidationResult.js","sourceRoot":"","sources":["../../src/validation/ValidationResult.ts"],"names":[],"mappings":""}
@@ -0,0 +1,35 @@
1
+ import { ValidationResult } from './ValidationResult.js';
2
+ /**
3
+ * Validation rule function
4
+ */
5
+ export type ValidationRule = (value: any, data?: any) => string | null;
6
+ /**
7
+ * Validation rules by field name
8
+ */
9
+ export type ValidationRules = Record<string, ValidationRule[]>;
10
+ /**
11
+ * Simple, extensible validation system
12
+ */
13
+ export declare class Validator {
14
+ private customRules;
15
+ /**
16
+ * Register a custom validation rule
17
+ * @param name - Rule name
18
+ * @param rule - Validation function
19
+ */
20
+ registerRule(name: string, rule: ValidationRule): void;
21
+ /**
22
+ * Validate data against rules
23
+ * @param data - Data to validate
24
+ * @param rules - Validation rules
25
+ * @returns ValidationResult
26
+ */
27
+ validate<T>(data: T, rules: ValidationRules): Promise<ValidationResult>;
28
+ /**
29
+ * Get a registered custom rule
30
+ * @param name - Rule name
31
+ * @returns ValidationRule or undefined
32
+ */
33
+ getRule(name: string): ValidationRule | undefined;
34
+ }
35
+ //# sourceMappingURL=Validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Validator.d.ts","sourceRoot":"","sources":["../../src/validation/Validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,GAAG,KAAK,MAAM,GAAG,IAAI,CAAC;AAEvE;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC;AAE/D;;GAEG;AACH,qBAAa,SAAS;IAClB,OAAO,CAAC,WAAW,CAA0C;IAE7D;;;;OAIG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI;IAItD;;;;;OAKG;IACG,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA6B7E;;;;OAIG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;CAGpD"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Simple, extensible validation system
3
+ */
4
+ export class Validator {
5
+ customRules = new Map();
6
+ /**
7
+ * Register a custom validation rule
8
+ * @param name - Rule name
9
+ * @param rule - Validation function
10
+ */
11
+ registerRule(name, rule) {
12
+ this.customRules.set(name, rule);
13
+ }
14
+ /**
15
+ * Validate data against rules
16
+ * @param data - Data to validate
17
+ * @param rules - Validation rules
18
+ * @returns ValidationResult
19
+ */
20
+ async validate(data, rules) {
21
+ const errors = {};
22
+ const dataObj = data;
23
+ for (const [fieldName, fieldRules] of Object.entries(rules)) {
24
+ const fieldErrors = [];
25
+ const fieldValue = dataObj[fieldName];
26
+ for (const rule of fieldRules) {
27
+ const errorMessage = rule(fieldValue, dataObj);
28
+ if (errorMessage) {
29
+ fieldErrors.push(errorMessage);
30
+ }
31
+ }
32
+ if (fieldErrors.length > 0) {
33
+ errors[fieldName] = fieldErrors;
34
+ }
35
+ }
36
+ const errorCount = Object.values(errors).reduce((sum, errs) => sum + errs.length, 0);
37
+ return {
38
+ isValid: errorCount === 0,
39
+ errors,
40
+ errorCount
41
+ };
42
+ }
43
+ /**
44
+ * Get a registered custom rule
45
+ * @param name - Rule name
46
+ * @returns ValidationRule or undefined
47
+ */
48
+ getRule(name) {
49
+ return this.customRules.get(name);
50
+ }
51
+ }
52
+ //# sourceMappingURL=Validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Validator.js","sourceRoot":"","sources":["../../src/validation/Validator.ts"],"names":[],"mappings":"AAYA;;GAEG;AACH,MAAM,OAAO,SAAS;IACV,WAAW,GAAgC,IAAI,GAAG,EAAE,CAAC;IAE7D;;;;OAIG;IACH,YAAY,CAAC,IAAY,EAAE,IAAoB;QAC3C,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACrC,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,QAAQ,CAAI,IAAO,EAAE,KAAsB;QAC7C,MAAM,MAAM,GAA6B,EAAE,CAAC;QAC5C,MAAM,OAAO,GAAG,IAA2B,CAAC;QAE5C,KAAK,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1D,MAAM,WAAW,GAAa,EAAE,CAAC;YACjC,MAAM,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;YAEtC,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;gBAC5B,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;gBAC/C,IAAI,YAAY,EAAE,CAAC;oBACf,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBACnC,CAAC;YACL,CAAC;YAED,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACzB,MAAM,CAAC,SAAS,CAAC,GAAG,WAAW,CAAC;YACpC,CAAC;QACL,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAErF,OAAO;YACH,OAAO,EAAE,UAAU,KAAK,CAAC;YACzB,MAAM;YACN,UAAU;SACb,CAAC;IACN,CAAC;IAED;;;;OAIG;IACH,OAAO,CAAC,IAAY;QAChB,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;CACJ"}