exisjs 0.7.12 → 0.7.14

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 (132) hide show
  1. package/README.md +195 -39
  2. package/dist/cli/commands/run.d.ts.map +1 -1
  3. package/dist/cli/commands/run.js +3 -1
  4. package/dist/cli/commands/run.js.map +1 -1
  5. package/dist/config/types.d.ts +2 -2
  6. package/dist/config/types.d.ts.map +1 -1
  7. package/dist/decorators/params.d.ts +21 -0
  8. package/dist/decorators/params.d.ts.map +1 -1
  9. package/dist/decorators/params.js +21 -1
  10. package/dist/decorators/params.js.map +1 -1
  11. package/dist/di/container.d.ts +15 -6
  12. package/dist/di/container.d.ts.map +1 -1
  13. package/dist/di/container.js +26 -3
  14. package/dist/di/container.js.map +1 -1
  15. package/dist/di/index.d.ts +1 -1
  16. package/dist/di/index.d.ts.map +1 -1
  17. package/dist/di/index.js.map +1 -1
  18. package/dist/di/inject.d.ts +2 -1
  19. package/dist/di/inject.d.ts.map +1 -1
  20. package/dist/di/inject.js +2 -1
  21. package/dist/di/inject.js.map +1 -1
  22. package/dist/docs/ARCHITECTURE.md +130 -78
  23. package/dist/docs/BENCHMARKS.md +4 -4
  24. package/dist/docs/content/README.md +43 -44
  25. package/dist/docs/content/boundaries.mdx +138 -61
  26. package/dist/docs/content/cli/commands.mdx +151 -128
  27. package/dist/docs/content/cli/overview.mdx +61 -47
  28. package/dist/docs/content/cli/usage.mdx +107 -30
  29. package/dist/docs/content/config.mdx +145 -158
  30. package/dist/docs/content/controllers.mdx +193 -464
  31. package/dist/docs/content/cron.mdx +183 -69
  32. package/dist/docs/content/decorators.mdx +449 -154
  33. package/dist/docs/content/errors.mdx +202 -305
  34. package/dist/docs/content/exisjs-mcp.mdx +59 -49
  35. package/dist/docs/content/installation.mdx +243 -157
  36. package/dist/docs/content/introduction.mdx +220 -48
  37. package/dist/docs/content/middleware.mdx +171 -497
  38. package/dist/docs/content/modules.mdx +141 -83
  39. package/dist/docs/content/providers.mdx +216 -180
  40. package/dist/docs/content/requests.mdx +168 -488
  41. package/dist/docs/content/responses.mdx +200 -533
  42. package/dist/docs/content/routing.mdx +235 -598
  43. package/dist/docs/content/security.mdx +233 -57
  44. package/dist/docs/content/structure.mdx +151 -240
  45. package/dist/docs/content/swagger.mdx +192 -91
  46. package/dist/docs/content/testing.mdx +205 -74
  47. package/dist/docs/content/validation.mdx +479 -341
  48. package/dist/docs/reference/README.md +34 -2
  49. package/dist/docs/reference/config.mdx +277 -75
  50. package/dist/docs/reference/context.mdx +197 -106
  51. package/dist/docs/reference/cron.mdx +266 -152
  52. package/dist/docs/reference/database.mdx +135 -53
  53. package/dist/docs/reference/decorators.mdx +234 -116
  54. package/dist/docs/reference/di.mdx +146 -112
  55. package/dist/docs/reference/error.mdx +155 -178
  56. package/dist/docs/reference/exis.mdx +141 -70
  57. package/dist/docs/reference/logger.mdx +110 -126
  58. package/dist/docs/reference/middleware.mdx +235 -158
  59. package/dist/docs/reference/plugin.mdx +136 -64
  60. package/dist/docs/reference/router.mdx +275 -293
  61. package/dist/docs/reference/sanitize.mdx +91 -87
  62. package/dist/docs/reference/swagger.mdx +280 -100
  63. package/dist/docs/reference/testing.mdx +223 -89
  64. package/dist/docs/reference/validator.mdx +194 -206
  65. package/dist/lib/start-server.js +22 -8
  66. package/dist/lib/start-server.js.map +1 -1
  67. package/dist/module/module.d.ts +6 -3
  68. package/dist/module/module.d.ts.map +1 -1
  69. package/dist/module/module.js +17 -3
  70. package/dist/module/module.js.map +1 -1
  71. package/dist/router/controller-registrar.d.ts.map +1 -1
  72. package/dist/router/controller-registrar.js +26 -4
  73. package/dist/router/controller-registrar.js.map +1 -1
  74. package/dist/router/scanner/fs-scanner.d.ts.map +1 -1
  75. package/dist/router/scanner/fs-scanner.js +22 -0
  76. package/dist/router/scanner/fs-scanner.js.map +1 -1
  77. package/dist/router/types.d.ts +6 -4
  78. package/dist/router/types.d.ts.map +1 -1
  79. package/dist/server/app.d.ts +3 -1
  80. package/dist/server/app.d.ts.map +1 -1
  81. package/dist/server/app.js +24 -8
  82. package/dist/server/app.js.map +1 -1
  83. package/dist/server/bootstrapper.d.ts.map +1 -1
  84. package/dist/server/bootstrapper.js +19 -0
  85. package/dist/server/bootstrapper.js.map +1 -1
  86. package/dist/server/request.d.ts +2 -0
  87. package/dist/server/request.d.ts.map +1 -1
  88. package/dist/server/request.js +11 -0
  89. package/dist/server/request.js.map +1 -1
  90. package/dist/server/response.d.ts +10 -5
  91. package/dist/server/response.d.ts.map +1 -1
  92. package/dist/server/response.js +65 -18
  93. package/dist/server/response.js.map +1 -1
  94. package/dist/swagger/generator.d.ts.map +1 -1
  95. package/dist/swagger/generator.js +130 -10
  96. package/dist/swagger/generator.js.map +1 -1
  97. package/dist/telemetry/index.d.ts +12 -0
  98. package/dist/telemetry/index.d.ts.map +1 -0
  99. package/dist/telemetry/index.js +121 -0
  100. package/dist/telemetry/index.js.map +1 -0
  101. package/dist/testing/client.d.ts +1 -0
  102. package/dist/testing/client.d.ts.map +1 -1
  103. package/dist/testing/client.js +4 -1
  104. package/dist/testing/client.js.map +1 -1
  105. package/dist/testing/index.d.ts.map +1 -1
  106. package/dist/testing/index.js +11 -4
  107. package/dist/testing/index.js.map +1 -1
  108. package/dist/validator/builder.d.ts +26 -1
  109. package/dist/validator/builder.d.ts.map +1 -1
  110. package/dist/validator/builder.js +31 -0
  111. package/dist/validator/builder.js.map +1 -1
  112. package/dist/validator/engine.d.ts +23 -0
  113. package/dist/validator/engine.d.ts.map +1 -1
  114. package/dist/validator/engine.js +228 -31
  115. package/dist/validator/engine.js.map +1 -1
  116. package/dist/validator/index.d.ts +8 -4
  117. package/dist/validator/index.d.ts.map +1 -1
  118. package/dist/validator/index.js +4 -1
  119. package/dist/validator/index.js.map +1 -1
  120. package/dist/validator/tex-types.d.ts +19 -4
  121. package/dist/validator/tex-types.d.ts.map +1 -1
  122. package/dist/validator/tex-types.js +102 -0
  123. package/dist/validator/tex-types.js.map +1 -1
  124. package/dist/validator/tex.d.ts +1 -1
  125. package/dist/validator/tex.d.ts.map +1 -1
  126. package/dist/validator/tex.js +3 -1
  127. package/dist/validator/tex.js.map +1 -1
  128. package/dist/validator/types.d.ts +1 -0
  129. package/dist/validator/types.d.ts.map +1 -1
  130. package/package.json +46 -14
  131. package/dist/docs/content/dataloader.mdx +0 -170
  132. package/dist/docs/reference/dataloader.mdx +0 -91
@@ -1,286 +1,241 @@
1
1
  ---
2
- nextUrl: '/docs/config'
3
- nextTitle: 'Configuration'
2
+ title: 'Project Structure'
3
+ description: 'Directory conventions, file naming rules, auto-discovery mechanisms, and structural architecture for ExisJS applications.'
4
+ nextUrl: '/docs/routing'
5
+ nextTitle: 'Routing & Endpoints'
4
6
  ---
5
7
 
6
8
  # Project Structure
7
9
 
8
- ExisJS is a minimal, opinionated core: file-system routing, dependency injection,
9
- validation, sanitization, and a request pipeline. Everything else — databases,
10
- auth, caching, queues, websockets — is an official `@exisjs/*` package you add
11
- only when you need it. Nothing in this structure requires them.
12
-
13
- ExisJS enforces a strict `src/` directory convention. All application code
14
- **must** live inside `src/`.
10
+ ExisJS enforces a convention-based project structure located inside the `src/` directory. File and folder locations declare their roles automatically, removing the need for manual routing configuration or boilerplate router files.
15
11
 
16
12
  ---
17
13
 
18
- ## The Default Structure
14
+ ## Standard Directory Layout
19
15
 
20
16
  ```text
21
- my-backend/
22
- ├── .exis/ # Internal framework cache and build artifacts
17
+ my-api/
18
+ ├── .agents/
19
+ │ └── rules/
20
+ │ └── AGENTS.md # LLM architectural rules and coding standards
21
+ ├── .exis/ # Framework cache and compiled route manifests (git-ignored)
23
22
  ├── src/
24
- │ ├── http/
25
- │ │ ├── server.ts # Application entry point & lifecycle hooks
26
- │ │ ├── error.ts # Centralized framework exception handler (onError)
27
- │ │ ├── route.ts # Root routes (e.g. GET /api)
28
- │ │ ├── boundary.ts # Root boundary (config + request pipeline)
23
+ │ ├── http/ # File-system routing and HTTP request pipeline (auto-discovered)
24
+ │ │ ├── server.ts # Server lifecycle hooks (onStart, onClose)
25
+ │ │ ├── boundary.ts # Root boundary (CORS, security headers, global error handling)
26
+ │ │ ├── route.ts # Root route handler (GET /)
27
+ │ │ ├── error.ts # Global exception and validation error handler (onError)
28
+ │ │ ├── health/
29
+ │ │ │ └── route.ts # GET /health endpoint
29
30
  │ │ ├── users/
30
- │ │ │ ├── route.ts # User endpoints
31
- │ │ │ ├── schema.ts # Validation schemas (tex) — mandatory alongside route.ts
32
- │ │ │ └── service.ts # Business logic / data access, DI-injectable
33
- │ │ ├── posts/
34
- │ │ │ ├── route.ts
35
- │ │ │ ├── schema.ts
36
- │ │ │ └── service.ts
31
+ │ │ │ ├── route.ts # Route endpoints for /users
32
+ │ │ │ ├── schema.ts # Input validation schemas (tex.*)
33
+ │ │ │ └── service.ts # Feature business logic and data access
37
34
  │ │ └── admin/
38
- │ │ ├── boundary.ts # Applies to /admin/* and everything nested
39
- │ │ ├── route.ts
35
+ │ │ ├── boundary.ts # Scoped boundary applying to /admin and nested routes
40
36
  │ │ └── posts/
41
- │ │ ├── route.ts
42
- │ │ ├── schema.ts
43
- │ │ └── service.ts
44
- │ ├── cron/ # Scheduled tasks & background cron jobs (auto-discovered)
45
- │ │ └── cleanup.ts
46
- │ ├── database/ # Database connection, models/schemas, migrations, or repositories
47
- │ │ ├── db.ts # Connection client & lifecycle registration (registerDatabase)
48
- │ │ └── models/ # Database entity models / ORM schemas (e.g. user.model.ts)
49
- │ ├── common/ # Shared cross-cutting guards, interceptors, or filters
37
+ │ │ ├── route.ts # Route endpoints for /admin/posts
38
+ │ │ ├── schema.ts # Validation schemas for /admin/posts
39
+ │ │ └── service.ts # Service logic for /admin/posts
40
+ │ ├── cron/ # Scheduled background tasks (auto-discovered)
41
+ │ │ └── cleanup.ts # Cron task definitions
42
+ │ ├── database/ # Persistent storage configuration and lifecycle
43
+ │ │ ├── db.ts # Database connection client and lifecycle registration
44
+ │ │ └── models/ # Database models, schemas, and entity definitions
45
+ │ ├── common/ # Shared cross-cutting components
50
46
  │ │ └── guards/
51
- │ │ └── auth.guard.ts
47
+ │ │ └── auth.guard.ts # Reusable route guards
52
48
  │ └── config/
53
- │ └── env.ts # Type-safe environment schema (tex.env)
54
- ├── tests/
55
- ├── .env
56
- ├── exis.config.ts
49
+ │ └── env.ts # Environment variable validation schema (tex.env)
50
+ ├── tests/ # Automated test suites (*.test.ts, *.e2e-spec.ts)
51
+ ├── .env # Local environment variables
52
+ ├── .gitignore
53
+ ├── .prettierrc
54
+ ├── eslint.config.mjs # ESLint flat configuration (optional)
55
+ ├── exis.config.ts # Application configuration file
57
56
  ├── package.json
58
57
  └── tsconfig.json
59
58
  ```
60
59
 
61
- > `src/cron/` is natively auto-discovered by the framework at boot. All files inside `src/cron/` or colocated at `src/http/**/cron.ts` are automatically mounted. Database connections and models reside under `src/database/` (or `src/models/`).
62
-
63
60
  ---
64
61
 
65
- ## File Roles (identical meaning in both paradigms)
62
+ ## File Conventions & Responsibilities
66
63
 
67
- A file's name declares its role. Functional vs. class-based (OOP) only changes
68
- _syntax_, never _responsibility_.
64
+ Within `src/http/`, each file name denotes a specific role in the HTTP lifecycle:
69
65
 
70
- ExisJS supports two naming conventions seamlessly:
66
+ | File Pattern | Role | Description |
67
+ | :--- | :--- | :--- |
68
+ | `route.ts` / `*.route.ts` | Endpoint Definition | Binds HTTP methods (`GET`, `POST`, `PUT`, `DELETE`, `PATCH`) to URL paths. |
69
+ | `schema.ts` / `*.schema.ts` | Request Validation | Defines `tex` schemas for request body, query parameters, URL path parameters, and headers. |
70
+ | `service.ts` / `*.service.ts` | Business Logic | Handles database operations and domain logic. Injected via Dependency Injection or called as pure functions. |
71
+ | `boundary.ts` / `*.boundary.ts` | Scoped Pipeline | Folder-level configuration (CORS, headers, rate limits, authentication guards, and error handling) cascading down directory trees. |
72
+ | `server.ts` | Server Lifecycle | Exports `onStart` and `onClose` hooks for database connections and plugin initialization. |
73
+ | `error.ts` / `*.error.ts` | Exception Handling | Centralized error interceptor exporting `onError(err, req, res)`. |
71
74
 
72
- 1. **Standard Flat Names** (default): `route.ts`, `schema.ts`, `service.ts`, `boundary.ts`.
73
- 2. **Feature-Prefixed Named Files**: `<name>.route.ts`, `<name>.schema.ts`, `<name>.service.ts`, `<name>.boundary.ts` (e.g., `user.route.ts`, `user.schema.ts`, `user.service.ts`).
75
+ ---
74
76
 
75
- Both styles are automatically detected by the route scanner, CLI manifest generator, and development watcher with 100% parity.
77
+ ## Directory Details
76
78
 
77
- | File Pattern | Role | Never contains |
78
- | :------------------------------ | :--------------------------------------------------------------------------------------------- | :------------------------------- |
79
- | `route.ts` / `*.route.ts` | Binds a URL + method to a handler. | Business logic, validation logic |
80
- | `schema.ts` / `*.schema.ts` | `tex` validation schemas, imported by route files. Mandatory for every route accepting input. | Handlers, routing |
81
- | `service.ts` / `*.service.ts` | Business logic and data access. DI-injectable. | Routing, response shaping |
82
- | `boundary.ts` / `*.boundary.ts` | Folder-scoped config + request pipeline for everything in this folder and below. | — |
83
- | `error.ts` / `*.error.ts` | Centralized exception and validation error handler (`onError`). Auto-mounted by the framework. | Business logic, routes |
79
+ ### 1. `src/http/` (File-System Routing)
84
80
 
85
- ---
81
+ Every folder inside `src/http/` maps directly to an HTTP endpoint path:
86
82
 
87
- ## `src/http/**/route.ts`
83
+ - `src/http/route.ts` → `/`
84
+ - `src/http/users/route.ts` → `/users`
85
+ - `src/http/users/[id]/route.ts` → `/users/:id`
86
+ - `src/http/(admin)/dashboard/route.ts` → `/dashboard` (parenthesized route groups do not affect the URL path)
88
87
 
89
- Any `route.ts` (or `.js`) under `src/http/` maps to a URL from its folder path:
88
+ #### Paradigm Examples
90
89
 
91
- - `src/http/route.ts` → `/api`
92
- - `src/http/users/route.ts` → `/api/users`
93
- - `src/http/users/[id]/route.ts` → `/api/users/:id`
94
- - `src/http/(internal)/debug/route.ts` → `/api/debug` (group folders are ignored)
95
-
96
- ### Functional
90
+ ##### Functional Paradigm
97
91
 
98
92
  ```typescript filename="src/http/users/route.ts"
99
93
  import { controller, route } from 'exisjs/router'
100
- import { UserParamsSchema } from './schema'
101
- import { fetchUser } from './service'
94
+ import { userParamsSchema } from './schema'
95
+ import { getUserById } from './service'
102
96
 
103
97
  export default controller({
104
- getUser: route.get('/users/:id', {
105
- params: UserParamsSchema,
106
- async handle({ params }) {
107
- return fetchUser(params.id)
98
+ getUser: route.get('/:id', {
99
+ summary: 'Retrieve user by ID',
100
+ params: userParamsSchema,
101
+ handle: async ({ params }) => {
102
+ return getUserById(params.id)
108
103
  },
109
104
  }),
110
105
  })
111
106
  ```
112
107
 
113
- ### Class-based (OOP)
114
-
115
- The decorated class **is** the route file — no separate controller file:
108
+ ##### Class-Based (OOP) Paradigm
116
109
 
117
110
  ```typescript filename="src/http/users/route.ts"
118
- import { Controller, Get, Param } from 'exisjs/decorators'
119
- import { UserParamsSchema } from './schema'
111
+ import { Controller, Get, Param, ApiOperation } from 'exisjs/decorators'
112
+ import { userParamsSchema } from './schema'
120
113
  import { UserService } from './service'
121
114
 
122
- @Controller('/users')
123
- export default class UserRoute {
124
- constructor(private userService: UserService) {}
115
+ @Controller()
116
+ export default class UsersController {
117
+ constructor(private readonly userService: UserService) {}
125
118
 
126
- @Get('/:id', UserParamsSchema)
119
+ @Get('/:id', { params: userParamsSchema })
120
+ @ApiOperation({ summary: 'Retrieve user by ID' })
127
121
  async getUser(@Param('id') id: string) {
128
- return this.userService.fetchUser(id)
122
+ return this.userService.getUserById(id)
129
123
  }
130
124
  }
131
125
  ```
132
126
 
133
- > [!IMPORTANT]
134
- > Choose **one paradigm** — Functional or OOP — for the entire project.
135
- > Mixing them causes a fatal error at startup.
136
-
137
127
  ---
138
128
 
139
- ## `src/http/**/schema.ts`
129
+ ### 2. `src/http/**/schema.ts` (Validation Schemas)
130
+
131
+ Define request payload and parameter schemas using the `tex` schema builder. Schemas defined here provide compile-time type inference and drive the OpenAPI documentation generator:
140
132
 
141
133
  ```typescript filename="src/http/users/schema.ts"
142
- import { tex } from 'exisjs/validator'
134
+ import { tex, type ResolveSchema } from 'exisjs/validator'
143
135
 
144
- export const UserParamsSchema = tex.object({ id: tex.string() })
145
- ```
136
+ export const userParamsSchema = tex.object({
137
+ id: tex.string({ min: 1 }),
138
+ })
146
139
 
147
- `tex` is the only validation engine. Schemas here are also the source for
148
- OpenAPI generation via `exisjs/swagger`.
140
+ export const createUserSchema = tex.object({
141
+ name: tex.string({ min: 2 }),
142
+ email: tex.email(),
143
+ role: tex.enum(['admin', 'member'], { default: 'member' }),
144
+ })
145
+
146
+ export type CreateUserDto = ResolveSchema<typeof createUserSchema>
147
+ export type UserParamsDto = ResolveSchema<typeof userParamsSchema>
148
+ ```
149
149
 
150
150
  ---
151
151
 
152
- ## `src/http/**/service.ts`
152
+ ### 3. `src/http/**/service.ts` (Business Logic)
153
153
 
154
- Plain functions (functional) or an `@Injectable()` class (OOP) — the data/business
155
- layer, identical concept in both paradigms:
154
+ Isolate database interactions and business logic from HTTP transport concerns:
155
+
156
+ #### Functional Service
156
157
 
157
158
  ```typescript filename="src/http/users/service.ts"
158
- // Functional
159
- export async function fetchUser(id: string) {
160
- // ...
159
+ export async function getUserById(id: string) {
160
+ return { id, name: 'Alice', role: 'member' }
161
161
  }
162
162
  ```
163
163
 
164
+ #### Class-Based (OOP) Service
165
+
164
166
  ```typescript filename="src/http/users/service.ts"
165
- // OOP
166
167
  import { Injectable } from 'exisjs/decorators'
167
168
 
168
169
  @Injectable()
169
170
  export class UserService {
170
- async fetchUser(id: string) {
171
- // ...
171
+ async getUserById(id: string) {
172
+ return { id, name: 'Alice', role: 'member' }
172
173
  }
173
174
  }
174
175
  ```
175
176
 
176
177
  ---
177
178
 
178
- ## `src/http/**/boundary.ts`
179
-
180
- A `boundary.ts` applies to every route in its folder and all subfolders. It has
181
- two independent halves:
182
-
183
- 1. **Config** — pure data, via `defineBoundary()` (functional) or `@Boundary()`
184
- (OOP argument). CORS, headers, DI providers, excluded paths, and lifecycle hooks.
185
- 2. **Pipeline & Hooks** — real code, auto-detected by function signature. No imports,
186
- no manual registration required.
179
+ ### 4. `src/http/**/boundary.ts` (Hierarchical Boundaries)
187
180
 
188
- | Signature | Detected as | Runs |
189
- | :----------------------------------------------------------------------- | :------------------ | :--------------------------------------------------------------------------------- |
190
- | `(req, res, next)` | Chain Step | In file/declaration order, before the route handler |
191
- | `beforeHandle(req, res)` | Boundary Guard Hook | Immediately before route execution. Short-circuits on `false` or when headers sent |
192
- | `afterHandle(req, res, data)` | Response Hook | Immediately after route execution. Receives returned data to transform or audit |
193
- | `(ctx, next)` — default export (functional) or `handle(ctx, next)` (OOP) | Pipeline Wrapper | Around all chain steps and the nested route/boundary |
181
+ A `boundary.ts` file applies scoped security guards, CORS settings, custom headers, and error handling to all routes within its directory and subdirectories:
194
182
 
195
- ### Functional
183
+ #### Functional Boundary
196
184
 
197
185
  ```typescript filename="src/http/admin/boundary.ts"
198
186
  import { defineBoundary } from 'exisjs/router'
199
- import type { Request, Response, Next, BoundaryContext } from 'exisjs/router'
187
+ import type { Request, Response, Next } from 'exisjs/router'
200
188
 
201
189
  export const config = defineBoundary({
202
- cors: { origin: ['https://myapp.com'], credentials: true },
203
- headers: { 'X-Powered-By': 'ExisJS' },
204
- exclude: [{ path: '/admin/health', method: 'GET' }],
205
-
206
- // Pre-handler hook (returns false to block with 403, or sends response)
207
- beforeHandle(req, res) {
208
- if (req.headers['x-role'] !== 'admin') {
209
- res.status(403).json({ error: 'Admin role required' })
190
+ cors: { origin: ['https://admin.example.com'], credentials: true },
191
+ headers: { 'X-Admin-Scope': 'active' },
192
+ exclude: ['/admin/health'],
193
+
194
+ beforeHandle(req: Request, res: Response) {
195
+ if (req.headers['x-admin-key'] !== process.env.ADMIN_KEY) {
196
+ res.status(403).json({ error: 'Unauthorized admin access' })
210
197
  return false
211
198
  }
212
199
  },
213
-
214
- // Post-handler hook (transforms returned payload or performs async audit)
215
- afterHandle(req, res, data) {
216
- res.setHeader('X-Audited-By', 'AdminBoundary')
217
- return { ...data, auditedAt: Date.now() }
218
- },
219
200
  })
220
201
 
221
- export function logStep(req: Request, res: Response, next: Next) {
222
- console.log(`[Admin] ${req.method} ${req.path}`)
202
+ export function logAdminAccess(req: Request, res: Response, next: Next) {
203
+ console.log(`[Admin Access] ${req.method} ${req.path}`)
223
204
  next()
224
205
  }
225
-
226
- export default async function (ctx: BoundaryContext, next: Next) {
227
- try {
228
- return { success: true, data: await next() }
229
- } catch (err) {
230
- return { success: false, error: { message: (err as Error).message } }
231
- }
232
- }
233
206
  ```
234
207
 
235
- ### Class-based (OOP)
208
+ #### Class-Based (OOP) Boundary
236
209
 
237
210
  ```typescript filename="src/http/admin/boundary.ts"
238
211
  import { Boundary } from 'exisjs/decorators'
239
- import type { Request, Response, Next, BoundaryContext } from 'exisjs/router'
212
+ import type { Request, Response, Next } from 'exisjs/router'
240
213
 
241
214
  @Boundary({
242
- cors: { origin: ['https://myapp.com'], credentials: true },
243
- headers: { 'X-Powered-By': 'ExisJS' },
215
+ cors: { origin: ['https://admin.example.com'], credentials: true },
216
+ headers: { 'X-Admin-Scope': 'active' },
244
217
  exclude: ['/admin/health'],
245
218
  })
246
219
  export default class AdminBoundary {
247
- // Pre-handler hook
248
220
  beforeHandle(req: Request, res: Response) {
249
- if (req.headers['x-role'] !== 'admin') {
250
- res.status(403).json({ error: 'Admin role required' })
221
+ if (req.headers['x-admin-key'] !== process.env.ADMIN_KEY) {
222
+ res.status(403).json({ error: 'Unauthorized admin access' })
251
223
  return false
252
224
  }
253
225
  }
254
226
 
255
- // Post-handler hook
256
- afterHandle(req: Request, res: Response, data: any) {
257
- return { ...data, auditedAt: Date.now() }
258
- }
259
-
260
- // Chain step
261
- logStep(req: Request, res: Response, next: Next) {
262
- console.log(`[Admin] ${req.method} ${req.path}`)
227
+ logAdminAccess(req: Request, res: Response, next: Next) {
228
+ console.log(`[Admin Access] ${req.method} ${req.path}`)
263
229
  next()
264
230
  }
265
-
266
- // Wrapper
267
- async handle(ctx: BoundaryContext, next: Next) {
268
- try {
269
- return { success: true, data: await next() }
270
- } catch (err) {
271
- return { success: false, error: { message: (err as Error).message } }
272
- }
273
- }
274
231
  }
275
232
  ```
276
233
 
277
234
  ---
278
235
 
279
- ## `src/http/error.ts` (Framework-Level Exception Handler)
236
+ ### 5. `src/http/error.ts` (Global Error Handler)
280
237
 
281
- ExisJS natively discovers and mounts `src/http/error.ts` (or `error.js`) at boot. It exports an `onError(err, req, res)` handler, giving developers a single, standard place to intercept, log, and format all unhandled or validation errors without writing custom `app.onError` boilerplate inside `server.ts`.
282
-
283
- ### Functional
238
+ ExisJS discovers `src/http/error.ts` to format application errors and validation failures consistently across all endpoints:
284
239
 
285
240
  ```typescript filename="src/http/error.ts"
286
241
  import type { Request, Response } from 'exisjs'
@@ -288,7 +243,6 @@ import type { Request, Response } from 'exisjs'
288
243
  export function onError(err: any, req: Request, res: Response) {
289
244
  const status = err.statusCode || err.status || 500
290
245
 
291
- // Format consistent error response across the entire API
292
246
  res.status(status).json({
293
247
  success: false,
294
248
  error: {
@@ -300,50 +254,29 @@ export function onError(err: any, req: Request, res: Response) {
300
254
  }
301
255
  ```
302
256
 
303
- ### Class-Based (OOP)
304
-
305
- ```typescript filename="src/http/error.ts"
306
- import type { Request, Response } from 'exisjs'
307
-
308
- export default class GlobalErrorHandler {
309
- onError(err: any, req: Request, res: Response) {
310
- const status = err.statusCode || err.status || 500
311
- res.status(status).json({
312
- success: false,
313
- error: {
314
- message: err.message || 'Internal Server Error',
315
- code: err.code || 'INTERNAL_ERROR',
316
- path: req.path,
317
- },
318
- })
319
- }
320
- }
321
- ```
322
-
323
- A nested folder's `boundary.ts` always runs _inside_ its parent's `next()` —
324
- pipeline depth mirrors folder depth automatically.
325
-
326
257
  ---
327
258
 
328
- ## `exis.config.ts`
259
+ ### 6. `src/cron/` (Scheduled Background Tasks)
329
260
 
330
- Global infrastructure: port, SSL, CORS defaults, security headers, and
331
- official package registration.
261
+ Files placed inside `src/cron/` are automatically mounted by the scheduler during server boot:
332
262
 
333
- ```typescript filename="exis.config.ts"
334
- import { defineConfig } from 'exisjs'
263
+ ```typescript filename="src/cron/cleanup.ts"
264
+ import { cron } from 'exisjs/cron'
335
265
 
336
- export default defineConfig({
337
- port: 3000,
338
- cors: { origin: '*' },
339
- // plugins: [] — official packages (@exisjs/database, @exisjs/auth, etc.)
340
- // are registered here once installed. None are required by default.
266
+ export default cron('0 0 * * *', {
267
+ name: 'daily-database-cleanup',
268
+ run: async () => {
269
+ console.log('[Cron] Executing nightly database maintenance...')
270
+ },
341
271
  })
342
272
  ```
343
273
 
344
274
  ---
345
275
 
346
- ## `src/config/env.ts`
276
+ ### 7. `src/database/` & `src/config/`
277
+
278
+ - **`src/database/db.ts`**: Contains database connections and lifecycle registration via `registerDatabase`.
279
+ - **`src/config/env.ts`**: Validates environment variables at boot using `tex.env`:
347
280
 
348
281
  ```typescript filename="src/config/env.ts"
349
282
  import { tex } from 'exisjs/validator'
@@ -359,46 +292,24 @@ export const env = tex
359
292
  .parse(process.env)
360
293
  ```
361
294
 
362
- Boot fails immediately with clear diagnostics if a required environment variable is missing or malformed.
363
-
364
- ---
365
-
366
- ## `src/database/`
367
-
368
- The `src/database/` directory organizes your persistent storage layer:
369
-
370
- - `src/database/db.ts`: Connection instance, client initialization, and lifecycle registration via `registerDatabase(app, { connect, disconnect, healthCheck })` (or ORMs like Prisma, Drizzle, Mongoose).
371
- - `src/database/models/` (or `src/models/`): Data models, entity definitions, and database schemas.
372
- - `src/database/repositories/`: Abstracted data access objects and custom query builders.
373
- - `src/database/migrations/`: Database migration scripts.
374
-
375
- ---
376
-
377
- ## `.exis/`
378
-
379
- Internal build cache — compiled route manifest, used for O(1) boot in
380
- production. Add to `.gitignore`.
381
-
382
295
  ---
383
296
 
384
- ## Auto-Discovered vs Custom Directories
297
+ ## Auto-Discovered vs Convention Directories
385
298
 
386
- - **Auto-Discovered by Framework**:
387
- - `src/http/`: Route handlers (`route.ts`), request schemas (`schema.ts`), boundaries (`boundary.ts`), and global error handler (`error.ts`).
388
- - `src/cron/`: Scheduled tasks and background cron jobs (`cleanup.ts`, `reports.ts`).
389
- - **Standard Recommended Conventions**:
390
- - `src/database/`: Database client (`db.ts`), models (`models/`), and migrations.
391
- - `src/common/`: Shared guards (`guards/`), interceptors, and exception filters.
392
- - `src/config/`: Environment configuration (`config/env.ts`).
393
- - `src/services/` or `src/dto/`: Optional shared business logic or global DTOs across multiple routes.
299
+ | Directory | Type | Description |
300
+ | :--- | :--- | :--- |
301
+ | `src/http/` | Auto-Discovered | Scanned at startup for routes, boundaries, schemas, services, and error handlers. |
302
+ | `src/cron/` | Auto-Discovered | Scanned at startup for scheduled background task definitions. |
303
+ | `src/database/` | Convention | Recommended folder for database connection instances, ORM models, and migrations. |
304
+ | `src/common/` | Convention | Recommended folder for shared guards, filters, and cross-cutting helpers. |
305
+ | `src/config/` | Convention | Recommended folder for environment schemas and static configurations. |
306
+ | `tests/` | Convention | Recommended folder for integration and end-to-end test suites. |
394
307
 
395
308
  ---
396
309
 
397
- ## The ExisJS CLI
310
+ ## Next Steps
398
311
 
399
- - `exis dev` — dev server with HMR
400
- - `exis build` — compile for production
401
- - `exis start` — run compiled output
402
- - `exis routes` — print every compiled endpoint
403
- - `exis generate <type>` — scaffold a route, boundary, service, or schema
404
- - `exis add <package>` — install and wire an official package (e.g. `exis add database`)
312
+ - **[Routing & Endpoints](/docs/routing)**: Detailed routing guide covering route methods, parameter extraction, and route grouping.
313
+ - **[Validation Guide](/docs/validation)**: Comprehensive reference for building schemas with `tex`.
314
+ - **[Boundaries](/docs/boundaries)**: Scoped middleware execution, CORS cascades, and error boundary wrappers.
315
+ - **[Configuration](/docs/config)**: Complete options reference for `exis.config.ts`.