fix: apply consistent-type-imports across API codebase (728 lint errors)

- Convert `import type { X }` to `import { type X }` (inline-type-imports style)
- Suppress consistent-type-imports for `typeof import()` in instrument.ts
- Includes uncommitted agent work: metrics module, redis caching, audit logs,
  saved searches, circuit breaker, rate limiting, and admin enhancements

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Ho Ngoc Hai
2026-04-10 23:22:21 +07:00
parent 8cdfe17205
commit 6ebacbc9bf
85 changed files with 3844 additions and 82 deletions

View File

@@ -0,0 +1,42 @@
import { QueryHandler, type IQueryHandler } from '@nestjs/cqrs';
import { ForbiddenException, NotFoundException, type PrismaService } from '@modules/shared';
import { GetSavedSearchQuery } from './get-saved-search.query';
export interface SavedSearchDetail {
id: string;
name: string;
filters: unknown;
alertEnabled: boolean;
lastAlertAt: Date | null;
createdAt: Date;
}
@QueryHandler(GetSavedSearchQuery)
export class GetSavedSearchHandler implements IQueryHandler<GetSavedSearchQuery> {
constructor(
private readonly prisma: PrismaService,
) {}
async execute(query: GetSavedSearchQuery): Promise<SavedSearchDetail> {
const savedSearch = await this.prisma.savedSearch.findUnique({
where: { id: query.id },
});
if (!savedSearch) {
throw new NotFoundException('SavedSearch', query.id);
}
if (savedSearch.userId !== query.userId) {
throw new ForbiddenException('Bạn không có quyền xem tìm kiếm này');
}
return {
id: savedSearch.id,
name: savedSearch.name,
filters: savedSearch.filters,
alertEnabled: savedSearch.alertEnabled,
lastAlertAt: savedSearch.lastAlertAt,
createdAt: savedSearch.createdAt,
};
}
}

View File

@@ -0,0 +1,6 @@
export class GetSavedSearchQuery {
constructor(
public readonly id: string,
public readonly userId: string,
) {}
}

View File

@@ -0,0 +1,56 @@
import { QueryHandler, type IQueryHandler } from '@nestjs/cqrs';
import { type PrismaService } from '@modules/shared';
import { GetSavedSearchesQuery } from './get-saved-searches.query';
export interface SavedSearchItem {
id: string;
name: string;
filters: unknown;
alertEnabled: boolean;
lastAlertAt: Date | null;
createdAt: Date;
}
export interface SavedSearchListResult {
data: SavedSearchItem[];
total: number;
page: number;
limit: number;
}
@QueryHandler(GetSavedSearchesQuery)
export class GetSavedSearchesHandler implements IQueryHandler<GetSavedSearchesQuery> {
constructor(
private readonly prisma: PrismaService,
) {}
async execute(query: GetSavedSearchesQuery): Promise<SavedSearchListResult> {
const skip = (query.page - 1) * query.limit;
const [data, total] = await Promise.all([
this.prisma.savedSearch.findMany({
where: { userId: query.userId },
orderBy: { createdAt: 'desc' },
skip,
take: query.limit,
}),
this.prisma.savedSearch.count({
where: { userId: query.userId },
}),
]);
return {
data: data.map((s) => ({
id: s.id,
name: s.name,
filters: s.filters,
alertEnabled: s.alertEnabled,
lastAlertAt: s.lastAlertAt,
createdAt: s.createdAt,
})),
total,
page: query.page,
limit: query.limit,
};
}
}

View File

@@ -0,0 +1,7 @@
export class GetSavedSearchesQuery {
constructor(
public readonly userId: string,
public readonly page: number = 1,
public readonly limit: number = 20,
) {}
}