@riktajs/swagger 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +258 -0
- package/dist/constants.d.ts +56 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +61 -0
- package/dist/constants.js.map +1 -0
- package/dist/decorators/api-body.decorator.d.ts +33 -0
- package/dist/decorators/api-body.decorator.d.ts.map +1 -0
- package/dist/decorators/api-body.decorator.js +40 -0
- package/dist/decorators/api-body.decorator.js.map +1 -0
- package/dist/decorators/api-exclude.decorator.d.ts +71 -0
- package/dist/decorators/api-exclude.decorator.d.ts.map +1 -0
- package/dist/decorators/api-exclude.decorator.js +95 -0
- package/dist/decorators/api-exclude.decorator.js.map +1 -0
- package/dist/decorators/api-header.decorator.d.ts +25 -0
- package/dist/decorators/api-header.decorator.d.ts.map +1 -0
- package/dist/decorators/api-header.decorator.js +33 -0
- package/dist/decorators/api-header.decorator.js.map +1 -0
- package/dist/decorators/api-operation.decorator.d.ts +32 -0
- package/dist/decorators/api-operation.decorator.d.ts.map +1 -0
- package/dist/decorators/api-operation.decorator.js +39 -0
- package/dist/decorators/api-operation.decorator.js.map +1 -0
- package/dist/decorators/api-param.decorator.d.ts +28 -0
- package/dist/decorators/api-param.decorator.d.ts.map +1 -0
- package/dist/decorators/api-param.decorator.js +36 -0
- package/dist/decorators/api-param.decorator.js.map +1 -0
- package/dist/decorators/api-property.decorator.d.ts +69 -0
- package/dist/decorators/api-property.decorator.d.ts.map +1 -0
- package/dist/decorators/api-property.decorator.js +76 -0
- package/dist/decorators/api-property.decorator.js.map +1 -0
- package/dist/decorators/api-query.decorator.d.ts +30 -0
- package/dist/decorators/api-query.decorator.d.ts.map +1 -0
- package/dist/decorators/api-query.decorator.js +38 -0
- package/dist/decorators/api-query.decorator.js.map +1 -0
- package/dist/decorators/api-response.decorator.d.ts +70 -0
- package/dist/decorators/api-response.decorator.d.ts.map +1 -0
- package/dist/decorators/api-response.decorator.js +100 -0
- package/dist/decorators/api-response.decorator.js.map +1 -0
- package/dist/decorators/api-security.decorator.d.ts +88 -0
- package/dist/decorators/api-security.decorator.d.ts.map +1 -0
- package/dist/decorators/api-security.decorator.js +119 -0
- package/dist/decorators/api-security.decorator.js.map +1 -0
- package/dist/decorators/api-tags.decorator.d.ts +31 -0
- package/dist/decorators/api-tags.decorator.d.ts.map +1 -0
- package/dist/decorators/api-tags.decorator.js +52 -0
- package/dist/decorators/api-tags.decorator.js.map +1 -0
- package/dist/decorators/index.d.ts +16 -0
- package/dist/decorators/index.d.ts.map +1 -0
- package/dist/decorators/index.js +24 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +68 -0
- package/dist/index.js.map +1 -0
- package/dist/openapi/generator.d.ts +98 -0
- package/dist/openapi/generator.d.ts.map +1 -0
- package/dist/openapi/generator.js +493 -0
- package/dist/openapi/generator.js.map +1 -0
- package/dist/openapi/index.d.ts +8 -0
- package/dist/openapi/index.d.ts.map +1 -0
- package/dist/openapi/index.js +11 -0
- package/dist/openapi/index.js.map +1 -0
- package/dist/openapi/zod-to-openapi.d.ts +52 -0
- package/dist/openapi/zod-to-openapi.d.ts.map +1 -0
- package/dist/openapi/zod-to-openapi.js +172 -0
- package/dist/openapi/zod-to-openapi.js.map +1 -0
- package/dist/plugin/index.d.ts +7 -0
- package/dist/plugin/index.d.ts.map +1 -0
- package/dist/plugin/index.js +7 -0
- package/dist/plugin/index.js.map +1 -0
- package/dist/plugin/swagger.plugin.d.ts +157 -0
- package/dist/plugin/swagger.plugin.d.ts.map +1 -0
- package/dist/plugin/swagger.plugin.js +235 -0
- package/dist/plugin/swagger.plugin.js.map +1 -0
- package/dist/types.d.ts +511 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# @riktajs/swagger
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@riktajs/swagger)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
Automatic OpenAPI/Swagger documentation generation for the Rikta Framework.
|
|
7
|
+
|
|
8
|
+
> **Note:** This package is completely agnostic from `@riktajs/core` - it only reads metadata and can be used with any Fastify application.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- 🚀 **Automatic route extraction** from `@Controller`, `@Get`, `@Post`, etc.
|
|
13
|
+
- 🏷️ **Rich decorators** for API documentation (`@ApiTags`, `@ApiOperation`, `@ApiResponse`, etc.)
|
|
14
|
+
- 📝 **Zod integration** for automatic request/response type documentation
|
|
15
|
+
- 🎨 **Interactive Swagger UI** powered by `@fastify/swagger-ui`
|
|
16
|
+
- 📋 **Full OpenAPI 3.0/3.1** specification support
|
|
17
|
+
- 🔌 **Zero-config** with sensible defaults
|
|
18
|
+
- 🏗️ **Completely agnostic** from `@riktajs/core` - can be used independently
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install @riktajs/swagger
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { Rikta, Controller, Get, Body, Post } from '@riktajs/core';
|
|
30
|
+
import { swaggerPlugin, ApiTags, ApiOperation, ApiResponse, ApiBody } from '@riktajs/swagger';
|
|
31
|
+
import { z } from 'zod';
|
|
32
|
+
|
|
33
|
+
// Define your schemas with Zod
|
|
34
|
+
const UserSchema = z.object({
|
|
35
|
+
id: z.string().uuid(),
|
|
36
|
+
name: z.string(),
|
|
37
|
+
email: z.string().email(),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const CreateUserSchema = z.object({
|
|
41
|
+
name: z.string().min(2),
|
|
42
|
+
email: z.string().email(),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
@ApiTags('Users')
|
|
46
|
+
@Controller('/users')
|
|
47
|
+
class UserController {
|
|
48
|
+
@Get('/')
|
|
49
|
+
@ApiOperation({ summary: 'List all users' })
|
|
50
|
+
@ApiResponse({ status: 200, description: 'Array of users', schema: z.array(UserSchema) })
|
|
51
|
+
async listUsers() {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@Post('/')
|
|
56
|
+
@ApiOperation({ summary: 'Create a new user' })
|
|
57
|
+
@ApiBody({ schema: CreateUserSchema })
|
|
58
|
+
@ApiResponse({ status: 201, description: 'User created', schema: UserSchema })
|
|
59
|
+
async createUser(@Body() data: z.infer<typeof CreateUserSchema>) {
|
|
60
|
+
return { id: 'uuid', ...data };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Create and start the application
|
|
65
|
+
const app = await Rikta.create({ port: 3000 });
|
|
66
|
+
|
|
67
|
+
// Register swagger plugin
|
|
68
|
+
await app.server.register(swaggerPlugin, {
|
|
69
|
+
title: 'My API',
|
|
70
|
+
version: '1.0.0',
|
|
71
|
+
description: 'My awesome API documentation',
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
await app.listen();
|
|
75
|
+
|
|
76
|
+
// Swagger UI: http://localhost:3000/docs
|
|
77
|
+
// OpenAPI JSON: http://localhost:3000/docs/json
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Configuration
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
await app.server.register(swaggerPlugin, {
|
|
84
|
+
// Required
|
|
85
|
+
title: 'My API',
|
|
86
|
+
version: '1.0.0',
|
|
87
|
+
|
|
88
|
+
// Optional
|
|
89
|
+
description: 'API description with **Markdown** support',
|
|
90
|
+
termsOfService: 'https://example.com/terms',
|
|
91
|
+
contact: {
|
|
92
|
+
name: 'API Support',
|
|
93
|
+
url: 'https://example.com/support',
|
|
94
|
+
email: 'support@example.com',
|
|
95
|
+
},
|
|
96
|
+
license: {
|
|
97
|
+
name: 'MIT',
|
|
98
|
+
url: 'https://opensource.org/licenses/MIT',
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
// Server configuration
|
|
102
|
+
servers: [
|
|
103
|
+
{ url: 'http://localhost:3000', description: 'Development' },
|
|
104
|
+
{ url: 'https://api.example.com', description: 'Production' },
|
|
105
|
+
],
|
|
106
|
+
|
|
107
|
+
// Security schemes
|
|
108
|
+
securitySchemes: {
|
|
109
|
+
bearerAuth: {
|
|
110
|
+
type: 'http',
|
|
111
|
+
scheme: 'bearer',
|
|
112
|
+
bearerFormat: 'JWT',
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
// Custom paths
|
|
117
|
+
uiPath: '/docs', // Default: /docs
|
|
118
|
+
jsonPath: '/docs/json', // Default: /docs/json
|
|
119
|
+
|
|
120
|
+
// OpenAPI version
|
|
121
|
+
openApiVersion: '3.0.3', // Default: 3.0.3
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Decorators
|
|
126
|
+
|
|
127
|
+
### Class Decorators
|
|
128
|
+
|
|
129
|
+
| Decorator | Description |
|
|
130
|
+
|-----------|-------------|
|
|
131
|
+
| `@ApiTags(...tags)` | Group endpoints by tags |
|
|
132
|
+
| `@ApiBearerAuth()` | Apply Bearer auth to all endpoints |
|
|
133
|
+
| `@ApiSecurity(name, scopes?)` | Apply security requirement |
|
|
134
|
+
|
|
135
|
+
### Method Decorators
|
|
136
|
+
|
|
137
|
+
| Decorator | Description |
|
|
138
|
+
|-----------|-------------|
|
|
139
|
+
| `@ApiOperation(options)` | Describe the operation (summary, description) |
|
|
140
|
+
| `@ApiResponse(options)` | Document a response (status, schema, description) |
|
|
141
|
+
| `@ApiBody(options)` | Document request body |
|
|
142
|
+
| `@ApiParam(options)` | Document path parameter |
|
|
143
|
+
| `@ApiQuery(options)` | Document query parameter |
|
|
144
|
+
| `@ApiHeader(options)` | Document header parameter |
|
|
145
|
+
| `@ApiExcludeEndpoint()` | Exclude endpoint from documentation |
|
|
146
|
+
|
|
147
|
+
### Property Decorators
|
|
148
|
+
|
|
149
|
+
| Decorator | Description |
|
|
150
|
+
|-----------|-------------|
|
|
151
|
+
| `@ApiProperty(options)` | Document DTO property |
|
|
152
|
+
|
|
153
|
+
## Zod Integration
|
|
154
|
+
|
|
155
|
+
The package automatically converts Zod schemas to OpenAPI schemas:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import { z } from 'zod';
|
|
159
|
+
|
|
160
|
+
const UserSchema = z.object({
|
|
161
|
+
id: z.string().uuid().describe('Unique user identifier'),
|
|
162
|
+
name: z.string().min(2).max(100),
|
|
163
|
+
email: z.string().email(),
|
|
164
|
+
age: z.number().int().min(0).max(150).optional(),
|
|
165
|
+
role: z.enum(['admin', 'user', 'guest']),
|
|
166
|
+
createdAt: z.date(),
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Use in decorators
|
|
170
|
+
@ApiResponse({ status: 200, schema: UserSchema })
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Supported Zod types:
|
|
174
|
+
- Primitives: `string`, `number`, `boolean`, `bigint`
|
|
175
|
+
- Complex: `object`, `array`, `tuple`, `record`
|
|
176
|
+
- Modifiers: `optional`, `nullable`, `default`
|
|
177
|
+
- Validators: `min`, `max`, `email`, `uuid`, `url`, etc.
|
|
178
|
+
- Enums: `enum`, `nativeEnum`
|
|
179
|
+
- Unions and intersections
|
|
180
|
+
|
|
181
|
+
## Development
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# Install dependencies
|
|
185
|
+
npm install
|
|
186
|
+
|
|
187
|
+
# Build
|
|
188
|
+
npm run build
|
|
189
|
+
|
|
190
|
+
# Run tests
|
|
191
|
+
npm run test
|
|
192
|
+
|
|
193
|
+
# Run tests with coverage
|
|
194
|
+
npm run test:coverage
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Alternative APIs
|
|
198
|
+
|
|
199
|
+
### registerSwagger Helper
|
|
200
|
+
|
|
201
|
+
A simpler API for registering the plugin:
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
import { registerSwagger } from '@riktajs/swagger';
|
|
205
|
+
|
|
206
|
+
await registerSwagger(app, {
|
|
207
|
+
info: {
|
|
208
|
+
title: 'My API',
|
|
209
|
+
version: '1.0.0',
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### createSwaggerConfig
|
|
215
|
+
|
|
216
|
+
For more control or integration with existing Fastify apps:
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
import fastify from 'fastify';
|
|
220
|
+
import fastifySwagger from '@fastify/swagger';
|
|
221
|
+
import fastifySwaggerUI from '@fastify/swagger-ui';
|
|
222
|
+
import { createSwaggerConfig } from '@riktajs/swagger';
|
|
223
|
+
|
|
224
|
+
const app = fastify();
|
|
225
|
+
const { swaggerOptions, swaggerUIOptions, specification } = createSwaggerConfig({
|
|
226
|
+
info: { title: 'My API', version: '1.0.0' },
|
|
227
|
+
controllers: [UserController, ProductController],
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
await app.register(fastifySwagger, swaggerOptions);
|
|
231
|
+
await app.register(fastifySwaggerUI, swaggerUIOptions);
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### OpenApiGenerator Direct Usage
|
|
235
|
+
|
|
236
|
+
Generate OpenAPI spec without Fastify:
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
import { OpenApiGenerator } from '@riktajs/swagger';
|
|
240
|
+
|
|
241
|
+
const generator = new OpenApiGenerator({
|
|
242
|
+
info: { title: 'My API', version: '1.0.0' },
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
generator.addController(UserController);
|
|
246
|
+
generator.addController(ProductController);
|
|
247
|
+
|
|
248
|
+
const spec = generator.generate();
|
|
249
|
+
console.log(JSON.stringify(spec, null, 2));
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## Related Packages
|
|
253
|
+
|
|
254
|
+
- [@riktajs/core](https://www.npmjs.com/package/@riktajs/core) - Rikta Framework core
|
|
255
|
+
|
|
256
|
+
## License
|
|
257
|
+
|
|
258
|
+
MIT
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Key for storing API tags on controller classes
|
|
3
|
+
* Used by @ApiTags() decorator
|
|
4
|
+
*/
|
|
5
|
+
export declare const API_TAGS_METADATA: unique symbol;
|
|
6
|
+
/**
|
|
7
|
+
* Key for storing API operation metadata on route methods
|
|
8
|
+
* Used by @ApiOperation() decorator
|
|
9
|
+
*/
|
|
10
|
+
export declare const API_OPERATION_METADATA: unique symbol;
|
|
11
|
+
/**
|
|
12
|
+
* Key for storing API response metadata on route methods
|
|
13
|
+
* Used by @ApiResponse() decorator
|
|
14
|
+
*/
|
|
15
|
+
export declare const API_RESPONSE_METADATA: unique symbol;
|
|
16
|
+
/**
|
|
17
|
+
* Key for storing API property metadata on class properties
|
|
18
|
+
* Used by @ApiProperty() decorator
|
|
19
|
+
*/
|
|
20
|
+
export declare const API_PROPERTY_METADATA: unique symbol;
|
|
21
|
+
/**
|
|
22
|
+
* Key for storing API body metadata on route methods
|
|
23
|
+
* Used by @ApiBody() decorator
|
|
24
|
+
*/
|
|
25
|
+
export declare const API_BODY_METADATA: unique symbol;
|
|
26
|
+
/**
|
|
27
|
+
* Key for storing API parameter metadata on route methods
|
|
28
|
+
* Used by @ApiParam() decorator
|
|
29
|
+
*/
|
|
30
|
+
export declare const API_PARAM_METADATA: unique symbol;
|
|
31
|
+
/**
|
|
32
|
+
* Key for storing API query metadata on route methods
|
|
33
|
+
* Used by @ApiQuery() decorator
|
|
34
|
+
*/
|
|
35
|
+
export declare const API_QUERY_METADATA: unique symbol;
|
|
36
|
+
/**
|
|
37
|
+
* Key for storing API header metadata on route methods
|
|
38
|
+
* Used by @ApiHeader() decorator
|
|
39
|
+
*/
|
|
40
|
+
export declare const API_HEADER_METADATA: unique symbol;
|
|
41
|
+
/**
|
|
42
|
+
* Key for storing API security metadata on route methods or controllers
|
|
43
|
+
* Used by @ApiSecurity() and @ApiBearerAuth() decorators
|
|
44
|
+
*/
|
|
45
|
+
export declare const API_SECURITY_METADATA: unique symbol;
|
|
46
|
+
/**
|
|
47
|
+
* Key for storing API exclude metadata on route methods
|
|
48
|
+
* Used by @ApiExcludeEndpoint() decorator
|
|
49
|
+
*/
|
|
50
|
+
export declare const API_EXCLUDE_METADATA: unique symbol;
|
|
51
|
+
/**
|
|
52
|
+
* Key for storing API deprecated metadata on route methods
|
|
53
|
+
* Used when operation is marked as deprecated
|
|
54
|
+
*/
|
|
55
|
+
export declare const API_DEPRECATED_METADATA: unique symbol;
|
|
56
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,eAAO,MAAM,iBAAiB,eAAsC,CAAC;AAErE;;;GAGG;AACH,eAAO,MAAM,sBAAsB,eAA2C,CAAC;AAE/E;;;GAGG;AACH,eAAO,MAAM,qBAAqB,eAA0C,CAAC;AAE7E;;;GAGG;AACH,eAAO,MAAM,qBAAqB,eAA0C,CAAC;AAE7E;;;GAGG;AACH,eAAO,MAAM,iBAAiB,eAAsC,CAAC;AAErE;;;GAGG;AACH,eAAO,MAAM,kBAAkB,eAAuC,CAAC;AAEvE;;;GAGG;AACH,eAAO,MAAM,kBAAkB,eAAuC,CAAC;AAEvE;;;GAGG;AACH,eAAO,MAAM,mBAAmB,eAAwC,CAAC;AAEzE;;;GAGG;AACH,eAAO,MAAM,qBAAqB,eAA0C,CAAC;AAE7E;;;GAGG;AACH,eAAO,MAAM,oBAAoB,eAAyC,CAAC;AAE3E;;;GAGG;AACH,eAAO,MAAM,uBAAuB,eAA4C,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Swagger Package - Metadata Keys
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// Using Symbol.for() to ensure symbols are shared across packages
|
|
5
|
+
// and different import contexts (bundlers, tests, etc.)
|
|
6
|
+
/**
|
|
7
|
+
* Key for storing API tags on controller classes
|
|
8
|
+
* Used by @ApiTags() decorator
|
|
9
|
+
*/
|
|
10
|
+
export const API_TAGS_METADATA = Symbol.for('rikta:swagger:apiTags');
|
|
11
|
+
/**
|
|
12
|
+
* Key for storing API operation metadata on route methods
|
|
13
|
+
* Used by @ApiOperation() decorator
|
|
14
|
+
*/
|
|
15
|
+
export const API_OPERATION_METADATA = Symbol.for('rikta:swagger:apiOperation');
|
|
16
|
+
/**
|
|
17
|
+
* Key for storing API response metadata on route methods
|
|
18
|
+
* Used by @ApiResponse() decorator
|
|
19
|
+
*/
|
|
20
|
+
export const API_RESPONSE_METADATA = Symbol.for('rikta:swagger:apiResponse');
|
|
21
|
+
/**
|
|
22
|
+
* Key for storing API property metadata on class properties
|
|
23
|
+
* Used by @ApiProperty() decorator
|
|
24
|
+
*/
|
|
25
|
+
export const API_PROPERTY_METADATA = Symbol.for('rikta:swagger:apiProperty');
|
|
26
|
+
/**
|
|
27
|
+
* Key for storing API body metadata on route methods
|
|
28
|
+
* Used by @ApiBody() decorator
|
|
29
|
+
*/
|
|
30
|
+
export const API_BODY_METADATA = Symbol.for('rikta:swagger:apiBody');
|
|
31
|
+
/**
|
|
32
|
+
* Key for storing API parameter metadata on route methods
|
|
33
|
+
* Used by @ApiParam() decorator
|
|
34
|
+
*/
|
|
35
|
+
export const API_PARAM_METADATA = Symbol.for('rikta:swagger:apiParam');
|
|
36
|
+
/**
|
|
37
|
+
* Key for storing API query metadata on route methods
|
|
38
|
+
* Used by @ApiQuery() decorator
|
|
39
|
+
*/
|
|
40
|
+
export const API_QUERY_METADATA = Symbol.for('rikta:swagger:apiQuery');
|
|
41
|
+
/**
|
|
42
|
+
* Key for storing API header metadata on route methods
|
|
43
|
+
* Used by @ApiHeader() decorator
|
|
44
|
+
*/
|
|
45
|
+
export const API_HEADER_METADATA = Symbol.for('rikta:swagger:apiHeader');
|
|
46
|
+
/**
|
|
47
|
+
* Key for storing API security metadata on route methods or controllers
|
|
48
|
+
* Used by @ApiSecurity() and @ApiBearerAuth() decorators
|
|
49
|
+
*/
|
|
50
|
+
export const API_SECURITY_METADATA = Symbol.for('rikta:swagger:apiSecurity');
|
|
51
|
+
/**
|
|
52
|
+
* Key for storing API exclude metadata on route methods
|
|
53
|
+
* Used by @ApiExcludeEndpoint() decorator
|
|
54
|
+
*/
|
|
55
|
+
export const API_EXCLUDE_METADATA = Symbol.for('rikta:swagger:apiExclude');
|
|
56
|
+
/**
|
|
57
|
+
* Key for storing API deprecated metadata on route methods
|
|
58
|
+
* Used when operation is marked as deprecated
|
|
59
|
+
*/
|
|
60
|
+
export const API_DEPRECATED_METADATA = Symbol.for('rikta:swagger:apiDeprecated');
|
|
61
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,kCAAkC;AAClC,+EAA+E;AAC/E,kEAAkE;AAClE,wDAAwD;AAExD;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;AAErE;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;AAE/E;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;AAE7E;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;AAE7E;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;AAErE;;;GAGG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;AAEvE;;;GAGG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;AAEvE;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;AAEzE;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;AAE7E;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;AAE3E;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import type { ApiBodyOptions } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* @ApiBody() decorator
|
|
5
|
+
*
|
|
6
|
+
* Documents the request body for an API operation.
|
|
7
|
+
* Supports both Zod schemas and OpenAPI schema objects.
|
|
8
|
+
*
|
|
9
|
+
* @param options - Body options including schema, description, and examples
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const CreateUserSchema = z.object({
|
|
14
|
+
* name: z.string().min(2),
|
|
15
|
+
* email: z.string().email(),
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* @Post('/')
|
|
19
|
+
* @ApiBody({
|
|
20
|
+
* description: 'User creation data',
|
|
21
|
+
* schema: CreateUserSchema,
|
|
22
|
+
* required: true,
|
|
23
|
+
* })
|
|
24
|
+
* createUser(@Body() data: z.infer<typeof CreateUserSchema>) { }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function ApiBody(options: ApiBodyOptions): MethodDecorator;
|
|
28
|
+
/**
|
|
29
|
+
* Get body metadata from a method
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
export declare function getApiBody(target: Function, propertyKey: string | symbol): ApiBodyOptions | undefined;
|
|
33
|
+
//# sourceMappingURL=api-body.decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-body.decorator.d.ts","sourceRoot":"","sources":["../../src/decorators/api-body.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,eAAe,CAchE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,QAAQ,EAChB,WAAW,EAAE,MAAM,GAAG,MAAM,GAC3B,cAAc,GAAG,SAAS,CAE5B"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { API_BODY_METADATA } from '../constants.js';
|
|
3
|
+
/**
|
|
4
|
+
* @ApiBody() decorator
|
|
5
|
+
*
|
|
6
|
+
* Documents the request body for an API operation.
|
|
7
|
+
* Supports both Zod schemas and OpenAPI schema objects.
|
|
8
|
+
*
|
|
9
|
+
* @param options - Body options including schema, description, and examples
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const CreateUserSchema = z.object({
|
|
14
|
+
* name: z.string().min(2),
|
|
15
|
+
* email: z.string().email(),
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* @Post('/')
|
|
19
|
+
* @ApiBody({
|
|
20
|
+
* description: 'User creation data',
|
|
21
|
+
* schema: CreateUserSchema,
|
|
22
|
+
* required: true,
|
|
23
|
+
* })
|
|
24
|
+
* createUser(@Body() data: z.infer<typeof CreateUserSchema>) { }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export function ApiBody(options) {
|
|
28
|
+
return (target, propertyKey, descriptor) => {
|
|
29
|
+
Reflect.defineMetadata(API_BODY_METADATA, { ...options, required: options.required ?? true }, target, propertyKey);
|
|
30
|
+
return descriptor;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Get body metadata from a method
|
|
35
|
+
* @internal
|
|
36
|
+
*/
|
|
37
|
+
export function getApiBody(target, propertyKey) {
|
|
38
|
+
return Reflect.getMetadata(API_BODY_METADATA, target.prototype, propertyKey);
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=api-body.decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-body.decorator.js","sourceRoot":"","sources":["../../src/decorators/api-body.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAGpD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,OAAO,CAAC,OAAuB;IAC7C,OAAO,CACL,MAAc,EACd,WAA4B,EAC5B,UAA8B,EACV,EAAE;QACtB,OAAO,CAAC,cAAc,CACpB,iBAAiB,EACjB,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,IAAI,EAAE,EAClD,MAAM,EACN,WAAW,CACZ,CAAC;QACF,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CACxB,MAAgB,EAChB,WAA4B;IAE5B,OAAO,OAAO,CAAC,WAAW,CAAC,iBAAiB,EAAE,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;AAC/E,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
/**
|
|
3
|
+
* @ApiExcludeEndpoint() decorator
|
|
4
|
+
*
|
|
5
|
+
* Excludes an endpoint from the Swagger documentation.
|
|
6
|
+
* The route will still work but won't appear in the docs.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* @Controller('/users')
|
|
11
|
+
* class UserController {
|
|
12
|
+
* @Get('/')
|
|
13
|
+
* listUsers() { } // Documented
|
|
14
|
+
*
|
|
15
|
+
* @Get('/internal')
|
|
16
|
+
* @ApiExcludeEndpoint()
|
|
17
|
+
* internalEndpoint() { } // Not documented
|
|
18
|
+
* }
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare function ApiExcludeEndpoint(): MethodDecorator;
|
|
22
|
+
/**
|
|
23
|
+
* @ApiExcludeController() decorator
|
|
24
|
+
*
|
|
25
|
+
* Excludes an entire controller from the Swagger documentation.
|
|
26
|
+
* All routes in the controller will still work but won't appear in the docs.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* @ApiExcludeController()
|
|
31
|
+
* @Controller('/internal')
|
|
32
|
+
* class InternalController {
|
|
33
|
+
* @Get('/health')
|
|
34
|
+
* health() { } // Not documented
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function ApiExcludeController(): ClassDecorator;
|
|
39
|
+
/**
|
|
40
|
+
* Check if an endpoint is excluded from documentation
|
|
41
|
+
* @internal
|
|
42
|
+
*/
|
|
43
|
+
export declare function isApiExcluded(target: Function, propertyKey?: string | symbol): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* @ApiDeprecated() decorator
|
|
46
|
+
*
|
|
47
|
+
* Marks an endpoint as deprecated in the documentation.
|
|
48
|
+
* The endpoint will be styled differently in Swagger UI.
|
|
49
|
+
*
|
|
50
|
+
* @param message - Optional deprecation message
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* @Controller('/users')
|
|
55
|
+
* class UserController {
|
|
56
|
+
* @Get('/v1')
|
|
57
|
+
* @ApiDeprecated('Use /v2 instead')
|
|
58
|
+
* legacyEndpoint() { }
|
|
59
|
+
* }
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare function ApiDeprecated(message?: string): MethodDecorator;
|
|
63
|
+
/**
|
|
64
|
+
* Check if an endpoint is deprecated
|
|
65
|
+
* @internal
|
|
66
|
+
*/
|
|
67
|
+
export declare function getApiDeprecated(target: Function, propertyKey: string | symbol): {
|
|
68
|
+
deprecated: boolean;
|
|
69
|
+
message?: string;
|
|
70
|
+
} | undefined;
|
|
71
|
+
//# sourceMappingURL=api-exclude.decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-exclude.decorator.d.ts","sourceRoot":"","sources":["../../src/decorators/api-exclude.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAG1B;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,IAAI,eAAe,CAcpD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,IAAI,cAAc,CAIrD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAUtF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,eAAe,CAc/D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,QAAQ,EAChB,WAAW,EAAE,MAAM,GAAG,MAAM,GAC3B;IAAE,UAAU,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAEvD"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { API_EXCLUDE_METADATA, API_DEPRECATED_METADATA } from '../constants.js';
|
|
3
|
+
/**
|
|
4
|
+
* @ApiExcludeEndpoint() decorator
|
|
5
|
+
*
|
|
6
|
+
* Excludes an endpoint from the Swagger documentation.
|
|
7
|
+
* The route will still work but won't appear in the docs.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* @Controller('/users')
|
|
12
|
+
* class UserController {
|
|
13
|
+
* @Get('/')
|
|
14
|
+
* listUsers() { } // Documented
|
|
15
|
+
*
|
|
16
|
+
* @Get('/internal')
|
|
17
|
+
* @ApiExcludeEndpoint()
|
|
18
|
+
* internalEndpoint() { } // Not documented
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function ApiExcludeEndpoint() {
|
|
23
|
+
return (target, propertyKey, descriptor) => {
|
|
24
|
+
Reflect.defineMetadata(API_EXCLUDE_METADATA, true, target, propertyKey);
|
|
25
|
+
return descriptor;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* @ApiExcludeController() decorator
|
|
30
|
+
*
|
|
31
|
+
* Excludes an entire controller from the Swagger documentation.
|
|
32
|
+
* All routes in the controller will still work but won't appear in the docs.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* @ApiExcludeController()
|
|
37
|
+
* @Controller('/internal')
|
|
38
|
+
* class InternalController {
|
|
39
|
+
* @Get('/health')
|
|
40
|
+
* health() { } // Not documented
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export function ApiExcludeController() {
|
|
45
|
+
return (target) => {
|
|
46
|
+
Reflect.defineMetadata(API_EXCLUDE_METADATA, true, target);
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Check if an endpoint is excluded from documentation
|
|
51
|
+
* @internal
|
|
52
|
+
*/
|
|
53
|
+
export function isApiExcluded(target, propertyKey) {
|
|
54
|
+
// Check class-level exclusion
|
|
55
|
+
if (Reflect.getMetadata(API_EXCLUDE_METADATA, target) === true) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
// Check method-level exclusion
|
|
59
|
+
if (propertyKey !== undefined) {
|
|
60
|
+
return Reflect.getMetadata(API_EXCLUDE_METADATA, target.prototype, propertyKey) === true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* @ApiDeprecated() decorator
|
|
66
|
+
*
|
|
67
|
+
* Marks an endpoint as deprecated in the documentation.
|
|
68
|
+
* The endpoint will be styled differently in Swagger UI.
|
|
69
|
+
*
|
|
70
|
+
* @param message - Optional deprecation message
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* @Controller('/users')
|
|
75
|
+
* class UserController {
|
|
76
|
+
* @Get('/v1')
|
|
77
|
+
* @ApiDeprecated('Use /v2 instead')
|
|
78
|
+
* legacyEndpoint() { }
|
|
79
|
+
* }
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export function ApiDeprecated(message) {
|
|
83
|
+
return (target, propertyKey, descriptor) => {
|
|
84
|
+
Reflect.defineMetadata(API_DEPRECATED_METADATA, { deprecated: true, message }, target, propertyKey);
|
|
85
|
+
return descriptor;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Check if an endpoint is deprecated
|
|
90
|
+
* @internal
|
|
91
|
+
*/
|
|
92
|
+
export function getApiDeprecated(target, propertyKey) {
|
|
93
|
+
return Reflect.getMetadata(API_DEPRECATED_METADATA, target.prototype, propertyKey);
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=api-exclude.decorator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-exclude.decorator.js","sourceRoot":"","sources":["../../src/decorators/api-exclude.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAEhF;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,CACL,MAAc,EACd,WAA4B,EAC5B,UAA8B,EACV,EAAE;QACtB,OAAO,CAAC,cAAc,CACpB,oBAAoB,EACpB,IAAI,EACJ,MAAM,EACN,WAAW,CACZ,CAAC;QACF,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO,CAAC,MAAgB,EAAQ,EAAE;QAChC,OAAO,CAAC,cAAc,CAAC,oBAAoB,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC7D,CAAC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,MAAgB,EAAE,WAA6B;IAC3E,8BAA8B;IAC9B,IAAI,OAAO,CAAC,WAAW,CAAC,oBAAoB,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;QAC/D,OAAO,IAAI,CAAC;IACd,CAAC;IACD,+BAA+B;IAC/B,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,OAAO,CAAC,WAAW,CAAC,oBAAoB,EAAE,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC,KAAK,IAAI,CAAC;IAC3F,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,OAAO,CACL,MAAc,EACd,WAA4B,EAC5B,UAA8B,EACV,EAAE;QACtB,OAAO,CAAC,cAAc,CACpB,uBAAuB,EACvB,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,EAC7B,MAAM,EACN,WAAW,CACZ,CAAC;QACF,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAAgB,EAChB,WAA4B;IAE5B,OAAO,OAAO,CAAC,WAAW,CAAC,uBAAuB,EAAE,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;AACrF,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import type { ApiHeaderOptions } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* @ApiHeader() decorator
|
|
5
|
+
*
|
|
6
|
+
* Documents a header parameter for an API operation.
|
|
7
|
+
* Multiple @ApiHeader decorators can be applied for routes with multiple headers.
|
|
8
|
+
*
|
|
9
|
+
* @param options - Header options including name, description, and required flag
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* @Get('/')
|
|
14
|
+
* @ApiHeader({ name: 'X-Request-ID', description: 'Unique request identifier', required: true })
|
|
15
|
+
* @ApiHeader({ name: 'X-Correlation-ID', description: 'Correlation ID for tracing' })
|
|
16
|
+
* listUsers() { }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function ApiHeader(options: ApiHeaderOptions): MethodDecorator;
|
|
20
|
+
/**
|
|
21
|
+
* Get all header parameter metadata from a method
|
|
22
|
+
* @internal
|
|
23
|
+
*/
|
|
24
|
+
export declare function getApiHeaders(target: Function, propertyKey: string | symbol): ApiHeaderOptions[];
|
|
25
|
+
//# sourceMappingURL=api-header.decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-header.decorator.d.ts","sourceRoot":"","sources":["../../src/decorators/api-header.decorator.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAiBpE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,QAAQ,EAChB,WAAW,EAAE,MAAM,GAAG,MAAM,GAC3B,gBAAgB,EAAE,CAEpB"}
|