@ajke/core 0.1.0
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/LICENSE +21 -0
- package/README.md +357 -0
- package/dist/chunk-AT2R2CGV.js +234 -0
- package/dist/chunk-AT2R2CGV.js.map +1 -0
- package/dist/chunk-EUXUH3YW.js +15 -0
- package/dist/chunk-EUXUH3YW.js.map +1 -0
- package/dist/chunk-YUBEJL4T.cjs +234 -0
- package/dist/chunk-YUBEJL4T.cjs.map +1 -0
- package/dist/chunk-ZBDE64SD.cjs +15 -0
- package/dist/chunk-ZBDE64SD.cjs.map +1 -0
- package/dist/config.cjs +10 -0
- package/dist/config.cjs.map +1 -0
- package/dist/config.d.cts +13 -0
- package/dist/config.d.ts +13 -0
- package/dist/config.js +10 -0
- package/dist/config.js.map +1 -0
- package/dist/index.cjs +974 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +255 -0
- package/dist/index.d.ts +255 -0
- package/dist/index.js +974 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/index.cjs +10 -0
- package/dist/middleware/index.cjs.map +1 -0
- package/dist/middleware/index.d.cts +18 -0
- package/dist/middleware/index.d.ts +18 -0
- package/dist/middleware/index.js +10 -0
- package/dist/middleware/index.js.map +1 -0
- package/package.json +56 -0
- package/src/README.md +285 -0
- package/src/config.ts +14 -0
- package/src/context/execution-context.ts +36 -0
- package/src/context/index.ts +1 -0
- package/src/decorators/core/exception-filters.decorator.ts +24 -0
- package/src/decorators/core/index.ts +6 -0
- package/src/decorators/core/injectable.decorator.ts +41 -0
- package/src/decorators/core/optional.decorator.ts +9 -0
- package/src/decorators/core/set-metadata.decorator.ts +20 -0
- package/src/decorators/core/use-guards.decorator.ts +14 -0
- package/src/decorators/core/use-interceptors.decorator.ts +16 -0
- package/src/decorators/http/controller.decorator.ts +230 -0
- package/src/decorators/http/header.decorator.ts +11 -0
- package/src/decorators/http/http-code.decorator.ts +8 -0
- package/src/decorators/http/index.ts +6 -0
- package/src/decorators/http/redirect.decorator.ts +13 -0
- package/src/decorators/http/route-mapping.decorator.ts +22 -0
- package/src/decorators/http/route-params.decorator.ts +60 -0
- package/src/decorators/index.ts +3 -0
- package/src/decorators/modules/global.decorator.ts +8 -0
- package/src/decorators/modules/index.ts +2 -0
- package/src/decorators/modules/module.decorator.ts +16 -0
- package/src/exceptions/http-exception.ts +17 -0
- package/src/exceptions/http-exceptions.ts +85 -0
- package/src/exceptions/index.ts +2 -0
- package/src/index.ts +11 -0
- package/src/injector/index.ts +1 -0
- package/src/injector/injector.ts +103 -0
- package/src/injector/module-compiler.ts +48 -0
- package/src/injector/module.factory.ts +74 -0
- package/src/interfaces/core/filter.interface.ts +5 -0
- package/src/interfaces/core/guard.interface.ts +5 -0
- package/src/interfaces/core/index.ts +5 -0
- package/src/interfaces/core/interceptor.interface.ts +9 -0
- package/src/interfaces/core/lifecycle.interface.ts +19 -0
- package/src/interfaces/core/pipe.interface.ts +9 -0
- package/src/interfaces/http/index.ts +1 -0
- package/src/interfaces/http/response.interface.ts +27 -0
- package/src/interfaces/index.ts +3 -0
- package/src/interfaces/modules/index.ts +1 -0
- package/src/interfaces/modules/module.interface.ts +17 -0
- package/src/middleware/error-handler.middleware.ts +63 -0
- package/src/middleware/index.ts +2 -0
- package/src/middleware/request-logger.middleware.ts +17 -0
- package/src/pipes/index.ts +3 -0
- package/src/pipes/validate.pipe.ts +79 -0
- package/src/pipes/zod-query.pipe.ts +42 -0
- package/src/pipes/zod-validate.pipe.ts +49 -0
- package/src/services/index.ts +1 -0
- package/src/services/reflector.service.ts +24 -0
- package/src/utils/apply-decorators.util.ts +17 -0
- package/src/utils/forward-ref.util.ts +14 -0
- package/src/utils/index.ts +22 -0
- package/src/utils/logger.util.ts +189 -0
- package/src/utils/response.util.ts +72 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Context } from "hono";
|
|
2
|
+
import { getCookie } from "hono/cookie";
|
|
3
|
+
|
|
4
|
+
export function replaceTemplatePlaceholders(template: string, data: Record<string, any>): string {
|
|
5
|
+
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
|
|
6
|
+
return data[key] !== undefined ? String(data[key]) : match;
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Extracts device/IP info from request
|
|
12
|
+
*/
|
|
13
|
+
export function extractRequestMetadata(c: Context) {
|
|
14
|
+
return {
|
|
15
|
+
ipAddress: getCookie(c, "x-client-ip"),
|
|
16
|
+
macAddress: getCookie(c, "x-client-mac"),
|
|
17
|
+
deviceId: getCookie(c, "x-client-device"),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export * from "./logger.util";
|
|
22
|
+
export * from "./forward-ref.util";
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
export enum LogLevel {
|
|
2
|
+
ERROR = "error",
|
|
3
|
+
WARN = "warn",
|
|
4
|
+
INFO = "info",
|
|
5
|
+
DEBUG = "debug",
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const META_PLACEHOLDER = "[unserializable-meta]";
|
|
9
|
+
|
|
10
|
+
/** Stable, one-line JSON for log drains / grepping (keys sorted). */
|
|
11
|
+
export function stringifyLogMeta(meta: Record<string, unknown>): string {
|
|
12
|
+
try {
|
|
13
|
+
const keys = Object.keys(meta).sort();
|
|
14
|
+
const sorted: Record<string, unknown> = {};
|
|
15
|
+
for (const k of keys) sorted[k] = meta[k];
|
|
16
|
+
return JSON.stringify(sorted);
|
|
17
|
+
} catch {
|
|
18
|
+
return META_PLACEHOLDER;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function formatError(error: unknown): string {
|
|
23
|
+
if (error instanceof Error) {
|
|
24
|
+
const stack = error.stack ? error.stack.split("\n").slice(0, 4).join(" | ") : "";
|
|
25
|
+
return stack ? `${error.message} | ${stack}` : error.message;
|
|
26
|
+
}
|
|
27
|
+
return String(error);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ANSI color codes for terminal output
|
|
31
|
+
const colors = {
|
|
32
|
+
reset: "\x1b[0m",
|
|
33
|
+
bright: "\x1b[1m",
|
|
34
|
+
red: "\x1b[31m",
|
|
35
|
+
green: "\x1b[32m",
|
|
36
|
+
yellow: "\x1b[33m",
|
|
37
|
+
blue: "\x1b[34m",
|
|
38
|
+
magenta: "\x1b[35m",
|
|
39
|
+
cyan: "\x1b[36m",
|
|
40
|
+
gray: "\x1b[90m",
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// HTTP status code colors
|
|
44
|
+
function getStatusColor(status: number): string {
|
|
45
|
+
if (status >= 500) return colors.red;
|
|
46
|
+
if (status >= 400) return colors.yellow;
|
|
47
|
+
if (status >= 300) return colors.cyan;
|
|
48
|
+
if (status >= 200) return colors.green;
|
|
49
|
+
return colors.gray;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// HTTP method colors
|
|
53
|
+
function getMethodColor(method: string): string {
|
|
54
|
+
switch (method) {
|
|
55
|
+
case "GET":
|
|
56
|
+
return colors.green;
|
|
57
|
+
case "POST":
|
|
58
|
+
return colors.blue;
|
|
59
|
+
case "PUT":
|
|
60
|
+
return colors.yellow;
|
|
61
|
+
case "DELETE":
|
|
62
|
+
return colors.red;
|
|
63
|
+
case "PATCH":
|
|
64
|
+
return colors.magenta;
|
|
65
|
+
default:
|
|
66
|
+
return colors.gray;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export class Logger {
|
|
71
|
+
private static instance: Logger;
|
|
72
|
+
private logLevel: LogLevel;
|
|
73
|
+
private enableColors: boolean;
|
|
74
|
+
|
|
75
|
+
private constructor() {
|
|
76
|
+
this.logLevel = LogLevel.INFO;
|
|
77
|
+
this.enableColors = true; // Enable colors by default
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public static getInstance(): Logger {
|
|
81
|
+
if (!Logger.instance) {
|
|
82
|
+
Logger.instance = new Logger();
|
|
83
|
+
}
|
|
84
|
+
return Logger.instance;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private shouldLog(level: LogLevel): boolean {
|
|
88
|
+
const levels = Object.values(LogLevel);
|
|
89
|
+
const currentLevelIndex = levels.indexOf(this.logLevel);
|
|
90
|
+
const messageLevelIndex = levels.indexOf(level);
|
|
91
|
+
return messageLevelIndex <= currentLevelIndex;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private formatMessage(level: LogLevel, message: string, context?: string, meta?: Record<string, unknown>): string {
|
|
95
|
+
const timestamp = new Date().toISOString();
|
|
96
|
+
const contextStr = context ? ` [${context}]` : "";
|
|
97
|
+
const metaStr = meta && Object.keys(meta).length > 0 ? ` | ${stringifyLogMeta(meta)}` : "";
|
|
98
|
+
const baseMessage = `[${timestamp}] ${level.toUpperCase()}${contextStr}: ${message}${metaStr}`;
|
|
99
|
+
|
|
100
|
+
if (!this.enableColors) return baseMessage;
|
|
101
|
+
|
|
102
|
+
const colorMap = {
|
|
103
|
+
[LogLevel.ERROR]: colors.red,
|
|
104
|
+
[LogLevel.WARN]: colors.yellow,
|
|
105
|
+
[LogLevel.INFO]: colors.blue,
|
|
106
|
+
[LogLevel.DEBUG]: colors.gray,
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
return `${colorMap[level]}${baseMessage}${colors.reset}`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// HTTP request logging (like Hono's logger)
|
|
113
|
+
http(method: string, path: string, status: number, duration: number, userAgent?: string): void {
|
|
114
|
+
if (!this.shouldLog(LogLevel.INFO)) return;
|
|
115
|
+
|
|
116
|
+
const methodColor = this.enableColors ? getMethodColor(method) : "";
|
|
117
|
+
const statusColor = this.enableColors ? getStatusColor(status) : "";
|
|
118
|
+
const reset = this.enableColors ? colors.reset : "";
|
|
119
|
+
|
|
120
|
+
const methodStr = `${methodColor}${method}${reset}`;
|
|
121
|
+
const statusStr = `${statusColor}${status}${reset}`;
|
|
122
|
+
const durationStr = duration > 1000 ? `${colors.red}${duration}ms${reset}` : `${duration}ms`;
|
|
123
|
+
|
|
124
|
+
const logMessage = `${methodStr} ${path} ${statusStr} ${durationStr}`;
|
|
125
|
+
|
|
126
|
+
if (userAgent) {
|
|
127
|
+
console.log(`${logMessage} - ${colors.gray}${userAgent}${reset}`);
|
|
128
|
+
} else {
|
|
129
|
+
console.log(logMessage);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Standard logging methods
|
|
134
|
+
error(message: string, context?: string, meta?: Record<string, unknown>): void {
|
|
135
|
+
if (this.shouldLog(LogLevel.ERROR)) {
|
|
136
|
+
console.error(this.formatMessage(LogLevel.ERROR, message, context, meta));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
warn(message: string, context?: string, meta?: Record<string, unknown>): void {
|
|
141
|
+
if (this.shouldLog(LogLevel.WARN)) {
|
|
142
|
+
console.warn(this.formatMessage(LogLevel.WARN, message, context, meta));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
info(message: string, context?: string, meta?: Record<string, unknown>): void {
|
|
147
|
+
if (this.shouldLog(LogLevel.INFO)) {
|
|
148
|
+
console.info(this.formatMessage(LogLevel.INFO, message, context, meta));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
debug(message: string, context?: string, meta?: Record<string, unknown>): void {
|
|
153
|
+
if (this.shouldLog(LogLevel.DEBUG)) {
|
|
154
|
+
console.debug(this.formatMessage(LogLevel.DEBUG, message, context, meta));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Static methods for convenience
|
|
159
|
+
static http(method: string, path: string, status: number, duration: number, userAgent?: string): void {
|
|
160
|
+
Logger.getInstance().http(method, path, status, duration, userAgent);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
static error(message: string, context?: string, meta?: Record<string, unknown>): void {
|
|
164
|
+
Logger.getInstance().error(message, context, meta);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
static warn(message: string, context?: string, meta?: Record<string, unknown>): void {
|
|
168
|
+
Logger.getInstance().warn(message, context, meta);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
static info(message: string, context?: string, meta?: Record<string, unknown>): void {
|
|
172
|
+
Logger.getInstance().info(message, context, meta);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
static debug(message: string, context?: string, meta?: Record<string, unknown>): void {
|
|
176
|
+
Logger.getInstance().debug(message, context, meta);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Configuration methods
|
|
180
|
+
setLogLevel(level: LogLevel): void {
|
|
181
|
+
this.logLevel = level;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
setColors(enabled: boolean): void {
|
|
185
|
+
this.enableColors = enabled;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export const logger = Logger.getInstance();
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { Context } from "hono";
|
|
2
|
+
import type {
|
|
3
|
+
BaseResponse,
|
|
4
|
+
HttpStatusCode,
|
|
5
|
+
PaginatedResponse,
|
|
6
|
+
} from "../interfaces/http/response.interface";
|
|
7
|
+
|
|
8
|
+
export class _ResponseUtil {
|
|
9
|
+
private static instance: _ResponseUtil;
|
|
10
|
+
private logger: Console = console;
|
|
11
|
+
|
|
12
|
+
private constructor() { } // Prevent direct instantiation
|
|
13
|
+
|
|
14
|
+
static getInstance(): _ResponseUtil {
|
|
15
|
+
if (!_ResponseUtil.instance) {
|
|
16
|
+
_ResponseUtil.instance = new _ResponseUtil();
|
|
17
|
+
}
|
|
18
|
+
return _ResponseUtil.instance;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
success<T>(c: Context, data: T, message?: string, status: HttpStatusCode = 200): Response {
|
|
22
|
+
const response: BaseResponse<T> = {
|
|
23
|
+
success: true,
|
|
24
|
+
data,
|
|
25
|
+
message,
|
|
26
|
+
timestamp: new Date().toISOString(),
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return c.json(response, status);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
error(c: Context, message: string, status: HttpStatusCode = 400): Response {
|
|
33
|
+
const response = {
|
|
34
|
+
success: false,
|
|
35
|
+
error: {
|
|
36
|
+
message,
|
|
37
|
+
},
|
|
38
|
+
message: message,
|
|
39
|
+
timestamp: new Date().toISOString(),
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return c.json(response, status);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
paginated<T>(
|
|
46
|
+
c: Context,
|
|
47
|
+
data: T[],
|
|
48
|
+
page: number,
|
|
49
|
+
limit: number,
|
|
50
|
+
total: number,
|
|
51
|
+
message?: string,
|
|
52
|
+
): Response {
|
|
53
|
+
const totalPages = Math.ceil(total / limit) ?? 1;
|
|
54
|
+
|
|
55
|
+
const response: PaginatedResponse<T> = {
|
|
56
|
+
success: true,
|
|
57
|
+
data,
|
|
58
|
+
message,
|
|
59
|
+
timestamp: new Date().toISOString(),
|
|
60
|
+
pagination: {
|
|
61
|
+
page,
|
|
62
|
+
limit,
|
|
63
|
+
total,
|
|
64
|
+
totalPages,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
return c.json(response);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export const ResponseUtil = _ResponseUtil.getInstance();
|