exisjs 0.7.11 → 0.7.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +195 -39
- package/dist/cli/commands/dev.d.ts +4 -0
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +136 -32
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/cli/commands/run.d.ts +7 -0
- package/dist/cli/commands/run.d.ts.map +1 -0
- package/dist/cli/commands/run.js +99 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/index.js +29 -13
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/manifest.d.ts.map +1 -1
- package/dist/cli/manifest.js +18 -3
- package/dist/cli/manifest.js.map +1 -1
- package/dist/cli/routes.d.ts +6 -0
- package/dist/cli/routes.d.ts.map +1 -1
- package/dist/cli/routes.js +224 -135
- package/dist/cli/routes.js.map +1 -1
- package/dist/config/config.d.ts +2 -1
- package/dist/config/config.d.ts.map +1 -1
- package/dist/config/config.js.map +1 -1
- package/dist/config/types.d.ts +30 -9
- package/dist/config/types.d.ts.map +1 -1
- package/dist/database/lifecycle.d.ts +6 -1
- package/dist/database/lifecycle.d.ts.map +1 -1
- package/dist/database/lifecycle.js +15 -4
- package/dist/database/lifecycle.js.map +1 -1
- package/dist/decorators/params.d.ts +21 -0
- package/dist/decorators/params.d.ts.map +1 -1
- package/dist/decorators/params.js +21 -1
- package/dist/decorators/params.js.map +1 -1
- package/dist/di/container.d.ts +15 -6
- package/dist/di/container.d.ts.map +1 -1
- package/dist/di/container.js +26 -3
- package/dist/di/container.js.map +1 -1
- package/dist/di/index.d.ts +1 -1
- package/dist/di/index.d.ts.map +1 -1
- package/dist/di/index.js.map +1 -1
- package/dist/di/inject.d.ts +2 -1
- package/dist/di/inject.d.ts.map +1 -1
- package/dist/di/inject.js +2 -1
- package/dist/di/inject.js.map +1 -1
- package/dist/docs/BENCHMARKS.md +4 -4
- package/dist/docs/content/README.md +43 -44
- package/dist/docs/content/boundaries.mdx +141 -48
- package/dist/docs/content/cli/commands.mdx +161 -107
- package/dist/docs/content/cli/overview.mdx +61 -46
- package/dist/docs/content/cli/usage.mdx +107 -30
- package/dist/docs/content/config.mdx +145 -147
- package/dist/docs/content/controllers.mdx +193 -464
- package/dist/docs/content/cron.mdx +183 -69
- package/dist/docs/content/decorators.mdx +449 -154
- package/dist/docs/content/errors.mdx +202 -305
- package/dist/docs/content/exisjs-mcp.mdx +59 -49
- package/dist/docs/content/installation.mdx +243 -157
- package/dist/docs/content/introduction.mdx +220 -48
- package/dist/docs/content/middleware.mdx +171 -497
- package/dist/docs/content/modules.mdx +141 -83
- package/dist/docs/content/providers.mdx +216 -180
- package/dist/docs/content/requests.mdx +168 -488
- package/dist/docs/content/responses.mdx +200 -533
- package/dist/docs/content/routing.mdx +239 -558
- package/dist/docs/content/security.mdx +233 -57
- package/dist/docs/content/structure.mdx +151 -240
- package/dist/docs/content/swagger.mdx +192 -91
- package/dist/docs/content/testing.mdx +205 -74
- package/dist/docs/content/validation.mdx +479 -341
- package/dist/docs/reference/README.md +34 -2
- package/dist/docs/reference/config.mdx +277 -73
- package/dist/docs/reference/context.mdx +197 -106
- package/dist/docs/reference/cron.mdx +266 -152
- package/dist/docs/reference/database.mdx +135 -53
- package/dist/docs/reference/decorators.mdx +234 -116
- package/dist/docs/reference/di.mdx +146 -112
- package/dist/docs/reference/error.mdx +155 -178
- package/dist/docs/reference/exis.mdx +141 -70
- package/dist/docs/reference/logger.mdx +110 -126
- package/dist/docs/reference/middleware.mdx +235 -158
- package/dist/docs/reference/plugin.mdx +136 -64
- package/dist/docs/reference/router.mdx +277 -251
- package/dist/docs/reference/sanitize.mdx +91 -87
- package/dist/docs/reference/swagger.mdx +280 -100
- package/dist/docs/reference/testing.mdx +223 -89
- package/dist/docs/reference/validator.mdx +194 -206
- package/dist/lib/inspect-routes.d.ts +2 -0
- package/dist/lib/inspect-routes.d.ts.map +1 -0
- package/dist/lib/inspect-routes.js +148 -0
- package/dist/lib/inspect-routes.js.map +1 -0
- package/dist/lib/start-server.js +13 -8
- package/dist/lib/start-server.js.map +1 -1
- package/dist/module/module.d.ts +6 -3
- package/dist/module/module.d.ts.map +1 -1
- package/dist/module/module.js +17 -3
- package/dist/module/module.js.map +1 -1
- package/dist/router/controller-registrar.d.ts.map +1 -1
- package/dist/router/controller-registrar.js +26 -4
- package/dist/router/controller-registrar.js.map +1 -1
- package/dist/router/scanner/cron-mounter.d.ts.map +1 -1
- package/dist/router/scanner/cron-mounter.js +9 -2
- package/dist/router/scanner/cron-mounter.js.map +1 -1
- package/dist/server/app.d.ts +3 -1
- package/dist/server/app.d.ts.map +1 -1
- package/dist/server/app.js +29 -8
- package/dist/server/app.js.map +1 -1
- package/dist/server/define.d.ts.map +1 -1
- package/dist/server/define.js +5 -0
- package/dist/server/define.js.map +1 -1
- package/dist/server/request.d.ts +2 -0
- package/dist/server/request.d.ts.map +1 -1
- package/dist/server/request.js +11 -0
- package/dist/server/request.js.map +1 -1
- package/dist/swagger/generator.d.ts.map +1 -1
- package/dist/swagger/generator.js +130 -10
- package/dist/swagger/generator.js.map +1 -1
- package/dist/telemetry/index.d.ts +12 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +121 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/testing/client.d.ts +1 -0
- package/dist/testing/client.d.ts.map +1 -1
- package/dist/testing/client.js +4 -1
- package/dist/testing/client.js.map +1 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +20 -4
- package/dist/testing/index.js.map +1 -1
- package/dist/validator/builder.d.ts +26 -1
- package/dist/validator/builder.d.ts.map +1 -1
- package/dist/validator/builder.js +31 -0
- package/dist/validator/builder.js.map +1 -1
- package/dist/validator/engine.d.ts +23 -0
- package/dist/validator/engine.d.ts.map +1 -1
- package/dist/validator/engine.js +228 -31
- package/dist/validator/engine.js.map +1 -1
- package/dist/validator/index.d.ts +8 -4
- package/dist/validator/index.d.ts.map +1 -1
- package/dist/validator/index.js +4 -1
- package/dist/validator/index.js.map +1 -1
- package/dist/validator/tex-types.d.ts +15 -0
- package/dist/validator/tex-types.d.ts.map +1 -1
- package/dist/validator/tex-types.js +102 -0
- package/dist/validator/tex-types.js.map +1 -1
- package/dist/validator/tex.d.ts +1 -1
- package/dist/validator/tex.d.ts.map +1 -1
- package/dist/validator/tex.js +3 -1
- package/dist/validator/tex.js.map +1 -1
- package/dist/validator/types.d.ts +1 -0
- package/dist/validator/types.d.ts.map +1 -1
- package/package.json +47 -14
- package/dist/docs/content/dataloader.mdx +0 -170
- package/dist/docs/reference/dataloader.mdx +0 -91
|
@@ -1,124 +1,195 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
3
|
-
description: "API Reference for the exis
|
|
2
|
+
title: "exisjs (Root API)"
|
|
3
|
+
description: "API Reference for the defineApp (exis) entrypoint, App instance methods, lifecycle hooks, and server bootstrap."
|
|
4
|
+
nextUrl: "/docs/reference/config"
|
|
5
|
+
nextTitle: "Config Reference"
|
|
4
6
|
---
|
|
5
7
|
|
|
6
|
-
#
|
|
8
|
+
# `exisjs` (Root API)
|
|
7
9
|
|
|
8
|
-
The `
|
|
10
|
+
The root `exisjs` module exports the core application builder `defineApp` (aliased as `exis`), the `App` class definition, active application resolvers, response helpers, and circuit breaker utilities.
|
|
9
11
|
|
|
10
|
-
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Module Exports
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import {
|
|
18
|
+
exis,
|
|
19
|
+
defineApp,
|
|
20
|
+
App,
|
|
21
|
+
getActiveApp,
|
|
22
|
+
defineConfig,
|
|
23
|
+
parseEnv,
|
|
24
|
+
loadEnv,
|
|
25
|
+
} from 'exisjs'
|
|
26
|
+
|
|
27
|
+
import type {
|
|
28
|
+
ExisConfig,
|
|
29
|
+
ExisPlugin,
|
|
30
|
+
ExisPluginInstance,
|
|
31
|
+
Logger,
|
|
32
|
+
CorsConfig,
|
|
33
|
+
LoggerConfig,
|
|
34
|
+
HookRequest,
|
|
35
|
+
HookResponse,
|
|
36
|
+
HookError,
|
|
37
|
+
HookReady,
|
|
38
|
+
HookClose,
|
|
39
|
+
} from 'exisjs'
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 1. Application Entrypoint: `exis()` / `defineApp()`
|
|
45
|
+
|
|
46
|
+
Defines an ExisJS application definition for CLI execution or programmatic booting.
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
function defineApp(options?: ExisAppOptions): ExisAppDefinition
|
|
50
|
+
export { defineApp as exis }
|
|
51
|
+
```
|
|
11
52
|
|
|
12
|
-
|
|
53
|
+
### `ExisAppOptions` Interface
|
|
13
54
|
|
|
14
|
-
|
|
55
|
+
Extends `ExisConfig` with application lifecycle hooks:
|
|
15
56
|
|
|
16
|
-
|
|
57
|
+
| Option | Type | Default | Description |
|
|
58
|
+
| :--- | :--- | :--- | :--- |
|
|
59
|
+
| `port` | `number` | `3000` | Port number to bind the server listener to. |
|
|
60
|
+
| `host` | `string` | `'0.0.0.0'` | Network address to bind the listener to. |
|
|
61
|
+
| `env` | `'development' \| 'production' \| 'test'` | `NODE_ENV` | Application execution environment. |
|
|
62
|
+
| `logger` | `boolean \| LoggerConfig` | `true` | Configures or disables the built-in Pino structured logger. |
|
|
63
|
+
| `helmet` | `boolean \| HelmetOptions` | `true` | Automatically injects security response headers. |
|
|
64
|
+
| `cors` | `boolean \| CorsConfig` | `false` | Manages Cross-Origin Resource Sharing headers and preflights. |
|
|
65
|
+
| `compression` | `boolean \| CompressionOptions` | `false` | Response payload compression via Gzip, Deflate, or Brotli. |
|
|
66
|
+
| `plugins` | `(ExisPlugin \| ExisPluginInstance)[]` | `[]` | Array of modules or plugins to initialize on boot. |
|
|
67
|
+
| `middlewares` | `Handler[]` | `[]` | Global middleware executed on all incoming requests. |
|
|
68
|
+
| `onStart` | `(app: App) => void \| Promise<void>` | `undefined` | Hook executed during startup before the listener begins accepting requests. |
|
|
69
|
+
| `onClose` | `(app: App) => void \| Promise<void>` | `undefined` | Hook executed during graceful shutdown. |
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 2. Dual-Paradigm Setup
|
|
74
|
+
|
|
75
|
+
### Functional Paradigm
|
|
17
76
|
|
|
18
77
|
```typescript filename="src/http/server.ts"
|
|
19
78
|
import { exis } from 'exisjs'
|
|
20
|
-
import { cors } from 'exisjs/middleware'
|
|
21
79
|
|
|
22
80
|
export default exis({
|
|
23
81
|
port: 3000,
|
|
82
|
+
logger: true,
|
|
24
83
|
helmet: true,
|
|
25
|
-
cors: {
|
|
26
|
-
origin: '*',
|
|
27
|
-
},
|
|
28
|
-
middlewares: [
|
|
29
|
-
cors()
|
|
30
|
-
],
|
|
84
|
+
cors: { origin: '*' },
|
|
31
85
|
async onStart(app) {
|
|
32
|
-
app.log.info(
|
|
33
|
-
}
|
|
86
|
+
app.log.info('Application initialized successfully')
|
|
87
|
+
},
|
|
88
|
+
async onClose(app) {
|
|
89
|
+
app.log.info('Graceful shutdown complete')
|
|
90
|
+
},
|
|
34
91
|
})
|
|
35
92
|
```
|
|
36
93
|
|
|
37
94
|
---
|
|
38
95
|
|
|
39
|
-
###
|
|
40
|
-
|
|
41
|
-
If you prefer an Object-Oriented approach, you can define your application entry point using the `@Server()` decorator.
|
|
96
|
+
### Class-Based (OOP) Paradigm
|
|
42
97
|
|
|
43
98
|
```typescript filename="src/http/server.ts"
|
|
44
99
|
import { Server } from 'exisjs/decorators'
|
|
45
100
|
import type { App } from 'exisjs'
|
|
46
101
|
|
|
47
102
|
@Server({
|
|
48
|
-
plugins: [
|
|
49
|
-
// You can register plugins or configuration directly in the decorator options
|
|
50
|
-
]
|
|
103
|
+
plugins: [],
|
|
51
104
|
})
|
|
52
105
|
export default class RootServer {
|
|
53
106
|
async onStart(app: App) {
|
|
54
|
-
app.log.info(
|
|
107
|
+
app.log.info('Application initialized successfully')
|
|
55
108
|
}
|
|
56
|
-
|
|
109
|
+
|
|
57
110
|
async onClose(app: App) {
|
|
58
|
-
app.log.info(
|
|
111
|
+
app.log.info('Graceful shutdown complete')
|
|
59
112
|
}
|
|
60
113
|
}
|
|
61
114
|
```
|
|
62
115
|
|
|
63
116
|
---
|
|
64
117
|
|
|
65
|
-
##
|
|
118
|
+
## 3. `App` Class Methods Reference
|
|
119
|
+
|
|
120
|
+
The `App` instance coordinates dependency injection, routing, middleware pipelines, lifecycle hooks, and background cron execution.
|
|
121
|
+
|
|
122
|
+
### Routing & Pipeline
|
|
123
|
+
|
|
124
|
+
| Method | Signature | Description |
|
|
125
|
+
| :--- | :--- | :--- |
|
|
126
|
+
| `use` | `(...handlers: (Handler \| ErrorHandler)[]): this` | Registers global request middlewares or 4-argument error handlers. |
|
|
127
|
+
| `get` | `(path: string, ...handlers: Handler[]): this` | Registers a `GET` route handler. |
|
|
128
|
+
| `post` | `(path: string, ...handlers: Handler[]): this` | Registers a `POST` route handler. |
|
|
129
|
+
| `put` | `(path: string, ...handlers: Handler[]): this` | Registers a `PUT` route handler. |
|
|
130
|
+
| `patch` | `(path: string, ...handlers: Handler[]): this` | Registers a `PATCH` route handler. |
|
|
131
|
+
| `delete` | `(path: string, ...handlers: Handler[]): this` | Registers a `DELETE` route handler. |
|
|
132
|
+
| `mount` | `(prefix: string, subRouter: Router): this` | Mounts a sub-router under a URL path prefix. |
|
|
133
|
+
| `getRoutes` | `(): Route[]` | Returns an array of all compiled route definitions. |
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
### Dependency Injection & Plugins
|
|
66
138
|
|
|
67
|
-
|
|
139
|
+
| Method | Signature | Description |
|
|
140
|
+
| :--- | :--- | :--- |
|
|
141
|
+
| `provide` | `<T>(token: ProviderToken<T>, provider: ProviderDefinition<T>): this` | Registers a dependency provider into the application container. |
|
|
142
|
+
| `resolve` | `<T>(token: ProviderToken<T>, requestCache?: Map<any, any>): T` | Resolves a singleton or request-scoped dependency from the container. |
|
|
143
|
+
| `register` | `(plugin: ExisPlugin \| ExisPluginInstance, options?: any): Promise<this>` | Registers an encapsulated plugin or module. |
|
|
144
|
+
| `hasPlugin` | `(name: string): boolean` | Checks whether a plugin has been registered. |
|
|
68
145
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
- The port the server will listen on during development or manual instantiation.
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
### Lifecycle Hooks
|
|
73
149
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
- The host the server will bind to.
|
|
150
|
+
```typescript
|
|
151
|
+
// Registers a hook called once the server is ready and listening
|
|
152
|
+
app.onReady((app: App) => void | Promise<void>)
|
|
78
153
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
- **Default**: Auto-detected via `NODE_ENV`.
|
|
82
|
-
- The current environment of the application.
|
|
154
|
+
// Registers a hook called when the server initiates graceful shutdown
|
|
155
|
+
app.onClose((app: App) => void | Promise<void>)
|
|
83
156
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
- **Default**: `true`
|
|
87
|
-
- Toggles the built-in Pino logger. You can pass a custom configuration object to set the log level, redact sensitive fields, or output JSON.
|
|
157
|
+
// Registers a hook called on each incoming HTTP request
|
|
158
|
+
app.onRequest((req: Request, res: Response) => void | Promise<void>)
|
|
88
159
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
- **Default**: `true`
|
|
92
|
-
- Automatically applies security headers to every response. Set to `false` to disable.
|
|
160
|
+
// Registers a hook called after an HTTP response finishes dispatching
|
|
161
|
+
app.onResponse((req: Request, res: Response) => void | Promise<void>)
|
|
93
162
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
- Automatically injects CORS headers into the request pipeline. You can pass a configuration object to specify allowed origins, methods, and credentials.
|
|
163
|
+
// Registers a hook called whenever an unhandled error occurs
|
|
164
|
+
app.onError((err: Error, req: Request, res: Response) => void | Promise<void>)
|
|
165
|
+
```
|
|
98
166
|
|
|
99
|
-
|
|
100
|
-
- **Type**: `boolean`
|
|
101
|
-
- **Default**: `true` (if applicable)
|
|
102
|
-
- Automatically compresses HTTP responses (gzip/brotli).
|
|
167
|
+
---
|
|
103
168
|
|
|
104
|
-
###
|
|
105
|
-
- **Type**: `Handler[]`
|
|
106
|
-
- **Default**: `[]`
|
|
107
|
-
- An array of global middleware functions that will run on every single request.
|
|
169
|
+
### Server Execution & Testing
|
|
108
170
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
-
|
|
112
|
-
|
|
171
|
+
| Method | Signature | Description |
|
|
172
|
+
| :--- | :--- | :--- |
|
|
173
|
+
| `create` | `(cwd?: string): Promise<this>` | Automatically loads configuration, mounts file-system routes, connects databases, and initializes lifecycles. |
|
|
174
|
+
| `listen` | `(portOrOptions?: number \| ListenOptions, callback?: () => void): Server` | Binds the underlying Node.js HTTP/HTTPS server and begins listening for connections. |
|
|
175
|
+
| `close` | `(timeout?: number): Promise<void>` | Initiates graceful server shutdown, drains cron jobs, and destroys DI singletons. |
|
|
176
|
+
| `inject` | `(options: InjectOptions): Promise<TestResponse>` | Dispatches an in-memory synthetic request without binding a real network socket (ideal for unit/E2E testing). |
|
|
113
177
|
|
|
114
178
|
---
|
|
115
179
|
|
|
116
|
-
##
|
|
180
|
+
## 4. `getActiveApp()`
|
|
117
181
|
|
|
118
|
-
|
|
182
|
+
Retrieves the currently running singleton `App` instance within the active Node.js process:
|
|
119
183
|
|
|
120
|
-
|
|
121
|
-
|
|
184
|
+
```typescript
|
|
185
|
+
function getActiveApp(): App
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
```typescript filename="src/services/billing.ts"
|
|
189
|
+
import { getActiveApp } from 'exisjs'
|
|
122
190
|
|
|
123
|
-
|
|
124
|
-
|
|
191
|
+
export function processInvoice(invoiceId: string) {
|
|
192
|
+
const app = getActiveApp()
|
|
193
|
+
app.log.info({ invoiceId }, 'Processing invoice')
|
|
194
|
+
}
|
|
195
|
+
```
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "
|
|
3
|
-
description: "API Reference
|
|
2
|
+
title: "exisjs/logger"
|
|
3
|
+
description: "API Reference for ExisJS structured logging, Pino integration, configureLogger, custom transports, and formatting helpers."
|
|
4
|
+
nextUrl: "/docs/reference/di"
|
|
5
|
+
nextTitle: "DI Reference"
|
|
4
6
|
---
|
|
5
7
|
|
|
6
|
-
#
|
|
8
|
+
# `exisjs/logger`
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
The `exisjs/logger` module provides structured logging powered by Pino. It includes a single-line terminal formatter for development, structured NDJSON output for production environments, automatic credential redaction, request-scoped loggers, and distributed tracing integration.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Module Exports
|
|
9
15
|
|
|
10
16
|
```typescript
|
|
11
17
|
import {
|
|
@@ -21,60 +27,23 @@ import {
|
|
|
21
27
|
formatStatus,
|
|
22
28
|
formatUrl,
|
|
23
29
|
formatIp,
|
|
30
|
+
extractValidationSummary,
|
|
31
|
+
extractErrorMessage,
|
|
24
32
|
} from 'exisjs/logger'
|
|
25
|
-
```
|
|
26
33
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
## 1. Terminal Request Logging (Development DX)
|
|
30
|
-
|
|
31
|
-
When running your application in development mode (`exis dev` or `pretty: true`), ExisJS automatically formats every incoming HTTP request into a clean, concise, single-line terminal log:
|
|
32
|
-
|
|
33
|
-
```text
|
|
34
|
-
[22:50:17] [exis] GET / 304 Not Modified 18ms
|
|
35
|
-
[22:50:55] [exis] GET /api/v1/profile 200 OK 1.2ms 240 B
|
|
36
|
-
[22:51:02] [exis] POST /api/v1/users 201 Created 14.5ms 1.4 KB
|
|
37
|
-
[22:51:10] [exis] PATCH /api/v1/users/42 400 Bad Request 3.1ms 120 B
|
|
38
|
-
└─ ⚠ Validation [body]: Field "email" must be a valid email format
|
|
39
|
-
[22:51:15] [exis] GET /api/v1/unknown 404 Not Found 0.8ms 45 B
|
|
40
|
-
[22:51:22] [exis] POST /api/v1/checkout 500 Internal Error 320ms 82 B
|
|
41
|
-
└─ ✖ Error: Database connection timeout
|
|
34
|
+
import type { Logger, LoggerConfig } from 'exisjs/logger'
|
|
42
35
|
```
|
|
43
36
|
|
|
44
|
-
### Visual Features & Formatting Elements
|
|
45
|
-
|
|
46
|
-
| Element | Description | Behavior / Color Coding |
|
|
47
|
-
| :--- | :--- | :--- |
|
|
48
|
-
| **Timestamp** | `[HH:MM:SS]` | Dimmed gray for non-intrusive readability |
|
|
49
|
-
| **Brand Badge** | `[exis]` | Framework brand color (`\x1b[38;2;160;70;255m`), `[warn]` (yellow), `[error]` (red) |
|
|
50
|
-
| **HTTP Method** | `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `QUERY`, `SEARCH`, `OPTIONS`, `HEAD`, `WS`, `SSE`, `CONNECT`, `TRACE`, `PURGE` | Fixed-width padded badge with distinct colors (`GET`/`SEARCH` cyan, `POST` green, `PUT`/`PATCH` yellow, `DELETE`/`PURGE` red, `QUERY` blue, `OPTIONS`/`HEAD`/`WS` magenta) |
|
|
51
|
-
| **Path & Query** | `/api/v1/items?page=1` | Path in bright white, query parameters in dimmed gray |
|
|
52
|
-
| **Status Code** | `101 Switching Protocols`, `200 OK`, `201 Created`, `400 Bad Request`, `404 Not Found`, `500 Internal Error` | Color-coded by range: `101` magenta, `2xx` green, `3xx` cyan, `4xx` yellow, `5xx` red |
|
|
53
|
-
| **Response Latency** | `1.2ms`, `18ms`, `1.45s` | Dynamic threshold color coding: `< 50ms` (green), `50ms - 250ms` (yellow), `> 250ms` (red) |
|
|
54
|
-
| **Content Size** | `120 B`, `1.4 KB`, `2.8 MB` | Formatted human-readable byte sizes from `Content-Length` |
|
|
55
|
-
| **Client IP** | `192.168.1.5` | Localhost (`127.0.0.1` / `::1`) is suppressed by default for minimal noise; remote client IPs are cleanly displayed |
|
|
56
|
-
| **Diagnostic Sublines** | `└─ ⚠ Validation: ...` / `└─ ✖ Error: ...` | Indented warning and error summaries printed directly below failed requests |
|
|
57
|
-
|
|
58
37
|
---
|
|
59
38
|
|
|
60
|
-
##
|
|
61
|
-
|
|
62
|
-
In production (`NODE_ENV === 'production'` or `pretty: false`), the logger outputs single-line structured JSON (NDJSON) directly to `stdout` with zero serialization overhead:
|
|
63
|
-
|
|
64
|
-
```json
|
|
65
|
-
{"level":30,"time":1774286390000,"pid":1234,"hostname":"prod-app-01","requestId":"req-42","method":"GET","url":"/api/v1/profile","statusCode":200,"responseTime":1.2,"contentLength":240,"ip":"10.0.0.4","trace_id":"4bf92f3577b34da6a3ce929d0e0e4736","span_id":"00f067aa0ba902b7","msg":"GET /api/v1/profile"}
|
|
66
|
-
```
|
|
39
|
+
## Global Logger Singleton (`logger`)
|
|
67
40
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
## 3. Global Logger Singleton (`logger`)
|
|
71
|
-
|
|
72
|
-
The `logger` singleton is a high-performance proxy that can be imported and used anywhere in your services, repositories, workers, and controllers:
|
|
41
|
+
`logger` is a global proxy satisfying the `Logger` interface. It can be imported and executed anywhere across controllers, services, repositories, or background tasks.
|
|
73
42
|
|
|
74
43
|
```typescript
|
|
75
44
|
import { logger } from 'exisjs/logger'
|
|
76
45
|
|
|
77
|
-
//
|
|
46
|
+
// Level logging methods
|
|
78
47
|
logger.info('Payment service initialized')
|
|
79
48
|
logger.warn({ ip: req.ip, attempts: 3 }, 'Multiple failed login attempts')
|
|
80
49
|
logger.error({ err, orderId: 'ord_123' }, 'Stripe webhook processing failed')
|
|
@@ -82,16 +51,54 @@ logger.debug({ payload }, 'Parsed RPC frame')
|
|
|
82
51
|
logger.trace('Entering database connection pool checkout')
|
|
83
52
|
logger.fatal({ err }, 'Unrecoverable process state')
|
|
84
53
|
|
|
85
|
-
//
|
|
54
|
+
// Contextual child loggers
|
|
86
55
|
const workerLogger = logger.child({ workerId: 'worker-1', queue: 'emails' })
|
|
87
56
|
workerLogger.info('Processing email batch')
|
|
88
57
|
```
|
|
89
58
|
|
|
59
|
+
### `Logger` Interface
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
export interface LogFn {
|
|
63
|
+
(msg: string, ...args: unknown[]): void
|
|
64
|
+
(obj: Record<string, unknown>, msg?: string, ...args: unknown[]): void
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface Logger {
|
|
68
|
+
fatal: LogFn
|
|
69
|
+
error: LogFn
|
|
70
|
+
warn: LogFn
|
|
71
|
+
info: LogFn
|
|
72
|
+
debug: LogFn
|
|
73
|
+
trace: LogFn
|
|
74
|
+
silent: LogFn
|
|
75
|
+
child(bindings: Record<string, unknown>): Logger
|
|
76
|
+
level: string
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
90
80
|
---
|
|
91
81
|
|
|
92
|
-
##
|
|
82
|
+
## Configuration (`configureLogger`)
|
|
83
|
+
|
|
84
|
+
Configures global logger settings, default log levels, terminal pretty printing, and sensitive field redaction.
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
function configureLogger(
|
|
88
|
+
config: LoggerConfig & { replaceRedact?: boolean }
|
|
89
|
+
): void
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Options Reference (`LoggerConfig`)
|
|
93
|
+
|
|
94
|
+
| Property | Type | Default | Description |
|
|
95
|
+
| :--- | :--- | :--- | :--- |
|
|
96
|
+
| `level` | `'fatal' \| 'error' \| 'warn' \| 'info' \| 'debug' \| 'trace' \| 'silent'` | `'info'` | Minimum severity level to emit. |
|
|
97
|
+
| `pretty` | `boolean` | `NODE_ENV !== 'production'` | Whether to use formatted single-line terminal output or raw NDJSON. |
|
|
98
|
+
| `redact` | `string[]` | *See Redaction section* | Array of object property paths to censor. |
|
|
99
|
+
| `replaceRedact` | `boolean` | `false` | When `true`, overrides the default redact list instead of merging with it. |
|
|
93
100
|
|
|
94
|
-
|
|
101
|
+
### Example
|
|
95
102
|
|
|
96
103
|
```typescript filename="src/http/server.ts"
|
|
97
104
|
import { configureLogger } from 'exisjs/logger'
|
|
@@ -99,28 +106,45 @@ import { configureLogger } from 'exisjs/logger'
|
|
|
99
106
|
configureLogger({
|
|
100
107
|
level: process.env.NODE_ENV === 'production' ? 'info' : 'debug',
|
|
101
108
|
pretty: process.env.NODE_ENV !== 'production',
|
|
102
|
-
redact: ['*.password', '*.token', '*.secret', 'req.headers.cookie'
|
|
109
|
+
redact: ['*.password', '*.token', '*.secret', 'req.headers.cookie'],
|
|
103
110
|
})
|
|
104
111
|
```
|
|
105
112
|
|
|
106
|
-
|
|
113
|
+
---
|
|
107
114
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
115
|
+
## Custom Logger Replacement (`setLogger`)
|
|
116
|
+
|
|
117
|
+
Replaces the underlying global logger instance with a custom Pino instance or third-party logger implementing the `Logger` interface.
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
function setLogger(custom: Logger): void
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Example: Custom Transport with `pino-loki`
|
|
124
|
+
|
|
125
|
+
```typescript filename="src/http/server.ts"
|
|
126
|
+
import { setLogger } from 'exisjs/logger'
|
|
127
|
+
import pino from 'pino'
|
|
128
|
+
|
|
129
|
+
const customPino = pino({
|
|
130
|
+
level: 'info',
|
|
131
|
+
transport: {
|
|
132
|
+
target: 'pino-loki',
|
|
133
|
+
options: { host: 'http://localhost:3100' },
|
|
134
|
+
},
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
setLogger(customPino)
|
|
138
|
+
```
|
|
114
139
|
|
|
115
140
|
---
|
|
116
141
|
|
|
117
|
-
##
|
|
142
|
+
## Sensitive Data Redaction
|
|
118
143
|
|
|
119
|
-
By default,
|
|
144
|
+
By default, the logger censors sensitive fields in logged objects, replacing values with `"[Redacted]"` before serialization:
|
|
120
145
|
|
|
121
146
|
```typescript
|
|
122
|
-
|
|
123
|
-
[
|
|
147
|
+
const DEFAULT_REDACT = [
|
|
124
148
|
'req.headers.authorization',
|
|
125
149
|
'req.headers.cookie',
|
|
126
150
|
'req.body.password',
|
|
@@ -131,44 +155,43 @@ By default, ExisJS automatically censors sensitive fields in all log payloads be
|
|
|
131
155
|
'*.secret',
|
|
132
156
|
'password',
|
|
133
157
|
'token',
|
|
134
|
-
'secret'
|
|
158
|
+
'secret',
|
|
135
159
|
]
|
|
136
160
|
```
|
|
137
161
|
|
|
138
|
-
When logging objects containing these keys (e.g. `{ username: 'alex', password: 'supersecretpassword' }`), the value is replaced with `"[Redacted]"`.
|
|
139
|
-
|
|
140
162
|
---
|
|
141
163
|
|
|
142
|
-
##
|
|
164
|
+
## Request-Scoped Logging (`req.log`)
|
|
165
|
+
|
|
166
|
+
Every incoming `ExisRequest` provides a lazy child logger bound to `req.log` containing contextual request metadata:
|
|
143
167
|
|
|
144
|
-
|
|
145
|
-
- `
|
|
146
|
-
- `
|
|
147
|
-
- `url` (`req.path`)
|
|
168
|
+
- `requestId`: Unique request identifier (`req.requestId`).
|
|
169
|
+
- `method`: HTTP method (e.g. `GET`, `POST`).
|
|
170
|
+
- `url`: Request path.
|
|
148
171
|
|
|
149
172
|
```typescript filename="src/http/orders/route.ts"
|
|
150
|
-
import {
|
|
173
|
+
import { controller, route } from 'exisjs/router'
|
|
151
174
|
|
|
152
175
|
export default controller({
|
|
153
176
|
create: route.post('/', {
|
|
154
177
|
async handle({ req, body }) {
|
|
155
|
-
// req.log automatically includes { requestId, method, url }
|
|
156
178
|
req.log.info({ orderId: body.id }, 'Creating order record')
|
|
157
179
|
return { success: true }
|
|
158
|
-
}
|
|
159
|
-
})
|
|
180
|
+
},
|
|
181
|
+
}),
|
|
160
182
|
})
|
|
161
183
|
```
|
|
162
184
|
|
|
163
185
|
---
|
|
164
186
|
|
|
165
|
-
##
|
|
187
|
+
## Distributed Tracing & OpenTelemetry
|
|
166
188
|
|
|
167
|
-
|
|
189
|
+
When `@opentelemetry/api` is present in the application runtime, log entries automatically include active distributed tracing identifiers:
|
|
168
190
|
|
|
169
191
|
```json
|
|
170
192
|
{
|
|
171
193
|
"level": 30,
|
|
194
|
+
"time": 1774286390000,
|
|
172
195
|
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
|
|
173
196
|
"span_id": "00f067aa0ba902b7",
|
|
174
197
|
"msg": "Order created successfully"
|
|
@@ -177,56 +200,17 @@ ExisJS automatically integrates with `@opentelemetry/api` when present in your e
|
|
|
177
200
|
|
|
178
201
|
---
|
|
179
202
|
|
|
180
|
-
##
|
|
203
|
+
## Formatting Utilities
|
|
181
204
|
|
|
182
|
-
|
|
205
|
+
The module exports helper utilities for formatting terminal outputs:
|
|
183
206
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
setLogger(customPino)
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
---
|
|
200
|
-
|
|
201
|
-
## 9. Formatting Helper Utilities
|
|
202
|
-
|
|
203
|
-
ExisJS exports all terminal formatting helpers from `exisjs/logger` so you can use them in custom CLI tools, workers, and plugins:
|
|
204
|
-
|
|
205
|
-
```typescript
|
|
206
|
-
import {
|
|
207
|
-
formatBytes,
|
|
208
|
-
formatLatency,
|
|
209
|
-
formatMethod,
|
|
210
|
-
formatStatus,
|
|
211
|
-
formatUrl,
|
|
212
|
-
formatIp,
|
|
213
|
-
extractValidationSummary,
|
|
214
|
-
extractErrorMessage,
|
|
215
|
-
} from 'exisjs/logger'
|
|
216
|
-
|
|
217
|
-
// Byte formatting
|
|
218
|
-
formatBytes(1420) // "1.4 KB"
|
|
219
|
-
|
|
220
|
-
// Latency with color threshold
|
|
221
|
-
formatLatency(14.5) // "\x1b[32m14.5ms\x1b[0m"
|
|
222
|
-
|
|
223
|
-
// Padded color-coded method
|
|
224
|
-
formatMethod('GET') // "\x1b[1;36mGET \x1b[0m"
|
|
225
|
-
|
|
226
|
-
// Status code with standard phrase
|
|
227
|
-
formatStatus(200) // "\x1b[1;32m200 OK\x1b[0m"
|
|
207
|
+
| Function | Signature | Output Example |
|
|
208
|
+
| :--- | :--- | :--- |
|
|
209
|
+
| `formatBytes` | `(bytes?: number) => string` | `1420` -> `'1.4 KB'` |
|
|
210
|
+
| `formatLatency` | `(ms?: number) => string` | `14.5` -> `'\x1b[32m14.5ms\x1b[0m'` |
|
|
211
|
+
| `formatMethod` | `(method?: string) => string` | `'GET'` -> `'\x1b[1;36mGET \x1b[0m'` |
|
|
212
|
+
| `formatStatus` | `(status: number) => string` | `200` -> `'\x1b[1;32m200 OK\x1b[0m'` |
|
|
213
|
+
| `formatIp` | `(ip?: string) => string` | `'192.168.1.10'` -> formatted IP string |
|
|
214
|
+
| `createSilentLogger` | `() => Logger` | Returns a no-op logger instance |
|
|
215
|
+
| `isLogger` | `(obj: unknown) => obj is Logger` | Type guard checking `Logger` compliance |
|
|
228
216
|
|
|
229
|
-
// Localhost suppression
|
|
230
|
-
formatIp('127.0.0.1') // "" (suppressed)
|
|
231
|
-
formatIp('192.168.1.10') // "\x1b[90m192.168.1.10\x1b[0m"
|
|
232
|
-
```
|