@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,279 @@
|
|
|
1
|
+
import { ZodError } from "zod";
|
|
2
|
+
import { META, getClassMeta, paramMetaStore } from "../types/index.js";
|
|
3
|
+
import { CookieSetter } from "../cookie/CookieSetter.js";
|
|
4
|
+
import { BaseException } from "../exceptions/BaseException.js";
|
|
5
|
+
import { BadRequestException } from "../exceptions/BadRequestException.js";
|
|
6
|
+
import { ServerErrorException } from "../exceptions/ServerErrorException.js";
|
|
7
|
+
import { Logger } from "./Logger.js";
|
|
8
|
+
/**
|
|
9
|
+
* Internal engine yang membaca metadata dari TC39 decorators (`Symbol.metadata`)
|
|
10
|
+
* dan WeakMap (parameter decorators), lalu mendaftarkan route ke framework adapter.
|
|
11
|
+
*
|
|
12
|
+
* Semua logic inti ada di sini: parameter injection, Zod validation,
|
|
13
|
+
* error handling, response envelope, auth middleware, dan logging.
|
|
14
|
+
*/
|
|
15
|
+
export class RouteResolver {
|
|
16
|
+
adapter;
|
|
17
|
+
loggerConfig;
|
|
18
|
+
authMiddleware;
|
|
19
|
+
refreshMiddleware;
|
|
20
|
+
responseEnvelope;
|
|
21
|
+
globalPrefix;
|
|
22
|
+
/** Melacak route yang sudah didaftarkan untuk deteksi duplikat */
|
|
23
|
+
registeredRoutes = new Set();
|
|
24
|
+
/** Semua route yang sudah di-resolve — digunakan untuk generate Swagger spec */
|
|
25
|
+
resolvedRoutes = [];
|
|
26
|
+
/**
|
|
27
|
+
* @param adapter - Framework adapter (Express / Fastify)
|
|
28
|
+
* @param loggerConfig - Konfigurasi logger
|
|
29
|
+
* @param authMiddleware - Middleware untuk authentication type "auth"
|
|
30
|
+
* @param refreshMiddleware - Middleware untuk authentication type "refresh"
|
|
31
|
+
* @param responseEnvelope - Mode response wrapping ("wrap" | "raw")
|
|
32
|
+
* @param globalPrefix - Prefix global untuk semua route (contoh: "/api")
|
|
33
|
+
*/
|
|
34
|
+
constructor(adapter, loggerConfig, authMiddleware, refreshMiddleware, responseEnvelope = "wrap", globalPrefix = "") {
|
|
35
|
+
this.adapter = adapter;
|
|
36
|
+
this.loggerConfig = loggerConfig;
|
|
37
|
+
this.authMiddleware = authMiddleware;
|
|
38
|
+
this.refreshMiddleware = refreshMiddleware;
|
|
39
|
+
this.responseEnvelope = responseEnvelope;
|
|
40
|
+
this.globalPrefix = globalPrefix;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Resolves and registers all routes from a controller class.
|
|
44
|
+
* Membaca metadata dari `Symbol.metadata` (TC39) dan WeakMap (parameter),
|
|
45
|
+
* lalu mendaftarkan setiap route ke adapter.
|
|
46
|
+
*
|
|
47
|
+
* @param Controller - Controller class yang sudah di-decorate dengan @ReqController
|
|
48
|
+
*
|
|
49
|
+
* @throws Error jika class tidak memiliki @ReqController
|
|
50
|
+
* @throws Error jika ditemukan duplikat route
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* const resolver = new RouteResolver(adapter);
|
|
55
|
+
* resolver.resolve(UserController);
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
resolve(Controller) {
|
|
59
|
+
const controllerMeta = getClassMeta(Controller, META.CONTROLLER);
|
|
60
|
+
if (!controllerMeta) {
|
|
61
|
+
throw new Error(`[RouterKit] Class "${Controller.name}" is not decorated with @ReqController. ` +
|
|
62
|
+
`Add @ReqController("/path") to the class definition.`);
|
|
63
|
+
}
|
|
64
|
+
const routes = getClassMeta(Controller, META.ROUTES) ?? [];
|
|
65
|
+
const controllerInstance = new Controller();
|
|
66
|
+
for (const route of routes) {
|
|
67
|
+
this.registerRoute(Controller, controllerInstance, controllerMeta, route);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Registers a single route: build path, resolve auth, inject params, register to adapter.
|
|
72
|
+
*/
|
|
73
|
+
registerRoute(Controller, instance, controllerMeta, route) {
|
|
74
|
+
const fullPath = this.buildFullPath(controllerMeta.basePath, route.path);
|
|
75
|
+
const routeKey = `${route.method.toUpperCase()} ${fullPath}`;
|
|
76
|
+
if (this.registeredRoutes.has(routeKey)) {
|
|
77
|
+
throw new Error(`[RouterKit] Duplicate route detected: ${routeKey}. ` +
|
|
78
|
+
`Each route must have a unique method + path combination.`);
|
|
79
|
+
}
|
|
80
|
+
this.registeredRoutes.add(routeKey);
|
|
81
|
+
const authType = this.resolveAuthType(route.options.authentication, controllerMeta.authentication);
|
|
82
|
+
const authMiddlewares = this.resolveAuthMiddleware(authType);
|
|
83
|
+
const middlewaresKey = META.MIDDLEWARES_PREFIX + route.propertyKey;
|
|
84
|
+
const methodMiddlewares = getClassMeta(Controller, middlewaresKey) ?? [];
|
|
85
|
+
const allMiddlewares = [...authMiddlewares, ...methodMiddlewares];
|
|
86
|
+
const params = paramMetaStore.get(Controller)?.get(route.propertyKey) ?? [];
|
|
87
|
+
const httpStatusKey = META.HTTP_STATUS_PREFIX + route.propertyKey;
|
|
88
|
+
const statusFromDecorator = getClassMeta(Controller, httpStatusKey);
|
|
89
|
+
const statusCode = route.options.status ?? statusFromDecorator ?? 200;
|
|
90
|
+
const swaggerVisible = controllerMeta.swagger !== false && route.options.swagger !== false;
|
|
91
|
+
const resolvedRoute = {
|
|
92
|
+
method: route.method,
|
|
93
|
+
fullPath,
|
|
94
|
+
middlewares: allMiddlewares,
|
|
95
|
+
params,
|
|
96
|
+
handler: instance[route.propertyKey],
|
|
97
|
+
statusCode,
|
|
98
|
+
controllerTag: controllerMeta.tag,
|
|
99
|
+
swagger: swaggerVisible,
|
|
100
|
+
routeOptions: route.options,
|
|
101
|
+
};
|
|
102
|
+
this.resolvedRoutes.push(resolvedRoute);
|
|
103
|
+
const handler = this.createHandler(instance, route.propertyKey, params, statusCode, route.method);
|
|
104
|
+
this.adapter.registerRoute(route.method, fullPath, allMiddlewares, handler);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Builds the full URL path from controller base path + method path + global prefix.
|
|
108
|
+
*/
|
|
109
|
+
buildFullPath(basePath, methodPath) {
|
|
110
|
+
const base = basePath.endsWith("/") ? basePath.slice(0, -1) : basePath;
|
|
111
|
+
const method = methodPath.startsWith("/") ? methodPath : "/" + methodPath;
|
|
112
|
+
const rawPrefix = this.globalPrefix ?? "";
|
|
113
|
+
if (!rawPrefix)
|
|
114
|
+
return base + method;
|
|
115
|
+
const prefix = rawPrefix.startsWith("/") ? rawPrefix : "/" + rawPrefix;
|
|
116
|
+
const normPrefix = prefix.endsWith("/") ? prefix.slice(0, -1) : prefix;
|
|
117
|
+
return normPrefix + base + method;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Resolves effective auth type: method-level override, else controller-level.
|
|
121
|
+
*/
|
|
122
|
+
resolveAuthType(methodAuth, controllerAuth) {
|
|
123
|
+
if (methodAuth !== undefined) {
|
|
124
|
+
return methodAuth;
|
|
125
|
+
}
|
|
126
|
+
return controllerAuth;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Resolves authentication middleware array from auth type.
|
|
130
|
+
* Returns empty array if auth is disabled or middleware not configured.
|
|
131
|
+
*/
|
|
132
|
+
resolveAuthMiddleware(authType) {
|
|
133
|
+
if (authType === false)
|
|
134
|
+
return [];
|
|
135
|
+
if (authType === "auth" && this.authMiddleware) {
|
|
136
|
+
return [this.authMiddleware];
|
|
137
|
+
}
|
|
138
|
+
if (authType === "refresh" && this.refreshMiddleware) {
|
|
139
|
+
return [this.refreshMiddleware];
|
|
140
|
+
}
|
|
141
|
+
return [];
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Creates the route handler that manages parameter injection, response sending,
|
|
145
|
+
* error handling, and logging.
|
|
146
|
+
*/
|
|
147
|
+
createHandler(instance, propertyKey, params, statusCode, routeMethod) {
|
|
148
|
+
const adapter = this.adapter;
|
|
149
|
+
const loggerConfig = this.loggerConfig;
|
|
150
|
+
return async (req, res) => {
|
|
151
|
+
const start = Date.now();
|
|
152
|
+
try {
|
|
153
|
+
const args = this.resolveParams(params, req, res);
|
|
154
|
+
const method = instance[propertyKey];
|
|
155
|
+
const result = await method.apply(instance, args);
|
|
156
|
+
const handlerWroteResponse = result === res ||
|
|
157
|
+
(typeof result === "object" &&
|
|
158
|
+
result !== null &&
|
|
159
|
+
result.__rawReply === true);
|
|
160
|
+
if (handlerWroteResponse) {
|
|
161
|
+
// No-op: response sudah dikirim oleh handler (misal: HTML redirect)
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
const responseBody = this.responseEnvelope === "raw"
|
|
165
|
+
? (result ?? null)
|
|
166
|
+
: { message: "OK", data: result ?? null };
|
|
167
|
+
adapter.sendResponse(res, statusCode, responseBody);
|
|
168
|
+
}
|
|
169
|
+
if (loggerConfig && (loggerConfig === true || (typeof loggerConfig === 'object' && loggerConfig.enabled !== false))) {
|
|
170
|
+
const duration = Date.now() - start;
|
|
171
|
+
const url = adapter.getUrl(req);
|
|
172
|
+
const handler = typeof loggerConfig === 'object' ? loggerConfig.handler : undefined;
|
|
173
|
+
Logger.logRequest(routeMethod, url, statusCode, duration, undefined, handler);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
const status = this.handleError(error, res);
|
|
178
|
+
if (loggerConfig && (loggerConfig === true || (typeof loggerConfig === 'object' && loggerConfig.enabled !== false))) {
|
|
179
|
+
const duration = Date.now() - start;
|
|
180
|
+
const url = adapter.getUrl(req);
|
|
181
|
+
const handler = typeof loggerConfig === 'object' ? loggerConfig.handler : undefined;
|
|
182
|
+
Logger.logRequest(routeMethod, url, status, duration, error, handler);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Resolves parameter values from the request based on param metadata.
|
|
189
|
+
* Parameters are sorted by index to ensure correct order.
|
|
190
|
+
*/
|
|
191
|
+
resolveParams(params, req, res) {
|
|
192
|
+
const sorted = [...params].sort((a, b) => a.index - b.index);
|
|
193
|
+
const args = [];
|
|
194
|
+
for (const param of sorted) {
|
|
195
|
+
args[param.index] = this.resolveParam(param, req, res);
|
|
196
|
+
}
|
|
197
|
+
return args;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Resolves a single parameter value from the request.
|
|
201
|
+
* Supports: body, query, param, req, cookie, reply.
|
|
202
|
+
*/
|
|
203
|
+
resolveParam(param, req, res) {
|
|
204
|
+
switch (param.type) {
|
|
205
|
+
case "body": {
|
|
206
|
+
const body = this.adapter.getBody(req);
|
|
207
|
+
if (param.schema) {
|
|
208
|
+
return this.validateWithZod(param.schema, body);
|
|
209
|
+
}
|
|
210
|
+
return body;
|
|
211
|
+
}
|
|
212
|
+
case "query": {
|
|
213
|
+
const query = this.adapter.getQuery(req);
|
|
214
|
+
if (param.schema) {
|
|
215
|
+
return this.validateWithZod(param.schema, query);
|
|
216
|
+
}
|
|
217
|
+
return query;
|
|
218
|
+
}
|
|
219
|
+
case "param": {
|
|
220
|
+
const params = this.adapter.getParams(req);
|
|
221
|
+
return param.key ? params[param.key] : undefined;
|
|
222
|
+
}
|
|
223
|
+
case "req":
|
|
224
|
+
return req;
|
|
225
|
+
case "cookie":
|
|
226
|
+
return new CookieSetter(this.adapter, req, res);
|
|
227
|
+
case "reply":
|
|
228
|
+
return res;
|
|
229
|
+
default:
|
|
230
|
+
return undefined;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Validates data against a Zod schema.
|
|
235
|
+
* Throws BadRequestException with field-level errors on validation failure.
|
|
236
|
+
*/
|
|
237
|
+
validateWithZod(schema, data) {
|
|
238
|
+
if (!schema)
|
|
239
|
+
return data;
|
|
240
|
+
try {
|
|
241
|
+
return schema.parse(data);
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
if (error instanceof ZodError) {
|
|
245
|
+
const errors = error.errors.map((e) => ({
|
|
246
|
+
field: e.path.join("."),
|
|
247
|
+
message: e.message,
|
|
248
|
+
}));
|
|
249
|
+
throw new BadRequestException("Validation failed", { errors });
|
|
250
|
+
}
|
|
251
|
+
throw error;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Handles errors thrown during route execution:
|
|
256
|
+
* - BaseException → send with its status code
|
|
257
|
+
* - Unknown errors → wrap as 500 ServerErrorException
|
|
258
|
+
*/
|
|
259
|
+
handleError(error, res) {
|
|
260
|
+
if (error instanceof BaseException) {
|
|
261
|
+
this.adapter.sendResponse(res, error.status, {
|
|
262
|
+
statusCode: error.status,
|
|
263
|
+
code: error.code,
|
|
264
|
+
message: error.message,
|
|
265
|
+
details: error.data ?? undefined,
|
|
266
|
+
});
|
|
267
|
+
return error.status;
|
|
268
|
+
}
|
|
269
|
+
const serverError = new ServerErrorException(error instanceof Error ? error.message : "Internal server error");
|
|
270
|
+
this.adapter.sendResponse(res, serverError.status, {
|
|
271
|
+
statusCode: serverError.status,
|
|
272
|
+
code: serverError.code,
|
|
273
|
+
message: serverError.message,
|
|
274
|
+
details: undefined,
|
|
275
|
+
});
|
|
276
|
+
return serverError.status;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=RouteResolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RouteResolver.js","sourceRoot":"","sources":["../../core/RouteResolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { RouterKitConfig, Class } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Main entry point for router-api-kit.
|
|
4
|
+
* Static facade for setup, registration, and lifecycle management.
|
|
5
|
+
*
|
|
6
|
+
* ---
|
|
7
|
+
* ### Lifecycle
|
|
8
|
+
* 1. `RouterKit.setup(config)` — inisialisasi adapter dan resolver
|
|
9
|
+
* 2. `RouterKit.register(ControllerA, ControllerB)` — daftarkan controller
|
|
10
|
+
* 3. `RouterKit.handleNotFound()` — (opsional) daftarkan handler 404 global
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import express from "express";
|
|
15
|
+
* import { RouterKit } from "@alis-kit/routers";
|
|
16
|
+
*
|
|
17
|
+
* const app = express();
|
|
18
|
+
* app.use(express.json());
|
|
19
|
+
*
|
|
20
|
+
* RouterKit.setup({
|
|
21
|
+
* framework: "express",
|
|
22
|
+
* app,
|
|
23
|
+
* authMiddleware: verifyAccessToken,
|
|
24
|
+
* swagger: { enabled: true, path: "/api/docs" },
|
|
25
|
+
* logger: true,
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* RouterKit.register(AuthController, UserController);
|
|
29
|
+
* RouterKit.handleNotFound();
|
|
30
|
+
*
|
|
31
|
+
* app.listen(3000);
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare class RouterKit {
|
|
35
|
+
private static adapter;
|
|
36
|
+
private static resolver;
|
|
37
|
+
private static config;
|
|
38
|
+
private static isSetup;
|
|
39
|
+
/**
|
|
40
|
+
* Configures RouterKit with framework adapter, authentication,
|
|
41
|
+
* swagger settings, and other global options.
|
|
42
|
+
*
|
|
43
|
+
* Wajib dipanggil **sebelum** `register()`.
|
|
44
|
+
*
|
|
45
|
+
* @param config - Konfigurasi lengkap RouterKit
|
|
46
|
+
*
|
|
47
|
+
* @throws Error jika framework tidak dikenali
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* // Express
|
|
52
|
+
* RouterKit.setup({
|
|
53
|
+
* framework: "express",
|
|
54
|
+
* app: expressApp,
|
|
55
|
+
* swagger: { enabled: true, path: "/docs" },
|
|
56
|
+
* logger: true,
|
|
57
|
+
* });
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* // Fastify dengan global prefix dan raw envelope
|
|
63
|
+
* RouterKit.setup({
|
|
64
|
+
* framework: "fastify",
|
|
65
|
+
* app: fastifyInstance,
|
|
66
|
+
* responseEnvelope: "raw",
|
|
67
|
+
* globalPrefix: "/api/v1",
|
|
68
|
+
* });
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
static setup(config: RouterKitConfig): void;
|
|
72
|
+
/**
|
|
73
|
+
* Registers one or more controller classes.
|
|
74
|
+
* Setiap controller harus di-decorate dengan `@ReqController`.
|
|
75
|
+
*
|
|
76
|
+
* Jika Swagger diaktifkan, spec akan digenerate otomatis setelah registrasi.
|
|
77
|
+
*
|
|
78
|
+
* @param controllers - Satu atau lebih controller class
|
|
79
|
+
*
|
|
80
|
+
* @throws Error jika `setup()` belum dipanggil
|
|
81
|
+
* @throws Error jika controller tidak memiliki `@ReqController`
|
|
82
|
+
* @throws Error jika ada duplikat route (method + path sama)
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```typescript
|
|
86
|
+
* // Single controller
|
|
87
|
+
* RouterKit.register(UserController);
|
|
88
|
+
*
|
|
89
|
+
* // Multiple sekaligus
|
|
90
|
+
* RouterKit.register(AuthController, UserController, ProductController);
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
static register(...controllers: Class[]): void;
|
|
94
|
+
/**
|
|
95
|
+
* Registers a global catch-all handler for 404 Not Found errors.
|
|
96
|
+
* Panggil method ini **setelah** semua route sudah didaftarkan.
|
|
97
|
+
*
|
|
98
|
+
* @throws Error jika `setup()` belum dipanggil
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* RouterKit.setup({ framework: "express", app });
|
|
103
|
+
* RouterKit.register(UserController);
|
|
104
|
+
*
|
|
105
|
+
* // Handler 404 harus setelah semua route
|
|
106
|
+
* RouterKit.handleNotFound();
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
static handleNotFound(): void;
|
|
110
|
+
/**
|
|
111
|
+
* Resets RouterKit state — berguna untuk testing agar state bersih antar test.
|
|
112
|
+
* @internal
|
|
113
|
+
*/
|
|
114
|
+
static reset(): void;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=RouterKit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RouterKit.d.ts","sourceRoot":"","sources":["../../core/RouterKit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAShE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAC,OAAO,CAA4B;IAClD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA8B;IACrD,OAAO,CAAC,MAAM,CAAC,MAAM,CAAgC;IACrD,OAAO,CAAC,MAAM,CAAC,OAAO,CAAS;IAE/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACH,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI;IA6B3C;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,MAAM,CAAC,QAAQ,CAAC,GAAG,WAAW,EAAE,KAAK,EAAE,GAAG,IAAI;IAmB9C;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,cAAc,IAAI,IAAI;IAyB7B;;;OAGG;IACH,MAAM,CAAC,KAAK,IAAI,IAAI;CAMrB"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { ExpressAdapter } from "../adapters/ExpressAdapter.js";
|
|
2
|
+
import { FastifyAdapter } from "../adapters/FastifyAdapter.js";
|
|
3
|
+
import { RouteResolver } from "./RouteResolver.js";
|
|
4
|
+
import { Logger } from "./Logger.js";
|
|
5
|
+
import { SwaggerGenerator } from "../swagger/SwaggerGenerator.js";
|
|
6
|
+
import { SwaggerUI } from "../swagger/SwaggerUI.js";
|
|
7
|
+
/**
|
|
8
|
+
* Main entry point for router-api-kit.
|
|
9
|
+
* Static facade for setup, registration, and lifecycle management.
|
|
10
|
+
*
|
|
11
|
+
* ---
|
|
12
|
+
* ### Lifecycle
|
|
13
|
+
* 1. `RouterKit.setup(config)` — inisialisasi adapter dan resolver
|
|
14
|
+
* 2. `RouterKit.register(ControllerA, ControllerB)` — daftarkan controller
|
|
15
|
+
* 3. `RouterKit.handleNotFound()` — (opsional) daftarkan handler 404 global
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import express from "express";
|
|
20
|
+
* import { RouterKit } from "@alis-kit/routers";
|
|
21
|
+
*
|
|
22
|
+
* const app = express();
|
|
23
|
+
* app.use(express.json());
|
|
24
|
+
*
|
|
25
|
+
* RouterKit.setup({
|
|
26
|
+
* framework: "express",
|
|
27
|
+
* app,
|
|
28
|
+
* authMiddleware: verifyAccessToken,
|
|
29
|
+
* swagger: { enabled: true, path: "/api/docs" },
|
|
30
|
+
* logger: true,
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* RouterKit.register(AuthController, UserController);
|
|
34
|
+
* RouterKit.handleNotFound();
|
|
35
|
+
*
|
|
36
|
+
* app.listen(3000);
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export class RouterKit {
|
|
40
|
+
static adapter = null;
|
|
41
|
+
static resolver = null;
|
|
42
|
+
static config = null;
|
|
43
|
+
static isSetup = false;
|
|
44
|
+
/**
|
|
45
|
+
* Configures RouterKit with framework adapter, authentication,
|
|
46
|
+
* swagger settings, and other global options.
|
|
47
|
+
*
|
|
48
|
+
* Wajib dipanggil **sebelum** `register()`.
|
|
49
|
+
*
|
|
50
|
+
* @param config - Konfigurasi lengkap RouterKit
|
|
51
|
+
*
|
|
52
|
+
* @throws Error jika framework tidak dikenali
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* // Express
|
|
57
|
+
* RouterKit.setup({
|
|
58
|
+
* framework: "express",
|
|
59
|
+
* app: expressApp,
|
|
60
|
+
* swagger: { enabled: true, path: "/docs" },
|
|
61
|
+
* logger: true,
|
|
62
|
+
* });
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* // Fastify dengan global prefix dan raw envelope
|
|
68
|
+
* RouterKit.setup({
|
|
69
|
+
* framework: "fastify",
|
|
70
|
+
* app: fastifyInstance,
|
|
71
|
+
* responseEnvelope: "raw",
|
|
72
|
+
* globalPrefix: "/api/v1",
|
|
73
|
+
* });
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
static setup(config) {
|
|
77
|
+
switch (config.framework) {
|
|
78
|
+
case "express":
|
|
79
|
+
RouterKit.adapter = new ExpressAdapter(config.app);
|
|
80
|
+
break;
|
|
81
|
+
case "fastify":
|
|
82
|
+
RouterKit.adapter = new FastifyAdapter(config.app);
|
|
83
|
+
break;
|
|
84
|
+
default:
|
|
85
|
+
throw new Error(`[RouterKit] Unsupported framework: "${config.framework}". ` +
|
|
86
|
+
`Supported frameworks are "express" and "fastify".`);
|
|
87
|
+
}
|
|
88
|
+
RouterKit.config = config;
|
|
89
|
+
RouterKit.resolver = new RouteResolver(RouterKit.adapter, config.logger, config.authMiddleware, config.refreshMiddleware, config.responseEnvelope ?? "wrap", config.globalPrefix ?? "");
|
|
90
|
+
RouterKit.isSetup = true;
|
|
91
|
+
console.log(`RouterKit initialized with ${config.framework} adapter`);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Registers one or more controller classes.
|
|
95
|
+
* Setiap controller harus di-decorate dengan `@ReqController`.
|
|
96
|
+
*
|
|
97
|
+
* Jika Swagger diaktifkan, spec akan digenerate otomatis setelah registrasi.
|
|
98
|
+
*
|
|
99
|
+
* @param controllers - Satu atau lebih controller class
|
|
100
|
+
*
|
|
101
|
+
* @throws Error jika `setup()` belum dipanggil
|
|
102
|
+
* @throws Error jika controller tidak memiliki `@ReqController`
|
|
103
|
+
* @throws Error jika ada duplikat route (method + path sama)
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```typescript
|
|
107
|
+
* // Single controller
|
|
108
|
+
* RouterKit.register(UserController);
|
|
109
|
+
*
|
|
110
|
+
* // Multiple sekaligus
|
|
111
|
+
* RouterKit.register(AuthController, UserController, ProductController);
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
static register(...controllers) {
|
|
115
|
+
if (!RouterKit.isSetup || !RouterKit.resolver || !RouterKit.config) {
|
|
116
|
+
throw new Error(`[RouterKit] RouterKit.setup() must be called before RouterKit.register(). ` +
|
|
117
|
+
`Configure the framework and adapter first.`);
|
|
118
|
+
}
|
|
119
|
+
for (const Controller of controllers) {
|
|
120
|
+
RouterKit.resolver.resolve(Controller);
|
|
121
|
+
console.log(`Registered controller: ${Controller.name}`);
|
|
122
|
+
}
|
|
123
|
+
if (RouterKit.config.swagger?.enabled && RouterKit.resolver.resolvedRoutes.length > 0) {
|
|
124
|
+
const spec = SwaggerGenerator.generate(RouterKit.resolver.resolvedRoutes, RouterKit.config.swagger);
|
|
125
|
+
SwaggerUI.serve(RouterKit.config.app, spec, RouterKit.config.swagger);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Registers a global catch-all handler for 404 Not Found errors.
|
|
130
|
+
* Panggil method ini **setelah** semua route sudah didaftarkan.
|
|
131
|
+
*
|
|
132
|
+
* @throws Error jika `setup()` belum dipanggil
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```typescript
|
|
136
|
+
* RouterKit.setup({ framework: "express", app });
|
|
137
|
+
* RouterKit.register(UserController);
|
|
138
|
+
*
|
|
139
|
+
* // Handler 404 harus setelah semua route
|
|
140
|
+
* RouterKit.handleNotFound();
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
static handleNotFound() {
|
|
144
|
+
if (!RouterKit.isSetup || !RouterKit.adapter) {
|
|
145
|
+
throw new Error(`[RouterKit] RouterKit.setup() must be called first.`);
|
|
146
|
+
}
|
|
147
|
+
RouterKit.adapter.registerNotFoundHandler((_req, res) => {
|
|
148
|
+
const start = Date.now();
|
|
149
|
+
RouterKit.adapter.sendResponse(res, 404, {
|
|
150
|
+
message: "Path not found",
|
|
151
|
+
data: null,
|
|
152
|
+
});
|
|
153
|
+
const config = RouterKit.config;
|
|
154
|
+
if (config?.logger && (config.logger === true || (typeof config.logger === 'object' && config.logger.enabled !== false))) {
|
|
155
|
+
const duration = Date.now() - start;
|
|
156
|
+
const method = RouterKit.adapter.getMethod(_req);
|
|
157
|
+
const url = RouterKit.adapter.getUrl(_req);
|
|
158
|
+
const handler = typeof config.logger === 'object' ? config.logger.handler : undefined;
|
|
159
|
+
Logger.logRequest(method, url, 404, duration, undefined, handler);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
console.log(`Registered global Not Found handler`);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Resets RouterKit state — berguna untuk testing agar state bersih antar test.
|
|
166
|
+
* @internal
|
|
167
|
+
*/
|
|
168
|
+
static reset() {
|
|
169
|
+
RouterKit.adapter = null;
|
|
170
|
+
RouterKit.resolver = null;
|
|
171
|
+
RouterKit.config = null;
|
|
172
|
+
RouterKit.isSetup = false;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=RouterKit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RouterKit.js","sourceRoot":"","sources":["../../core/RouterKit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ControllerOptions } from "../../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Marks a class as a route controller with a base path and optional configuration.
|
|
4
|
+
*
|
|
5
|
+
* Menyimpan metadata controller ke `context.metadata` via TC39 native decorator.
|
|
6
|
+
* Semua route dalam class ini akan mewarisi `authentication` dan `tag` dari sini.
|
|
7
|
+
*
|
|
8
|
+
* @param basePath - Base URL path untuk semua route di controller ini.
|
|
9
|
+
* Akan otomatis diprefiks dengan "/" jika tidak ada.
|
|
10
|
+
* @param options - Opsi tambahan untuk controller.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* @ReqController("/users", { authentication: "auth", tag: "User Management" })
|
|
15
|
+
* class UserController {
|
|
16
|
+
* // semua route inheritance authentication: "auth"
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* @ReqController("/public")
|
|
23
|
+
* class PublicController {
|
|
24
|
+
* // authentication: false (default)
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function ReqController(basePath: string, options?: ControllerOptions): (_value: Function, context: ClassDecoratorContext) => void;
|
|
29
|
+
//# sourceMappingURL=ReqController.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReqController.d.ts","sourceRoot":"","sources":["../../../decorators/controller/ReqController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAsB,MAAM,sBAAsB,CAAC;AAGlF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,IACxD,QAAQ,QAAQ,EAAE,SAAS,qBAAqB,UAalE"}
|