@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.
Files changed (84) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +357 -0
  3. package/dist/chunk-AT2R2CGV.js +234 -0
  4. package/dist/chunk-AT2R2CGV.js.map +1 -0
  5. package/dist/chunk-EUXUH3YW.js +15 -0
  6. package/dist/chunk-EUXUH3YW.js.map +1 -0
  7. package/dist/chunk-YUBEJL4T.cjs +234 -0
  8. package/dist/chunk-YUBEJL4T.cjs.map +1 -0
  9. package/dist/chunk-ZBDE64SD.cjs +15 -0
  10. package/dist/chunk-ZBDE64SD.cjs.map +1 -0
  11. package/dist/config.cjs +10 -0
  12. package/dist/config.cjs.map +1 -0
  13. package/dist/config.d.cts +13 -0
  14. package/dist/config.d.ts +13 -0
  15. package/dist/config.js +10 -0
  16. package/dist/config.js.map +1 -0
  17. package/dist/index.cjs +974 -0
  18. package/dist/index.cjs.map +1 -0
  19. package/dist/index.d.cts +255 -0
  20. package/dist/index.d.ts +255 -0
  21. package/dist/index.js +974 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/middleware/index.cjs +10 -0
  24. package/dist/middleware/index.cjs.map +1 -0
  25. package/dist/middleware/index.d.cts +18 -0
  26. package/dist/middleware/index.d.ts +18 -0
  27. package/dist/middleware/index.js +10 -0
  28. package/dist/middleware/index.js.map +1 -0
  29. package/package.json +56 -0
  30. package/src/README.md +285 -0
  31. package/src/config.ts +14 -0
  32. package/src/context/execution-context.ts +36 -0
  33. package/src/context/index.ts +1 -0
  34. package/src/decorators/core/exception-filters.decorator.ts +24 -0
  35. package/src/decorators/core/index.ts +6 -0
  36. package/src/decorators/core/injectable.decorator.ts +41 -0
  37. package/src/decorators/core/optional.decorator.ts +9 -0
  38. package/src/decorators/core/set-metadata.decorator.ts +20 -0
  39. package/src/decorators/core/use-guards.decorator.ts +14 -0
  40. package/src/decorators/core/use-interceptors.decorator.ts +16 -0
  41. package/src/decorators/http/controller.decorator.ts +230 -0
  42. package/src/decorators/http/header.decorator.ts +11 -0
  43. package/src/decorators/http/http-code.decorator.ts +8 -0
  44. package/src/decorators/http/index.ts +6 -0
  45. package/src/decorators/http/redirect.decorator.ts +13 -0
  46. package/src/decorators/http/route-mapping.decorator.ts +22 -0
  47. package/src/decorators/http/route-params.decorator.ts +60 -0
  48. package/src/decorators/index.ts +3 -0
  49. package/src/decorators/modules/global.decorator.ts +8 -0
  50. package/src/decorators/modules/index.ts +2 -0
  51. package/src/decorators/modules/module.decorator.ts +16 -0
  52. package/src/exceptions/http-exception.ts +17 -0
  53. package/src/exceptions/http-exceptions.ts +85 -0
  54. package/src/exceptions/index.ts +2 -0
  55. package/src/index.ts +11 -0
  56. package/src/injector/index.ts +1 -0
  57. package/src/injector/injector.ts +103 -0
  58. package/src/injector/module-compiler.ts +48 -0
  59. package/src/injector/module.factory.ts +74 -0
  60. package/src/interfaces/core/filter.interface.ts +5 -0
  61. package/src/interfaces/core/guard.interface.ts +5 -0
  62. package/src/interfaces/core/index.ts +5 -0
  63. package/src/interfaces/core/interceptor.interface.ts +9 -0
  64. package/src/interfaces/core/lifecycle.interface.ts +19 -0
  65. package/src/interfaces/core/pipe.interface.ts +9 -0
  66. package/src/interfaces/http/index.ts +1 -0
  67. package/src/interfaces/http/response.interface.ts +27 -0
  68. package/src/interfaces/index.ts +3 -0
  69. package/src/interfaces/modules/index.ts +1 -0
  70. package/src/interfaces/modules/module.interface.ts +17 -0
  71. package/src/middleware/error-handler.middleware.ts +63 -0
  72. package/src/middleware/index.ts +2 -0
  73. package/src/middleware/request-logger.middleware.ts +17 -0
  74. package/src/pipes/index.ts +3 -0
  75. package/src/pipes/validate.pipe.ts +79 -0
  76. package/src/pipes/zod-query.pipe.ts +42 -0
  77. package/src/pipes/zod-validate.pipe.ts +49 -0
  78. package/src/services/index.ts +1 -0
  79. package/src/services/reflector.service.ts +24 -0
  80. package/src/utils/apply-decorators.util.ts +17 -0
  81. package/src/utils/forward-ref.util.ts +14 -0
  82. package/src/utils/index.ts +22 -0
  83. package/src/utils/logger.util.ts +189 -0
  84. 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();