@alis-kit/routers 1.0.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/README.md +302 -0
- package/dist/adapters/BaseAdapter.d.ts +63 -0
- package/dist/adapters/BaseAdapter.d.ts.map +1 -0
- package/dist/adapters/BaseAdapter.js +17 -0
- package/dist/adapters/BaseAdapter.js.map +1 -0
- package/dist/adapters/ExpressAdapter.d.ts +44 -0
- package/dist/adapters/ExpressAdapter.d.ts.map +1 -0
- package/dist/adapters/ExpressAdapter.js +73 -0
- package/dist/adapters/ExpressAdapter.js.map +1 -0
- package/dist/adapters/FastifyAdapter.d.ts +61 -0
- package/dist/adapters/FastifyAdapter.d.ts.map +1 -0
- package/dist/adapters/FastifyAdapter.js +132 -0
- package/dist/adapters/FastifyAdapter.js.map +1 -0
- package/dist/cookie/CookieSetter.d.ts +74 -0
- package/dist/cookie/CookieSetter.d.ts.map +1 -0
- package/dist/cookie/CookieSetter.js +89 -0
- package/dist/cookie/CookieSetter.js.map +1 -0
- package/dist/core/Logger.d.ts +36 -0
- package/dist/core/Logger.d.ts.map +1 -0
- package/dist/core/Logger.js +53 -0
- package/dist/core/Logger.js.map +1 -0
- package/dist/core/RouteResolver.d.ts +91 -0
- package/dist/core/RouteResolver.d.ts.map +1 -0
- package/dist/core/RouteResolver.js +279 -0
- package/dist/core/RouteResolver.js.map +1 -0
- package/dist/core/RouterKit.d.ts +116 -0
- package/dist/core/RouterKit.d.ts.map +1 -0
- package/dist/core/RouterKit.js +175 -0
- package/dist/core/RouterKit.js.map +1 -0
- package/dist/decorators/controller/ReqController.d.ts +29 -0
- package/dist/decorators/controller/ReqController.d.ts.map +1 -0
- package/dist/decorators/controller/ReqController.js +62 -0
- package/dist/decorators/controller/ReqController.js.map +1 -0
- package/dist/decorators/mapping/index.d.ts +93 -0
- package/dist/decorators/mapping/index.d.ts.map +1 -0
- package/dist/decorators/mapping/index.js +128 -0
- package/dist/decorators/mapping/index.js.map +1 -0
- package/dist/decorators/method/index.d.ts +67 -0
- package/dist/decorators/method/index.d.ts.map +1 -0
- package/dist/decorators/method/index.js +83 -0
- package/dist/decorators/method/index.js.map +1 -0
- package/dist/decorators/parameter/index.d.ts +155 -0
- package/dist/decorators/parameter/index.d.ts.map +1 -0
- package/dist/decorators/parameter/index.js +196 -0
- package/dist/decorators/parameter/index.js.map +1 -0
- package/dist/exceptions/BadRequestException.d.ts +37 -0
- package/dist/exceptions/BadRequestException.d.ts.map +1 -0
- package/dist/exceptions/BadRequestException.js +37 -0
- package/dist/exceptions/BadRequestException.js.map +1 -0
- package/dist/exceptions/BaseException.d.ts +29 -0
- package/dist/exceptions/BaseException.d.ts.map +1 -0
- package/dist/exceptions/BaseException.js +29 -0
- package/dist/exceptions/BaseException.js.map +1 -0
- package/dist/exceptions/ConflictException.d.ts +28 -0
- package/dist/exceptions/ConflictException.d.ts.map +1 -0
- package/dist/exceptions/ConflictException.js +28 -0
- package/dist/exceptions/ConflictException.js.map +1 -0
- package/dist/exceptions/ForbiddenException.d.ts +26 -0
- package/dist/exceptions/ForbiddenException.d.ts.map +1 -0
- package/dist/exceptions/ForbiddenException.js +26 -0
- package/dist/exceptions/ForbiddenException.js.map +1 -0
- package/dist/exceptions/NotFoundException.d.ts +28 -0
- package/dist/exceptions/NotFoundException.d.ts.map +1 -0
- package/dist/exceptions/NotFoundException.js +28 -0
- package/dist/exceptions/NotFoundException.js.map +1 -0
- package/dist/exceptions/ServerErrorException.d.ts +33 -0
- package/dist/exceptions/ServerErrorException.d.ts.map +1 -0
- package/dist/exceptions/ServerErrorException.js +33 -0
- package/dist/exceptions/ServerErrorException.js.map +1 -0
- package/dist/exceptions/UnauthorizedException.d.ts +28 -0
- package/dist/exceptions/UnauthorizedException.d.ts.map +1 -0
- package/dist/exceptions/UnauthorizedException.js +28 -0
- package/dist/exceptions/UnauthorizedException.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/swagger/SwaggerGenerator.d.ts +63 -0
- package/dist/swagger/SwaggerGenerator.d.ts.map +1 -0
- package/dist/swagger/SwaggerGenerator.js +266 -0
- package/dist/swagger/SwaggerGenerator.js.map +1 -0
- package/dist/swagger/SwaggerUI.d.ts +30 -0
- package/dist/swagger/SwaggerUI.d.ts.map +1 -0
- package/dist/swagger/SwaggerUI.js +52 -0
- package/dist/swagger/SwaggerUI.js.map +1 -0
- package/dist/types/index.d.ts +255 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +31 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { BaseAdapter } from "./BaseAdapter.js";
|
|
2
|
+
/**
|
|
3
|
+
* Fastify adapter implementation.
|
|
4
|
+
*
|
|
5
|
+
* Middleware Express-style dikonversi ke Fastify `preHandler` hooks.
|
|
6
|
+
* Handler di-await dan reply di-return untuk mencegah Fastify auto-send.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const fastify = Fastify();
|
|
11
|
+
* const adapter = new FastifyAdapter(fastify);
|
|
12
|
+
* adapter.registerRoute("get", "/hello", [], async (req, reply) => {
|
|
13
|
+
* reply.code(200).send({ message: "OK" });
|
|
14
|
+
* });
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export class FastifyAdapter extends BaseAdapter {
|
|
18
|
+
app;
|
|
19
|
+
constructor(app) {
|
|
20
|
+
super();
|
|
21
|
+
this.app = app;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Fastify route handler signature berbeda dari Express.
|
|
25
|
+
* Middleware dikonversi ke preHandler, handler di-await.
|
|
26
|
+
*/
|
|
27
|
+
registerRoute(method, path, middlewares, handler) {
|
|
28
|
+
const fastifyPath = path;
|
|
29
|
+
const routeHandler = this.app[method].bind(this.app);
|
|
30
|
+
const preHandlers = middlewares.map((mw) => {
|
|
31
|
+
return async (request, reply) => {
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
mw(request, reply, (err) => {
|
|
34
|
+
if (err)
|
|
35
|
+
reject(err);
|
|
36
|
+
else
|
|
37
|
+
resolve();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
routeHandler(fastifyPath, { preHandler: preHandlers }, async (request, reply) => {
|
|
43
|
+
await handler(request, reply);
|
|
44
|
+
return reply;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
getBody(req) {
|
|
48
|
+
return req.body;
|
|
49
|
+
}
|
|
50
|
+
getQuery(req) {
|
|
51
|
+
return req.query;
|
|
52
|
+
}
|
|
53
|
+
getParams(req) {
|
|
54
|
+
return req.params;
|
|
55
|
+
}
|
|
56
|
+
getHeaders(req) {
|
|
57
|
+
return req.headers;
|
|
58
|
+
}
|
|
59
|
+
getCookies(req) {
|
|
60
|
+
return req.cookies ?? {};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Sets a cookie on Fastify reply.
|
|
64
|
+
* Fallback ke manual Set-Cookie header jika `setCookie` tidak tersedia.
|
|
65
|
+
*/
|
|
66
|
+
setCookie(res, key, value, options) {
|
|
67
|
+
const fastifyReply = res;
|
|
68
|
+
if (typeof fastifyReply.setCookie === "function") {
|
|
69
|
+
fastifyReply.setCookie(key, value, {
|
|
70
|
+
httpOnly: options.httpOnly,
|
|
71
|
+
secure: options.secure,
|
|
72
|
+
maxAge: options.maxAge ?? undefined,
|
|
73
|
+
path: options.path,
|
|
74
|
+
sameSite: options.sameSite,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
const parts = [`${key}=${value}`];
|
|
79
|
+
if (options.path)
|
|
80
|
+
parts.push(`Path=${options.path}`);
|
|
81
|
+
if (options.httpOnly)
|
|
82
|
+
parts.push("HttpOnly");
|
|
83
|
+
if (options.secure)
|
|
84
|
+
parts.push("Secure");
|
|
85
|
+
if (options.maxAge)
|
|
86
|
+
parts.push(`Max-Age=${options.maxAge}`);
|
|
87
|
+
if (options.sameSite)
|
|
88
|
+
parts.push(`SameSite=${options.sameSite}`);
|
|
89
|
+
fastifyReply.header("Set-Cookie", parts.join("; "));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Deletes a cookie on Fastify reply.
|
|
94
|
+
* Fallback ke Expires header manual jika `clearCookie` tidak tersedia.
|
|
95
|
+
*/
|
|
96
|
+
deleteCookie(res, key) {
|
|
97
|
+
const fastifyReply = res;
|
|
98
|
+
if (typeof fastifyReply.clearCookie === "function") {
|
|
99
|
+
fastifyReply.clearCookie(key, { path: "/" });
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
fastifyReply.header("Set-Cookie", `${key}=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
getUrl(req) {
|
|
106
|
+
const r = req;
|
|
107
|
+
return r.raw?.url || r.url || "";
|
|
108
|
+
}
|
|
109
|
+
getMethod(req) {
|
|
110
|
+
const r = req;
|
|
111
|
+
return r.raw?.method || r.method || "UNKNOWN";
|
|
112
|
+
}
|
|
113
|
+
sendResponse(res, status, body) {
|
|
114
|
+
const fastifyReply = res;
|
|
115
|
+
fastifyReply.code(status).send(body);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Fastify memiliki `setNotFoundHandler` native. Jika tidak ada,
|
|
119
|
+
* fallback ke warning — tidak runtime error.
|
|
120
|
+
*/
|
|
121
|
+
registerNotFoundHandler(handler) {
|
|
122
|
+
if (typeof this.app.setNotFoundHandler === "function") {
|
|
123
|
+
this.app.setNotFoundHandler((request, reply) => {
|
|
124
|
+
handler(request, reply);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
console.warn("[RouterKit] Fastify instance is missing setNotFoundHandler. Catch-all route not registered.");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=FastifyAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FastifyAdapter.js","sourceRoot":"","sources":["../../adapters/FastifyAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { CookieOptions } from "../types/index.js";
|
|
2
|
+
import type { BaseAdapter } from "../adapters/BaseAdapter.js";
|
|
3
|
+
/**
|
|
4
|
+
* Helper class for reading, setting, and deleting cookies.
|
|
5
|
+
*
|
|
6
|
+
* Mengabstraksi operasi cookie antara Express dan Fastify melalui adapter pattern.
|
|
7
|
+
* Di-inject ke controller method via decorator `@Cookie()`.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* @ReqController("/auth")
|
|
12
|
+
* class AuthController {
|
|
13
|
+
* @PostMapping("/login")
|
|
14
|
+
* async login(@Body(LoginSchema) body: ILogin, @Cookie() cookie: CookieSetter) {
|
|
15
|
+
* // Set cookie
|
|
16
|
+
* cookie.set("refresh_token", "jwt-token", {
|
|
17
|
+
* httpOnly: true,
|
|
18
|
+
* secure: true,
|
|
19
|
+
* maxAge: 7 * 24 * 60 * 60, // 7 hari dalam detik
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* // Read cookie
|
|
23
|
+
* const existing = cookie.get("refresh_token");
|
|
24
|
+
*
|
|
25
|
+
* // Delete cookie
|
|
26
|
+
* cookie.delete("old_session");
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare class CookieSetter {
|
|
32
|
+
private readonly adapter;
|
|
33
|
+
private readonly req;
|
|
34
|
+
private readonly res;
|
|
35
|
+
constructor(adapter: BaseAdapter, req: unknown, res: unknown);
|
|
36
|
+
/**
|
|
37
|
+
* Sets a cookie with the given key, value, and options.
|
|
38
|
+
*
|
|
39
|
+
* @param key - Cookie name
|
|
40
|
+
* @param value - Cookie value
|
|
41
|
+
* @param options - Cookie options (httpOnly, secure, maxAge, path, sameSite)
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* cookie.set("session", "abc123", { httpOnly: true, maxAge: 3600 });
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
set(key: string, value: string, options?: CookieOptions): void;
|
|
49
|
+
/**
|
|
50
|
+
* Gets a cookie value by key.
|
|
51
|
+
*
|
|
52
|
+
* @param key - Cookie name
|
|
53
|
+
* @returns The cookie value, or `undefined` if the cookie doesn't exist
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* const token = cookie.get("refresh_token");
|
|
58
|
+
* if (token) { /* use token *\/ }
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
get(key: string): string | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Deletes a cookie by key (sets empty value with expired date).
|
|
64
|
+
*
|
|
65
|
+
* @param key - Cookie name to delete
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* cookie.delete("refresh_token");
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
delete(key: string): void;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=CookieSetter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CookieSetter.d.ts","sourceRoot":"","sources":["../../cookie/CookieSetter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,YAAY;IAErB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAFH,OAAO,EAAE,WAAW,EACpB,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,OAAO;IAG/B;;;;;;;;;;;OAWG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI;IAU9D;;;;;;;;;;;OAWG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAKpC;;;;;;;;;OASG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;CAG1B"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper class for reading, setting, and deleting cookies.
|
|
3
|
+
*
|
|
4
|
+
* Mengabstraksi operasi cookie antara Express dan Fastify melalui adapter pattern.
|
|
5
|
+
* Di-inject ke controller method via decorator `@Cookie()`.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* @ReqController("/auth")
|
|
10
|
+
* class AuthController {
|
|
11
|
+
* @PostMapping("/login")
|
|
12
|
+
* async login(@Body(LoginSchema) body: ILogin, @Cookie() cookie: CookieSetter) {
|
|
13
|
+
* // Set cookie
|
|
14
|
+
* cookie.set("refresh_token", "jwt-token", {
|
|
15
|
+
* httpOnly: true,
|
|
16
|
+
* secure: true,
|
|
17
|
+
* maxAge: 7 * 24 * 60 * 60, // 7 hari dalam detik
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* // Read cookie
|
|
21
|
+
* const existing = cookie.get("refresh_token");
|
|
22
|
+
*
|
|
23
|
+
* // Delete cookie
|
|
24
|
+
* cookie.delete("old_session");
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export class CookieSetter {
|
|
30
|
+
adapter;
|
|
31
|
+
req;
|
|
32
|
+
res;
|
|
33
|
+
constructor(adapter, req, res) {
|
|
34
|
+
this.adapter = adapter;
|
|
35
|
+
this.req = req;
|
|
36
|
+
this.res = res;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Sets a cookie with the given key, value, and options.
|
|
40
|
+
*
|
|
41
|
+
* @param key - Cookie name
|
|
42
|
+
* @param value - Cookie value
|
|
43
|
+
* @param options - Cookie options (httpOnly, secure, maxAge, path, sameSite)
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* cookie.set("session", "abc123", { httpOnly: true, maxAge: 3600 });
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
set(key, value, options) {
|
|
51
|
+
this.adapter.setCookie(this.res, key, value, {
|
|
52
|
+
httpOnly: options?.httpOnly !== false,
|
|
53
|
+
secure: options?.secure !== false,
|
|
54
|
+
maxAge: options?.maxAge,
|
|
55
|
+
path: options?.path ?? "/",
|
|
56
|
+
sameSite: options?.sameSite,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Gets a cookie value by key.
|
|
61
|
+
*
|
|
62
|
+
* @param key - Cookie name
|
|
63
|
+
* @returns The cookie value, or `undefined` if the cookie doesn't exist
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* const token = cookie.get("refresh_token");
|
|
68
|
+
* if (token) { /* use token *\/ }
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
get(key) {
|
|
72
|
+
const cookies = this.adapter.getCookies(this.req);
|
|
73
|
+
return cookies[key];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Deletes a cookie by key (sets empty value with expired date).
|
|
77
|
+
*
|
|
78
|
+
* @param key - Cookie name to delete
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```typescript
|
|
82
|
+
* cookie.delete("refresh_token");
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
delete(key) {
|
|
86
|
+
this.adapter.deleteCookie(this.res, key);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=CookieSetter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CookieSetter.js","sourceRoot":"","sources":["../../cookie/CookieSetter.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,OAAO,YAAY;IAEJ;IACA;IACA;IAHnB,YACmB,OAAoB,EACpB,GAAY,EACZ,GAAY;QAFZ,YAAO,GAAP,OAAO,CAAa;QACpB,QAAG,GAAH,GAAG,CAAS;QACZ,QAAG,GAAH,GAAG,CAAS;IAC5B,CAAC;IAEJ;;;;;;;;;;;OAWG;IACH,GAAG,CAAC,GAAW,EAAE,KAAa,EAAE,OAAuB;QACrD,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE;YAC3C,QAAQ,EAAE,OAAO,EAAE,QAAQ,KAAK,KAAK;YACrC,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,KAAK;YACjC,MAAM,EAAE,OAAO,EAAE,MAAM;YACvB,IAAI,EAAE,OAAO,EAAE,IAAI,IAAI,GAAG;YAC1B,QAAQ,EAAE,OAAO,EAAE,QAAQ;SAC5B,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;;;;OAWG;IACH,GAAG,CAAC,GAAW;QACb,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC;IACtB,CAAC;IAED;;;;;;;;;OASG;IACH,MAAM,CAAC,GAAW;QAChB,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC3C,CAAC;CACF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { LoggerMeta } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Utility class for structured request logging with ANSI-colored output.
|
|
4
|
+
* Mendukung console logging dan custom handler untuk integrasi eksternal.
|
|
5
|
+
*/
|
|
6
|
+
export declare class Logger {
|
|
7
|
+
/**
|
|
8
|
+
* Logs an HTTP request with method, URL, status code, and duration.
|
|
9
|
+
* Error responses (status >= 500) include the error object for debugging.
|
|
10
|
+
*
|
|
11
|
+
* @param method - HTTP method (GET, POST, dll)
|
|
12
|
+
* @param url - Request URL path
|
|
13
|
+
* @param status - HTTP response status code
|
|
14
|
+
* @param durationMs - Request duration in milliseconds
|
|
15
|
+
* @param error - Optional error object (ditampilkan jika status >= 500)
|
|
16
|
+
* @param customHandler - Optional custom handler untuk log ke file/service eksternal
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* // Default console logging
|
|
21
|
+
* Logger.logRequest("GET", "/users", 200, 42);
|
|
22
|
+
* // Output: ✅ [GET] /users - 200 (42ms)
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* // Custom handler — kirim ke file atau service monitoring
|
|
28
|
+
* const customLogger = (level, msg, meta) => {
|
|
29
|
+
* fileLog.write(`[${level}] ${msg}`);
|
|
30
|
+
* };
|
|
31
|
+
* Logger.logRequest("POST", "/users", 201, 120, undefined, customLogger);
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
static logRequest(method: string, url: string, status: number, durationMs: number, error?: unknown, customHandler?: (level: "info" | "error", message: string, meta: LoggerMeta) => void): void;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=Logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Logger.d.ts","sourceRoot":"","sources":["../../core/Logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD;;;GAGG;AACH,qBAAa,MAAM;IACjB;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,MAAM,CAAC,UAAU,CACf,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,OAAO,EACf,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,KAAK,IAAI;CAwBvF"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility class for structured request logging with ANSI-colored output.
|
|
3
|
+
* Mendukung console logging dan custom handler untuk integrasi eksternal.
|
|
4
|
+
*/
|
|
5
|
+
export class Logger {
|
|
6
|
+
/**
|
|
7
|
+
* Logs an HTTP request with method, URL, status code, and duration.
|
|
8
|
+
* Error responses (status >= 500) include the error object for debugging.
|
|
9
|
+
*
|
|
10
|
+
* @param method - HTTP method (GET, POST, dll)
|
|
11
|
+
* @param url - Request URL path
|
|
12
|
+
* @param status - HTTP response status code
|
|
13
|
+
* @param durationMs - Request duration in milliseconds
|
|
14
|
+
* @param error - Optional error object (ditampilkan jika status >= 500)
|
|
15
|
+
* @param customHandler - Optional custom handler untuk log ke file/service eksternal
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* // Default console logging
|
|
20
|
+
* Logger.logRequest("GET", "/users", 200, 42);
|
|
21
|
+
* // Output: ✅ [GET] /users - 200 (42ms)
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* // Custom handler — kirim ke file atau service monitoring
|
|
27
|
+
* const customLogger = (level, msg, meta) => {
|
|
28
|
+
* fileLog.write(`[${level}] ${msg}`);
|
|
29
|
+
* };
|
|
30
|
+
* Logger.logRequest("POST", "/users", 201, 120, undefined, customLogger);
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
static logRequest(method, url, status, durationMs, error, customHandler) {
|
|
34
|
+
const isError = status >= 400;
|
|
35
|
+
const level = isError ? "error" : "info";
|
|
36
|
+
const icon = isError ? "❌" : "✅";
|
|
37
|
+
const reset = "\x1b[0m";
|
|
38
|
+
const methodColor = "\x1b[36m";
|
|
39
|
+
const statusColor = isError ? "\x1b[31m" : "\x1b[32m";
|
|
40
|
+
const timeColor = "\x1b[90m";
|
|
41
|
+
const methodUpper = String(method).toUpperCase();
|
|
42
|
+
const message = `${icon} ${methodColor}[${methodUpper}]${reset} ${url} - ${statusColor}${status}${reset} ${timeColor}(${durationMs}ms)${reset}`;
|
|
43
|
+
console.log(message);
|
|
44
|
+
if (isError && error && status >= 500) {
|
|
45
|
+
console.error(error);
|
|
46
|
+
}
|
|
47
|
+
if (customHandler) {
|
|
48
|
+
const cleanMessage = `${icon} [${methodUpper}] ${url} - ${status} (${durationMs}ms)`;
|
|
49
|
+
customHandler(level, cleanMessage, { method: methodUpper, path: url, status, durationMs, error });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=Logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Logger.js","sourceRoot":"","sources":["../../core/Logger.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,OAAO,MAAM;IACjB;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,MAAM,CAAC,UAAU,CACf,MAAc,EACd,GAAW,EACX,MAAc,EACd,UAAkB,EAClB,KAAe,EACf,aAAoF;QAEpF,MAAM,OAAO,GAAG,MAAM,IAAI,GAAG,CAAC;QAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;QACzC,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QAEjC,MAAM,KAAK,GAAG,SAAS,CAAC;QACxB,MAAM,WAAW,GAAG,UAAU,CAAC;QAC/B,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC;QACtD,MAAM,SAAS,GAAG,UAAU,CAAC;QAE7B,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QACjD,MAAM,OAAO,GAAG,GAAG,IAAI,IAAI,WAAW,IAAI,WAAW,IAAI,KAAK,IAAI,GAAG,MAAM,WAAW,GAAG,MAAM,GAAG,KAAK,IAAI,SAAS,IAAI,UAAU,MAAM,KAAK,EAAE,CAAC;QAEhJ,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACrB,IAAI,OAAO,IAAI,KAAK,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;QAED,IAAI,aAAa,EAAE,CAAC;YAClB,MAAM,YAAY,GAAG,GAAG,IAAI,KAAK,WAAW,KAAK,GAAG,MAAM,MAAM,KAAK,UAAU,KAAK,CAAC;YACrF,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;QACpG,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { MiddlewareFn, ResolvedRoute, Class } from "../types/index.js";
|
|
2
|
+
import type { BaseAdapter } from "../adapters/BaseAdapter.js";
|
|
3
|
+
/**
|
|
4
|
+
* Internal engine yang membaca metadata dari TC39 decorators (`Symbol.metadata`)
|
|
5
|
+
* dan WeakMap (parameter decorators), lalu mendaftarkan route ke framework adapter.
|
|
6
|
+
*
|
|
7
|
+
* Semua logic inti ada di sini: parameter injection, Zod validation,
|
|
8
|
+
* error handling, response envelope, auth middleware, dan logging.
|
|
9
|
+
*/
|
|
10
|
+
export declare class RouteResolver {
|
|
11
|
+
private readonly adapter;
|
|
12
|
+
private readonly loggerConfig?;
|
|
13
|
+
private readonly authMiddleware?;
|
|
14
|
+
private readonly refreshMiddleware?;
|
|
15
|
+
private readonly responseEnvelope;
|
|
16
|
+
private readonly globalPrefix;
|
|
17
|
+
/** Melacak route yang sudah didaftarkan untuk deteksi duplikat */
|
|
18
|
+
private readonly registeredRoutes;
|
|
19
|
+
/** Semua route yang sudah di-resolve — digunakan untuk generate Swagger spec */
|
|
20
|
+
readonly resolvedRoutes: ResolvedRoute[];
|
|
21
|
+
/**
|
|
22
|
+
* @param adapter - Framework adapter (Express / Fastify)
|
|
23
|
+
* @param loggerConfig - Konfigurasi logger
|
|
24
|
+
* @param authMiddleware - Middleware untuk authentication type "auth"
|
|
25
|
+
* @param refreshMiddleware - Middleware untuk authentication type "refresh"
|
|
26
|
+
* @param responseEnvelope - Mode response wrapping ("wrap" | "raw")
|
|
27
|
+
* @param globalPrefix - Prefix global untuk semua route (contoh: "/api")
|
|
28
|
+
*/
|
|
29
|
+
constructor(adapter: BaseAdapter, loggerConfig?: (boolean | import("../types/index.js").LoggerConfig) | undefined, authMiddleware?: MiddlewareFn | undefined, refreshMiddleware?: MiddlewareFn | undefined, responseEnvelope?: "wrap" | "raw", globalPrefix?: string);
|
|
30
|
+
/**
|
|
31
|
+
* Resolves and registers all routes from a controller class.
|
|
32
|
+
* Membaca metadata dari `Symbol.metadata` (TC39) dan WeakMap (parameter),
|
|
33
|
+
* lalu mendaftarkan setiap route ke adapter.
|
|
34
|
+
*
|
|
35
|
+
* @param Controller - Controller class yang sudah di-decorate dengan @ReqController
|
|
36
|
+
*
|
|
37
|
+
* @throws Error jika class tidak memiliki @ReqController
|
|
38
|
+
* @throws Error jika ditemukan duplikat route
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* const resolver = new RouteResolver(adapter);
|
|
43
|
+
* resolver.resolve(UserController);
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
resolve(Controller: Class): void;
|
|
47
|
+
/**
|
|
48
|
+
* Registers a single route: build path, resolve auth, inject params, register to adapter.
|
|
49
|
+
*/
|
|
50
|
+
private registerRoute;
|
|
51
|
+
/**
|
|
52
|
+
* Builds the full URL path from controller base path + method path + global prefix.
|
|
53
|
+
*/
|
|
54
|
+
private buildFullPath;
|
|
55
|
+
/**
|
|
56
|
+
* Resolves effective auth type: method-level override, else controller-level.
|
|
57
|
+
*/
|
|
58
|
+
private resolveAuthType;
|
|
59
|
+
/**
|
|
60
|
+
* Resolves authentication middleware array from auth type.
|
|
61
|
+
* Returns empty array if auth is disabled or middleware not configured.
|
|
62
|
+
*/
|
|
63
|
+
private resolveAuthMiddleware;
|
|
64
|
+
/**
|
|
65
|
+
* Creates the route handler that manages parameter injection, response sending,
|
|
66
|
+
* error handling, and logging.
|
|
67
|
+
*/
|
|
68
|
+
private createHandler;
|
|
69
|
+
/**
|
|
70
|
+
* Resolves parameter values from the request based on param metadata.
|
|
71
|
+
* Parameters are sorted by index to ensure correct order.
|
|
72
|
+
*/
|
|
73
|
+
private resolveParams;
|
|
74
|
+
/**
|
|
75
|
+
* Resolves a single parameter value from the request.
|
|
76
|
+
* Supports: body, query, param, req, cookie, reply.
|
|
77
|
+
*/
|
|
78
|
+
private resolveParam;
|
|
79
|
+
/**
|
|
80
|
+
* Validates data against a Zod schema.
|
|
81
|
+
* Throws BadRequestException with field-level errors on validation failure.
|
|
82
|
+
*/
|
|
83
|
+
private validateWithZod;
|
|
84
|
+
/**
|
|
85
|
+
* Handles errors thrown during route execution:
|
|
86
|
+
* - BaseException → send with its status code
|
|
87
|
+
* - Unknown errors → wrap as 500 ServerErrorException
|
|
88
|
+
*/
|
|
89
|
+
private handleError;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=RouteResolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RouteResolver.d.ts","sourceRoot":"","sources":["../../core/RouteResolver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAIV,YAAY,EACZ,aAAa,EACb,KAAK,EAEN,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAO9D;;;;;;GAMG;AACH,qBAAa,aAAa;IAgBtB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;IAC9B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;IAChC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC;IACnC,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,YAAY;IApB/B,kEAAkE;IAClE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;IAEtD,gFAAgF;IAChF,QAAQ,CAAC,cAAc,EAAE,aAAa,EAAE,CAAM;IAE9C;;;;;;;OAOG;gBAEgB,OAAO,EAAE,WAAW,EACpB,YAAY,CAAC,GAAE,OAAO,GAAG,OAAO,mBAAmB,EAAE,YAAY,aAAA,EACjE,cAAc,CAAC,EAAE,YAAY,YAAA,EAC7B,iBAAiB,CAAC,EAAE,YAAY,YAAA,EAChC,gBAAgB,GAAE,MAAM,GAAG,KAAc,EACzC,YAAY,GAAE,MAAW;IAG5C;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,UAAU,EAAE,KAAK,GAAG,IAAI;IAmBhC;;OAEG;IACH,OAAO,CAAC,aAAa;IAkDrB;;OAEG;IACH,OAAO,CAAC,aAAa;IAUrB;;OAEG;IACH,OAAO,CAAC,eAAe;IAUvB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAW7B;;;OAGG;IACH,OAAO,CAAC,aAAa;IAqDrB;;;OAGG;IACH,OAAO,CAAC,aAAa;IAWrB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAqCpB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAiBvB;;;;OAIG;IACH,OAAO,CAAC,WAAW;CAsBpB"}
|