@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.
Files changed (90) hide show
  1. package/README.md +302 -0
  2. package/dist/adapters/BaseAdapter.d.ts +63 -0
  3. package/dist/adapters/BaseAdapter.d.ts.map +1 -0
  4. package/dist/adapters/BaseAdapter.js +17 -0
  5. package/dist/adapters/BaseAdapter.js.map +1 -0
  6. package/dist/adapters/ExpressAdapter.d.ts +44 -0
  7. package/dist/adapters/ExpressAdapter.d.ts.map +1 -0
  8. package/dist/adapters/ExpressAdapter.js +73 -0
  9. package/dist/adapters/ExpressAdapter.js.map +1 -0
  10. package/dist/adapters/FastifyAdapter.d.ts +61 -0
  11. package/dist/adapters/FastifyAdapter.d.ts.map +1 -0
  12. package/dist/adapters/FastifyAdapter.js +132 -0
  13. package/dist/adapters/FastifyAdapter.js.map +1 -0
  14. package/dist/cookie/CookieSetter.d.ts +74 -0
  15. package/dist/cookie/CookieSetter.d.ts.map +1 -0
  16. package/dist/cookie/CookieSetter.js +89 -0
  17. package/dist/cookie/CookieSetter.js.map +1 -0
  18. package/dist/core/Logger.d.ts +36 -0
  19. package/dist/core/Logger.d.ts.map +1 -0
  20. package/dist/core/Logger.js +53 -0
  21. package/dist/core/Logger.js.map +1 -0
  22. package/dist/core/RouteResolver.d.ts +91 -0
  23. package/dist/core/RouteResolver.d.ts.map +1 -0
  24. package/dist/core/RouteResolver.js +279 -0
  25. package/dist/core/RouteResolver.js.map +1 -0
  26. package/dist/core/RouterKit.d.ts +116 -0
  27. package/dist/core/RouterKit.d.ts.map +1 -0
  28. package/dist/core/RouterKit.js +175 -0
  29. package/dist/core/RouterKit.js.map +1 -0
  30. package/dist/decorators/controller/ReqController.d.ts +29 -0
  31. package/dist/decorators/controller/ReqController.d.ts.map +1 -0
  32. package/dist/decorators/controller/ReqController.js +62 -0
  33. package/dist/decorators/controller/ReqController.js.map +1 -0
  34. package/dist/decorators/mapping/index.d.ts +93 -0
  35. package/dist/decorators/mapping/index.d.ts.map +1 -0
  36. package/dist/decorators/mapping/index.js +128 -0
  37. package/dist/decorators/mapping/index.js.map +1 -0
  38. package/dist/decorators/method/index.d.ts +67 -0
  39. package/dist/decorators/method/index.d.ts.map +1 -0
  40. package/dist/decorators/method/index.js +83 -0
  41. package/dist/decorators/method/index.js.map +1 -0
  42. package/dist/decorators/parameter/index.d.ts +155 -0
  43. package/dist/decorators/parameter/index.d.ts.map +1 -0
  44. package/dist/decorators/parameter/index.js +196 -0
  45. package/dist/decorators/parameter/index.js.map +1 -0
  46. package/dist/exceptions/BadRequestException.d.ts +37 -0
  47. package/dist/exceptions/BadRequestException.d.ts.map +1 -0
  48. package/dist/exceptions/BadRequestException.js +37 -0
  49. package/dist/exceptions/BadRequestException.js.map +1 -0
  50. package/dist/exceptions/BaseException.d.ts +29 -0
  51. package/dist/exceptions/BaseException.d.ts.map +1 -0
  52. package/dist/exceptions/BaseException.js +29 -0
  53. package/dist/exceptions/BaseException.js.map +1 -0
  54. package/dist/exceptions/ConflictException.d.ts +28 -0
  55. package/dist/exceptions/ConflictException.d.ts.map +1 -0
  56. package/dist/exceptions/ConflictException.js +28 -0
  57. package/dist/exceptions/ConflictException.js.map +1 -0
  58. package/dist/exceptions/ForbiddenException.d.ts +26 -0
  59. package/dist/exceptions/ForbiddenException.d.ts.map +1 -0
  60. package/dist/exceptions/ForbiddenException.js +26 -0
  61. package/dist/exceptions/ForbiddenException.js.map +1 -0
  62. package/dist/exceptions/NotFoundException.d.ts +28 -0
  63. package/dist/exceptions/NotFoundException.d.ts.map +1 -0
  64. package/dist/exceptions/NotFoundException.js +28 -0
  65. package/dist/exceptions/NotFoundException.js.map +1 -0
  66. package/dist/exceptions/ServerErrorException.d.ts +33 -0
  67. package/dist/exceptions/ServerErrorException.d.ts.map +1 -0
  68. package/dist/exceptions/ServerErrorException.js +33 -0
  69. package/dist/exceptions/ServerErrorException.js.map +1 -0
  70. package/dist/exceptions/UnauthorizedException.d.ts +28 -0
  71. package/dist/exceptions/UnauthorizedException.d.ts.map +1 -0
  72. package/dist/exceptions/UnauthorizedException.js +28 -0
  73. package/dist/exceptions/UnauthorizedException.js.map +1 -0
  74. package/dist/index.d.ts +15 -0
  75. package/dist/index.d.ts.map +1 -0
  76. package/dist/index.js +21 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/swagger/SwaggerGenerator.d.ts +63 -0
  79. package/dist/swagger/SwaggerGenerator.d.ts.map +1 -0
  80. package/dist/swagger/SwaggerGenerator.js +266 -0
  81. package/dist/swagger/SwaggerGenerator.js.map +1 -0
  82. package/dist/swagger/SwaggerUI.d.ts +30 -0
  83. package/dist/swagger/SwaggerUI.d.ts.map +1 -0
  84. package/dist/swagger/SwaggerUI.js +52 -0
  85. package/dist/swagger/SwaggerUI.js.map +1 -0
  86. package/dist/types/index.d.ts +255 -0
  87. package/dist/types/index.d.ts.map +1 -0
  88. package/dist/types/index.js +31 -0
  89. package/dist/types/index.js.map +1 -0
  90. package/package.json +52 -0
package/README.md ADDED
@@ -0,0 +1,302 @@
1
+ # @alis-kit/routers
2
+
3
+ A TC39 native decorator-based controller library for Node.js APIs. Supports **Express** and **Fastify**, includes **Zod-based request validation**, structured **exception handling**, optional **Swagger UI** generation, and **cookie management**.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @alis-kit/routers zod
9
+ ```
10
+
11
+ > **Note:** You also need one of the supported frameworks:
12
+ > ```bash
13
+ > npm install express # for Express
14
+ > npm install fastify # for Fastify
15
+ > ```
16
+
17
+ ## Requirements
18
+
19
+ - **Node.js** >= 18
20
+ - **TypeScript** >= 5.2
21
+
22
+ No `reflect-metadata` needed — this library uses **TC39 native decorators** (stage 3):
23
+
24
+ ```json
25
+ {
26
+ "compilerOptions": {
27
+ "experimentalDecorators": false,
28
+ "useDefineForClassFields": true,
29
+ "strict": true
30
+ }
31
+ }
32
+ ```
33
+
34
+ ---
35
+
36
+ ## Quick Start
37
+
38
+ ```typescript
39
+ import express from "express";
40
+ import { RouterKit, ReqController, GetMapping, PostMapping } from "@alis-kit/routers";
41
+
42
+ @ReqController("/hello")
43
+ class HelloController {
44
+ @GetMapping("/")
45
+ async sayHello() {
46
+ return { greeting: "Hello, World!" };
47
+ }
48
+ }
49
+
50
+ const app = express();
51
+ app.use(express.json());
52
+
53
+ RouterKit.setup({
54
+ framework: "express",
55
+ app,
56
+ swagger: { enabled: true, path: "/api/docs" },
57
+ });
58
+
59
+ RouterKit.register(HelloController);
60
+
61
+ app.listen(3000, () => console.log("Server running on port 3000"));
62
+ ```
63
+
64
+ ---
65
+
66
+ ## API Reference
67
+
68
+ ### `RouterKit`
69
+
70
+ Central setup class. Configured once at application entry point.
71
+
72
+ ```typescript
73
+ RouterKit.setup(config: RouterKitConfig): void
74
+ RouterKit.register(...controllers: Class[]): void
75
+ RouterKit.handleNotFound(): void
76
+ ```
77
+
78
+ **Configuration:**
79
+
80
+ ```typescript
81
+ interface RouterKitConfig {
82
+ framework: "express" | "fastify";
83
+ app: express.Application | FastifyInstance;
84
+ authMiddleware?: MiddlewareFn; // for authentication: "auth"
85
+ refreshMiddleware?: MiddlewareFn; // for authentication: "refresh"
86
+ swagger?: {
87
+ enabled: boolean;
88
+ path?: string; // default: "/api/docs"
89
+ title?: string; // default: "API Documentation"
90
+ version?: string; // default: "1.0.0"
91
+ sortBy?: "path" | "method";
92
+ searchByPath?: boolean;
93
+ searchByMethod?: boolean;
94
+ searchByTag?: boolean;
95
+ };
96
+ logger?: boolean | {
97
+ enabled?: boolean;
98
+ handler?: (level: "info" | "error", message: string, meta: LoggerMeta) => void;
99
+ };
100
+ responseEnvelope?: "wrap" | "raw"; // "wrap" (default) or "raw"
101
+ globalPrefix?: string; // e.g. "/api"
102
+ }
103
+ ```
104
+
105
+ ### `@ReqController(basePath, options?)`
106
+
107
+ Marks a class as a route controller with a base path and default authentication.
108
+
109
+ ```typescript
110
+ @ReqController("/users", { authentication: "auth", tag: "User Management" })
111
+ class UserController { ... }
112
+ ```
113
+
114
+ **Options:**
115
+ | Option | Type | Default | Description |
116
+ |---|---|---|---|
117
+ | `authentication` | `"auth" \| "refresh" \| false` | `false` | Default auth for all routes |
118
+ | `tag` | `string` | Derived from class name | Swagger tag |
119
+ | `swagger` | `boolean` | `true` | Include in Swagger docs |
120
+
121
+ ### Method Mapping Decorators
122
+
123
+ ```typescript
124
+ @GetMapping(path, options?)
125
+ @PostMapping(path, options?)
126
+ @PutMapping(path, options?)
127
+ @PatchMapping(path, options?)
128
+ @DeleteMapping(path, options?)
129
+ ```
130
+
131
+ **Options:**
132
+ | Option | Type | Description |
133
+ |---|---|---|
134
+ | `authentication` | `"auth" \| "refresh" \| false` | Override controller-level auth |
135
+ | `swagger` | `boolean` | Include in Swagger docs |
136
+ | `tag` | `string` | Override controller tag |
137
+ | `summary` | `string` | Swagger summary |
138
+ | `description` | `string` | Swagger description |
139
+ | `status` | `number` | Default response status code |
140
+
141
+ ### Parameter Decorators
142
+
143
+ | Decorator | Description |
144
+ |---|---|
145
+ | `@Body(schema?)` | Injects and validates `req.body` with Zod |
146
+ | `@Query(schema?)` | Injects and validates `req.query` with Zod |
147
+ | `@Param(key)` | Injects a single route parameter |
148
+ | `@Req()` | Injects the raw request object |
149
+ | `@Cookie()` | Injects a `CookieSetter` instance |
150
+ | `@Reply()` | Injects the raw framework reply object (FastifyReply / express.Response) |
151
+
152
+ ### Method Decorators
153
+
154
+ | Decorator | Description |
155
+ |---|---|
156
+ | `@UseMiddleware(...fns)` | Applies middleware to a route |
157
+ | `@HttpStatus(code)` | Sets default response status code |
158
+
159
+ ### Exceptions
160
+
161
+ All exceptions extend `BaseException` and auto-send the appropriate HTTP response.
162
+
163
+ | Exception | Status | Code |
164
+ |---|---|---|
165
+ | `BadRequestException` | 400 | `BAD_REQUEST` |
166
+ | `UnauthorizedException` | 401 | `UNAUTHORIZED` |
167
+ | `ForbiddenException` | 403 | `FORBIDDEN` |
168
+ | `NotFoundException` | 404 | `NOT_FOUND` |
169
+ | `ConflictException` | 409 | `CONFLICT` |
170
+ | `ServerErrorException` | 500 | `INTERNAL_ERROR` |
171
+
172
+ ### `CookieSetter`
173
+
174
+ Injected via `@Cookie()`. Abstracts cookie operations across frameworks.
175
+
176
+ ```typescript
177
+ cookie.set(key, value, options?) // Set a cookie
178
+ cookie.get(key) // Get a cookie value
179
+ cookie.delete(key) // Delete a cookie
180
+ ```
181
+
182
+ ---
183
+
184
+ ## Full Usage Example
185
+
186
+ ```typescript
187
+ import express from "express";
188
+ import { z } from "zod";
189
+ import {
190
+ RouterKit,
191
+ ReqController,
192
+ GetMapping, PostMapping, PutMapping, DeleteMapping,
193
+ Body, Query, Param, Req, Cookie,
194
+ UseMiddleware, HttpStatus,
195
+ BadRequestException, NotFoundException, ConflictException,
196
+ CookieSetter,
197
+ } from "@alis-kit/routers";
198
+
199
+ // ── Zod Schemas ───────────────────────────────────────────────────
200
+
201
+ const CreateUserSchema = z.object({
202
+ firstName: z.string().min(1),
203
+ lastName: z.string().min(1),
204
+ email: z.string().email(),
205
+ age: z.coerce.number().min(1),
206
+ });
207
+
208
+ const UserQuerySchema = z.object({
209
+ page: z.coerce.number().default(1),
210
+ size: z.coerce.number().default(10),
211
+ search: z.string().optional(),
212
+ });
213
+
214
+ // ── Controllers ───────────────────────────────────────────────────
215
+
216
+ @ReqController("/auth", { tag: "Authentication", authentication: false })
217
+ class AuthController {
218
+ @PostMapping("/login", { summary: "Login user" })
219
+ async login(
220
+ @Body(z.object({ email: z.string().email(), password: z.string().min(6) })) body: { email: string; password: string },
221
+ @Cookie() cookie: CookieSetter
222
+ ) {
223
+ cookie.set("refresh_token", "token-value", { httpOnly: true, secure: true });
224
+ return { accessToken: "jwt-token" };
225
+ }
226
+ }
227
+
228
+ @ReqController("/users", { authentication: "auth", tag: "User Management" })
229
+ class UserController {
230
+ @GetMapping("/", { summary: "Get all users with pagination" })
231
+ async getAll(@Query(UserQuerySchema) query: { page: number; size: number; search?: string }) {
232
+ // return await UserService.findAll(query);
233
+ }
234
+
235
+ @GetMapping("/:id", { summary: "Get user by ID" })
236
+ async getById(@Param("id") id: string) {
237
+ // if (!user) throw new NotFoundException("User not found");
238
+ }
239
+
240
+ @PostMapping("/", { authentication: false, summary: "Register new user" })
241
+ @HttpStatus(201)
242
+ async create(@Body(CreateUserSchema) body: { firstName: string; lastName: string; email: string; age: number }) {
243
+ // return await UserService.create(body);
244
+ }
245
+
246
+ @PutMapping("/:id", { summary: "Update user" })
247
+ async update(@Param("id") id: string, @Body(CreateUserSchema.partial()) body: Partial<{ firstName: string; lastName: string; email: string; age: number }>) {
248
+ // return await UserService.update(id, body);
249
+ }
250
+
251
+ @DeleteMapping("/:id", { summary: "Delete user" })
252
+ async delete(@Param("id") id: string) {
253
+ // return await UserService.delete(id);
254
+ }
255
+ }
256
+
257
+ // ── App Setup ─────────────────────────────────────────────────────
258
+
259
+ const app = express();
260
+ app.use(express.json());
261
+
262
+ RouterKit.setup({
263
+ framework: "express",
264
+ app,
265
+ swagger: { enabled: true, path: "/api/docs", title: "My API", version: "1.0.0" },
266
+ });
267
+
268
+ RouterKit.register(AuthController, UserController);
269
+ RouterKit.handleNotFound();
270
+
271
+ app.listen(3000, () => console.log("Server running on port 3000"));
272
+ ```
273
+
274
+ ### Response Format
275
+
276
+ **Success:**
277
+ ```json
278
+ { "message": "OK", "data": { "_id": "...", "firstName": "Dudi" } }
279
+ ```
280
+
281
+ **Error:**
282
+ ```json
283
+ { "message": "User not found", "data": null }
284
+ ```
285
+
286
+ ---
287
+
288
+ ## Architecture
289
+
290
+ This library follows a **Functional Core + Decorator Sugar** pattern:
291
+
292
+ - **`core/`** — All logic lives here: route resolution, parameter injection, Zod validation, error handling
293
+ - **`decorators/`** — Pure metadata writers using TC39 native decorators (`context.metadata`)
294
+ - **`adapters/`** — Framework-agnostic adapters for Express and Fastify
295
+
296
+ See `ARCHITECTURE-RULES.md` for detailed guidelines.
297
+
298
+ ---
299
+
300
+ ## License
301
+
302
+ MIT
@@ -0,0 +1,63 @@
1
+ import type { HttpMethod, MiddlewareFn, CookieOptions } from "../types/index.js";
2
+ /**
3
+ * Abstract adapter interface untuk framework-agnostic route registration.
4
+ *
5
+ * Setiap framework (Express, Fastify, dll) perlu mengimplementasikan class ini.
6
+ * RouteResolver hanya berkomunikasi melalui BaseAdapter — tidak pernah
7
+ * langsung menyentuh Express/Fastify API.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * class KoaAdapter extends BaseAdapter {
12
+ * // implement semua abstract method
13
+ * }
14
+ * ```
15
+ */
16
+ export declare abstract class BaseAdapter {
17
+ /**
18
+ * Framework application instance (raw).
19
+ * Contoh: Express `app`, Fastify instance, dll.
20
+ */
21
+ abstract readonly app: unknown;
22
+ /**
23
+ * Registers a route on the framework instance.
24
+ *
25
+ * @param method - HTTP method (get, post, put, patch, delete)
26
+ * @param path - Route path (contoh: "/users/:id")
27
+ * @param middlewares - Array middleware yang dijalankan sebelum handler
28
+ * @param handler - Route handler utama
29
+ */
30
+ abstract registerRoute(method: HttpMethod, path: string, middlewares: MiddlewareFn[], handler: (req: unknown, res: unknown, next?: unknown) => void): void;
31
+ /** Extracts the request body from the framework's request object */
32
+ abstract getBody(req: unknown): unknown;
33
+ /** Extracts the query parameters from the framework's request object */
34
+ abstract getQuery(req: unknown): unknown;
35
+ /** Extracts the route parameters (contoh: `:id` → `{ id: "123" }`) */
36
+ abstract getParams(req: unknown): Record<string, string>;
37
+ /** Extracts the request headers */
38
+ abstract getHeaders(req: unknown): Record<string, string>;
39
+ /** Extracts cookies from the request */
40
+ abstract getCookies(req: unknown): Record<string, string>;
41
+ /**
42
+ * Sets a cookie on the response.
43
+ * @param res - Framework response object
44
+ * @param key - Cookie name
45
+ * @param value - Cookie value
46
+ * @param options - Cookie configuration (httpOnly, secure, maxAge, path, sameSite)
47
+ */
48
+ abstract setCookie(res: unknown, key: string, value: string, options: CookieOptions): void;
49
+ /** Deletes a cookie by key (sets empty value with expired date) */
50
+ abstract deleteCookie(res: unknown, key: string): void;
51
+ /** Extracts request URL path (contoh: "/users/123") */
52
+ abstract getUrl(req: unknown): string;
53
+ /** Extracts request HTTP method string (GET, POST, dll) */
54
+ abstract getMethod(req: unknown): string;
55
+ /** Sends a JSON response with the given status code and body */
56
+ abstract sendResponse(res: unknown, status: number, body: unknown): void;
57
+ /**
58
+ * Registers a catch-all handler for unmatched routes (404 Not Found).
59
+ * @param handler - Handler yang dipanggil saat route tidak ditemukan
60
+ */
61
+ abstract registerNotFoundHandler(handler: (req: unknown, res: unknown) => void): void;
62
+ }
63
+ //# sourceMappingURL=BaseAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseAdapter.d.ts","sourceRoot":"","sources":["../../adapters/BaseAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEjF;;;;;;;;;;;;;GAaG;AACH,8BAAsB,WAAW;IAC/B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IAE/B;;;;;;;OAOG;IACH,QAAQ,CAAC,aAAa,CACpB,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,YAAY,EAAE,EAC3B,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,GAC5D,IAAI;IAEP,oEAAoE;IACpE,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO;IAEvC,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO;IAExC,sEAAsE;IACtE,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAExD,mCAAmC;IACnC,QAAQ,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAEzD,wCAAwC;IACxC,QAAQ,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAEzD;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI;IAE1F,mEAAmE;IACnE,QAAQ,CAAC,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAEtD,uDAAuD;IACvD,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM;IAErC,2DAA2D;IAC3D,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM;IAExC,gEAAgE;IAChE,QAAQ,CAAC,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI;IAExE;;;OAGG;IACH,QAAQ,CAAC,uBAAuB,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;CACtF"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Abstract adapter interface untuk framework-agnostic route registration.
3
+ *
4
+ * Setiap framework (Express, Fastify, dll) perlu mengimplementasikan class ini.
5
+ * RouteResolver hanya berkomunikasi melalui BaseAdapter — tidak pernah
6
+ * langsung menyentuh Express/Fastify API.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * class KoaAdapter extends BaseAdapter {
11
+ * // implement semua abstract method
12
+ * }
13
+ * ```
14
+ */
15
+ export class BaseAdapter {
16
+ }
17
+ //# sourceMappingURL=BaseAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseAdapter.js","sourceRoot":"","sources":["../../adapters/BaseAdapter.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAgB,WAAW;CA+DhC"}
@@ -0,0 +1,44 @@
1
+ import { BaseAdapter } from "./BaseAdapter.js";
2
+ import type { HttpMethod, MiddlewareFn, CookieOptions } from "../types/index.js";
3
+ /** Express-like application interface */
4
+ interface ExpressApp {
5
+ get(path: string, ...handlers: unknown[]): void;
6
+ post(path: string, ...handlers: unknown[]): void;
7
+ put(path: string, ...handlers: unknown[]): void;
8
+ patch(path: string, ...handlers: unknown[]): void;
9
+ delete(path: string, ...handlers: unknown[]): void;
10
+ use(path: string, ...handlers: unknown[]): void;
11
+ }
12
+ /**
13
+ * Express.js adapter implementation.
14
+ *
15
+ * Mengkonversi method+middleware+handler Express-style ke route registration.
16
+ * Digunakan oleh RouteResolver saat framework yang dipilih adalah "express".
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * const app = express();
21
+ * const adapter = new ExpressAdapter(app);
22
+ * adapter.registerRoute("get", "/hello", [], (req, res) => {
23
+ * res.status(200).json({ message: "OK" });
24
+ * });
25
+ * ```
26
+ */
27
+ export declare class ExpressAdapter extends BaseAdapter {
28
+ readonly app: ExpressApp;
29
+ constructor(app: unknown);
30
+ registerRoute(method: HttpMethod, path: string, middlewares: MiddlewareFn[], handler: (req: unknown, res: unknown, next?: unknown) => void): void;
31
+ getBody(req: unknown): unknown;
32
+ getQuery(req: unknown): unknown;
33
+ getParams(req: unknown): Record<string, string>;
34
+ getHeaders(req: unknown): Record<string, string>;
35
+ getCookies(req: unknown): Record<string, string>;
36
+ setCookie(res: unknown, key: string, value: string, options: CookieOptions): void;
37
+ deleteCookie(res: unknown, key: string): void;
38
+ getUrl(req: unknown): string;
39
+ getMethod(req: unknown): string;
40
+ sendResponse(res: unknown, status: number, body: unknown): void;
41
+ registerNotFoundHandler(handler: (req: unknown, res: unknown) => void): void;
42
+ }
43
+ export {};
44
+ //# sourceMappingURL=ExpressAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpressAdapter.d.ts","sourceRoot":"","sources":["../../adapters/ExpressAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAmBjF,yCAAyC;AACzC,UAAU,UAAU;IAClB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChD,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IACjD,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAClD,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IACnD,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CACjD;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,cAAe,SAAQ,WAAW;IAC7C,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;gBAEb,GAAG,EAAE,OAAO;IAKxB,aAAa,CACX,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,YAAY,EAAE,EAC3B,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,GAC5D,IAAI;IAKP,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO;IAI9B,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO;IAI/B,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAI/C,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAIhD,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAIhD,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI;IAWjF,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAK7C,MAAM,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM;IAK5B,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM;IAI/B,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI;IAK/D,uBAAuB,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;CAK7E"}
@@ -0,0 +1,73 @@
1
+ import { BaseAdapter } from "./BaseAdapter.js";
2
+ /**
3
+ * Express.js adapter implementation.
4
+ *
5
+ * Mengkonversi method+middleware+handler Express-style ke route registration.
6
+ * Digunakan oleh RouteResolver saat framework yang dipilih adalah "express".
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const app = express();
11
+ * const adapter = new ExpressAdapter(app);
12
+ * adapter.registerRoute("get", "/hello", [], (req, res) => {
13
+ * res.status(200).json({ message: "OK" });
14
+ * });
15
+ * ```
16
+ */
17
+ export class ExpressAdapter extends BaseAdapter {
18
+ app;
19
+ constructor(app) {
20
+ super();
21
+ this.app = app;
22
+ }
23
+ registerRoute(method, path, middlewares, handler) {
24
+ const routeHandler = this.app[method].bind(this.app);
25
+ routeHandler(path, ...middlewares, handler);
26
+ }
27
+ getBody(req) {
28
+ return req.body;
29
+ }
30
+ getQuery(req) {
31
+ return req.query;
32
+ }
33
+ getParams(req) {
34
+ return req.params;
35
+ }
36
+ getHeaders(req) {
37
+ return req.headers;
38
+ }
39
+ getCookies(req) {
40
+ return req.cookies ?? {};
41
+ }
42
+ setCookie(res, key, value, options) {
43
+ const expressRes = res;
44
+ expressRes.cookie(key, value, {
45
+ httpOnly: options.httpOnly,
46
+ secure: options.secure,
47
+ maxAge: options.maxAge ? options.maxAge * 1000 : undefined,
48
+ path: options.path,
49
+ sameSite: options.sameSite,
50
+ });
51
+ }
52
+ deleteCookie(res, key) {
53
+ const expressRes = res;
54
+ expressRes.clearCookie(key, { path: "/" });
55
+ }
56
+ getUrl(req) {
57
+ const r = req;
58
+ return r.originalUrl || r.url || "";
59
+ }
60
+ getMethod(req) {
61
+ return req.method || "UNKNOWN";
62
+ }
63
+ sendResponse(res, status, body) {
64
+ const expressRes = res;
65
+ expressRes.status(status).json(body);
66
+ }
67
+ registerNotFoundHandler(handler) {
68
+ this.app.use("*", (req, res) => {
69
+ handler(req, res);
70
+ });
71
+ }
72
+ }
73
+ //# sourceMappingURL=ExpressAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpressAdapter.js","sourceRoot":"","sources":["../../adapters/ExpressAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AA8B/C;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,cAAe,SAAQ,WAAW;IACpC,GAAG,CAAa;IAEzB,YAAY,GAAY;QACtB,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,GAAG,GAAG,GAAiB,CAAC;IAC/B,CAAC;IAED,aAAa,CACX,MAAkB,EAClB,IAAY,EACZ,WAA2B,EAC3B,OAA6D;QAE7D,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrD,YAAY,CAAC,IAAI,EAAE,GAAG,WAAW,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,CAAC,GAAY;QAClB,OAAQ,GAAsB,CAAC,IAAI,CAAC;IACtC,CAAC;IAED,QAAQ,CAAC,GAAY;QACnB,OAAQ,GAAsB,CAAC,KAAK,CAAC;IACvC,CAAC;IAED,SAAS,CAAC,GAAY;QACpB,OAAQ,GAAsB,CAAC,MAAM,CAAC;IACxC,CAAC;IAED,UAAU,CAAC,GAAY;QACrB,OAAQ,GAAsB,CAAC,OAAO,CAAC;IACzC,CAAC;IAED,UAAU,CAAC,GAAY;QACrB,OAAQ,GAAsB,CAAC,OAAO,IAAI,EAAE,CAAC;IAC/C,CAAC;IAED,SAAS,CAAC,GAAY,EAAE,GAAW,EAAE,KAAa,EAAE,OAAsB;QACxE,MAAM,UAAU,GAAG,GAAsB,CAAC;QAC1C,UAAU,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,EAAE;YAC5B,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS;YAC1D,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC3B,CAAC,CAAC;IACL,CAAC;IAED,YAAY,CAAC,GAAY,EAAE,GAAW;QACpC,MAAM,UAAU,GAAG,GAAsB,CAAC;QAC1C,UAAU,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED,MAAM,CAAC,GAAY;QACjB,MAAM,CAAC,GAAG,GAA6C,CAAC;QACxD,OAAO,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC;IACtC,CAAC;IAED,SAAS,CAAC,GAAY;QACpB,OAAQ,GAA2B,CAAC,MAAM,IAAI,SAAS,CAAC;IAC1D,CAAC;IAED,YAAY,CAAC,GAAY,EAAE,MAAc,EAAE,IAAa;QACtD,MAAM,UAAU,GAAG,GAAsB,CAAC;QAC1C,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC;IAED,uBAAuB,CAAC,OAA6C;QACnE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAY,EAAE,GAAY,EAAE,EAAE;YAC/C,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,61 @@
1
+ import { BaseAdapter } from "./BaseAdapter.js";
2
+ import type { HttpMethod, MiddlewareFn, CookieOptions } from "../types/index.js";
3
+ /** Fastify-like application interface */
4
+ interface FastifyApp {
5
+ get(path: string, options: Record<string, unknown>, handler: unknown): void;
6
+ post(path: string, options: Record<string, unknown>, handler: unknown): void;
7
+ put(path: string, options: Record<string, unknown>, handler: unknown): void;
8
+ patch(path: string, options: Record<string, unknown>, handler: unknown): void;
9
+ delete(path: string, options: Record<string, unknown>, handler: unknown): void;
10
+ addHook(name: string, hook: unknown): void;
11
+ setNotFoundHandler(handler: unknown): void;
12
+ }
13
+ /**
14
+ * Fastify adapter implementation.
15
+ *
16
+ * Middleware Express-style dikonversi ke Fastify `preHandler` hooks.
17
+ * Handler di-await dan reply di-return untuk mencegah Fastify auto-send.
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const fastify = Fastify();
22
+ * const adapter = new FastifyAdapter(fastify);
23
+ * adapter.registerRoute("get", "/hello", [], async (req, reply) => {
24
+ * reply.code(200).send({ message: "OK" });
25
+ * });
26
+ * ```
27
+ */
28
+ export declare class FastifyAdapter extends BaseAdapter {
29
+ readonly app: FastifyApp;
30
+ constructor(app: unknown);
31
+ /**
32
+ * Fastify route handler signature berbeda dari Express.
33
+ * Middleware dikonversi ke preHandler, handler di-await.
34
+ */
35
+ registerRoute(method: HttpMethod, path: string, middlewares: MiddlewareFn[], handler: (req: unknown, res: unknown) => void): void;
36
+ getBody(req: unknown): unknown;
37
+ getQuery(req: unknown): unknown;
38
+ getParams(req: unknown): Record<string, string>;
39
+ getHeaders(req: unknown): Record<string, string>;
40
+ getCookies(req: unknown): Record<string, string>;
41
+ /**
42
+ * Sets a cookie on Fastify reply.
43
+ * Fallback ke manual Set-Cookie header jika `setCookie` tidak tersedia.
44
+ */
45
+ setCookie(res: unknown, key: string, value: string, options: CookieOptions): void;
46
+ /**
47
+ * Deletes a cookie on Fastify reply.
48
+ * Fallback ke Expires header manual jika `clearCookie` tidak tersedia.
49
+ */
50
+ deleteCookie(res: unknown, key: string): void;
51
+ getUrl(req: unknown): string;
52
+ getMethod(req: unknown): string;
53
+ sendResponse(res: unknown, status: number, body: unknown): void;
54
+ /**
55
+ * Fastify memiliki `setNotFoundHandler` native. Jika tidak ada,
56
+ * fallback ke warning — tidak runtime error.
57
+ */
58
+ registerNotFoundHandler(handler: (req: unknown, res: unknown) => void): void;
59
+ }
60
+ export {};
61
+ //# sourceMappingURL=FastifyAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FastifyAdapter.d.ts","sourceRoot":"","sources":["../../adapters/FastifyAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAqBjF,yCAAyC;AACzC,UAAU,UAAU;IAClB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5E,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAC7E,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5E,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9E,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/E,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3C,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;CAC5C;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,cAAe,SAAQ,WAAW;IAC7C,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;gBAEb,GAAG,EAAE,OAAO;IAKxB;;;OAGG;IACH,aAAa,CACX,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,YAAY,EAAE,EAC3B,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,GAC5C,IAAI;IAqBP,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO;IAI9B,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO;IAI/B,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAI/C,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAIhD,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAIhD;;;OAGG;IACH,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI;IAqBjF;;;OAGG;IACH,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAS7C,MAAM,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM;IAK5B,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM;IAK/B,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI;IAK/D;;;OAGG;IACH,uBAAuB,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;CAS7E"}