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,376 @@
1
+ ---
2
+ nextUrl: "/docs/validation"
3
+ nextTitle: "Validation"
4
+ ---
5
+
6
+ # Gateways (Middleware & Modules)
7
+
8
+ Gateways act as a configuration entry point for specific folders in your file-system routing architecture.
9
+
10
+ Instead of writing programmatic middleware declarations like `app.use('/admin', requireAuth)`, you can place a `gateway.ts` file inside a folder to scope **Middleware**, **CORS**, and **Dependency Injection** to that specific domain.
11
+
12
+ ## Cascading Middleware
13
+
14
+ The most common use-case for a gateway is applying middleware arrays to a group of routes.
15
+
16
+ ### Functional Paradigm
17
+
18
+ ```typescript className="language-typescript" filename="src/http/admin/gateway.ts"
19
+ import { defineGateway } from 'exisjs/router'
20
+ import { requireAuth } from '../../middleware/auth'
21
+ import { cors, helmet } from 'exisjs/middleware'
22
+
23
+ export default defineGateway({
24
+ // This middleware array runs before ANY route in /admin/*
25
+ middleware: [
26
+ helmet(),
27
+ compress(),
28
+ cache({ ttlMs: 60000 }),
29
+ requireAuth
30
+ ],
31
+
32
+ // Enforce strict CORS for this folder
33
+ cors: {
34
+ origin: 'https://admin.yourdomain.com',
35
+ methods: ['GET', 'POST', 'DELETE']
36
+ },
37
+
38
+ // Append custom default headers to all responses
39
+ headers: {
40
+ 'X-Admin-Api-Version': '2.0'
41
+ }
42
+ })
43
+ ```
44
+
45
+ ### Class-Based (OOP) Paradigm
46
+
47
+ ```typescript className="language-typescript" filename="src/http/admin/gateway.ts"
48
+ import { Gateway } from 'exisjs/decorators'
49
+ import { requireAuth } from '../../middleware/auth'
50
+ import { helmet } from 'exisjs/middleware'
51
+
52
+ @Gateway({
53
+ // This middleware array runs before ANY route in /admin/*
54
+ middleware: [
55
+ helmet(),
56
+ compress(),
57
+ cache({ ttlMs: 60000 }),
58
+ requireAuth
59
+ ],
60
+
61
+ // Enforce strict CORS for this folder
62
+ cors: {
63
+ origin: 'https://admin.yourdomain.com',
64
+ methods: ['GET', 'POST', 'DELETE']
65
+ },
66
+
67
+ // Append custom default headers to all responses
68
+ headers: {
69
+ 'X-Admin-Api-Version': '2.0'
70
+ }
71
+ })
72
+ export default class AdminGateway {}
73
+ ```
74
+
75
+ When a request comes in for `/admin/users`, ExisJS processes the Gateway's middleware sequentially before it ever reaches your `route.ts` file.
76
+
77
+ ## Folder-Scoped CORS
78
+
79
+ Handling CORS across an API can require granular control. For instance, you might want your `/public` folder to accept requests from anywhere, while restricting your `/billing` folder to a strict frontend domain. ExisJS allows you to define the `cors` property in your Gateway, overriding the global configuration for that specific folder.
80
+
81
+ ## File-Based Modules (Domain-Driven Design)
82
+
83
+ In addition to serving as an interceptor for middleware, `gateway.ts` acts as a module boundary, enabling **Domain-Driven Design (DDD)** via the file system.
84
+
85
+ ### Providers (Dependency Injection)
86
+
87
+ If you have a database service unique to your `/users` domain, encapsulate it strictly inside the users gateway:
88
+
89
+ ```typescript className="language-typescript" filename="src/http/users/gateway.ts"
90
+ import { defineGateway } from 'exisjs/router'
91
+ import { UsersRepository } from './repository'
92
+
93
+ export default defineGateway({
94
+ // Provide the UsersRepository directly to this folder's DI container!
95
+ providers: [
96
+ ['UsersRepository', { useClass: UsersRepository }]
97
+ ]
98
+ })
99
+ ```
100
+
101
+ When ExisJS boots, it automatically discovers `gateway.ts`, parses the `providers`, and hydrates them into the internal Dependency Injection container before executing the routes. Inside your route handler, you can inject them:
102
+
103
+ #### Functional Paradigm
104
+
105
+ ```typescript className="language-typescript" filename="src/http/users/route.ts"
106
+ import { controller, route } from 'exisjs/router'
107
+ import { inject } from 'exisjs/di'
108
+ import type { UsersRepository } from './repository'
109
+
110
+ export default controller({
111
+ list: route.get('/', {
112
+ async handle() {
113
+ // Access the scoped dependency
114
+ const usersRepo = inject<UsersRepository>('UsersRepository')
115
+ return await usersRepo.findAll()
116
+ }
117
+ })
118
+ })
119
+ ```
120
+
121
+ #### Class-Based (OOP) Paradigm
122
+
123
+ ```typescript className="language-typescript" filename="src/http/users/route.ts"
124
+ import { Controller, Get } from 'exisjs/decorators'
125
+ import { inject } from 'exisjs/di'
126
+ import type { UsersRepository } from './repository'
127
+
128
+ @Controller()
129
+ export default class UsersController {
130
+ @Get('/')
131
+ async list() {
132
+ const usersRepo = inject<UsersRepository>('UsersRepository')
133
+ return await usersRepo.findAll()
134
+ }
135
+ }
136
+ ```
137
+
138
+ ### Imports & Plugins
139
+
140
+ Gateways allow you to bundle other modules and plugins into a domain.
141
+
142
+ ### Functional Paradigm
143
+
144
+ ```typescript className="language-typescript" filename="src/http/orders/gateway.ts"
145
+ import { defineGateway } from 'exisjs/router'
146
+ import AuthModule from '../auth/module'
147
+ import { stripePlugin } from '../../plugins/stripe'
148
+
149
+ export default defineGateway({
150
+ // Pull in the Auth feature set
151
+ imports: [AuthModule],
152
+
153
+ // Isolate Stripe setup for the orders domain
154
+ plugins: [stripePlugin({ apiKey: process.env.STRIPE_KEY })]
155
+ })
156
+ ```
157
+
158
+ ### Class-Based (OOP) Paradigm
159
+
160
+ ```typescript className="language-typescript" filename="src/http/orders/gateway.ts"
161
+ import { Gateway } from 'exisjs/decorators'
162
+ import AuthModule from '../auth/module'
163
+ import { stripePlugin } from '../../plugins/stripe'
164
+
165
+ @Gateway({
166
+ // Pull in the Auth feature set
167
+ imports: [AuthModule],
168
+
169
+ // Isolate Stripe setup for the orders domain
170
+ plugins: [stripePlugin({ apiKey: process.env.STRIPE_KEY })]
171
+ })
172
+ export default class OrdersGateway {}
173
+ ```
174
+
175
+ <Hint>
176
+ - **Imports**: Automatically deduplicated. If multiple gateways import `AuthModule`, its internal singletons are only initialized once.
177
+ - **Plugins**: Setup logic runs specifically for the scoped folder.
178
+ </Hint>
179
+
180
+ ## Gateway Inheritance (Cascading)
181
+
182
+ Gateways inherently **cascade**. If you define a Gateway at the absolute root (`src/http/gateway.ts`), it applies globally.
183
+
184
+ If you define another Gateway at `src/http/admin/gateway.ts`, requests to `/admin/dashboard` will sequentially pass through the Root Gateway, and *then* pass through the Admin Gateway!
185
+
186
+ ```text className="language-text"
187
+ src/
188
+ └── http/
189
+ ├── gateway.ts <-- Runs first (Global Rate Limits)
190
+ └── admin/
191
+ ├── gateway.ts <-- Runs second (JWT Validation)
192
+ └── users/
193
+ └── route.ts <-- Runs last (Only if both gateways succeed!)
194
+ ```
195
+
196
+ ## Advanced Features
197
+
198
+ Gateways provide features to manage cross-cutting concerns like Exception Filters or Guards for an entire folder.
199
+
200
+ ### 1. Folder-Scoped Guards
201
+
202
+ Apply Authorization Guards directly to a folder. If the guard returns `false`, the entire folder is protected.
203
+
204
+ #### Functional Paradigm
205
+
206
+ ```typescript className="language-typescript" filename="src/http/api/gateway.ts"
207
+ import { defineGateway } from 'exisjs/router'
208
+ import { RequireAdminRoleGuard } from '../../guards'
209
+
210
+ export default defineGateway({
211
+ // Protects the entire /api folder
212
+ guards: [RequireAdminRoleGuard]
213
+ })
214
+ ```
215
+
216
+ #### Class-Based (OOP) Paradigm
217
+
218
+ ```typescript className="language-typescript" filename="src/http/api/gateway.ts"
219
+ import { Gateway } from 'exisjs/decorators'
220
+ import { RequireAdminRoleGuard } from '../../guards'
221
+
222
+ @Gateway({
223
+ // Protects the entire /api folder
224
+ guards: [RequireAdminRoleGuard]
225
+ })
226
+ export default class ApiGateway {}
227
+ ```
228
+
229
+ ### 2. Folder-Scoped Exception Filters
230
+
231
+ Catch exceptions for a specific domain. For example, you can return HTML error pages for `/views`, but standardized JSON errors for `/api`.
232
+
233
+ #### Functional Paradigm
234
+
235
+ ```typescript className="language-typescript" filename="src/http/api/gateway.ts"
236
+ import { defineGateway } from 'exisjs/router'
237
+ import { ApiVersion2ErrorFilter } from '../../filters'
238
+
239
+ export default defineGateway({
240
+ // Catches all exceptions thrown inside /api/*
241
+ filters: [ApiVersion2ErrorFilter]
242
+ })
243
+ ```
244
+
245
+ #### Class-Based (OOP) Paradigm
246
+
247
+ ```typescript className="language-typescript" filename="src/http/api/gateway.ts"
248
+ import { Gateway } from 'exisjs/decorators'
249
+ import { ApiVersion2ErrorFilter } from '../../filters'
250
+
251
+ @Gateway({
252
+ // Catches all exceptions thrown inside /api/*
253
+ filters: [ApiVersion2ErrorFilter]
254
+ })
255
+ export default class ApiGateway {}
256
+ ```
257
+
258
+ ### 3. Folder-Scoped Interceptors
259
+
260
+ Transform or wrap all responses exiting a specific folder.
261
+
262
+ #### Functional Paradigm
263
+
264
+ ```typescript className="language-typescript" filename="src/http/api/gateway.ts"
265
+ import { defineGateway } from 'exisjs/router'
266
+ import { StandardResponseInterceptor } from '../../interceptors'
267
+
268
+ export default defineGateway({
269
+ // Wraps all responses from /api/* in a standard format
270
+ interceptors: [StandardResponseInterceptor]
271
+ })
272
+ ```
273
+
274
+ #### Class-Based (OOP) Paradigm
275
+
276
+ ```typescript className="language-typescript" filename="src/http/api/gateway.ts"
277
+ import { Gateway } from 'exisjs/decorators'
278
+ import { StandardResponseInterceptor } from '../../interceptors'
279
+
280
+ @Gateway({
281
+ // Wraps all responses from /api/* in a standard format
282
+ interceptors: [StandardResponseInterceptor]
283
+ })
284
+ export default class ApiGateway {}
285
+ ```
286
+
287
+ ### 4. Bypassing Gateways (Exclude)
288
+
289
+ Bypass the Gateway's middleware, guards, and filters for specific sub-paths or methods without breaking your folder structure.
290
+
291
+ #### Functional Paradigm
292
+
293
+ ```typescript className="language-typescript" filename="src/http/api/gateway.ts"
294
+ import { defineGateway } from 'exisjs/router'
295
+
296
+ export default defineGateway({
297
+ exclude: [
298
+ '/api/public/status', // Exact Match
299
+ '/api/webhooks/*', // Wildcard Match
300
+ { path: '/api/users', methods: ['GET'] } // Method-specific bypass
301
+ ]
302
+ })
303
+ ```
304
+
305
+ #### Class-Based (OOP) Paradigm
306
+
307
+ ```typescript className="language-typescript" filename="src/http/api/gateway.ts"
308
+ import { Gateway } from 'exisjs/decorators'
309
+
310
+ @Gateway({
311
+ exclude: [
312
+ '/api/public/status', // Exact Match
313
+ '/api/webhooks/*', // Wildcard Match
314
+ { path: '/api/users', methods: ['GET'] } // Method-specific bypass
315
+ ]
316
+ })
317
+ export default class ApiGateway {}
318
+ ```
319
+
320
+ ### 5. Dynamic Request Timeouts
321
+
322
+ Define dynamic, folder-scoped request timeouts. For example, give your `/reports` folder 60 seconds, but restrict `/api` to 5 seconds. You can evaluate the timeout dynamically per-request.
323
+
324
+ #### Functional Paradigm
325
+
326
+ ```typescript className="language-typescript" filename="src/http/reports/gateway.ts"
327
+ import { defineGateway } from 'exisjs/router'
328
+
329
+ export default defineGateway({
330
+ // Dynamic request timeouts evaluated per-request
331
+ timeout: (req) => req.headers['x-premium'] ? 30000 : 5000
332
+ })
333
+ ```
334
+
335
+ #### Class-Based (OOP) Paradigm
336
+
337
+ ```typescript className="language-typescript" filename="src/http/reports/gateway.ts"
338
+ import { Gateway } from 'exisjs/decorators'
339
+
340
+ @Gateway({
341
+ // Dynamic request timeouts evaluated per-request
342
+ timeout: (req) => req.headers['x-premium'] ? 30000 : 5000
343
+ })
344
+ export default class ReportsGateway {}
345
+ ```
346
+
347
+ ### 6. Cascading Metadata
348
+
349
+ Define tags (like OpenAPI/Swagger tags or Role definitions) at the folder level that automatically cascade down to every route inside.
350
+
351
+ #### Functional Paradigm
352
+
353
+ ```typescript className="language-typescript" filename="src/http/admin/gateway.ts"
354
+ import { defineGateway } from 'exisjs/router'
355
+
356
+ export default defineGateway({
357
+ // Automatically cascades OpenAPI tags to every route in the folder
358
+ metadata: {
359
+ openapi: { tags: ['Admin API'], security: ['bearerAuth'] }
360
+ }
361
+ })
362
+ ```
363
+
364
+ #### Class-Based (OOP) Paradigm
365
+
366
+ ```typescript className="language-typescript" filename="src/http/admin/gateway.ts"
367
+ import { Gateway } from 'exisjs/decorators'
368
+
369
+ @Gateway({
370
+ // Automatically cascades OpenAPI tags to every route in the folder
371
+ metadata: {
372
+ openapi: { tags: ['Admin API'], security: ['bearerAuth'] }
373
+ }
374
+ })
375
+ export default class AdminGateway {}
376
+ ```
@@ -0,0 +1,210 @@
1
+ ---
2
+ nextUrl: '/docs/structure'
3
+ nextTitle: 'Project Structure'
4
+ ---
5
+
6
+ # Getting Started
7
+
8
+ In this guide, you'll learn the core fundamentals of ExisJS. To get familiar with the essential building blocks, we'll scaffold a new project, explore the file structure, and create our very first API server.
9
+
10
+ <Info title="Language Support">
11
+ We recommend **TypeScript** for type-safety and automatic frontend client generation. However, ExisJS fully supports vanilla JavaScript as well. ExisJS leverages esbuild under the hood, meaning you do not need to manually run `tsc` to start your server.
12
+ </Info>
13
+
14
+ ## Prerequisites
15
+
16
+ Please make sure that **Node.js (version >= 20)** is installed on your operating system.
17
+
18
+ ## Setup
19
+
20
+ Setting up a new project can be done using our CLI tool. Open your terminal and run the following command to scaffold a new ExisJS project:
21
+
22
+ <div className="my-6 max-w-lg">
23
+ <CopyCommand command="npx @exisjs/create@latest my-backend" />
24
+ </div>
25
+
26
+ The CLI will prompt you with a few simple questions to customize your project:
27
+
28
+ ```text filename="Terminal"
29
+ √ Would you like to use TypeScript? ... No / Yes
30
+ √ Would you like to use ESLint? ... No / Yes
31
+ √ Would you like your code inside a `src/` directory? ... No / Yes
32
+ √ Would you like to customize the import alias (`@/*` by default)? ... No / Yes
33
+
34
+ Creating a new Exis JS app in my-backend.
35
+ ```
36
+
37
+ The CLI will then create the `my-backend` directory, install all required dependencies, and populate the project with a conventional base structure.
38
+
39
+ ## Core Files
40
+
41
+ Once the installation is complete, your project directory will look something like this:
42
+
43
+ <div className="bg-muted/30 border border-border/50 rounded-md p-4 mb-6 font-mono text-sm">
44
+ <div className="flex gap-4 mb-2">
45
+ <span className="text-muted-foreground w-40 shrink-0">exis.config.ts</span>{' '}
46
+ <span>
47
+ The root configuration for your application (CORS, Logger, Port).
48
+ </span>
49
+ </div>
50
+ <div className="flex gap-4 mb-2">
51
+ <span className="text-muted-foreground w-40 shrink-0">src/env.ts</span>{' '}
52
+ <span>Environment variable validation and typing.</span>
53
+ </div>
54
+ <div className="flex gap-4 mb-2">
55
+ <span className="text-muted-foreground w-40 shrink-0">src/http/</span>{' '}
56
+ <span>The file-system routing directory.</span>
57
+ </div>
58
+ <div className="flex gap-4 mb-2 pl-4">
59
+ <span className="text-muted-foreground w-36 shrink-0">server.ts</span>{' '}
60
+ <span>The strict entry point of your application.</span>
61
+ </div>
62
+ <div className="flex gap-4 pl-4">
63
+ <span className="text-muted-foreground w-36 shrink-0">route.ts</span>{' '}
64
+ <span>A basic GET endpoint mapped to the root route.</span>
65
+ </div>
66
+ </div>
67
+
68
+ ## Your First Server
69
+
70
+ Let's look at the generated `src/http/server.ts`. This is the strict entry point of your application, where you can connect to databases and register global plugins.
71
+
72
+ ### Functional Server Setup
73
+
74
+ ```typescript filename="src/http/server.ts"
75
+ import { exis } from 'exisjs'
76
+
77
+ export default exis({
78
+ async onStart(app) {
79
+ // 1. Connect to your database
80
+ // await db.connect()
81
+ // 2. Register plugins
82
+ // app.plugin(authPlugin)
83
+ // The Exis CLI automatically boots the server and file-system routes
84
+ },
85
+
86
+ async onClose(app) {
87
+ // Gracefully close database connections here
88
+ // await db.disconnect()
89
+ },
90
+ })
91
+ ```
92
+
93
+ ### Class-Based (OOP) Server Setup
94
+
95
+ ```typescript filename="src/http/server.ts"
96
+ import { Server } from 'exisjs/decorators'
97
+ import type { App } from 'exisjs'
98
+
99
+ @Server()
100
+ export default class RootServer {
101
+ async onStart(app: App) {
102
+ // 1. Connect to your database
103
+ // await db.connect()
104
+ // 2. Register plugins
105
+ // app.plugin(authPlugin)
106
+ // The Exis CLI automatically boots the server and file-system routes
107
+ }
108
+
109
+ async onClose(app: App) {
110
+ // Gracefully close database connections here
111
+ // await db.disconnect()
112
+ }
113
+ }
114
+ ```
115
+
116
+ With ExisJS, the framework automatically handles booting up your server and loading your routes based on the file system. You don't need to manually call `app.listen()`!
117
+
118
+ ## Your First Route
119
+
120
+ ExisJS uses **folder-based routing**. Your API structure maps directly to your folders in `src/http/`.
121
+
122
+ ExisJS supports two primary styles of writing routes: **Functional** and **OOP (Class-based)**. You are free to use whichever paradigm fits your team best.
123
+
124
+ ### Functional Routing
125
+
126
+ Functional routing provides a lean, inference-heavy developer experience similar to modern frontend frameworks. Let's declare our first route in `src/http/users/route.ts`:
127
+
128
+ ```typescript filename="src/http/users/route.ts"
129
+ import { controller, route } from 'exisjs/router'
130
+
131
+ export default controller({
132
+ getUsers: route.get('/', {
133
+ handle(req) {
134
+ // Return a realistic response structure
135
+ return {
136
+ data: [
137
+ { id: 1, name: 'Alice' },
138
+ { id: 2, name: 'Bob' }
139
+ ],
140
+ total: 2
141
+ }
142
+ },
143
+ }),
144
+ })
145
+ ```
146
+
147
+ ### OOP Routing
148
+
149
+ If you prefer a highly-structured architecture heavily inspired by Angular and NestJS, ExisJS natively provides robust class-based routing using Decorators:
150
+
151
+ ```typescript filename="src/http/users/route.ts"
152
+ import { Controller, Get, Req } from 'exisjs/decorators'
153
+ import type { Request } from 'exisjs'
154
+
155
+ @Controller()
156
+ export default class UsersController {
157
+ @Get('/')
158
+ getUsers(@Req() req: Request) {
159
+ // Return a realistic response structure
160
+ return {
161
+ data: [
162
+ { id: 1, name: 'Alice' },
163
+ { id: 2, name: 'Bob' }
164
+ ],
165
+ total: 2
166
+ }
167
+ }
168
+ }
169
+ ```
170
+
171
+ In both examples, because this file is named `route.ts` and is located in the `users` folder, it automatically responds to `GET /users` requests. Whatever you return is automatically serialized to JSON.
172
+
173
+ ## Running the Application
174
+
175
+ Your generated `package.json` comes pre-configured with the Exis CLI commands. Start the development server with hot-reload by running:
176
+
177
+ <div className="my-6 max-w-lg">
178
+ <CopyCommand command="npm run dev" />
179
+ </div>
180
+
181
+ You will see the server boot up in your terminal:
182
+
183
+ ```text filename="Terminal"
184
+ 6:18:28 pm [exis] starting development server (v0.1.0)...
185
+
186
+ EXIS v0.1.0 ready in 125 ms
187
+
188
+ → Local: http://localhost:4000/
189
+ → Network: http://10.39.14.177:4000/
190
+ → Environ: development
191
+ → press h + enter to show help
192
+ ```
193
+
194
+ Open your browser and navigate to [http://localhost:4000/](http://localhost:4000/) (or the port defined in your `.env`). You will see:
195
+
196
+ ```json filename="Response"
197
+ {
198
+ "data": [
199
+ {
200
+ "id": 1,
201
+ "name": "Alice"
202
+ },
203
+ {
204
+ "id": 2,
205
+ "name": "Bob"
206
+ }
207
+ ],
208
+ "total": 2
209
+ }
210
+ ```
@@ -0,0 +1,96 @@
1
+ ---
2
+ nextUrl: '/docs/installation'
3
+ nextTitle: 'Installation'
4
+ ---
5
+
6
+ # Introduction
7
+
8
+ Exis (ExisJS) is a batteries-included backend framework for Node.js. It brings the file-based, convention-over-configuration developer experience of modern frontend meta-frameworks to backend API development: folders and files instead of manual wiring, with the essentials (routing, validation, queues, WebSockets, cron, DI) built in rather than assembled from a dozen separate packages.
9
+
10
+ Routing is handled by a radix-tree matcher, and the framework supports two ways to define the same routes: **Functional** (factory functions) and **Class-Based / OOP** (decorators, in the style of Angular/NestJS). Both compile to the same internal route representation, run through the same middleware pipeline, and can be mixed file-by-file in the same project. Pick whichever fits a given part of your codebase.
11
+
12
+ ## Philosophy
13
+
14
+ Frontend frameworks like Next.js, Remix, and Nuxt improved developer productivity significantly through file-based routing and convention-over-configuration architecture. Good tools exist for Node.js backends too, but assembling them into a coherent application still typically means a lot of manual wiring and architectural boilerplate.
15
+
16
+ Exis aims to provide that out-of-the-box application architecture for backends: create a folder, get a route; create a `gateway.ts`, get folder-scoped middleware; import a module, get its providers registered. Job queues, WebSockets, cron scheduling, and schema validation are part of the standard library rather than bring-your-own dependencies. This means a new project starts with a coherent structure instead of a blank `index.js` and a pile of choices to make first.
17
+
18
+ ## Installation
19
+
20
+ The fastest way to start is the Exis CLI, which scaffolds a new project directory with the core files and a conventional base structure already in place. This is the recommended path for first-time users.
21
+
22
+ <div className="my-6 max-w-lg">
23
+ <CopyCommand command="npx @exisjs/create@latest my-backend" />
24
+ </div>
25
+
26
+ <Hint>
27
+ The CLI walks you through initial project setup (TypeScript config, import
28
+ aliases, and package manager selection: it detects npm, yarn, pnpm, or bun
29
+ automatically). See [Installation](/docs/installation) for the full list of
30
+ prompts and options.
31
+ </Hint>
32
+
33
+ ## Quick Start
34
+
35
+ Both paradigms are shown throughout these docs side by side. Pick whichever you're using, or mix them across your project.
36
+
37
+ ### Functional API
38
+
39
+ ```typescript filename="src/http/users/route.ts"
40
+ import { controller, route } from 'exisjs/router'
41
+
42
+ export default controller({
43
+ getUsers: route.get('/', {
44
+ handle(req) {
45
+ // Return a realistic response structure
46
+ return {
47
+ data: [
48
+ { id: 1, name: 'Alice' },
49
+ { id: 2, name: 'Bob' }
50
+ ],
51
+ total: 2
52
+ }
53
+ },
54
+ }),
55
+ })
56
+ ```
57
+
58
+ ### Class-Based (OOP) API
59
+
60
+ ```typescript filename="src/http/users/route.ts"
61
+ import { Controller, Get, Req } from 'exisjs/decorators'
62
+ import type { Request } from 'exisjs'
63
+
64
+ @Controller()
65
+ export default class UsersController {
66
+ @Get('/')
67
+ getUsers(@Req() req: Request) {
68
+ // Return a realistic response structure
69
+ return {
70
+ data: [
71
+ { id: 1, name: 'Alice' },
72
+ { id: 2, name: 'Bob' }
73
+ ],
74
+ total: 2
75
+ }
76
+ }
77
+ }
78
+ ```
79
+
80
+ Save this as `src/http/users/route.ts`, run `exis dev`, and `GET /users` will return your mocked users list.
81
+
82
+ ## Adding to an existing project
83
+
84
+ You can also add Exis to an existing Node.js project instead of scaffolding a new one:
85
+
86
+ <div className="my-6 max-w-lg">
87
+ <CopyCommand command="npm install exisjs" />
88
+ </div>
89
+
90
+ In this case you'll set up the project structure yourself: an `exis.config.ts` at the project root and a `src/http` directory for your routes. See [Structure](/docs/structure) for the conventions the framework expects.
91
+
92
+ ## What's next
93
+
94
+ - [Installation](/docs/installation): CLI setup and project scaffolding in detail.
95
+ - [Structure](/docs/structure): the folder conventions Exis expects and why.
96
+ - [Routing](/docs/routing): how file-based routing, dynamic segments, and gateways work together.