UNPKG

@cleancode-id/nestjs-sequelize-auditor

Version:

Audit trail package for NestJS + Sequelize ORM with AsyncLocalStorage context management

220 lines (209 loc) 7.17 kB
import { AsyncLocalStorage } from 'async_hooks'; import { NestInterceptor, ExecutionContext, CallHandler, DynamicModule } from '@nestjs/common'; import { Observable } from 'rxjs'; import { ModelStatic, Model, QueryInterface } from 'sequelize'; import { Sequelize } from 'sequelize-typescript'; declare enum AuditEvent { CREATED = "created", UPDATED = "updated", DELETED = "deleted", RESTORED = "restored" } interface AuditContext { actorableType?: string; actorableId?: string | number; ip?: string; userAgent?: string; url?: string; tags?: Record<string, any>; } interface AuditConfig { exclude?: string[]; mask?: string[]; auditEvents?: AuditEvent[]; onlyDirty?: boolean; } interface AuditRecord { id?: string | number; event: 'created' | 'updated' | 'deleted' | 'restored'; auditableType: string; auditableId: string | number; oldValues?: Record<string, any>; newValues?: Record<string, any>; actorableType?: string; actorableId?: string | number; ip?: string; userAgent?: string; url?: string; tags?: Record<string, any>; createdAt: Date; } interface AuditModelOptions { tableName?: string; exclude?: string[]; mask?: string[]; } interface AuditModuleOptions { connection?: string; tableName?: string; autoSync?: boolean; alterTable?: boolean; isGlobal?: boolean; auth?: AuthConfig; onlyDirty?: boolean; /** * List of model names that can act as actors in audit records * These models will have dynamic relationships created with the audit model * @example ['User', 'Admin', 'ApiClient'] * @default ['User'] */ actorTypes?: string[]; } interface AuthConfig { type?: 'passport' | 'custom'; userProperty?: string; userIdField?: string; actorModel?: string; } interface AuditModuleAsyncOptions { imports?: any[]; useFactory?: (...args: any[]) => Promise<AuditModuleOptions> | AuditModuleOptions; inject?: any[]; connection?: string; isGlobal?: boolean; } declare const contextStorage: AsyncLocalStorage<AuditContext>; declare class RequestContext { static getContext(): AuditContext | undefined; static setContext(context: AuditContext): void; static runWithContext<T>(context: AuditContext, callback: () => T): T; static updateContext(updates: Partial<AuditContext>): void; } declare function setRequestContext(context: AuditContext): void; declare class RequestContextInterceptor implements NestInterceptor { private options; private userResolver; constructor(options: AuditModuleOptions); intercept(context: ExecutionContext, next: CallHandler): Observable<any>; } /** * Configuration for the @Auditable decorator * Extends the base AuditConfig with additional relationship options */ interface AuditableConfig extends AuditConfig { /** * Enable automatic 'creator' virtual field that returns the user who created this record * @default true */ enableCreatorRelationship?: boolean; /** * Enable automatic 'audits' relationship that returns all audit records for this model * @default true */ enableAuditsRelationship?: boolean; /** * Enable automatic 'creationAudit' relationship that returns the creation audit record * @default true */ enableCreationAuditRelationship?: boolean; /** * Enable verbose logging for debugging audit setup * @default false */ verbose?: boolean; } declare function Auditable(config?: AuditableConfig): <T extends ModelStatic<Model>>(target: T) => T; /** * Initialize audit functionality for a model decorated with @Auditable * This creates the audit hooks and relationships at runtime when the audit model is available * * @param model The model class decorated with @Auditable * * @example * ```typescript * @Injectable() * export class UserService implements OnModuleInit { * constructor(@InjectModel(User) private userModel: typeof User) {} * * onModuleInit() { * initializeAuditableModel(this.userModel); * } * } * ``` */ declare function initializeAuditableModel<T extends Model>(model: ModelStatic<T>): Promise<void>; /** * Initialize audit functionality for multiple models decorated with @Auditable * Convenience method for services that handle multiple auditable models * * @param models Array of model classes decorated with @Auditable * * @example * ```typescript * @Injectable() * export class CombinedService implements OnModuleInit { * constructor( * @InjectModel(User) private userModel: typeof User, * @InjectModel(Post) private postModel: typeof Post, * ) {} * * onModuleInit() { * initializeAuditableModels(this.userModel, this.postModel); * } * } * ``` */ declare function initializeAuditableModels(...models: ModelStatic<any>[]): Promise<void>; /** * Force initialization of all pending @Auditable models * This can be called from the application startup to ensure all models are initialized * * @example * ```typescript * // In your main.ts or app initialization * import { initializeAllAuditableModels } from '@cleancode-id/nestjs-sequelize-auditor'; * * async function bootstrap() { * const app = await NestFactory.create(AppModule); * * // Force initialize all @Auditable models after app is created * initializeAllAuditableModels(); * * await app.listen(3000); * } * ``` */ declare function initializeAllAuditableModels(): Promise<void>; declare class AuditModule { /** * Register the audit module with synchronous configuration */ static forRoot(options?: AuditModuleOptions): DynamicModule; /** * Register the audit module with asynchronous configuration */ static forRootAsync(options: AuditModuleAsyncOptions): DynamicModule; } declare class AuditService { private readonly options; private isInitialized; constructor(options: AuditModuleOptions); initializeAuditModel(sequelize: Sequelize): Promise<void>; } /** * Generates SQL migration for creating the audits table */ declare function generateAuditMigration(tableName?: string): { up: (queryInterface: QueryInterface) => Promise<void>; down: (queryInterface: QueryInterface) => Promise<void>; }; /** * Generates a JavaScript migration file content */ declare function generateMigrationFileContent(tableName?: string): string; /** * SQL script for creating the audits table (for manual execution) */ declare function generateSQLScript(tableName?: string, dialect?: 'postgres' | 'mysql'): string; declare function getAuditModel(): ModelStatic<Model> | null; export { type AuditConfig, type AuditContext, AuditEvent, type AuditModelOptions, AuditModule, type AuditModuleAsyncOptions, type AuditModuleOptions, type AuditRecord, AuditService, Auditable, type AuditableConfig, type AuthConfig, RequestContext, RequestContextInterceptor, contextStorage, generateAuditMigration, generateMigrationFileContent, generateSQLScript, getAuditModel, initializeAllAuditableModels, initializeAuditableModel, initializeAuditableModels, setRequestContext };