chore(repo): restructure as monorepo with server and client workspaces
- move NestJS app into server/ subdirectory - add client/ React+TypeScript (Vite) app with Hello World - update docker-compose to build and run both services - add root package.json declaring npm workspaces - update .gitignore to cover node_modules and dist at all depths
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
import { ApiPropertyOptional } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import { IsIn, IsInt, IsOptional, IsString, Min } from "class-validator";
|
||||
|
||||
export class PaginationQueryDto<TOrderBy extends string = string> {
|
||||
@ApiPropertyOptional({ example: 1, default: 1 })
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
page?: number = 1;
|
||||
|
||||
@ApiPropertyOptional({ example: 20, default: 20 })
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsInt()
|
||||
@Min(1)
|
||||
limit?: number = 20;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
example: "id",
|
||||
default: "id",
|
||||
description: "Field to order by",
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
orderBy?: TOrderBy;
|
||||
|
||||
@ApiPropertyOptional({ enum: ["ASC", "DESC"], default: "ASC" })
|
||||
@IsOptional()
|
||||
@IsIn(["ASC", "DESC"])
|
||||
orderDir?: "ASC" | "DESC" = "ASC";
|
||||
}
|
||||
|
||||
export interface PaginatedResult<T> {
|
||||
data: T[];
|
||||
total: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { AsyncLocalStorage } from "async_hooks";
|
||||
|
||||
export interface TraceStore {
|
||||
traceId: string;
|
||||
}
|
||||
|
||||
export const traceStorage = new AsyncLocalStorage<TraceStore>();
|
||||
|
||||
export function getTraceId(): string | undefined {
|
||||
return traceStorage.getStore()?.traceId;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { ConsoleLogger, ConsoleLoggerOptions, LogLevel } from "@nestjs/common";
|
||||
import { getTraceId } from "./trace-context";
|
||||
|
||||
export class TraceLogger extends ConsoleLogger {
|
||||
constructor(context?: string, options: ConsoleLoggerOptions = {}) {
|
||||
super(context as string, options);
|
||||
}
|
||||
|
||||
protected override getTimestamp(): string {
|
||||
return new Date().toISOString();
|
||||
}
|
||||
|
||||
protected override formatMessage(
|
||||
logLevel: LogLevel,
|
||||
message: unknown,
|
||||
_pidMessage: string,
|
||||
_formattedLogLevel: string,
|
||||
contextMessage: string,
|
||||
timestampDiff: string,
|
||||
): string {
|
||||
const output = this.stringifyMessage(message, logLevel);
|
||||
const level = this.colorize(logLevel.toUpperCase(), logLevel);
|
||||
return `${this.getTimestamp()} ${level} ${contextMessage}${output}${timestampDiff}\n`;
|
||||
}
|
||||
|
||||
protected override formatContext(context: string): string {
|
||||
const traceId = getTraceId();
|
||||
const traced = traceId ? `${context}:${traceId}` : context;
|
||||
return super.formatContext(traced);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user