@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
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"}
|