exisjs 0.7.7 → 0.7.9
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/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +14 -4
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/cli/resolve-aliases.js +1 -1
- package/dist/cli/resolve-aliases.js.map +1 -1
- package/dist/decorators/caching.d.ts +53 -0
- package/dist/decorators/caching.d.ts.map +1 -0
- package/dist/decorators/caching.js +154 -0
- package/dist/decorators/caching.js.map +1 -0
- package/dist/decorators/constants.d.ts +4 -0
- package/dist/decorators/constants.d.ts.map +1 -1
- package/dist/decorators/constants.js +5 -1
- package/dist/decorators/constants.js.map +1 -1
- package/dist/decorators/filters.d.ts +37 -0
- package/dist/decorators/filters.d.ts.map +1 -0
- package/dist/decorators/filters.js +30 -0
- package/dist/decorators/filters.js.map +1 -0
- package/dist/decorators/index.d.ts +6 -0
- package/dist/decorators/index.d.ts.map +1 -1
- package/dist/decorators/index.js +6 -0
- package/dist/decorators/index.js.map +1 -1
- package/dist/decorators/lifecycle.d.ts +37 -0
- package/dist/decorators/lifecycle.d.ts.map +1 -0
- package/dist/decorators/lifecycle.js +3 -0
- package/dist/decorators/lifecycle.js.map +1 -0
- package/dist/decorators/middleware.d.ts +24 -3
- package/dist/decorators/middleware.d.ts.map +1 -1
- package/dist/decorators/middleware.js +24 -3
- package/dist/decorators/middleware.js.map +1 -1
- package/dist/decorators/params.d.ts.map +1 -1
- package/dist/decorators/params.js +1 -7
- package/dist/decorators/params.js.map +1 -1
- package/dist/decorators/profile.d.ts +32 -0
- package/dist/decorators/profile.d.ts.map +1 -0
- package/dist/decorators/profile.js +61 -0
- package/dist/decorators/profile.js.map +1 -0
- package/dist/decorators/response.d.ts +0 -1
- package/dist/decorators/response.d.ts.map +1 -1
- package/dist/decorators/response.js +1 -18
- package/dist/decorators/response.js.map +1 -1
- package/dist/decorators/routing.d.ts +22 -12
- package/dist/decorators/routing.d.ts.map +1 -1
- package/dist/decorators/routing.js +49 -3
- package/dist/decorators/routing.js.map +1 -1
- package/dist/decorators/security.d.ts +42 -0
- package/dist/decorators/security.d.ts.map +1 -0
- package/dist/decorators/security.js +110 -0
- package/dist/decorators/security.js.map +1 -0
- package/dist/decorators/transaction.d.ts +29 -0
- package/dist/decorators/transaction.d.ts.map +1 -0
- package/dist/decorators/transaction.js +91 -0
- package/dist/decorators/transaction.js.map +1 -0
- package/dist/di/container.d.ts +2 -0
- package/dist/di/container.d.ts.map +1 -1
- package/dist/di/container.js +30 -0
- package/dist/di/container.js.map +1 -1
- package/dist/docs/content/decorators.mdx +89 -4
- package/dist/docs/content/errors.mdx +29 -13
- package/dist/docs/content/providers.mdx +48 -0
- package/dist/docs/content/structure.mdx +1 -1
- package/dist/docs/content/swagger.mdx +94 -33
- package/dist/docs/reference/decorators.mdx +27 -4
- package/dist/docs/reference/di.mdx +26 -0
- package/dist/docs/reference/swagger.mdx +118 -35
- package/dist/docs/reference/validator.mdx +1 -1
- package/dist/error/errors.d.ts +24 -12
- package/dist/error/errors.d.ts.map +1 -1
- package/dist/error/errors.js +36 -12
- package/dist/error/errors.js.map +1 -1
- package/dist/router/controller-registrar.d.ts.map +1 -1
- package/dist/router/controller-registrar.js +75 -7
- package/dist/router/controller-registrar.js.map +1 -1
- package/dist/server/app.d.ts.map +1 -1
- package/dist/server/app.js +2 -0
- package/dist/server/app.js.map +1 -1
- package/dist/testing/client.d.ts +1 -1
- package/dist/testing/client.d.ts.map +1 -1
- package/dist/testing/client.js +30 -15
- package/dist/testing/client.js.map +1 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +10 -0
- package/dist/testing/index.js.map +1 -1
- package/package.json +5 -1
|
@@ -5,7 +5,7 @@ nextTitle: "Swagger API Reference"
|
|
|
5
5
|
|
|
6
6
|
# Swagger & OpenAPI 3.1 Documentation
|
|
7
7
|
|
|
8
|
-
ExisJS comes with a native,
|
|
8
|
+
ExisJS comes with a native, built-in **Swagger & OpenAPI 3.1** documentation engine. It automatically discovers all registered routes, introspects **Tex** and **Zod** validation schemas, and serves interactive API documentation at `/docs`.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -44,6 +44,8 @@ The industry-standard interactive Swagger explorer featuring **Try it out**, liv
|
|
|
44
44
|
A modern, high-performance, dark-mode-first API reference documentation viewer with integrated code snippets and fast search.
|
|
45
45
|
|
|
46
46
|
```typescript filename="exis.config.ts"
|
|
47
|
+
import { defineConfig } from 'exisjs/config'
|
|
48
|
+
|
|
47
49
|
export default defineConfig({
|
|
48
50
|
docs: {
|
|
49
51
|
enabled: true,
|
|
@@ -56,14 +58,14 @@ export default defineConfig({
|
|
|
56
58
|
|
|
57
59
|
## Documenting Functional Routes
|
|
58
60
|
|
|
59
|
-
|
|
61
|
+
In ExisJS folder-based routing, each endpoint folder contains a `route.ts` file that exports a default `controller({ ... })`. You can add OpenAPI metadata directly to each route definition:
|
|
60
62
|
|
|
61
63
|
```typescript filename="src/http/users/route.ts"
|
|
62
64
|
import { controller, route } from 'exisjs/router'
|
|
63
65
|
import { tex, getPaginationSkip } from 'exisjs/validator'
|
|
64
66
|
|
|
65
67
|
export default controller({
|
|
66
|
-
|
|
68
|
+
list: route.get('/', {
|
|
67
69
|
summary: 'List active users',
|
|
68
70
|
description: 'Returns a paginated list of all active users in the system.',
|
|
69
71
|
tags: ['Users'],
|
|
@@ -80,11 +82,19 @@ export default controller({
|
|
|
80
82
|
},
|
|
81
83
|
async handle({ query }) {
|
|
82
84
|
const { skip, limit } = getPaginationSkip(query)
|
|
83
|
-
return
|
|
85
|
+
return {
|
|
86
|
+
data: [
|
|
87
|
+
{ id: '550e8400-e29b-41d4-a716-446655440000', name: 'Alice' },
|
|
88
|
+
{ id: '550e8400-e29b-41d4-a716-446655440001', name: 'Bob' },
|
|
89
|
+
],
|
|
90
|
+
total: 2,
|
|
91
|
+
skip,
|
|
92
|
+
limit,
|
|
93
|
+
}
|
|
84
94
|
},
|
|
85
95
|
}),
|
|
86
96
|
|
|
87
|
-
|
|
97
|
+
create: route.post('/', {
|
|
88
98
|
summary: 'Create a new user',
|
|
89
99
|
tags: ['Users'],
|
|
90
100
|
body: tex.object({
|
|
@@ -96,11 +106,11 @@ export default controller({
|
|
|
96
106
|
400: { description: 'Validation error' },
|
|
97
107
|
},
|
|
98
108
|
async handle({ body }) {
|
|
99
|
-
return
|
|
109
|
+
return { id: '550e8400-e29b-41d4-a716-446655440002', ...body }
|
|
100
110
|
},
|
|
101
111
|
}),
|
|
102
112
|
|
|
103
|
-
|
|
113
|
+
getById: route.get('/:id', {
|
|
104
114
|
summary: 'Get user by UUID',
|
|
105
115
|
tags: ['Users'],
|
|
106
116
|
params: tex.object({ id: tex.uuid() }),
|
|
@@ -109,7 +119,7 @@ export default controller({
|
|
|
109
119
|
404: { description: 'User not found' },
|
|
110
120
|
},
|
|
111
121
|
async handle({ params }) {
|
|
112
|
-
return
|
|
122
|
+
return { id: params.id, name: 'Alice' }
|
|
113
123
|
},
|
|
114
124
|
}),
|
|
115
125
|
})
|
|
@@ -119,9 +129,9 @@ export default controller({
|
|
|
119
129
|
|
|
120
130
|
## Documenting Class-Based Controllers (OOP)
|
|
121
131
|
|
|
122
|
-
For class-based controllers
|
|
132
|
+
For class-based controllers in `route.ts`, use OpenAPI decorators from `exisjs/swagger` alongside standard routing decorators:
|
|
123
133
|
|
|
124
|
-
```typescript filename="src/http/products/
|
|
134
|
+
```typescript filename="src/http/products/route.ts"
|
|
125
135
|
import { Controller, Get, Post, Body, Param, Query } from 'exisjs/decorators'
|
|
126
136
|
import {
|
|
127
137
|
ApiTags,
|
|
@@ -130,32 +140,42 @@ import {
|
|
|
130
140
|
ApiBearerAuth,
|
|
131
141
|
ApiExclude,
|
|
132
142
|
} from 'exisjs/swagger'
|
|
133
|
-
import { tex } from 'exisjs/validator'
|
|
134
143
|
|
|
135
144
|
@ApiTags('Products')
|
|
136
145
|
@ApiBearerAuth()
|
|
137
|
-
@Controller(
|
|
138
|
-
export class
|
|
146
|
+
@Controller()
|
|
147
|
+
export default class ProductsController {
|
|
139
148
|
@Get('/')
|
|
140
149
|
@ApiOperation({
|
|
141
150
|
summary: 'List products',
|
|
142
151
|
description: 'Fetches paginated list of catalog products',
|
|
143
152
|
})
|
|
144
153
|
@ApiResponse({ status: 200, description: 'List of products' })
|
|
145
|
-
async list(@Query('page') page: number) {
|
|
146
|
-
return
|
|
154
|
+
async list(@Query('page') page: number = 1) {
|
|
155
|
+
return [
|
|
156
|
+
{ id: 1, name: 'Mechanical Keyboard', price: 99 },
|
|
157
|
+
{ id: 2, name: 'Ergonomic Mouse', price: 49 },
|
|
158
|
+
]
|
|
147
159
|
}
|
|
148
160
|
|
|
149
161
|
@Post('/')
|
|
150
162
|
@ApiOperation({ summary: 'Create new product' })
|
|
151
163
|
@ApiResponse({ status: 201, description: 'Product created' })
|
|
152
|
-
async create(@Body() dto:
|
|
153
|
-
return
|
|
164
|
+
async create(@Body() dto: { name: string; price: number }) {
|
|
165
|
+
return { id: 3, ...dto }
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
@Get('/:id')
|
|
169
|
+
@ApiOperation({ summary: 'Get product by ID' })
|
|
170
|
+
@ApiResponse({ status: 200, description: 'Product found' })
|
|
171
|
+
@ApiResponse({ status: 404, description: 'Product not found' })
|
|
172
|
+
async getById(@Param('id') id: string) {
|
|
173
|
+
return { id, name: 'Mechanical Keyboard', price: 99 }
|
|
154
174
|
}
|
|
155
175
|
|
|
156
|
-
@Get('/internal
|
|
176
|
+
@Get('/internal/metrics')
|
|
157
177
|
@ApiExclude() // Excluded from Swagger documentation
|
|
158
|
-
async
|
|
178
|
+
async metrics() {
|
|
159
179
|
return { uptime: process.uptime() }
|
|
160
180
|
}
|
|
161
181
|
}
|
|
@@ -165,7 +185,7 @@ export class ProductController {
|
|
|
165
185
|
|
|
166
186
|
## Cascading Boundary Metadata
|
|
167
187
|
|
|
168
|
-
Cascading boundaries (`boundary.ts`) can assign shared tags, descriptions, or security requirements to all nested routes:
|
|
188
|
+
Cascading boundaries (`boundary.ts`) can assign shared tags, descriptions, or security requirements to all nested routes in the directory:
|
|
169
189
|
|
|
170
190
|
```typescript filename="src/http/admin/boundary.ts"
|
|
171
191
|
import { defineBoundary } from 'exisjs/router'
|
|
@@ -183,6 +203,8 @@ export const config = defineBoundary({
|
|
|
183
203
|
Define reusable security schemes (such as Bearer JWT, API Keys, or OAuth2) in `exis.config.ts`:
|
|
184
204
|
|
|
185
205
|
```typescript filename="exis.config.ts"
|
|
206
|
+
import { defineConfig } from 'exisjs/config'
|
|
207
|
+
|
|
186
208
|
export default defineConfig({
|
|
187
209
|
docs: {
|
|
188
210
|
enabled: true,
|
|
@@ -208,21 +230,60 @@ export default defineConfig({
|
|
|
208
230
|
|
|
209
231
|
---
|
|
210
232
|
|
|
211
|
-
##
|
|
233
|
+
## Advanced Configuration (`exis.config.ts`)
|
|
212
234
|
|
|
213
|
-
|
|
235
|
+
For advanced customization, such as modifying the generated OpenAPI spec before serving or injecting custom styling:
|
|
214
236
|
|
|
215
|
-
```typescript filename="
|
|
216
|
-
import {
|
|
217
|
-
import { swagger } from 'exisjs/swagger'
|
|
237
|
+
```typescript filename="exis.config.ts"
|
|
238
|
+
import { defineConfig } from 'exisjs/config'
|
|
218
239
|
|
|
219
|
-
|
|
240
|
+
export default defineConfig({
|
|
241
|
+
docs: {
|
|
242
|
+
enabled: true,
|
|
243
|
+
title: 'Enterprise API Gateway',
|
|
244
|
+
version: '2.0.0',
|
|
245
|
+
description: 'Internal and external microservices API reference',
|
|
246
|
+
ui: 'scalar', // 'swagger-ui' | 'scalar'
|
|
247
|
+
servers: [
|
|
248
|
+
{ url: 'https://api.example.com', description: 'Production Server' },
|
|
249
|
+
{ url: 'http://localhost:3000', description: 'Local Development' },
|
|
250
|
+
],
|
|
251
|
+
transformSpec(spec) {
|
|
252
|
+
// Programmatically mutate or enrich OpenAPI specification
|
|
253
|
+
spec.info.contact = { name: 'API Support', email: 'support@example.com' }
|
|
254
|
+
return spec
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
})
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Server Lifecycle Hook (`server.ts`)
|
|
263
|
+
|
|
264
|
+
You can also interact with the Swagger subsystem or application instance during server boot in `src/http/server.ts`:
|
|
265
|
+
|
|
266
|
+
### Functional Paradigm
|
|
267
|
+
```typescript filename="src/http/server.ts"
|
|
268
|
+
import { exis } from 'exisjs'
|
|
269
|
+
|
|
270
|
+
export default exis({
|
|
271
|
+
onStart(app) {
|
|
272
|
+
console.log('[API] Swagger documentation ready at /docs')
|
|
273
|
+
},
|
|
274
|
+
})
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Class-Based (OOP) Paradigm
|
|
278
|
+
```typescript filename="src/http/server.ts"
|
|
279
|
+
import { Server } from 'exisjs/decorators'
|
|
280
|
+
import type { App } from 'exisjs'
|
|
220
281
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
})(app)
|
|
282
|
+
@Server()
|
|
283
|
+
export default class RootServer {
|
|
284
|
+
async onStart(app: App) {
|
|
285
|
+
console.log('[API] Swagger documentation ready at /docs')
|
|
286
|
+
}
|
|
287
|
+
}
|
|
228
288
|
```
|
|
289
|
+
|
|
@@ -86,6 +86,10 @@ Parameter decorators automatically extract data from the incoming request and in
|
|
|
86
86
|
## 3. Middleware & Pipeline Decorators
|
|
87
87
|
|
|
88
88
|
- `@Use(...middlewaresOrGuardsOrInterceptorsOrFilters)`: Unified decorator that binds middlewares, guards (`canActivate`), interceptors (`intercept`), or exception filters (`catch`) to a controller class or method.
|
|
89
|
+
- `@UseGuards(...guards)`: Dedicated decorator to apply guards to a class or method.
|
|
90
|
+
- `@UseInterceptors(...interceptors)`: Dedicated decorator to apply interceptors to a class or method.
|
|
91
|
+
- `@UseFilters(...filters)`: Dedicated decorator to apply exception filters to a class or method.
|
|
92
|
+
- `@Catch(...exceptions)`: Class decorator for `ExceptionFilter` implementations declaring handled exception types.
|
|
89
93
|
- `@Upload(fieldName, options?)` / `@UseUpload(...)`: Configures multipart file upload handling for a method, populating `@UploadedFile()` or `@UploadedFiles()`.
|
|
90
94
|
- `@Timeout(ms: number | TimeoutOptions)`: Overrides the request timeout for a class or method (e.g. `@Timeout(120000)`). Passing `0` disables timeouts for long-running streaming or exports.
|
|
91
95
|
- `@Idempotent(options?)`: Caches responses based on the `Idempotency-Key` header using native in-memory off-heap storage. Works at class and method level.
|
|
@@ -98,13 +102,32 @@ Parameter decorators automatically extract data from the incoming request and in
|
|
|
98
102
|
|
|
99
103
|
---
|
|
100
104
|
|
|
101
|
-
## 4.
|
|
105
|
+
## 4. Security & Access Control Decorators
|
|
106
|
+
|
|
107
|
+
- `@Permissions(...permissions: string[])`: Sets required permission keys for a controller or route method (automatically bypassed if `req.user.isSuperAdmin` is true).
|
|
108
|
+
- `@Roles(...roles: string[])`: Sets required role names for a controller or route method.
|
|
109
|
+
- `@Public()` / `@IsPublic()` / `@AllowAnonymous()`: Marks a controller or route as public, instructing global authentication guards to bypass credential checks.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## 5. Service Enhancements: Caching, Transactions & Profiling
|
|
114
|
+
|
|
115
|
+
- `@Cacheable({ ttl?: number, key?: string | ((...args) => string) })`: Caches method return values in ExisJS's off-heap native memory LRU cache.
|
|
116
|
+
- `@CacheEvict({ key: string | ((...args) => string) })`: Evicts cached entries matching the key when the method completes.
|
|
117
|
+
- `@Transactional(options?)`: Automatically wraps service operations in an atomic database transaction.
|
|
118
|
+
- `@Profile({ thresholdMs?: number, warnSlow?: boolean, log?: Function })`: Profiles method execution time with sub-millisecond precision.
|
|
119
|
+
- `OnInit` (`onInit()`): Invoked when the application or service boots up.
|
|
120
|
+
- `OnDestroy` (`onDestroy()`): Invoked when the application gracefully terminates.
|
|
121
|
+
- `OnModuleInit`, `OnModuleDestroy`, `OnApplicationBootstrap`: Modular lifecycle hooks.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## 6. Response & Metadata Modifiers
|
|
102
126
|
|
|
103
127
|
- `@HttpCode(code: number)`: Enforces a custom HTTP status code on success.
|
|
104
128
|
- `@Header(name: string, value: string)`: Appends an HTTP header to the response.
|
|
105
129
|
- `@Returns(schema)`: Attaches response schema for OpenAPI documentation.
|
|
106
130
|
- `@Redirect(url: string, statusCode?: number)`: Redirects request to target URL.
|
|
107
|
-
- `@Permissions(...permissions: string[])`: Sets required permissions on the route.
|
|
108
131
|
- `@Hosts(...hosts: string[])`: Restricts routes to specific Host headers.
|
|
109
132
|
- `@SetMetadata(key, value)`: Attaches arbitrary custom metadata to a class or handler method, retrievable via `Reflector`.
|
|
110
133
|
- `Reflector`: Utility class to inspect metadata attached by `@SetMetadata`:
|
|
@@ -114,7 +137,7 @@ Parameter decorators automatically extract data from the incoming request and in
|
|
|
114
137
|
|
|
115
138
|
---
|
|
116
139
|
|
|
117
|
-
##
|
|
140
|
+
## 7. Dependency Injection & Modules
|
|
118
141
|
|
|
119
142
|
- `@Module({ imports?, controllers?, providers?, exports? })`: OOP class decorator equivalent to `defineModule()` for structuring application modules.
|
|
120
143
|
- `@Injectable(options?)`: Marks a service class as an IoC provider managed by the container. Supports `{ scope: 'singleton' | 'request' | 'transient' }`.
|
|
@@ -125,7 +148,7 @@ Parameter decorators automatically extract data from the incoming request and in
|
|
|
125
148
|
|
|
126
149
|
---
|
|
127
150
|
|
|
128
|
-
##
|
|
151
|
+
## 8. Cron & Task Scheduling
|
|
129
152
|
|
|
130
153
|
- `@Cron(schedule: string, options?: CronJobOptions)`: Schedules a class method as a recurring cron job on any `@Injectable()` service.
|
|
131
154
|
- `@Interval(ms: number, options?: IntervalOptions)`: Schedules a class method to execute repeatedly every `ms` milliseconds.
|
|
@@ -145,3 +145,29 @@ export default class UserController {
|
|
|
145
145
|
}
|
|
146
146
|
```
|
|
147
147
|
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Lifecycle Hooks (`OnInit`, `OnDestroy`)
|
|
151
|
+
|
|
152
|
+
Providers can implement lifecycle interfaces. When the application container initializes or gracefully closes, ExisJS automatically triggers these hooks:
|
|
153
|
+
|
|
154
|
+
- **`OnInit` (`onInit()` / `onModuleInit()`)**: Executed when the container initializes during `app.create()` or `app.listen()`.
|
|
155
|
+
- **`OnDestroy` (`onDestroy()` / `onModuleDestroy()`)**: Executed when the application receives a termination signal or `app.close()` is called.
|
|
156
|
+
- **`OnApplicationBootstrap` (`onApplicationBootstrap()`)**: Executed after all modules are initialized and before the server begins listening for incoming requests.
|
|
157
|
+
|
|
158
|
+
```typescript filename="src/http/database/service.ts"
|
|
159
|
+
import { Injectable, type OnInit, type OnDestroy } from 'exisjs/decorators'
|
|
160
|
+
|
|
161
|
+
@Injectable()
|
|
162
|
+
export class DatabaseService implements OnInit, OnDestroy {
|
|
163
|
+
async onInit(): Promise<void> {
|
|
164
|
+
await this.pool.connect()
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async onDestroy(): Promise<void> {
|
|
168
|
+
await this.pool.end()
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
|
|
@@ -53,91 +53,174 @@ import {
|
|
|
53
53
|
Assigns one or more tags to a controller class or method handler.
|
|
54
54
|
*(Alias: `@Tags()`)*
|
|
55
55
|
|
|
56
|
-
```typescript
|
|
56
|
+
```typescript filename="src/http/users/route.ts"
|
|
57
|
+
import { Controller, Get } from 'exisjs/decorators'
|
|
58
|
+
import { ApiTags } from 'exisjs/swagger'
|
|
59
|
+
|
|
57
60
|
@ApiTags('Users', 'Authentication')
|
|
58
|
-
@Controller(
|
|
59
|
-
export class UserController {
|
|
61
|
+
@Controller()
|
|
62
|
+
export default class UserController {
|
|
63
|
+
@Get('/')
|
|
64
|
+
findAll() {
|
|
65
|
+
return []
|
|
66
|
+
}
|
|
67
|
+
}
|
|
60
68
|
```
|
|
61
69
|
|
|
62
70
|
### `@ApiOperation(options)`
|
|
63
71
|
Attaches summary, description, operationId, and deprecated status to a route method.
|
|
64
72
|
*(Alias: `@Operation()`)*
|
|
65
73
|
|
|
66
|
-
```typescript
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
+
```typescript filename="src/http/users/route.ts"
|
|
75
|
+
import { Controller, Get, Param } from 'exisjs/decorators'
|
|
76
|
+
import { ApiOperation } from 'exisjs/swagger'
|
|
77
|
+
|
|
78
|
+
@Controller()
|
|
79
|
+
export default class UserController {
|
|
80
|
+
@Get('/:id')
|
|
81
|
+
@ApiOperation({
|
|
82
|
+
summary: 'Get user by UUID',
|
|
83
|
+
description: 'Fetches user details from database',
|
|
84
|
+
deprecated: false,
|
|
85
|
+
})
|
|
86
|
+
getUser(@Param('id') id: string) {
|
|
87
|
+
return { id, name: 'Alice' }
|
|
88
|
+
}
|
|
89
|
+
}
|
|
74
90
|
```
|
|
75
91
|
|
|
76
92
|
### `@ApiResponse(options)`
|
|
77
93
|
Defines an expected HTTP response status code and optional schema.
|
|
78
94
|
|
|
79
|
-
```typescript
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
95
|
+
```typescript filename="src/http/users/route.ts"
|
|
96
|
+
import { Controller, Get, Param } from 'exisjs/decorators'
|
|
97
|
+
import { ApiOperation, ApiResponse } from 'exisjs/swagger'
|
|
98
|
+
import { tex } from 'exisjs/validator'
|
|
99
|
+
|
|
100
|
+
const UserSchema = tex.object({
|
|
101
|
+
id: tex.uuid(),
|
|
102
|
+
name: tex.string(),
|
|
84
103
|
})
|
|
85
|
-
|
|
86
|
-
|
|
104
|
+
|
|
105
|
+
@Controller()
|
|
106
|
+
export default class UserController {
|
|
107
|
+
@Get('/:id')
|
|
108
|
+
@ApiResponse({
|
|
109
|
+
status: 200,
|
|
110
|
+
description: 'User details found',
|
|
111
|
+
schema: UserSchema,
|
|
112
|
+
})
|
|
113
|
+
@ApiResponse({ status: 404, description: 'User not found' })
|
|
114
|
+
getUser(@Param('id') id: string) {
|
|
115
|
+
return { id, name: 'Alice' }
|
|
116
|
+
}
|
|
117
|
+
}
|
|
87
118
|
```
|
|
88
119
|
|
|
89
120
|
### `@ApiBearerAuth(name?: string)`
|
|
90
121
|
Requires Bearer JWT authentication for this endpoint or controller.
|
|
91
122
|
*(Alias: `@BearerAuth()`)*
|
|
92
123
|
|
|
93
|
-
```typescript
|
|
124
|
+
```typescript filename="src/http/users/route.ts"
|
|
125
|
+
import { Controller, Get } from 'exisjs/decorators'
|
|
126
|
+
import { ApiBearerAuth } from 'exisjs/swagger'
|
|
127
|
+
|
|
94
128
|
@ApiBearerAuth()
|
|
95
|
-
@
|
|
96
|
-
|
|
129
|
+
@Controller()
|
|
130
|
+
export default class UserController {
|
|
131
|
+
@Get('/me')
|
|
132
|
+
getMe() {
|
|
133
|
+
return { id: 'user-123', role: 'admin' }
|
|
134
|
+
}
|
|
135
|
+
}
|
|
97
136
|
```
|
|
98
137
|
|
|
99
138
|
### `@ApiSecurity(name: string, scopes?: string[])`
|
|
100
139
|
Requires custom security scheme authentication for this endpoint or controller.
|
|
101
140
|
|
|
102
|
-
```typescript
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
141
|
+
```typescript filename="src/http/metrics/route.ts"
|
|
142
|
+
import { Controller, Get } from 'exisjs/decorators'
|
|
143
|
+
import { ApiSecurity } from 'exisjs/swagger'
|
|
144
|
+
|
|
145
|
+
@Controller()
|
|
146
|
+
export default class MetricsController {
|
|
147
|
+
@Get('/')
|
|
148
|
+
@ApiSecurity('apiKeyAuth')
|
|
149
|
+
getMetrics() {
|
|
150
|
+
return { uptime: process.uptime() }
|
|
151
|
+
}
|
|
152
|
+
}
|
|
106
153
|
```
|
|
107
154
|
|
|
108
155
|
### `@ApiExclude()`
|
|
109
156
|
Excludes an endpoint or controller class from OpenAPI and Swagger generation.
|
|
110
157
|
|
|
111
|
-
```typescript
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
158
|
+
```typescript filename="src/http/internal/route.ts"
|
|
159
|
+
import { Controller, Get } from 'exisjs/decorators'
|
|
160
|
+
import { ApiExclude } from 'exisjs/swagger'
|
|
161
|
+
|
|
162
|
+
@Controller()
|
|
163
|
+
export default class InternalController {
|
|
164
|
+
@Get('/health')
|
|
165
|
+
@ApiExclude()
|
|
166
|
+
getHealth() {
|
|
167
|
+
return { status: 'healthy' }
|
|
168
|
+
}
|
|
169
|
+
}
|
|
115
170
|
```
|
|
116
171
|
|
|
117
172
|
### `@ApiProperty(options?: { description?: string; example?: any; required?: boolean })`
|
|
118
173
|
Annotates a class property with metadata for OpenAPI schema models.
|
|
119
174
|
|
|
175
|
+
```typescript filename="src/http/users/dto.ts"
|
|
176
|
+
import { ApiProperty } from 'exisjs/swagger'
|
|
177
|
+
|
|
178
|
+
export class CreateUserDto {
|
|
179
|
+
@ApiProperty({ description: 'Full name of the user', example: 'Alice Johnson', required: true })
|
|
180
|
+
name!: string
|
|
181
|
+
|
|
182
|
+
@ApiProperty({ description: 'Work email address', example: 'alice@example.com', required: true })
|
|
183
|
+
email!: string
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
120
187
|
---
|
|
121
188
|
|
|
122
189
|
## Functions
|
|
123
190
|
|
|
124
191
|
### `swagger(config?: SwaggerConfig)`
|
|
125
|
-
Convenience helper to mount Swagger/OpenAPI documentation on an ExisJS App instance.
|
|
192
|
+
Convenience helper to mount Swagger/OpenAPI documentation on an ExisJS App instance (typically inside `onStart` or custom server setups).
|
|
126
193
|
|
|
127
|
-
```typescript
|
|
128
|
-
import {
|
|
194
|
+
```typescript filename="src/http/server.ts"
|
|
195
|
+
import { exis } from 'exisjs'
|
|
129
196
|
import { swagger } from 'exisjs/swagger'
|
|
130
197
|
|
|
131
|
-
|
|
132
|
-
|
|
198
|
+
export default exis({
|
|
199
|
+
onStart(app) {
|
|
200
|
+
swagger({ title: 'My API', path: '/docs' })(app)
|
|
201
|
+
},
|
|
202
|
+
})
|
|
133
203
|
```
|
|
134
204
|
|
|
135
205
|
### `generateOpenApiSpec(routesOrApp, config)`
|
|
136
|
-
Pure generator function that introspects routes, parameters,
|
|
206
|
+
Pure generator function that introspects routes, parameters, and `TexEngine`/Zod schemas and returns a complete `OpenApiSpec` object.
|
|
137
207
|
|
|
138
208
|
```typescript
|
|
209
|
+
import { generateOpenApiSpec } from 'exisjs/swagger'
|
|
210
|
+
|
|
139
211
|
const spec = generateOpenApiSpec(app, { title: 'My API', version: '1.0.0' })
|
|
140
212
|
```
|
|
141
213
|
|
|
142
214
|
### `renderDocumentationHtml(config)`
|
|
143
215
|
Renders standalone HTML markup for Swagger UI or Scalar API reference.
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
import { renderDocumentationHtml } from 'exisjs/swagger'
|
|
219
|
+
|
|
220
|
+
const html = renderDocumentationHtml({
|
|
221
|
+
title: 'My API',
|
|
222
|
+
specPath: '/docs/json',
|
|
223
|
+
ui: 'scalar',
|
|
224
|
+
})
|
|
225
|
+
```
|
|
226
|
+
|
|
@@ -234,7 +234,7 @@ type Profile = ResolveSchema<typeof ProfileSchema>
|
|
|
234
234
|
|
|
235
235
|
## OpenAPI Generation
|
|
236
236
|
|
|
237
|
-
The `TexEngine` automatically converts validation schemas into strictly compliant OpenAPI/Swagger JSON schemas when attached to routes. This powers zero-config Swagger documentation
|
|
237
|
+
The `TexEngine` automatically converts validation schemas into strictly compliant OpenAPI/Swagger JSON schemas when attached to routes. This powers zero-config Swagger documentation in `exisjs/swagger`.
|
|
238
238
|
|
|
239
239
|
---
|
|
240
240
|
|
package/dist/error/errors.d.ts
CHANGED
|
@@ -51,18 +51,30 @@ export declare class ServiceUnavailableError extends HttpError {
|
|
|
51
51
|
export declare class GatewayTimeoutError extends HttpError {
|
|
52
52
|
constructor(message?: string);
|
|
53
53
|
}
|
|
54
|
-
export declare
|
|
55
|
-
|
|
56
|
-
export declare
|
|
57
|
-
|
|
58
|
-
export declare
|
|
59
|
-
|
|
60
|
-
export declare
|
|
61
|
-
|
|
62
|
-
export declare
|
|
63
|
-
|
|
64
|
-
export declare
|
|
65
|
-
|
|
54
|
+
export declare class HttpException extends HttpError {
|
|
55
|
+
}
|
|
56
|
+
export declare class BadRequestException extends BadRequestError {
|
|
57
|
+
}
|
|
58
|
+
export declare class UnauthorizedException extends UnauthorizedError {
|
|
59
|
+
}
|
|
60
|
+
export declare class ForbiddenException extends ForbiddenError {
|
|
61
|
+
}
|
|
62
|
+
export declare class NotFoundException extends NotFoundError {
|
|
63
|
+
}
|
|
64
|
+
export declare class ConflictException extends ConflictError {
|
|
65
|
+
}
|
|
66
|
+
export declare class PayloadTooLargeException extends PayloadTooLargeError {
|
|
67
|
+
}
|
|
68
|
+
export declare class UnprocessableException extends UnprocessableError {
|
|
69
|
+
}
|
|
70
|
+
export declare class RateLimitException extends RateLimitError {
|
|
71
|
+
}
|
|
72
|
+
export declare class InternalException extends InternalError {
|
|
73
|
+
}
|
|
74
|
+
export declare class ServiceUnavailableException extends ServiceUnavailableError {
|
|
75
|
+
}
|
|
76
|
+
export declare class GatewayTimeoutException extends GatewayTimeoutError {
|
|
77
|
+
}
|
|
66
78
|
export declare function renderValidationTable(rows: {
|
|
67
79
|
field: string;
|
|
68
80
|
received: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/error/errors.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAKrD,qBAAa,SAAU,SAAQ,KAAK;IAClC,SAAgB,UAAU,EAAE,MAAM,CAAA;IAClC,SAAgB,IAAI,EAAE,MAAM,CAAA;IAC5B,SAAgB,aAAa,EAAE,OAAO,CAAA;IACtC,SAAgB,OAAO,CAAC,EAAE,OAAO,CAAA;gBAG/B,OAAO,EAAE,MAAM,EACf,UAAU,SAAM,EAChB,IAAI,SAAmB,EACvB,OAAO,CAAC,EAAE,OAAO;IAenB,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS;IAIhE,MAAM,CAAC,YAAY,CAAC,OAAO,SAAiB,GAAG,SAAS;IAIxD,MAAM,CAAC,SAAS,CAAC,OAAO,SAAc,GAAG,SAAS;IAIlD,MAAM,CAAC,QAAQ,CAAC,QAAQ,SAAa,GAAG,SAAS;IAIjD,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS;IAI3C,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS;IAInE,MAAM,CAAC,eAAe,CACpB,OAAO,SAAsB,EAC7B,OAAO,CAAC,EAAE,OAAO,GAChB,SAAS;IAIZ,MAAM,CAAC,eAAe,CAAC,OAAO,SAAsB,GAAG,SAAS;IAIhE,MAAM,CAAC,QAAQ,CAAC,OAAO,SAA0B,GAAG,SAAS;IAI7D,MAAM,CAAC,kBAAkB,CAAC,OAAO,SAAwB,GAAG,SAAS;IAIrE,MAAM,CAAC,cAAc,CAAC,OAAO,SAAoB,GAAG,SAAS;IAI7D,MAAM,IAAI,MAAM;CAUjB;AAED,qBAAa,eAAgB,SAAQ,SAAS;gBAChC,OAAO,SAAgB,EAAE,OAAO,CAAC,EAAE,OAAO;CAIvD;AAED,qBAAa,iBAAkB,SAAQ,SAAS;gBAClC,OAAO,SAAiB;CAIrC;AAED,qBAAa,cAAe,SAAQ,SAAS;gBAC/B,OAAO,SAAc;CAIlC;AAED,qBAAa,aAAc,SAAQ,SAAS;gBAC9B,QAAQ,SAAa;CAIlC;AAED,qBAAa,aAAc,SAAQ,SAAS;gBAC9B,OAAO,SAAa;CAIjC;AAED,qBAAa,kBAAmB,SAAQ,SAAS;gBACnC,OAAO,SAAyB,EAAE,OAAO,CAAC,EAAE,OAAO;CAIhE;AAED,qBAAa,oBAAqB,SAAQ,SAAS;gBACrC,OAAO,SAAsB,EAAE,OAAO,CAAC,EAAE,OAAO;CAI7D;AAED,qBAAa,cAAe,SAAQ,SAAS;gBAC/B,OAAO,SAAsB;CAI1C;AAED,qBAAa,aAAc,SAAQ,SAAS;gBAC9B,OAAO,SAA0B;CAI9C;AAED,qBAAa,uBAAwB,SAAQ,SAAS;gBACxC,OAAO,SAAwB;CAI5C;AAED,qBAAa,mBAAoB,SAAQ,SAAS;gBACpC,OAAO,SAAoB;CAIxC;AAGD,
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/error/errors.ts"],"names":[],"mappings":"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"}
|
package/dist/error/errors.js
CHANGED
|
@@ -145,18 +145,42 @@ class GatewayTimeoutError extends HttpError {
|
|
|
145
145
|
}
|
|
146
146
|
exports.GatewayTimeoutError = GatewayTimeoutError;
|
|
147
147
|
// ─── Exception Aliases ────────────────────────────────────────────────────────
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
exports.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
exports.
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
exports.
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
exports.
|
|
148
|
+
class HttpException extends HttpError {
|
|
149
|
+
}
|
|
150
|
+
exports.HttpException = HttpException;
|
|
151
|
+
class BadRequestException extends BadRequestError {
|
|
152
|
+
}
|
|
153
|
+
exports.BadRequestException = BadRequestException;
|
|
154
|
+
class UnauthorizedException extends UnauthorizedError {
|
|
155
|
+
}
|
|
156
|
+
exports.UnauthorizedException = UnauthorizedException;
|
|
157
|
+
class ForbiddenException extends ForbiddenError {
|
|
158
|
+
}
|
|
159
|
+
exports.ForbiddenException = ForbiddenException;
|
|
160
|
+
class NotFoundException extends NotFoundError {
|
|
161
|
+
}
|
|
162
|
+
exports.NotFoundException = NotFoundException;
|
|
163
|
+
class ConflictException extends ConflictError {
|
|
164
|
+
}
|
|
165
|
+
exports.ConflictException = ConflictException;
|
|
166
|
+
class PayloadTooLargeException extends PayloadTooLargeError {
|
|
167
|
+
}
|
|
168
|
+
exports.PayloadTooLargeException = PayloadTooLargeException;
|
|
169
|
+
class UnprocessableException extends UnprocessableError {
|
|
170
|
+
}
|
|
171
|
+
exports.UnprocessableException = UnprocessableException;
|
|
172
|
+
class RateLimitException extends RateLimitError {
|
|
173
|
+
}
|
|
174
|
+
exports.RateLimitException = RateLimitException;
|
|
175
|
+
class InternalException extends InternalError {
|
|
176
|
+
}
|
|
177
|
+
exports.InternalException = InternalException;
|
|
178
|
+
class ServiceUnavailableException extends ServiceUnavailableError {
|
|
179
|
+
}
|
|
180
|
+
exports.ServiceUnavailableException = ServiceUnavailableException;
|
|
181
|
+
class GatewayTimeoutException extends GatewayTimeoutError {
|
|
182
|
+
}
|
|
183
|
+
exports.GatewayTimeoutException = GatewayTimeoutException;
|
|
160
184
|
// ─── Global Error Handler ─────────────────────────────────────────────────────
|
|
161
185
|
function escapeHtml(str) {
|
|
162
186
|
if (typeof str !== 'string')
|