exisjs 0.5.9 → 0.5.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/dist/auth/index.d.ts +3 -1
  2. package/dist/auth/index.d.ts.map +1 -1
  3. package/dist/auth/index.js +4 -1
  4. package/dist/auth/index.js.map +1 -1
  5. package/dist/auth/oauth/core.d.ts +96 -0
  6. package/dist/auth/oauth/core.d.ts.map +1 -0
  7. package/dist/auth/oauth/core.js +203 -0
  8. package/dist/auth/oauth/core.js.map +1 -0
  9. package/dist/auth/oauth/index.d.ts +45 -0
  10. package/dist/auth/oauth/index.d.ts.map +1 -0
  11. package/dist/auth/oauth/index.js +64 -0
  12. package/dist/auth/oauth/index.js.map +1 -0
  13. package/dist/auth/oauth/middleware.d.ts +63 -0
  14. package/dist/auth/oauth/middleware.d.ts.map +1 -0
  15. package/dist/auth/oauth/middleware.js +164 -0
  16. package/dist/auth/oauth/middleware.js.map +1 -0
  17. package/dist/auth/oauth/providers/custom.d.ts +41 -0
  18. package/dist/auth/oauth/providers/custom.d.ts.map +1 -0
  19. package/dist/auth/oauth/providers/custom.js +204 -0
  20. package/dist/auth/oauth/providers/custom.js.map +1 -0
  21. package/dist/auth/oauth/providers/discord.d.ts +23 -0
  22. package/dist/auth/oauth/providers/discord.d.ts.map +1 -0
  23. package/dist/auth/oauth/providers/discord.js +130 -0
  24. package/dist/auth/oauth/providers/discord.js.map +1 -0
  25. package/dist/auth/oauth/providers/facebook.d.ts +28 -0
  26. package/dist/auth/oauth/providers/facebook.d.ts.map +1 -0
  27. package/dist/auth/oauth/providers/facebook.js +124 -0
  28. package/dist/auth/oauth/providers/facebook.js.map +1 -0
  29. package/dist/auth/oauth/providers/github.d.ts +25 -0
  30. package/dist/auth/oauth/providers/github.d.ts.map +1 -0
  31. package/dist/auth/oauth/providers/github.js +132 -0
  32. package/dist/auth/oauth/providers/github.js.map +1 -0
  33. package/dist/auth/oauth/providers/google.d.ts +23 -0
  34. package/dist/auth/oauth/providers/google.d.ts.map +1 -0
  35. package/dist/auth/oauth/providers/google.js +134 -0
  36. package/dist/auth/oauth/providers/google.js.map +1 -0
  37. package/dist/auth/oauth/providers/microsoft.d.ts +28 -0
  38. package/dist/auth/oauth/providers/microsoft.d.ts.map +1 -0
  39. package/dist/auth/oauth/providers/microsoft.js +136 -0
  40. package/dist/auth/oauth/providers/microsoft.js.map +1 -0
  41. package/dist/auth/oauth/types.d.ts +158 -0
  42. package/dist/auth/oauth/types.d.ts.map +1 -0
  43. package/dist/auth/oauth/types.js +4 -0
  44. package/dist/auth/oauth/types.js.map +1 -0
  45. package/dist/auth/session.d.ts +4 -1
  46. package/dist/auth/session.d.ts.map +1 -1
  47. package/dist/auth/session.js +33 -5
  48. package/dist/auth/session.js.map +1 -1
  49. package/dist/cache/store.d.ts +11 -3
  50. package/dist/cache/store.d.ts.map +1 -1
  51. package/dist/cache/store.js +87 -19
  52. package/dist/cache/store.js.map +1 -1
  53. package/dist/cli/commands/dev.d.ts.map +1 -1
  54. package/dist/cli/commands/dev.js +4 -6
  55. package/dist/cli/commands/dev.js.map +1 -1
  56. package/dist/database/adapters/mongodb.d.ts +58 -0
  57. package/dist/database/adapters/mongodb.d.ts.map +1 -0
  58. package/dist/database/adapters/mongodb.js +264 -0
  59. package/dist/database/adapters/mongodb.js.map +1 -0
  60. package/dist/database/adapters/mysql.d.ts +27 -0
  61. package/dist/database/adapters/mysql.d.ts.map +1 -0
  62. package/dist/database/adapters/mysql.js +188 -0
  63. package/dist/database/adapters/mysql.js.map +1 -0
  64. package/dist/database/adapters/postgres.d.ts +28 -0
  65. package/dist/database/adapters/postgres.d.ts.map +1 -0
  66. package/dist/database/adapters/postgres.js +174 -0
  67. package/dist/database/adapters/postgres.js.map +1 -0
  68. package/dist/database/adapters/sqlite.d.ts +27 -0
  69. package/dist/database/adapters/sqlite.d.ts.map +1 -0
  70. package/dist/database/adapters/sqlite.js +149 -0
  71. package/dist/database/adapters/sqlite.js.map +1 -0
  72. package/dist/database/index.d.ts +42 -0
  73. package/dist/database/index.d.ts.map +1 -0
  74. package/dist/database/index.js +58 -0
  75. package/dist/database/index.js.map +1 -0
  76. package/dist/database/manager.d.ts +114 -0
  77. package/dist/database/manager.d.ts.map +1 -0
  78. package/dist/database/manager.js +269 -0
  79. package/dist/database/manager.js.map +1 -0
  80. package/dist/database/migration.d.ts +57 -0
  81. package/dist/database/migration.d.ts.map +1 -0
  82. package/dist/database/migration.js +329 -0
  83. package/dist/database/migration.js.map +1 -0
  84. package/dist/database/query-builder.d.ts +89 -0
  85. package/dist/database/query-builder.d.ts.map +1 -0
  86. package/dist/database/query-builder.js +353 -0
  87. package/dist/database/query-builder.js.map +1 -0
  88. package/dist/database/types.d.ts +184 -0
  89. package/dist/database/types.d.ts.map +1 -0
  90. package/dist/database/types.js +4 -0
  91. package/dist/database/types.js.map +1 -0
  92. package/dist/docs/ARCHITECTURE.md +349 -0
  93. package/dist/docs/BENCHMARKS.md +36 -0
  94. package/dist/docs/README.md +34 -0
  95. package/dist/docs/content/README.md +44 -0
  96. package/dist/docs/content/adapters.mdx +199 -0
  97. package/dist/docs/content/cache.mdx +239 -0
  98. package/dist/docs/content/circuit-breaker.mdx +130 -0
  99. package/dist/docs/content/cli/commands.mdx +214 -0
  100. package/dist/docs/content/cli/overview.mdx +92 -0
  101. package/dist/docs/content/cli/usage.mdx +61 -0
  102. package/dist/docs/content/config.mdx +214 -0
  103. package/dist/docs/content/controllers.mdx +241 -0
  104. package/dist/docs/content/cron.mdx +109 -0
  105. package/dist/docs/content/database.mdx +209 -0
  106. package/dist/docs/content/dataloader.mdx +170 -0
  107. package/dist/docs/content/decorators.mdx +204 -0
  108. package/dist/docs/content/errors.mdx +344 -0
  109. package/dist/docs/content/gateways.mdx +376 -0
  110. package/dist/docs/content/installation.mdx +210 -0
  111. package/dist/docs/content/introduction.mdx +96 -0
  112. package/dist/docs/content/middleware.mdx +441 -0
  113. package/dist/docs/content/modules.mdx +144 -0
  114. package/dist/docs/content/oauth.mdx +179 -0
  115. package/dist/docs/content/providers.mdx +147 -0
  116. package/dist/docs/content/queues.mdx +177 -0
  117. package/dist/docs/content/requests.mdx +293 -0
  118. package/dist/docs/content/responses.mdx +271 -0
  119. package/dist/docs/content/routing.mdx +541 -0
  120. package/dist/docs/content/rpc.mdx +146 -0
  121. package/dist/docs/content/security.mdx +294 -0
  122. package/dist/docs/content/sse.mdx +159 -0
  123. package/dist/docs/content/structure.mdx +116 -0
  124. package/dist/docs/content/testing.mdx +139 -0
  125. package/dist/docs/content/validation.mdx +249 -0
  126. package/dist/docs/content/websockets.mdx +289 -0
  127. package/dist/docs/integrations/README.md +23 -0
  128. package/dist/docs/integrations/jwt.mdx +151 -0
  129. package/dist/docs/integrations/mongo.mdx +183 -0
  130. package/dist/docs/integrations/observability.mdx +125 -0
  131. package/dist/docs/integrations/openai.mdx +108 -0
  132. package/dist/docs/integrations/postgres.mdx +190 -0
  133. package/dist/docs/integrations/posthog.mdx +122 -0
  134. package/dist/docs/integrations/redis.mdx +141 -0
  135. package/dist/docs/integrations/resend.mdx +117 -0
  136. package/dist/docs/integrations/s3.mdx +122 -0
  137. package/dist/docs/integrations/swagger.mdx +113 -0
  138. package/dist/docs/reference/README.md +3 -0
  139. package/dist/docs/reference/adapters.mdx +130 -0
  140. package/dist/docs/reference/auth.mdx +183 -0
  141. package/dist/docs/reference/cache.mdx +132 -0
  142. package/dist/docs/reference/circuit-breaker.mdx +71 -0
  143. package/dist/docs/reference/config.mdx +118 -0
  144. package/dist/docs/reference/context.mdx +168 -0
  145. package/dist/docs/reference/dataloader.mdx +91 -0
  146. package/dist/docs/reference/decorators.mdx +293 -0
  147. package/dist/docs/reference/di.mdx +123 -0
  148. package/dist/docs/reference/error.mdx +170 -0
  149. package/dist/docs/reference/exis.mdx +124 -0
  150. package/dist/docs/reference/middleware.mdx +304 -0
  151. package/dist/docs/reference/plugin.mdx +113 -0
  152. package/dist/docs/reference/queue.mdx +155 -0
  153. package/dist/docs/reference/router.mdx +248 -0
  154. package/dist/docs/reference/sanitize.mdx +130 -0
  155. package/dist/docs/reference/storage.mdx +116 -0
  156. package/dist/docs/reference/swagger.mdx +132 -0
  157. package/dist/docs/reference/testing.mdx +145 -0
  158. package/dist/docs/reference/validator.mdx +186 -0
  159. package/dist/index.d.ts +4 -0
  160. package/dist/index.d.ts.map +1 -1
  161. package/dist/index.js +10 -1
  162. package/dist/index.js.map +1 -1
  163. package/dist/middleware/backpressure.d.ts.map +1 -1
  164. package/dist/middleware/backpressure.js +21 -12
  165. package/dist/middleware/backpressure.js.map +1 -1
  166. package/dist/middleware/cache.d.ts +6 -0
  167. package/dist/middleware/cache.d.ts.map +1 -1
  168. package/dist/middleware/cache.js +84 -28
  169. package/dist/middleware/cache.js.map +1 -1
  170. package/dist/middleware/idempotency.d.ts +4 -1
  171. package/dist/middleware/idempotency.d.ts.map +1 -1
  172. package/dist/middleware/idempotency.js +29 -4
  173. package/dist/middleware/idempotency.js.map +1 -1
  174. package/dist/middleware/ip-filter.d.ts.map +1 -1
  175. package/dist/middleware/ip-filter.js +16 -0
  176. package/dist/middleware/ip-filter.js.map +1 -1
  177. package/dist/middleware/rate-limit.d.ts.map +1 -1
  178. package/dist/middleware/rate-limit.js +29 -12
  179. package/dist/middleware/rate-limit.js.map +1 -1
  180. package/dist/queue/drivers/MemoryDriver.d.ts +6 -3
  181. package/dist/queue/drivers/MemoryDriver.d.ts.map +1 -1
  182. package/dist/queue/drivers/MemoryDriver.js +76 -23
  183. package/dist/queue/drivers/MemoryDriver.js.map +1 -1
  184. package/dist/server/bootstrapper.d.ts +3 -0
  185. package/dist/server/bootstrapper.d.ts.map +1 -1
  186. package/dist/server/bootstrapper.js +56 -8
  187. package/dist/server/bootstrapper.js.map +1 -1
  188. package/dist/server/bun-adapter.d.ts +2 -0
  189. package/dist/server/bun-adapter.d.ts.map +1 -1
  190. package/dist/server/bun-adapter.js +23 -12
  191. package/dist/server/bun-adapter.js.map +1 -1
  192. package/dist/server/request-handler.d.ts +0 -2
  193. package/dist/server/request-handler.d.ts.map +1 -1
  194. package/dist/server/request-handler.js +2 -24
  195. package/dist/server/request-handler.js.map +1 -1
  196. package/dist/server/request.d.ts.map +1 -1
  197. package/dist/server/request.js +24 -11
  198. package/dist/server/request.js.map +1 -1
  199. package/dist/server/uws-adapter.d.ts +80 -0
  200. package/dist/server/uws-adapter.d.ts.map +1 -0
  201. package/dist/server/uws-adapter.js +357 -0
  202. package/dist/server/uws-adapter.js.map +1 -0
  203. package/dist/server/ws-orchestrator.d.ts +1 -0
  204. package/dist/server/ws-orchestrator.d.ts.map +1 -1
  205. package/dist/server/ws-orchestrator.js +83 -0
  206. package/dist/server/ws-orchestrator.js.map +1 -1
  207. package/dist/types.d.ts +1 -1
  208. package/dist/types.d.ts.map +1 -1
  209. package/dist/utils/config.js.map +1 -1
  210. package/dist/validator/tex.d.ts +21 -16
  211. package/dist/validator/tex.d.ts.map +1 -1
  212. package/dist/validator/tex.js.map +1 -1
  213. package/package.json +11 -3
@@ -0,0 +1,170 @@
1
+ ---
2
+ nextUrl: "/docs/security"
3
+ nextTitle: "Security & Auth"
4
+ ---
5
+
6
+ # Dataloader (N+1 Queries)
7
+
8
+ The **N+1 problem** is a common performance issue in backend development. It occurs when your code executes one query to fetch a list of items (e.g. 100 Posts), and then executes $N$ additional queries to fetch related data (e.g. 100 separate queries for each Post's Author).
9
+
10
+ ExisJS ships with a native `Dataloader` implementation (inspired by GraphQL/Facebook's DataLoader) built directly into the core framework. It automatically **batches** and **caches** requests over a single tick of the Node.js event loop.
11
+
12
+ ---
13
+
14
+ ## 1. Defining Loaders
15
+
16
+ The best practice in ExisJS is to define a central registry of Dataloaders that are **securely scoped to the current HTTP Request** (to prevent data leaking between different users).
17
+
18
+ ExisJS provides `defineLoaders` to create this context-aware registry.
19
+
20
+ ```typescript filename="src/loaders.ts"
21
+ import { Dataloader, defineLoaders } from 'exisjs/dataloader'
22
+ import { getRequest } from 'exisjs/router'
23
+ import { db } from './db'
24
+
25
+ export const { loaderMiddleware, getLoaders } = defineLoaders({
26
+ // 1. Author Loader
27
+ authorLoader: () => new Dataloader<number, any>(async (keys) => {
28
+ // You can access the current HTTP Request anywhere using getRequest()
29
+ const req = getRequest()
30
+ const authToken = req.headers.authorization
31
+
32
+ // This function will only be called ONCE per event-loop tick,
33
+ // receiving an array of all requested Author IDs: e.g. [1, 2, 3]
34
+ const authors = await db.authors.findMany({
35
+ where: { id: { in: keys } }
36
+ })
37
+
38
+ // You MUST return an array of results in the EXACT same order as the keys
39
+ return keys.map(key => authors.find(a => a.id === key) || new Error('Not found'))
40
+ }),
41
+
42
+ // 2. Comments Loader
43
+ commentsLoader: () => new Dataloader<number, any[]>(async (keys) => {
44
+ const comments = await db.comments.findMany({
45
+ where: { postId: { in: keys } }
46
+ })
47
+
48
+ // Group comments by postId
49
+ return keys.map(key => comments.filter(c => c.postId === key))
50
+ })
51
+ })
52
+ ```
53
+
54
+ ---
55
+
56
+ ## 2. Registering the Middleware
57
+
58
+ `defineLoaders` returns a `loaderMiddleware`. You must register this middleware so that ExisJS can securely inject a fresh, isolated instance of your Dataloaders into every incoming request.
59
+
60
+ Because ExisJS uses lazy-initialization, there is **zero performance penalty** for routes that don't actually use the loaders.
61
+
62
+ #### Functional Paradigm
63
+
64
+ ```typescript filename="src/http/server.ts"
65
+ import { exis } from 'exisjs'
66
+ import { loaderMiddleware } from '../loaders'
67
+
68
+ export default exis({
69
+ async onStart(app) {
70
+ // Register globally for all routes
71
+ app.use(loaderMiddleware)
72
+ }
73
+ })
74
+ ```
75
+
76
+ #### Class-Based (OOP) Paradigm
77
+
78
+ ```typescript filename="src/http/server.ts"
79
+ import { Server } from 'exisjs/decorators'
80
+ import { loaderMiddleware } from '../loaders'
81
+ import type { App } from 'exisjs'
82
+
83
+ @Server()
84
+ export default class RootServer {
85
+ async onStart(app: App) {
86
+ // Register globally for all routes
87
+ app.use(loaderMiddleware)
88
+ }
89
+ }
90
+ ```
91
+
92
+ ---
93
+
94
+ ## 3. Using Dataloader in Routes
95
+
96
+ Anywhere in your application (Routes, Controllers, Services), you can call `getLoaders()` to retrieve the securely isolated loaders for the *current* request.
97
+
98
+ #### Functional Paradigm
99
+
100
+ ```typescript filename="src/http/posts/route.ts"
101
+ import { controller, route } from 'exisjs/router'
102
+ import { getLoaders } from '../../loaders'
103
+
104
+ export default controller({
105
+ list: route.get('/', {
106
+ async handle() {
107
+ // 1. Fetch 100 posts (1 Query)
108
+ const posts = await db.posts.findMany()
109
+
110
+ const { authorLoader } = getLoaders()
111
+
112
+ // 2. Loop through 100 posts and call .load()
113
+ const postsWithAuthors = await Promise.all(
114
+ posts.map(async (post) => {
115
+ // Instead of firing 100 queries to the database,
116
+ // Dataloader queues them up and fires exactly ONE batched query.
117
+ const author = await authorLoader.load(post.authorId)
118
+ return { ...post, author }
119
+ })
120
+ )
121
+
122
+ return postsWithAuthors
123
+ // Total Queries: 2 (Not 101)
124
+ }
125
+ })
126
+ })
127
+ ```
128
+
129
+ #### Class-Based (OOP) Paradigm
130
+
131
+ ```typescript filename="src/http/posts/route.ts"
132
+ import { Controller, Get } from 'exisjs/decorators'
133
+ import { getLoaders } from '../../loaders'
134
+
135
+ @Controller()
136
+ export default class PostsController {
137
+ @Get('/')
138
+ async list() {
139
+ // 1. Fetch 100 posts (1 Query)
140
+ const posts = await db.posts.findMany()
141
+
142
+ const { authorLoader } = getLoaders()
143
+
144
+ // 2. Loop through 100 posts and call .load()
145
+ const postsWithAuthors = await Promise.all(
146
+ posts.map(async (post) => {
147
+ // Instead of firing 100 queries to the database,
148
+ // Dataloader queues them up and fires exactly ONE batched query.
149
+ const author = await authorLoader.load(post.authorId)
150
+ return { ...post, author }
151
+ })
152
+ )
153
+
154
+ return postsWithAuthors
155
+ // Total Queries: 2 (Not 101)
156
+ }
157
+ }
158
+ ```
159
+
160
+ ---
161
+
162
+ ## API Reference (`exisjs/dataloader`)
163
+
164
+ The `Dataloader` class exposes the standard, battle-tested API:
165
+
166
+ - **`load(key: K): Promise<V>`**: Queues a key to be fetched and returns a Promise.
167
+ - **`loadMany(keys: K[]): Promise<V[]>`**: Equivalent to calling `Promise.all(keys.map(k => load(k)))`.
168
+ - **`clear(key: K): this`**: Clears the cached result for a specific key.
169
+ - **`clearAll(): this`**: Clears the entire cache for this dataloader instance.
170
+ - **`prime(key: K, value: V): this`**: Primes the cache with a predefined value, preventing the batch function from being called for that key.
@@ -0,0 +1,204 @@
1
+ # Decorators
2
+
3
+ ExisJS provides standard ES6 decorators for developers who prefer the Object-Oriented Programming (OOP) paradigm (inspired by NestJS).
4
+
5
+ Because ExisJS does not rely on reflection libraries like `reflect-metadata`, these decorators are fast and memory-efficient.
6
+
7
+ All decorators can be imported directly from `exisjs/decorators`.
8
+
9
+ ---
10
+
11
+ ## 1. Servers & Gateways
12
+
13
+ ExisJS allows you to configure your root application and directory-scoped gateways using decorators, replacing the need for functional `exis()` and `defineGateway()` wrappers if you prefer OOP.
14
+
15
+ ### `@Server(config)`
16
+ Used exclusively in your `src/http/server.ts` file to bootstrap the application.
17
+
18
+ ```typescript filename="src/http/server.ts"
19
+ import { Server } from 'exisjs/decorators'
20
+ import { metricsPlugin } from './plugins/metrics'
21
+ import type { App } from 'exisjs'
22
+
23
+ @Server({
24
+ plugins: [metricsPlugin],
25
+ providers: [['Logger', { useValue: console }]]
26
+ })
27
+ export default class RootServer {
28
+ async onStart(app: App) {
29
+ console.log('Server started')
30
+ }
31
+ }
32
+ ```
33
+
34
+ ### `@Gateway(config)`
35
+ Used inside any folder (e.g. `src/http/admin/gateway.ts`) to act as a gatekeeper for all routes within that directory and its subdirectories.
36
+
37
+ ```typescript filename="src/http/admin/gateway.ts"
38
+ import { Gateway } from 'exisjs/decorators'
39
+ import { requireAuth } from '../../middleware/auth'
40
+
41
+ @Gateway({
42
+ middleware: [requireAuth],
43
+ cors: { origin: 'https://admin.com' },
44
+ timeout: 10000,
45
+ metadata: { openapi: { tags: ['Admin'] } }
46
+ })
47
+ export default class AdminGateway {}
48
+ ```
49
+
50
+ ---
51
+
52
+ ## 1. Controllers & Routing
53
+
54
+ To map a class to a route prefix, use the `@Controller()` decorator. You can then use HTTP Method decorators to map class methods to specific endpoints.
55
+
56
+ ```typescript filename="src/http/users/route.ts"
57
+ import { Controller, Get, Post, Put, Delete } from 'exisjs/decorators'
58
+
59
+ @Controller('/users')
60
+ export default class UsersController {
61
+
62
+ @Get('/')
63
+ async listUsers() {
64
+ return { users: [] }
65
+ }
66
+
67
+ @Post('/create')
68
+ async createUser() {
69
+ return { success: true }
70
+ }
71
+
72
+ @Delete('/:id')
73
+ async deleteUser() {}
74
+ }
75
+ ```
76
+
77
+ ### Available Method Decorators
78
+ - `@Get(path?, schema?)`
79
+ - `@Post(path?, schema?)`
80
+ - `@Put(path?, schema?)`
81
+ - `@Patch(path?, schema?)`
82
+ - `@Delete(path?, schema?)`
83
+ - `@Options(path?, schema?)`
84
+ - `@Head(path?, schema?)`
85
+ - `@All(path?, schema?)`
86
+ - `@Ws(path?, schema?)` (For WebSockets)
87
+ - `@Sse(path?, schema?)` (For Server-Sent Events)
88
+
89
+ ---
90
+
91
+ ## 2. Request Parameters
92
+
93
+ Instead of manually digging through the `req` object, ExisJS allows you to inject request properties directly into your method parameters.
94
+
95
+ ```typescript filename="src/http/users/route.ts"
96
+ import { Controller, Post, Body, Param, Headers, Req, Res } from 'exisjs/decorators'
97
+
98
+ @Controller('/users')
99
+ export default class UsersController {
100
+
101
+ @Post('/:id')
102
+ async update(
103
+ @Param('id') id: string,
104
+ @Body() payload: any,
105
+ @Headers('authorization') token: string,
106
+ @Req() req: any,
107
+ @Res() res: any
108
+ ) {
109
+ return { success: true, id, payload }
110
+ }
111
+ }
112
+ ```
113
+
114
+ ### Available Parameter Decorators
115
+ - `@Body(key?)` - Extracts `req.body` or a specific key.
116
+ - `@Param(key?)` - Extracts `req.params` or a specific key.
117
+ - `@Query(key?)` - Extracts `req.query` or a specific key.
118
+ - `@Headers(key?)` - Extracts `req.headers` or a specific key.
119
+ - `@Req()` - Injects the underlying `ExisRequest` object.
120
+ - `@Res({ passthrough?: boolean })` - Injects the underlying `ExisResponse` object.
121
+ - `@Ip()` - Extracts the client IP address.
122
+ - `@Next()` - Injects the `next()` function for middleware bypass.
123
+ - `@Session()` - Injects `req.session` (if a session plugin is active).
124
+ - `@Socket()` - Injects the `ExisWebSocket` (only valid in `@Ws` routes).
125
+ - `@Stream()` - Injects the `ExisSSE` stream (only valid in `@Sse` routes).
126
+ - `@UploadedFile()` / `@UploadedFiles()` - Automatically extracts multipart form-data files.
127
+
128
+ ---
129
+
130
+ ## 3. Middleware & Lifecycles
131
+
132
+ You can bind Middleware, Guards, Exception Filters, and Interceptors directly to your Controllers or individual methods using decorators.
133
+
134
+ ```typescript filename="src/http/admin/route.ts"
135
+ import { Controller, Get, Use, UseGuards, UseFilters } from 'exisjs/decorators'
136
+ import { requireAuth } from '../../middleware/auth'
137
+ import { RoleGuard } from '../../guards/role'
138
+ import { AdminErrorFilter } from '../../filters/admin'
139
+
140
+ @Controller('/admin')
141
+ @Use(requireAuth) // Applies to the entire class
142
+ @UseFilters(AdminErrorFilter) // Applies to the entire class
143
+ export default class AdminController {
144
+
145
+ @Get('/dashboard')
146
+ @UseGuards(RoleGuard) // Applies ONLY to this method
147
+ async getDashboard() {
148
+ return { secret: 'data' }
149
+ }
150
+ }
151
+ ```
152
+
153
+ ### Available Lifecycle Decorators
154
+ - `@Use(...middlewares)` - Binds standard Express-style middleware.
155
+ - `@UseGuards(...guards)` - Binds ExisJS authorization Guards.
156
+ - `@UseInterceptors(...interceptors)` - Binds response Interceptors.
157
+ - `@UseFilters(...filters)` - Binds Exception Filters.
158
+
159
+ ---
160
+
161
+ ## 4. Response Modifiers
162
+
163
+ Sometimes you need to modify the HTTP Response (like changing the status code or adding a header) without injecting the raw `@Res()` object.
164
+
165
+ ```typescript filename="src/http/api/route.ts"
166
+ import { Controller, Post, HttpCode, Header, Redirect } from 'exisjs/decorators'
167
+
168
+ @Controller('/api')
169
+ export default class ApiController {
170
+
171
+ @Post('/create')
172
+ @HttpCode(201) // Forces the response status to 201 Created
173
+ @Header('X-Custom-Version', '2.0') // Appends a custom header
174
+ async create() {
175
+ return { success: true }
176
+ }
177
+
178
+ @Get('/legacy')
179
+ @Redirect('/new-api', 301) // Automatically redirects the client
180
+ async legacy() {}
181
+ }
182
+ ```
183
+
184
+ ### Available Response & Metadata Decorators
185
+ - `@HttpCode(code: number)`
186
+ - `@Header(name: string, value: string)`
187
+ - `@Redirect(url: string, statusCode?: number)`
188
+ - `@Hosts(...hosts: string[])` - Restricts a route/controller to a specific Host header (e.g. `api.example.com`).
189
+ - `@Permissions(...permissions: string[])` - Restricts a route/controller to users with specific permissions.
190
+
191
+ ---
192
+
193
+ ## 5. Dependency Injection
194
+
195
+ To mark a class as a service that can be injected into your controllers, use the `@Injectable()` decorator.
196
+
197
+ ```typescript filename="src/services/db.ts"
198
+ import { Injectable } from 'exisjs/decorators'
199
+
200
+ @Injectable({ scope: 'singleton' })
201
+ export class DatabaseService {
202
+ async findUser() { ... }
203
+ }
204
+ ```