exisjs 0.5.10 → 0.5.12

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 (191) 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/cli/commands/dev.d.ts.map +1 -1
  46. package/dist/cli/commands/dev.js +0 -1
  47. package/dist/cli/commands/dev.js.map +1 -1
  48. package/dist/database/adapters/mongodb.d.ts +58 -0
  49. package/dist/database/adapters/mongodb.d.ts.map +1 -0
  50. package/dist/database/adapters/mongodb.js +264 -0
  51. package/dist/database/adapters/mongodb.js.map +1 -0
  52. package/dist/database/adapters/mysql.d.ts +27 -0
  53. package/dist/database/adapters/mysql.d.ts.map +1 -0
  54. package/dist/database/adapters/mysql.js +188 -0
  55. package/dist/database/adapters/mysql.js.map +1 -0
  56. package/dist/database/adapters/postgres.d.ts +28 -0
  57. package/dist/database/adapters/postgres.d.ts.map +1 -0
  58. package/dist/database/adapters/postgres.js +174 -0
  59. package/dist/database/adapters/postgres.js.map +1 -0
  60. package/dist/database/adapters/sqlite.d.ts +27 -0
  61. package/dist/database/adapters/sqlite.d.ts.map +1 -0
  62. package/dist/database/adapters/sqlite.js +149 -0
  63. package/dist/database/adapters/sqlite.js.map +1 -0
  64. package/dist/database/index.d.ts +42 -0
  65. package/dist/database/index.d.ts.map +1 -0
  66. package/dist/database/index.js +58 -0
  67. package/dist/database/index.js.map +1 -0
  68. package/dist/database/manager.d.ts +114 -0
  69. package/dist/database/manager.d.ts.map +1 -0
  70. package/dist/database/manager.js +269 -0
  71. package/dist/database/manager.js.map +1 -0
  72. package/dist/database/migration.d.ts +57 -0
  73. package/dist/database/migration.d.ts.map +1 -0
  74. package/dist/database/migration.js +329 -0
  75. package/dist/database/migration.js.map +1 -0
  76. package/dist/database/query-builder.d.ts +89 -0
  77. package/dist/database/query-builder.d.ts.map +1 -0
  78. package/dist/database/query-builder.js +353 -0
  79. package/dist/database/query-builder.js.map +1 -0
  80. package/dist/database/types.d.ts +184 -0
  81. package/dist/database/types.d.ts.map +1 -0
  82. package/dist/database/types.js +4 -0
  83. package/dist/database/types.js.map +1 -0
  84. package/dist/docs/ARCHITECTURE.md +349 -0
  85. package/dist/docs/BENCHMARKS.md +36 -0
  86. package/dist/docs/README.md +34 -0
  87. package/dist/docs/content/README.md +44 -0
  88. package/dist/docs/content/adapters.mdx +199 -0
  89. package/dist/docs/content/cache.mdx +239 -0
  90. package/dist/docs/content/circuit-breaker.mdx +130 -0
  91. package/dist/docs/content/cli/commands.mdx +214 -0
  92. package/dist/docs/content/cli/overview.mdx +92 -0
  93. package/dist/docs/content/cli/usage.mdx +61 -0
  94. package/dist/docs/content/config.mdx +214 -0
  95. package/dist/docs/content/controllers.mdx +241 -0
  96. package/dist/docs/content/cron.mdx +109 -0
  97. package/dist/docs/content/database.mdx +209 -0
  98. package/dist/docs/content/dataloader.mdx +170 -0
  99. package/dist/docs/content/decorators.mdx +204 -0
  100. package/dist/docs/content/errors.mdx +344 -0
  101. package/dist/docs/content/exisjs-mcp.mdx +97 -0
  102. package/dist/docs/content/gateways.mdx +376 -0
  103. package/dist/docs/content/installation.mdx +210 -0
  104. package/dist/docs/content/introduction.mdx +96 -0
  105. package/dist/docs/content/middleware.mdx +441 -0
  106. package/dist/docs/content/modules.mdx +144 -0
  107. package/dist/docs/content/oauth.mdx +179 -0
  108. package/dist/docs/content/providers.mdx +147 -0
  109. package/dist/docs/content/queues.mdx +177 -0
  110. package/dist/docs/content/requests.mdx +293 -0
  111. package/dist/docs/content/responses.mdx +271 -0
  112. package/dist/docs/content/routing.mdx +541 -0
  113. package/dist/docs/content/rpc.mdx +146 -0
  114. package/dist/docs/content/security.mdx +294 -0
  115. package/dist/docs/content/sse.mdx +159 -0
  116. package/dist/docs/content/structure.mdx +116 -0
  117. package/dist/docs/content/testing.mdx +139 -0
  118. package/dist/docs/content/validation.mdx +249 -0
  119. package/dist/docs/content/websockets.mdx +289 -0
  120. package/dist/docs/integrations/README.md +23 -0
  121. package/dist/docs/integrations/jwt.mdx +151 -0
  122. package/dist/docs/integrations/mongo.mdx +183 -0
  123. package/dist/docs/integrations/observability.mdx +125 -0
  124. package/dist/docs/integrations/openai.mdx +108 -0
  125. package/dist/docs/integrations/postgres.mdx +190 -0
  126. package/dist/docs/integrations/posthog.mdx +122 -0
  127. package/dist/docs/integrations/redis.mdx +141 -0
  128. package/dist/docs/integrations/resend.mdx +117 -0
  129. package/dist/docs/integrations/s3.mdx +122 -0
  130. package/dist/docs/integrations/swagger.mdx +113 -0
  131. package/dist/docs/reference/README.md +3 -0
  132. package/dist/docs/reference/adapters.mdx +130 -0
  133. package/dist/docs/reference/auth.mdx +183 -0
  134. package/dist/docs/reference/cache.mdx +132 -0
  135. package/dist/docs/reference/circuit-breaker.mdx +71 -0
  136. package/dist/docs/reference/config.mdx +118 -0
  137. package/dist/docs/reference/context.mdx +168 -0
  138. package/dist/docs/reference/dataloader.mdx +91 -0
  139. package/dist/docs/reference/decorators.mdx +293 -0
  140. package/dist/docs/reference/di.mdx +123 -0
  141. package/dist/docs/reference/error.mdx +170 -0
  142. package/dist/docs/reference/exis.mdx +124 -0
  143. package/dist/docs/reference/middleware.mdx +304 -0
  144. package/dist/docs/reference/plugin.mdx +113 -0
  145. package/dist/docs/reference/queue.mdx +155 -0
  146. package/dist/docs/reference/router.mdx +248 -0
  147. package/dist/docs/reference/sanitize.mdx +130 -0
  148. package/dist/docs/reference/storage.mdx +116 -0
  149. package/dist/docs/reference/swagger.mdx +132 -0
  150. package/dist/docs/reference/testing.mdx +145 -0
  151. package/dist/docs/reference/validator.mdx +186 -0
  152. package/dist/index.d.ts +4 -0
  153. package/dist/index.d.ts.map +1 -1
  154. package/dist/index.js +10 -1
  155. package/dist/index.js.map +1 -1
  156. package/dist/middleware/compression.d.ts +12 -0
  157. package/dist/middleware/compression.d.ts.map +1 -1
  158. package/dist/middleware/compression.js +61 -99
  159. package/dist/middleware/compression.js.map +1 -1
  160. package/dist/middleware/middleware.d.ts.map +1 -1
  161. package/dist/middleware/middleware.js +25 -8
  162. package/dist/middleware/middleware.js.map +1 -1
  163. package/dist/middleware/security.d.ts.map +1 -1
  164. package/dist/middleware/security.js +6 -3
  165. package/dist/middleware/security.js.map +1 -1
  166. package/dist/router/router.d.ts.map +1 -1
  167. package/dist/router/router.js +11 -7
  168. package/dist/router/router.js.map +1 -1
  169. package/dist/server/bootstrapper.js +1 -1
  170. package/dist/server/bootstrapper.js.map +1 -1
  171. package/dist/server/bun-adapter.d.ts.map +1 -1
  172. package/dist/server/bun-adapter.js +2 -2
  173. package/dist/server/bun-adapter.js.map +1 -1
  174. package/dist/server/request-handler.d.ts +7 -0
  175. package/dist/server/request-handler.d.ts.map +1 -1
  176. package/dist/server/request-handler.js +37 -2
  177. package/dist/server/request-handler.js.map +1 -1
  178. package/dist/server/request.d.ts.map +1 -1
  179. package/dist/server/request.js +4 -6
  180. package/dist/server/request.js.map +1 -1
  181. package/dist/server/route-scanner.d.ts.map +1 -1
  182. package/dist/server/route-scanner.js +4 -1
  183. package/dist/server/route-scanner.js.map +1 -1
  184. package/dist/server/uws-adapter.d.ts +5 -3
  185. package/dist/server/uws-adapter.d.ts.map +1 -1
  186. package/dist/server/uws-adapter.js +39 -4
  187. package/dist/server/uws-adapter.js.map +1 -1
  188. package/dist/server/ws-orchestrator.d.ts.map +1 -1
  189. package/dist/server/ws-orchestrator.js +4 -13
  190. package/dist/server/ws-orchestrator.js.map +1 -1
  191. package/package.json +17 -10
@@ -0,0 +1,344 @@
1
+ ---
2
+ nextUrl: "/docs/websockets"
3
+ nextTitle: "WebSockets"
4
+ ---
5
+
6
+ # Error Handling
7
+
8
+ ExisJS implements a comprehensive error boundary and observability system. The framework is designed to reduce the need to manually construct HTTP error responses.
9
+
10
+ ## The `HttpError` System
11
+
12
+ You can throw an `HttpError` anywhere in your application, and the ExisJS router will automatically intercept it, log it, and format it into a standardized JSON response for the client.
13
+
14
+ ### Functional Paradigm
15
+
16
+ ```typescript filename="src/http/users/route.ts"
17
+ import { controller, route } from 'exisjs/router'
18
+ import { HttpError } from 'exisjs/error'
19
+
20
+ export default controller({
21
+ getUser: route.get('/:id', {
22
+ async handle({ params }) {
23
+ const user = db.findUser(params.id)
24
+
25
+ if (!user) {
26
+ // This stops execution and returns a 404
27
+ throw HttpError.notFound('User')
28
+ }
29
+
30
+ if (user.isBanned) {
31
+ // This returns a 403 Forbidden
32
+ throw HttpError.forbidden('User is banned from the platform')
33
+ }
34
+
35
+ return { user }
36
+ }
37
+ })
38
+ })
39
+ ```
40
+
41
+ ### Class-Based (OOP) Paradigm
42
+
43
+ ```typescript filename="src/http/users/route.ts"
44
+ import { Controller, Get, Param } from 'exisjs/decorators'
45
+ import { HttpError } from 'exisjs/error'
46
+
47
+ @Controller()
48
+ export default class UsersController {
49
+ @Get('/:id')
50
+ async getUser(@Param('id') id: string) {
51
+ const user = db.findUser(id)
52
+
53
+ if (!user) {
54
+ // This stops execution and returns a 404
55
+ throw HttpError.notFound('User')
56
+ }
57
+
58
+ if (user.isBanned) {
59
+ // This returns a 403 Forbidden
60
+ throw HttpError.forbidden('User is banned from the platform')
61
+ }
62
+
63
+ return { user }
64
+ }
65
+ }
66
+ ```
67
+
68
+ ### Common Error Factories
69
+
70
+ The `HttpError` class provides static factory methods for standard HTTP status codes:
71
+
72
+ - `HttpError.badRequest('Message')` - 400
73
+ - `HttpError.unauthorized('Message')` - 401
74
+ - `HttpError.forbidden('Message')` - 403
75
+ - `HttpError.notFound('Resource')` - 404
76
+ - `HttpError.conflict('Message')` - 409
77
+ - `HttpError.unprocessable('Message', details)` - 422
78
+ - `HttpError.internal('Message')` - 500
79
+
80
+ ### Direct Error Classes & Exceptions
81
+
82
+ If you prefer a class-based approach, ExisJS exports every standard error as its own class. We also provide `Exception` aliases for every error class. You can import and throw them directly:
83
+
84
+ ```typescript filename="example.ts"
85
+ import { NotFoundException, UnauthorizedException, BadRequestError } from 'exisjs/error'
86
+
87
+ export const deleteBook = (req, res) => {
88
+ const book = db.findBook(req.params.id)
89
+
90
+ if (!book) throw new NotFoundException('Book not found')
91
+ if (book.ownerId !== req.user.id) throw new UnauthorizedException('Unauthorized')
92
+
93
+ // ...
94
+ }
95
+ ```
96
+
97
+ ### The Standardized Response
98
+
99
+ When an `HttpError` is thrown, the client will automatically receive a structured JSON payload.
100
+
101
+ ```json filename="Response"
102
+ {
103
+ "success": false,
104
+ "error": {
105
+ "code": "NOT_FOUND",
106
+ "message": "User not found"
107
+ }
108
+ }
109
+ ```
110
+
111
+ If you throw an unhandled exception (like a database connection failure or a `TypeError`), ExisJS catches it and securely returns a `500 Internal Server Error`, hiding the stack trace from the client in production mode while logging the full trace to your internal logger.
112
+
113
+ ## Error Handling Decision Tree
114
+
115
+ To keep your codebase clean and consistent, use this decision tree when deciding how to handle errors:
116
+
117
+ 1. **Is it a known client error (e.g., missing parameter, forbidden)?**
118
+ 👉 **Throw an `HttpError` directly.** Let the framework format the 4xx response automatically.
119
+ 2. **Do you need to intercept an unexpected failure (e.g., Database Connection failure) globally?**
120
+ 👉 **Use an Exception Filter (`catchError`) in `server.ts`.** Map the specific exception class to a 5xx response.
121
+ 3. **Do you need to intercept errors only for a specific route group (e.g., Admin Panel)?**
122
+ 👉 **Use Local Error Hooks (`onError`) in the gateway/controller.** Keep the logic isolated to that specific module.
123
+ 4. **Is it standard 4-arg middleware from the Express ecosystem?**
124
+ 👉 **Use `app.use(errorHandler)`** (where `errorHandler = (err, req, res, next) => {}`). ExisJS supports standard Connect/Express error middleware natively.
125
+
126
+ ## Advanced Error Handling
127
+
128
+ ExisJS provides mechanisms for granular error handling.
129
+
130
+ ### 1. Exception Filters (`catchError`)
131
+
132
+ ExisJS allows you to create **Exception Filters** to globally intercept specific types of errors.
133
+
134
+ Using the `catchError` middleware, you can map specific custom errors to custom responses globally:
135
+
136
+ ### Functional Paradigm
137
+
138
+ ```typescript filename="src/http/server.ts"
139
+ import { exis } from 'exisjs'
140
+ import { catchError } from 'exisjs/middleware'
141
+
142
+ export class DatabaseConnectionError extends Error {
143
+ constructor(message: string) {
144
+ super(message)
145
+ this.name = 'DatabaseConnectionError'
146
+ }
147
+ }
148
+
149
+ export default exis({
150
+ async onStart(app) {
151
+ // Globally intercept DatabaseConnectionError
152
+ app.use(catchError(DatabaseConnectionError, (err, req, res) => {
153
+ res.status(503).json({
154
+ success: false,
155
+ error: { code: 'DB_OFFLINE', message: err.message }
156
+ })
157
+ }))
158
+ }
159
+ })
160
+ ```
161
+
162
+ ### Class-Based (OOP) Paradigm
163
+
164
+ ```typescript filename="src/http/server.ts"
165
+ import { Server } from 'exisjs/decorators'
166
+ import { catchError } from 'exisjs/middleware'
167
+ import type { App } from 'exisjs'
168
+
169
+ export class DatabaseConnectionError extends Error {
170
+ constructor(message: string) {
171
+ super(message)
172
+ this.name = 'DatabaseConnectionError'
173
+ }
174
+ }
175
+
176
+ @Server()
177
+ export default class RootServer {
178
+ async onStart(app: App) {
179
+ // Globally intercept DatabaseConnectionError
180
+ app.use(catchError(DatabaseConnectionError, (err, req, res) => {
181
+ res.status(503).json({
182
+ success: false,
183
+ error: { code: 'DB_OFFLINE', message: err.message }
184
+ })
185
+ }))
186
+ }
187
+ }
188
+ ```
189
+
190
+ This prevents you from having to write `try/catch` blocks in every single route just to handle standard database failures.
191
+
192
+ ### 2. Local Error Hooks (`onError`)
193
+
194
+ If you want to catch errors only within a specific module or route grouping, you can use the `onError` hook directly in your controller definition.
195
+
196
+ When a controller throws an error, the local `onError` hook will intercept it before it reaches the global error handler.
197
+
198
+ ### Functional Paradigm
199
+
200
+ ```typescript filename="src/http/users/route.ts"
201
+ import { controller, route } from 'exisjs/router'
202
+
203
+ export default controller({
204
+ // This local hook catches errors thrown by the routes in this controller
205
+ onError: (err, req, res) => {
206
+ console.log('Users Controller Error Handler Caught:', err.message)
207
+ res.status(400).json({ success: false, localError: err.message })
208
+ },
209
+
210
+ crash: route.get('/crash', async () => {
211
+ // This error will be caught by the local onError hook
212
+ throw new Error("Something went wrong in the users module")
213
+ })
214
+ })
215
+ ```
216
+
217
+ ### Class-Based (OOP) Paradigm
218
+
219
+ ```typescript filename="src/http/users/route.ts"
220
+ import { Controller, Get, UseFilters } from 'exisjs/decorators'
221
+ import type { Request, Response } from 'exisjs/router'
222
+
223
+ function localErrorHandler(err: any, req: Request, res: Response, next: any) {
224
+ console.log('Users Controller Error Handler Caught:', err.message)
225
+ res.status(400).json({ success: false, localError: err.message })
226
+ }
227
+
228
+ @Controller()
229
+ @UseFilters(localErrorHandler)
230
+ export default class UsersController {
231
+ @Get('/crash')
232
+ async crash() {
233
+ throw new Error("Something went wrong in the users module")
234
+ }
235
+ }
236
+ ```
237
+
238
+ By combining Exception Filters and Local Error Hooks, ExisJS gives you control over your error boundaries.
239
+
240
+ ## Observability (BYOM/BYOT)
241
+
242
+ ExisJS ships with tracing and metric adapters. Instead of tying you to a specific telemetry ecosystem, ExisJS lets you **Bring Your Own Metrics** (BYOM) and **Bring Your Own Tracer** (BYOT).
243
+
244
+ ### Metrics
245
+
246
+ You can use the `metrics` middleware to track request durations and counts.
247
+
248
+ ### Functional Paradigm
249
+
250
+ ```typescript filename="src/http/gateway.ts"
251
+ import { defineGateway } from 'exisjs/router'
252
+ import { metrics } from 'exisjs/observability'
253
+
254
+ const myPrometheusAdapter = {
255
+ onRequestStart: ({ method, path }) => {
256
+ // A request just started. Start a timer.
257
+ return ({ statusCode, durationMs }) => {
258
+ // The request just finished. Push to Prometheus.
259
+ console.log(`[Metrics] ${method} ${path} took ${durationMs}ms with status ${statusCode}`)
260
+ }
261
+ }
262
+ }
263
+
264
+ export default defineGateway({
265
+ middleware: [metrics(myPrometheusAdapter)]
266
+ })
267
+ ```
268
+
269
+ ### Class-Based (OOP) Paradigm
270
+
271
+ ```typescript filename="src/http/gateway.ts"
272
+ import { Gateway } from 'exisjs/decorators'
273
+ import { metrics } from 'exisjs/observability'
274
+
275
+ const myPrometheusAdapter = {
276
+ onRequestStart: ({ method, path }) => {
277
+ return ({ statusCode, durationMs }) => {
278
+ console.log(`[Metrics] ${method} ${path} took ${durationMs}ms with status ${statusCode}`)
279
+ }
280
+ }
281
+ }
282
+
283
+ @Gateway({
284
+ middleware: [metrics(myPrometheusAdapter)]
285
+ })
286
+ export default class RootGateway {}
287
+ ```
288
+
289
+ *Note: ExisJS normalizes dynamic paths (e.g., turning `/users/123` into `/users/:id`) to prevent metrics cardinality issues.*
290
+
291
+ ### OpenTelemetry Tracing
292
+
293
+ ExisJS seamlessly integrates with OpenTelemetry (OTel) via the `tracing` middleware.
294
+
295
+ ### Functional Paradigm
296
+
297
+ ```typescript filename="src/http/gateway.ts"
298
+ import { defineGateway } from 'exisjs/router'
299
+ import { tracing } from 'exisjs/observability'
300
+
301
+ const myOtelAdapter = {
302
+ startActiveSpan: (name, metadata, callback) => {
303
+ // Create an OTel span
304
+ const span = tracer.startSpan(name)
305
+ // Run the callback and pass the span proxy
306
+ callback({
307
+ setAttribute: (k, v) => span.setAttribute(k, v),
308
+ setStatus: (status) => span.setStatus(status),
309
+ recordException: (e) => span.recordException(e),
310
+ end: () => span.end()
311
+ })
312
+ }
313
+ }
314
+
315
+ export default defineGateway({
316
+ middleware: [tracing(myOtelAdapter)]
317
+ })
318
+ ```
319
+
320
+ ### Class-Based (OOP) Paradigm
321
+
322
+ ```typescript filename="src/http/gateway.ts"
323
+ import { Gateway } from 'exisjs/decorators'
324
+ import { tracing } from 'exisjs/observability'
325
+
326
+ const myOtelAdapter = {
327
+ startActiveSpan: (name, metadata, callback) => {
328
+ const span = tracer.startSpan(name)
329
+ callback({
330
+ setAttribute: (k, v) => span.setAttribute(k, v),
331
+ setStatus: (status) => span.setStatus(status),
332
+ recordException: (e) => span.recordException(e),
333
+ end: () => span.end()
334
+ })
335
+ }
336
+ }
337
+
338
+ @Gateway({
339
+ middleware: [tracing(myOtelAdapter)]
340
+ })
341
+ export default class RootGateway {}
342
+ ```
343
+
344
+ By providing these standard interfaces natively, your application metrics and traces are bound to the ExisJS router lifecycle.
@@ -0,0 +1,97 @@
1
+ ---
2
+ title: 'AI Assistants (MCP)'
3
+ description: 'Connect AI agents like Claude and Cursor directly to your ExisJS projects.'
4
+ ---
5
+
6
+ # ExisJS MCP Server
7
+
8
+ The **Model Context Protocol (MCP)** is an open standard that allows AI coding assistants (like Claude, Cursor, and Google Antigravity) to access external tools and data sources.
9
+
10
+ ExisJS provides an official MCP Server (`@exisjs/mcp`) that acts as a bridge between your AI agent and your local ExisJS workspace. It empowers the AI with the ability to dynamically read your framework documentation offline and flawlessly scaffold idiomatic ExisJS boilerplate code (routes, plugins, gateways, configurations).
11
+
12
+ <Info title="Why use the MCP?">
13
+ Without the MCP, AI agents often hallucinate Express or NestJS syntax when asked to write ExisJS code because ExisJS might not be fully present in their training data. By using the ExisJS MCP, the AI reads the exact documentation for your installed version and uses strict generators to scaffold perfect code.
14
+ </Info>
15
+
16
+ ## Prerequisites
17
+
18
+ - **Node.js (version >= 20.19)** installed on your machine.
19
+ - An AI Coding Assistant that supports the Model Context Protocol (e.g., Claude Code, Cursor, Windsurf, or Google Antigravity).
20
+
21
+ ## Installation
22
+
23
+ The easiest way to install the MCP server across all your coding agents is by using the `add-mcp` CLI:
24
+
25
+ <div className="my-6 max-w-lg">
26
+ <CopyCommand command="npx add-mcp @exisjs/mcp@latest" />
27
+ </div>
28
+
29
+ Add `-y` to skip the prompt and install to all detected agents. Add `-g` to install globally across all projects.
30
+
31
+ ### Manual Configuration
32
+
33
+ If you prefer to configure your AI client manually (or are using an unsupported client), you can add the following JSON to your client's MCP settings file:
34
+
35
+ ```json filename="mcp.json"
36
+ {
37
+ "mcpServers": {
38
+ "exisjs-mcp": {
39
+ "command": "npx",
40
+ "args": ["-y", "@exisjs/mcp@latest"]
41
+ }
42
+ }
43
+ }
44
+ ```
45
+
46
+ <details>
47
+ <summary className="cursor-pointer font-medium text-foreground py-2">Claude Code Setup</summary>
48
+
49
+ Run the following command in your terminal:
50
+ ```bash
51
+ claude mcp add exisjs-mcp npx @exisjs/mcp@latest
52
+ ```
53
+ </details>
54
+
55
+ <details>
56
+ <summary className="cursor-pointer font-medium text-foreground py-2">Cursor Setup</summary>
57
+
58
+ 1. Open Cursor Settings.
59
+ 2. Navigate to **Features > MCP**.
60
+ 3. Click **+ Add New MCP Server**.
61
+ 4. Type: `exisjs-mcp`
62
+ 5. Command: `npx -y @exisjs/mcp@latest`
63
+ </details>
64
+
65
+ ## Available Tools
66
+
67
+ Once the MCP server is installed and running, your AI assistant automatically gains access to the following capabilities:
68
+
69
+ ### 1. Documentation Readers
70
+
71
+ ExisJS ships its official markdown documentation directly inside the npm package. The MCP server reads these files locally from your `node_modules`.
72
+
73
+ - **`exis_list_local_docs`**: Recursively scans and lists all available ExisJS documentation topics.
74
+ - **`exis_read_local_docs`**: Reads the exact markdown file requested by the AI so it can learn ExisJS best practices.
75
+
76
+ *Because this runs locally, the AI reads the exact documentation that matches the ExisJS version installed in your project, preventing version mismatches!*
77
+
78
+ ### 2. Code Generators
79
+
80
+ When you ask the AI to build a new feature, it will use these strict scaffolding tools to generate the correct file structures instead of guessing the syntax.
81
+
82
+ - **`exis_generate_route`**: Scaffolds an idiomatic ExisJS route controller (Functional or OOP).
83
+ - **`exis_generate_plugin`**: Scaffolds a hybrid ExisJS plugin module.
84
+ - **`exis_generate_gateway`**: Scaffolds a WebSockets gateway.
85
+ - **`exis_generate_config`**: Scaffolds the strict `exis.config.ts` configuration system.
86
+
87
+ ## Usage Example
88
+
89
+ Once configured, simply open your ExisJS project in your AI IDE and ask it a question!
90
+
91
+ Try asking:
92
+ > *"I want to create a new WebSockets gateway in ExisJS. Can you read the docs on how Gateways work and then scaffold one for me?"*
93
+
94
+ The AI will:
95
+ 1. Use `exis_list_local_docs` to find the documentation on Gateways.
96
+ 2. Use `exis_read_local_docs` to learn the exact syntax for your ExisJS version.
97
+ 3. Use `exis_generate_gateway` to safely write the boilerplate into your codebase.