@xenterprises/fastify-xconfig 2.1.4 → 2.2.1
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/LICENSE +100 -0
- package/README.md +140 -141
- package/examples/.env.example +17 -0
- package/examples/basic.js +127 -0
- package/index.d.ts +75 -0
- package/package.json +12 -5
- package/src/integrations/prisma.js +13 -17
- package/src/lifecycle/xFastifyAfter.js +4 -15
- package/src/middleware/bugsnag.js +7 -7
- package/src/middleware/cors.js +14 -15
- package/src/middleware/fancyErrors.js +17 -22
- package/src/middleware/multipart.js +4 -4
- package/src/middleware/rateLimit.js +4 -4
- package/src/middleware/underPressure.js +4 -4
- package/src/utils/formatBytes.js +3 -1
- package/src/utils/health.js +10 -36
- package/src/xConfig.js +21 -39
- package/dist/integrations/cloudinary.d.ts +0 -1
- package/dist/integrations/cloudinary.js +0 -25
- package/dist/integrations/cloudinary.js.map +0 -1
- package/dist/integrations/prisma.d.ts +0 -1
- package/dist/integrations/prisma.js +0 -13
- package/dist/integrations/prisma.js.map +0 -1
- package/dist/integrations/sendgrid.d.ts +0 -1
- package/dist/integrations/sendgrid.js +0 -22
- package/dist/integrations/sendgrid.js.map +0 -1
- package/dist/integrations/stripe.d.ts +0 -1
- package/dist/integrations/stripe.js +0 -15
- package/dist/integrations/stripe.js.map +0 -1
- package/dist/integrations/twilio.d.ts +0 -1
- package/dist/integrations/twilio.js +0 -17
- package/dist/integrations/twilio.js.map +0 -1
- package/dist/middleware/bugsnag.d.ts +0 -2
- package/dist/middleware/bugsnag.js +0 -9
- package/dist/middleware/bugsnag.js.map +0 -1
- package/dist/middleware/cors.d.ts +0 -2
- package/dist/middleware/cors.js +0 -11
- package/dist/middleware/cors.js.map +0 -1
- package/dist/middleware/errorHandler.d.ts +0 -2
- package/dist/middleware/errorHandler.js +0 -19
- package/dist/middleware/errorHandler.js.map +0 -1
- package/dist/middleware/multipart.d.ts +0 -2
- package/dist/middleware/multipart.js +0 -7
- package/dist/middleware/multipart.js.map +0 -1
- package/dist/middleware/rateLimit.d.ts +0 -2
- package/dist/middleware/rateLimit.js +0 -7
- package/dist/middleware/rateLimit.js.map +0 -1
- package/dist/middleware/underPressure.d.ts +0 -2
- package/dist/middleware/underPressure.js +0 -7
- package/dist/middleware/underPressure.js.map +0 -1
- package/dist/utils/colorize.d.ts +0 -4
- package/dist/utils/colorize.js +0 -33
- package/dist/utils/colorize.js.map +0 -1
- package/dist/utils/formatBytes.d.ts +0 -1
- package/dist/utils/formatBytes.js +0 -10
- package/dist/utils/formatBytes.js.map +0 -1
- package/dist/utils/randomUUID.d.ts +0 -1
- package/dist/utils/randomUUID.js +0 -3
- package/dist/utils/randomUUID.js.map +0 -1
- package/dist/utils/statAsync.d.ts +0 -2
- package/dist/utils/statAsync.js +0 -4
- package/dist/utils/statAsync.js.map +0 -1
- package/dist/xConfig.d.ts +0 -3
- package/dist/xConfig.js +0 -9
- package/dist/xConfig.js.map +0 -1
- package/ts-reference/integrations/cloudinary.ts +0 -26
- package/ts-reference/integrations/prisma.ts +0 -13
- package/ts-reference/integrations/sendgrid.ts +0 -27
- package/ts-reference/integrations/stripe.ts +0 -15
- package/ts-reference/integrations/twilio.ts +0 -20
- package/ts-reference/middleware/bugsnag.ts +0 -10
- package/ts-reference/middleware/cors.ts +0 -13
- package/ts-reference/middleware/errorHandler.ts +0 -24
- package/ts-reference/middleware/multipart.ts +0 -8
- package/ts-reference/middleware/rateLimit.ts +0 -8
- package/ts-reference/middleware/underPressure.ts +0 -11
- package/ts-reference/utils/colorize.ts +0 -45
- package/ts-reference/utils/formatBytes.ts +0 -8
- package/ts-reference/utils/randomUUID.ts +0 -3
- package/ts-reference/utils/statAsync.ts +0 -4
- package/tsconfig.json +0 -14
- package/xConfigReference.js +0 -119
package/LICENSE
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
PROPRIETARY SOFTWARE LICENSE
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 X Enterprises LLC. All Rights Reserved.
|
|
4
|
+
|
|
5
|
+
This software and associated documentation files (the "Software") are the
|
|
6
|
+
exclusive property of X Enterprises LLC, a Washington limited liability
|
|
7
|
+
company ("X Enterprises"). The Software is distributed through public
|
|
8
|
+
package registries (including npm) for operational convenience only; such
|
|
9
|
+
distribution does not grant any rights beyond those expressly stated below.
|
|
10
|
+
|
|
11
|
+
TERMS AND CONDITIONS
|
|
12
|
+
|
|
13
|
+
1. OWNERSHIP
|
|
14
|
+
All rights, title, and interest in and to the Software, including all
|
|
15
|
+
intellectual property rights, are and shall remain the exclusive property
|
|
16
|
+
of X Enterprises. No rights are granted except as expressly set forth in
|
|
17
|
+
this License.
|
|
18
|
+
|
|
19
|
+
2. PERMITTED USE
|
|
20
|
+
Subject to the restrictions in Section 3, you are permitted to download,
|
|
21
|
+
install, and execute the Software solely as a dependency of:
|
|
22
|
+
|
|
23
|
+
(a) software developed, owned, or operated by X Enterprises;
|
|
24
|
+
|
|
25
|
+
(b) software that X Enterprises has developed, delivered, or licensed to
|
|
26
|
+
a third party ("Client") under a written engagement agreement with
|
|
27
|
+
X Enterprises, when such use is performed by or on behalf of that
|
|
28
|
+
Client; or
|
|
29
|
+
|
|
30
|
+
(c) end-user access to, or consumption of, a product or service described
|
|
31
|
+
in (a) or (b), provided that such access does not involve
|
|
32
|
+
redistribution, modification, or separate use of the Software.
|
|
33
|
+
|
|
34
|
+
Permitted Use includes automated installation and execution by continuous
|
|
35
|
+
integration systems, container builds, hosting platforms, and similar
|
|
36
|
+
infrastructure, to the extent necessary to support (a), (b), or (c).
|
|
37
|
+
|
|
38
|
+
3. RESTRICTIONS
|
|
39
|
+
Except as expressly permitted in Section 2, and without the prior written
|
|
40
|
+
consent of X Enterprises, you may not:
|
|
41
|
+
|
|
42
|
+
(a) copy, modify, adapt, translate, or create derivative works of the
|
|
43
|
+
Software for any purpose outside the scope of Section 2;
|
|
44
|
+
|
|
45
|
+
(b) redistribute, republish, sublicense, sell, lease, rent, or otherwise
|
|
46
|
+
transfer the Software, in whole or in part, whether standalone or
|
|
47
|
+
bundled with other software;
|
|
48
|
+
|
|
49
|
+
(c) reverse engineer, decompile, disassemble, or attempt to derive the
|
|
50
|
+
source code or underlying ideas, algorithms, structure, or
|
|
51
|
+
organization of the Software, except to the extent such activity is
|
|
52
|
+
expressly permitted by applicable law notwithstanding this
|
|
53
|
+
restriction;
|
|
54
|
+
|
|
55
|
+
(d) use the Software, in whole or in part, to develop, operate, or
|
|
56
|
+
provide any product or service that competes with or substitutes for
|
|
57
|
+
any X Enterprises product or service;
|
|
58
|
+
|
|
59
|
+
(e) remove, obscure, or alter any copyright, trademark, license, or other
|
|
60
|
+
proprietary notice contained in or on the Software; or
|
|
61
|
+
|
|
62
|
+
(f) use the Software in violation of any applicable law or regulation.
|
|
63
|
+
|
|
64
|
+
4. NO WARRANTY
|
|
65
|
+
THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
66
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
67
|
+
FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
68
|
+
X ENTERPRISES BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY,
|
|
69
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT
|
|
70
|
+
OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
71
|
+
THE SOFTWARE.
|
|
72
|
+
|
|
73
|
+
5. LIMITATION OF LIABILITY
|
|
74
|
+
IN NO EVENT SHALL X ENTERPRISES BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
|
|
75
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
|
76
|
+
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
77
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
78
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
79
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
80
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
81
|
+
|
|
82
|
+
6. GOVERNING LAW
|
|
83
|
+
This License shall be governed by and construed in accordance with the
|
|
84
|
+
laws of the State of Washington, United States, without regard to its
|
|
85
|
+
conflict of law provisions. Exclusive jurisdiction for any dispute
|
|
86
|
+
arising out of this License shall lie in the state or federal courts
|
|
87
|
+
located in King County, Washington.
|
|
88
|
+
|
|
89
|
+
7. TERMINATION
|
|
90
|
+
This License is effective until terminated. Your rights under this
|
|
91
|
+
License will terminate automatically and without notice if you fail to
|
|
92
|
+
comply with any term herein. Upon termination, you must cease all use of
|
|
93
|
+
the Software and destroy all copies in your possession or control.
|
|
94
|
+
Sections 1, 3, 4, 5, 6, and 7 survive termination.
|
|
95
|
+
|
|
96
|
+
For licensing inquiries, contact: legal@x.enterprises
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
X Enterprises LLC
|
|
100
|
+
Bothell, Washington, United States
|
package/README.md
CHANGED
|
@@ -1,18 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @xenterprises/fastify-xconfig
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Fastify plugin for centralized middleware orchestration, health checks, and utility decorators.
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
xConfig is a lightweight configuration and middleware orchestration plugin for Fastify. It handles:
|
|
8
|
-
|
|
9
|
-
- **Middleware Setup**: CORS, rate limiting, multipart handling, error handling
|
|
10
|
-
- **Health Checks**: Disk space monitoring and application uptime tracking
|
|
11
|
-
- **Error Tracking**: Bugsnag integration for production error monitoring
|
|
12
|
-
- **Prisma Integration**: Database connectivity through @prisma/client
|
|
13
|
-
- **Back Pressure Handling**: Automatic shutdown management for overloaded servers
|
|
14
|
-
|
|
15
|
-
## Installation
|
|
5
|
+
## Install
|
|
16
6
|
|
|
17
7
|
```bash
|
|
18
8
|
npm install @xenterprises/fastify-xconfig
|
|
@@ -20,155 +10,164 @@ npm install @xenterprises/fastify-xconfig
|
|
|
20
10
|
|
|
21
11
|
## Usage
|
|
22
12
|
|
|
23
|
-
### Basic Configuration
|
|
24
|
-
|
|
25
13
|
```javascript
|
|
26
14
|
import Fastify from 'fastify';
|
|
27
15
|
import xConfig from '@xenterprises/fastify-xconfig';
|
|
28
16
|
|
|
29
|
-
const fastify = Fastify();
|
|
17
|
+
const fastify = Fastify({ logger: true });
|
|
30
18
|
|
|
31
19
|
await fastify.register(xConfig, {
|
|
32
|
-
prisma: {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
},
|
|
38
|
-
rateLimit: {
|
|
39
|
-
max: 100,
|
|
40
|
-
timeWindow: '1 minute'
|
|
41
|
-
},
|
|
42
|
-
bugsnag: {
|
|
43
|
-
apiKey: process.env.BUGSNAG_API_KEY // Optional
|
|
44
|
-
}
|
|
20
|
+
prisma: { active: false },
|
|
21
|
+
bugsnag: { active: false },
|
|
22
|
+
cors: { origin: ['http://localhost:3000'], credentials: true },
|
|
23
|
+
rateLimit: { max: 100, timeWindow: '1 minute' },
|
|
24
|
+
multipart: { limits: { fileSize: 52428800 } },
|
|
25
|
+
underPressure: { maxEventLoopDelay: 1000 },
|
|
45
26
|
});
|
|
46
27
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
### Core Options
|
|
53
|
-
|
|
54
|
-
| Option | Type | Required | Description |
|
|
55
|
-
|--------|------|----------|-------------|
|
|
56
|
-
| `prisma` | Object | No | Prisma client configuration. If empty, plugin uses default connection pool. |
|
|
57
|
-
| `professional` | Boolean | No | Enable professional mode features (default: false) |
|
|
58
|
-
| `fancyErrors` | Boolean | No | Enable formatted error responses (default: true) |
|
|
28
|
+
// Utility decorators are now available:
|
|
29
|
+
fastify.xSlugify('Hello World'); // "hello-world"
|
|
30
|
+
fastify.xRandomUUID(); // "a1b2c3d4-..."
|
|
31
|
+
fastify.xFormatBytes(1048576); // "1 MB"
|
|
32
|
+
fastify.xEcho(); // "Hello from X Enterprises!"
|
|
59
33
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
| Option | Type | Required | Description |
|
|
63
|
-
|--------|------|----------|-------------|
|
|
64
|
-
| `cors` | Object | No | CORS configuration with `active`, `origin`, and `credentials` |
|
|
65
|
-
| `rateLimit` | Object | No | Rate limiting with `max` requests and `timeWindow` |
|
|
66
|
-
| `multipart` | Object | No | Multipart form handling configuration |
|
|
67
|
-
| `underPressure` | Object | No | Back pressure monitoring configuration |
|
|
68
|
-
|
|
69
|
-
### Observability Options
|
|
70
|
-
|
|
71
|
-
| Option | Type | Required | Description |
|
|
72
|
-
|--------|------|----------|-------------|
|
|
73
|
-
| `bugsnag` | Object | No | Bugsnag error tracking with `apiKey` |
|
|
74
|
-
|
|
75
|
-
## Available Decorators
|
|
76
|
-
|
|
77
|
-
After registration, the following are available on the fastify instance:
|
|
78
|
-
|
|
79
|
-
```javascript
|
|
80
|
-
// Health check function
|
|
81
|
-
fastify.health.check() // Returns { status, diskSpace, uptime }
|
|
82
|
-
|
|
83
|
-
// Prisma client (if configured)
|
|
84
|
-
fastify.prisma
|
|
34
|
+
await fastify.listen({ port: 3000 });
|
|
85
35
|
```
|
|
86
36
|
|
|
87
|
-
##
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
37
|
+
## Options
|
|
38
|
+
|
|
39
|
+
| Name | Type | Default | Required | Description |
|
|
40
|
+
|------|------|---------|----------|-------------|
|
|
41
|
+
| `professional` | `boolean` | `false` | No | Disable route listing on startup |
|
|
42
|
+
| `fancyErrors` | `boolean` | `true` | No | Enable formatted error responses with status codes |
|
|
43
|
+
| `prisma` | `object` | `{}` | No | Prisma client configuration (see below) |
|
|
44
|
+
| `bugsnag` | `object` | `{}` | No | Bugsnag error tracking configuration (see below) |
|
|
45
|
+
| `cors` | `object` | `{}` | No | CORS configuration passed to @fastify/cors |
|
|
46
|
+
| `rateLimit` | `object` | `{}` | No | Rate limiting configuration passed to @fastify/rate-limit |
|
|
47
|
+
| `multipart` | `object` | `{}` | No | Multipart configuration passed to @fastify/multipart |
|
|
48
|
+
| `underPressure` | `object` | `{}` | No | Back-pressure configuration passed to @fastify/under-pressure |
|
|
49
|
+
|
|
50
|
+
### `prisma` Options
|
|
51
|
+
|
|
52
|
+
| Name | Type | Default | Required | Description |
|
|
53
|
+
|------|------|---------|----------|-------------|
|
|
54
|
+
| `active` | `boolean` | `true` | No | Enable/disable Prisma integration |
|
|
55
|
+
| `client` | `PrismaClient` | — | Yes (if active) | Your generated PrismaClient class |
|
|
56
|
+
| `...rest` | `object` | — | No | Passed directly to `new PrismaClient(...)` |
|
|
57
|
+
|
|
58
|
+
### `bugsnag` Options
|
|
59
|
+
|
|
60
|
+
| Name | Type | Default | Required | Description |
|
|
61
|
+
|------|------|---------|----------|-------------|
|
|
62
|
+
| `active` | `boolean` | `true` | No | Enable/disable Bugsnag integration |
|
|
63
|
+
| `apiKey` | `string` | — | Yes (if active) | Bugsnag project API key |
|
|
64
|
+
|
|
65
|
+
### `cors` Options
|
|
66
|
+
|
|
67
|
+
| Name | Type | Default | Required | Description |
|
|
68
|
+
|------|------|---------|----------|-------------|
|
|
69
|
+
| `active` | `boolean` | `true` | No | Enable/disable CORS |
|
|
70
|
+
| `origin` | `string\|array` | env-based | No | Allowed origins (production reads `CORS_ORIGIN` env var) |
|
|
71
|
+
| `credentials` | `boolean` | `true` | No | Allow credentials |
|
|
72
|
+
| `methods` | `array` | `["GET","POST","PUT","DELETE","OPTIONS"]` | No | Allowed HTTP methods |
|
|
73
|
+
| `...rest` | `object` | — | No | Passed directly to @fastify/cors |
|
|
74
|
+
|
|
75
|
+
### Middleware `active` Flag
|
|
76
|
+
|
|
77
|
+
All middleware options (`cors`, `rateLimit`, `multipart`, `underPressure`, `bugsnag`, `prisma`) accept `active: false` to disable the middleware entirely. When omitted, the middleware is enabled by default.
|
|
78
|
+
|
|
79
|
+
## Decorated Properties
|
|
80
|
+
|
|
81
|
+
| Name | Type | Description |
|
|
82
|
+
|------|------|-------------|
|
|
83
|
+
| `fastify.prisma` | `PrismaClient` | Prisma client instance (only if prisma is active) |
|
|
84
|
+
| `fastify.xEcho()` | `function` | Returns `"Hello from X Enterprises!"` |
|
|
85
|
+
| `fastify.xSlugify(str)` | `function` | Converts string to URL-safe slug |
|
|
86
|
+
| `fastify.xRandomUUID()` | `function` | Generates a UUID v4 string |
|
|
87
|
+
| `fastify.xGenerateUUID()` | `function` | Alias for `xRandomUUID` |
|
|
88
|
+
| `fastify.xFormatBytes(bytes, decimals?)` | `function` | Formats bytes to human-readable string |
|
|
89
|
+
|
|
90
|
+
## Routes
|
|
91
|
+
|
|
92
|
+
| Method | Path | Description |
|
|
93
|
+
|--------|------|-------------|
|
|
94
|
+
| `GET` | `/health` | Health check endpoint with system metrics |
|
|
95
|
+
|
|
96
|
+
### Health Check Response
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"status": "healthy",
|
|
101
|
+
"timestamp": "2025-01-15T12:00:00.000Z",
|
|
102
|
+
"uptime": 3600,
|
|
103
|
+
"environment": "production",
|
|
104
|
+
"dependencies": {
|
|
105
|
+
"database": "up",
|
|
106
|
+
"redis": "not configured"
|
|
107
|
+
},
|
|
108
|
+
"resources": {
|
|
109
|
+
"memory": { "rss": "50 MB", "heapTotal": "30 MB", "heapUsed": "25 MB" },
|
|
110
|
+
"cpu": { "loadAverage": [1.2, 0.8, 0.5], "cpus": 4 },
|
|
111
|
+
"disk": { "free": "100 GB", "size": "500 GB" }
|
|
112
|
+
},
|
|
113
|
+
"details": {}
|
|
114
|
+
}
|
|
107
115
|
```
|
|
108
116
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
The following services have been extracted to separate, dedicated plugins:
|
|
112
|
-
|
|
113
|
-
| Service | Plugin | Package |
|
|
114
|
-
|---------|--------|---------|
|
|
115
|
-
| Authentication/JWKS | xAuthJWSK | @xenterprises/fastify-xauth-jwks |
|
|
116
|
-
| Geocoding | xGeocode | @xenterprises/fastify-xgeocode |
|
|
117
|
-
| SMS/Email | xTwilio | @xenterprises/fastify-xtwilio (separate module) |
|
|
118
|
-
| File Storage | xStorage | @xenterprises/fastify-xstorage (separate module) |
|
|
119
|
-
| Payment Processing | xStripe | @xenterprises/fastify-xstripe (separate module) |
|
|
120
|
-
|
|
121
|
-
## Development
|
|
122
|
-
|
|
123
|
-
### Running Tests
|
|
117
|
+
Returns `200` when healthy, `503` when degraded.
|
|
124
118
|
|
|
125
|
-
|
|
126
|
-
npm test
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
### Starting Development Server
|
|
119
|
+
## Environment Variables
|
|
130
120
|
|
|
131
|
-
|
|
132
|
-
|
|
121
|
+
| Name | Required | Description |
|
|
122
|
+
|------|----------|-------------|
|
|
123
|
+
| `NODE_ENV` | No | `development` or `production` (affects error stack traces, CORS defaults) |
|
|
124
|
+
| `PORT` | No | Server port (default: `3000`) |
|
|
125
|
+
| `FASTIFY_ADDRESS` | No | Server bind address (default: `0.0.0.0`) |
|
|
126
|
+
| `CORS_ORIGIN` | No | Comma-separated CORS origins for production |
|
|
127
|
+
| `RATE_LIMIT_MAX` | No | Max requests per window (default: `100`) |
|
|
128
|
+
| `RATE_LIMIT_TIME_WINDOW` | No | Rate limit window (default: `1 minute`) |
|
|
129
|
+
| `BUGSNAG_API_KEY` | If bugsnag active | Bugsnag project API key |
|
|
130
|
+
| `DATABASE_URL` | If prisma active | Database connection string |
|
|
131
|
+
|
|
132
|
+
## Error Reference
|
|
133
|
+
|
|
134
|
+
| Error | When |
|
|
135
|
+
|-------|------|
|
|
136
|
+
| `[xConfig] professional must be a boolean` | `professional` option is not a boolean |
|
|
137
|
+
| `[xConfig] fancyErrors must be a boolean` | `fancyErrors` option is not a boolean |
|
|
138
|
+
| `[xConfig] prisma.client is required - pass your PrismaClient class from your generated client` | Prisma is active but `client` not provided |
|
|
139
|
+
| `[xConfig] prisma.client must be a PrismaClient constructor` | `prisma.client` is not a function/class |
|
|
140
|
+
| `[xConfig] bugsnag.apiKey is required and must be a string` | Bugsnag is active but `apiKey` missing or not a string |
|
|
141
|
+
|
|
142
|
+
## Fancy Error Response Format
|
|
143
|
+
|
|
144
|
+
When `fancyErrors: true` (default), unhandled errors return:
|
|
145
|
+
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"status": 500,
|
|
149
|
+
"message": "Error description",
|
|
150
|
+
"stack": "..."
|
|
151
|
+
}
|
|
133
152
|
```
|
|
134
153
|
|
|
135
|
-
The
|
|
154
|
+
The `stack` field is only included when `NODE_ENV !== "production"`.
|
|
136
155
|
|
|
137
|
-
|
|
156
|
+
## How It Works
|
|
138
157
|
|
|
139
|
-
|
|
140
|
-
npm start
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
## Architecture
|
|
144
|
-
|
|
145
|
-
```
|
|
146
|
-
fastify app
|
|
147
|
-
↓
|
|
148
|
-
└─→ xConfig (core middleware & config)
|
|
149
|
-
├─→ @fastify/cors
|
|
150
|
-
├─→ @fastify/rate-limit
|
|
151
|
-
├─→ @fastify/multipart
|
|
152
|
-
├─→ @fastify/under-pressure
|
|
153
|
-
├─→ @fastify/sensible
|
|
154
|
-
├─→ fastify-bugsnag (optional)
|
|
155
|
-
└─→ Prisma client
|
|
156
|
-
```
|
|
158
|
+
xConfig is a single Fastify plugin that orchestrates registration of multiple sub-plugins in a specific order:
|
|
157
159
|
|
|
158
|
-
|
|
160
|
+
1. **Prisma** — decorates `fastify.prisma` with a connected PrismaClient and registers an `onClose` hook to disconnect on shutdown.
|
|
161
|
+
2. **Middleware** — registers CORS, under-pressure monitoring, rate limiting, and multipart handling (each skippable via `active: false`).
|
|
162
|
+
3. **Bugsnag** — optional error tracking that integrates with the fancy error handler.
|
|
163
|
+
4. **Fancy Errors** — sets a custom `errorHandler` that normalizes error responses and optionally reports to Bugsnag.
|
|
164
|
+
5. **@fastify/sensible** — adds `.httpErrors`, `.to()`, and other HTTP utilities.
|
|
165
|
+
6. **Utilities** — registers `xEcho`, `xSlugify`, `xRandomUUID`, and `xFormatBytes` decorators.
|
|
166
|
+
7. **Health Check** — registers `GET /health` with dependency checks (database, redis), resource monitoring (memory, CPU, disk), and environment validation.
|
|
167
|
+
8. **Lifecycle** — sets up route listing on startup (unless `professional: true`) and a goodbye log on shutdown.
|
|
159
168
|
|
|
160
|
-
|
|
161
|
-
- `@fastify/cors` - CORS middleware
|
|
162
|
-
- `@fastify/rate-limit` - Rate limiting
|
|
163
|
-
- `@fastify/multipart` - Multipart form handling
|
|
164
|
-
- `@fastify/sensible` - HTTP utilities
|
|
165
|
-
- `@fastify/under-pressure` - Back pressure handling
|
|
166
|
-
- `@prisma/client` - ORM for database access
|
|
167
|
-
- `fastify-bugsnag` - Error tracking (optional)
|
|
168
|
-
- `fastify-plugin` - Plugin wrapper
|
|
169
|
-
- `uncrypto` - Crypto utilities
|
|
170
|
-
- `check-disk-space` - Disk space monitoring
|
|
169
|
+
The plugin is wrapped with `fastify-plugin` so all decorators and routes are available in the parent scope.
|
|
171
170
|
|
|
172
171
|
## License
|
|
173
172
|
|
|
174
|
-
|
|
173
|
+
UNLICENSED
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Server
|
|
2
|
+
PORT=3000
|
|
3
|
+
FASTIFY_ADDRESS=0.0.0.0
|
|
4
|
+
NODE_ENV=development
|
|
5
|
+
|
|
6
|
+
# CORS
|
|
7
|
+
CORS_ORIGIN=http://localhost:3000,http://localhost:3001
|
|
8
|
+
|
|
9
|
+
# Rate Limiting
|
|
10
|
+
RATE_LIMIT_MAX=100
|
|
11
|
+
RATE_LIMIT_TIME_WINDOW=1 minute
|
|
12
|
+
|
|
13
|
+
# Bugsnag (optional)
|
|
14
|
+
# BUGSNAG_API_KEY=your-bugsnag-api-key
|
|
15
|
+
|
|
16
|
+
# Database (required only if prisma.active is true)
|
|
17
|
+
# DATABASE_URL=postgresql://user:password@localhost:5432/mydb
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fastify-x-config — Basic Example
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates all features of the xConfig plugin:
|
|
5
|
+
* - CORS, rate limiting, multipart, under-pressure middleware
|
|
6
|
+
* - Fancy error handling
|
|
7
|
+
* - Health check endpoint
|
|
8
|
+
* - Utility decorators: xEcho, xSlugify, xRandomUUID, xFormatBytes
|
|
9
|
+
*
|
|
10
|
+
* Run: node examples/basic.js
|
|
11
|
+
* Requires: .env or environment variables (see .env.example)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import Fastify from "fastify";
|
|
15
|
+
import xConfig from "../src/xConfig.js";
|
|
16
|
+
|
|
17
|
+
const fastify = Fastify({
|
|
18
|
+
logger: true,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// ─── Register xConfig with all options ───────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
await fastify.register(xConfig, {
|
|
24
|
+
// Disable route listing in production
|
|
25
|
+
professional: process.env.NODE_ENV === "production",
|
|
26
|
+
|
|
27
|
+
// Enable fancy error formatting (default: true)
|
|
28
|
+
fancyErrors: true,
|
|
29
|
+
|
|
30
|
+
// Prisma — disabled for this demo; pass { client: PrismaClient } to enable
|
|
31
|
+
prisma: { active: false },
|
|
32
|
+
|
|
33
|
+
// Bugsnag — disabled for this demo; pass { apiKey: "..." } to enable
|
|
34
|
+
bugsnag: { active: false },
|
|
35
|
+
|
|
36
|
+
// CORS configuration
|
|
37
|
+
cors: {
|
|
38
|
+
origin: process.env.CORS_ORIGIN
|
|
39
|
+
? process.env.CORS_ORIGIN.split(",")
|
|
40
|
+
: ["http://localhost:3000"],
|
|
41
|
+
credentials: true,
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
// Rate limiting
|
|
45
|
+
rateLimit: {
|
|
46
|
+
max: parseInt(process.env.RATE_LIMIT_MAX || "100", 10),
|
|
47
|
+
timeWindow: process.env.RATE_LIMIT_TIME_WINDOW || "1 minute",
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
// Multipart file uploads
|
|
51
|
+
multipart: {
|
|
52
|
+
limits: {
|
|
53
|
+
fileSize: 52428800, // 50 MB
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
// Back-pressure monitoring
|
|
58
|
+
underPressure: {
|
|
59
|
+
maxEventLoopDelay: 1000,
|
|
60
|
+
maxHeapUsedBytes: 1_000_000_000,
|
|
61
|
+
maxRssBytes: 1_000_000_000,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// ─── 1. Health check (auto-registered by xConfig at /health) ─────────────────
|
|
66
|
+
|
|
67
|
+
// Try: curl http://localhost:3000/health
|
|
68
|
+
|
|
69
|
+
// ─── 2. xEcho — simple ping utility ─────────────────────────────────────────
|
|
70
|
+
|
|
71
|
+
fastify.get("/echo", async () => {
|
|
72
|
+
return { message: fastify.xEcho() };
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// ─── 3. xSlugify — URL-safe slugification ───────────────────────────────────
|
|
76
|
+
|
|
77
|
+
fastify.get("/slug/:text", async (request) => {
|
|
78
|
+
const { text } = request.params;
|
|
79
|
+
return {
|
|
80
|
+
original: text,
|
|
81
|
+
slug: fastify.xSlugify(text),
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// ─── 4. xRandomUUID — UUID generation ───────────────────────────────────────
|
|
86
|
+
|
|
87
|
+
fastify.get("/uuid", async () => {
|
|
88
|
+
return {
|
|
89
|
+
uuid: fastify.xRandomUUID(),
|
|
90
|
+
// xGenerateUUID is also available as an alias
|
|
91
|
+
uuid2: fastify.xGenerateUUID(),
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// ─── 5. xFormatBytes — human-readable byte formatting ───────────────────────
|
|
96
|
+
|
|
97
|
+
fastify.get("/format-bytes/:bytes", async (request) => {
|
|
98
|
+
const bytes = parseInt(request.params.bytes, 10);
|
|
99
|
+
return {
|
|
100
|
+
bytes,
|
|
101
|
+
formatted: fastify.xFormatBytes(bytes),
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// ─── 6. Fancy error handling demo ────────────────────────────────────────────
|
|
106
|
+
|
|
107
|
+
fastify.get("/error", async () => {
|
|
108
|
+
throw new Error("This demonstrates fancy error formatting");
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
fastify.get("/error/:code", async (request) => {
|
|
112
|
+
const err = new Error(`Custom ${request.params.code} error`);
|
|
113
|
+
err.statusCode = parseInt(request.params.code, 10);
|
|
114
|
+
throw err;
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// ─── Start server ────────────────────────────────────────────────────────────
|
|
118
|
+
|
|
119
|
+
const port = parseInt(process.env.PORT || "3000", 10);
|
|
120
|
+
const address = process.env.FASTIFY_ADDRESS || "0.0.0.0";
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
await fastify.listen({ port, host: address });
|
|
124
|
+
} catch (err) {
|
|
125
|
+
fastify.log.error(err);
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { FastifyPluginAsync } from 'fastify';
|
|
2
|
+
|
|
3
|
+
declare module 'fastify' {
|
|
4
|
+
interface FastifyInstance {
|
|
5
|
+
/** Prisma client instance (only available if prisma option is active) */
|
|
6
|
+
prisma?: any;
|
|
7
|
+
/** Returns "Hello from X Enterprises!" */
|
|
8
|
+
xEcho(): string;
|
|
9
|
+
/** Converts a string to a URL-safe slug */
|
|
10
|
+
xSlugify(input: string | number): string;
|
|
11
|
+
/** Generates a UUID v4 string */
|
|
12
|
+
xRandomUUID(): string;
|
|
13
|
+
/** Generates a UUID v4 string (alias for xRandomUUID) */
|
|
14
|
+
xGenerateUUID(): string;
|
|
15
|
+
/** Formats bytes into a human-readable string (e.g. "1.5 MB") */
|
|
16
|
+
xFormatBytes(bytes: number, decimals?: number): string;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface XConfigCorsOptions {
|
|
21
|
+
active?: boolean;
|
|
22
|
+
origin?: string | string[] | boolean;
|
|
23
|
+
credentials?: boolean;
|
|
24
|
+
methods?: string[];
|
|
25
|
+
[key: string]: any;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface XConfigRateLimitOptions {
|
|
29
|
+
active?: boolean;
|
|
30
|
+
max?: number;
|
|
31
|
+
timeWindow?: string | number;
|
|
32
|
+
[key: string]: any;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface XConfigMultipartOptions {
|
|
36
|
+
active?: boolean;
|
|
37
|
+
limits?: {
|
|
38
|
+
fileSize?: number;
|
|
39
|
+
[key: string]: any;
|
|
40
|
+
};
|
|
41
|
+
[key: string]: any;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface XConfigUnderPressureOptions {
|
|
45
|
+
active?: boolean;
|
|
46
|
+
maxEventLoopDelay?: number;
|
|
47
|
+
maxHeapUsedBytes?: number;
|
|
48
|
+
maxRssBytes?: number;
|
|
49
|
+
[key: string]: any;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface XConfigPrismaOptions {
|
|
53
|
+
active?: boolean;
|
|
54
|
+
client?: any;
|
|
55
|
+
[key: string]: any;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface XConfigBugsnagOptions {
|
|
59
|
+
active?: boolean;
|
|
60
|
+
apiKey?: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface XConfigOptions {
|
|
64
|
+
professional?: boolean;
|
|
65
|
+
fancyErrors?: boolean;
|
|
66
|
+
prisma?: XConfigPrismaOptions;
|
|
67
|
+
bugsnag?: XConfigBugsnagOptions;
|
|
68
|
+
cors?: XConfigCorsOptions;
|
|
69
|
+
rateLimit?: XConfigRateLimitOptions;
|
|
70
|
+
multipart?: XConfigMultipartOptions;
|
|
71
|
+
underPressure?: XConfigUnderPressureOptions;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
declare const xConfig: FastifyPluginAsync<XConfigOptions>;
|
|
75
|
+
export default xConfig;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xenterprises/fastify-xconfig",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.1
|
|
4
|
+
"version": "2.2.1",
|
|
5
5
|
"description": "Fastify configuration plugin for setting up middleware, services, and route handling.",
|
|
6
6
|
"main": "src/xConfig.js",
|
|
7
7
|
"scripts": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"test": "node --test test/xConfig.test.js"
|
|
11
11
|
},
|
|
12
12
|
"author": "Tim Mushen",
|
|
13
|
-
"license": "
|
|
13
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
14
14
|
"repository": {
|
|
15
15
|
"type": "git",
|
|
16
16
|
"url": "https://gitlab.com/x-enterprises/fastify-plugins/fastify-x-config"
|
|
@@ -33,14 +33,21 @@
|
|
|
33
33
|
"@fastify/rate-limit": "^10.0.0",
|
|
34
34
|
"@fastify/sensible": "^6.0.0",
|
|
35
35
|
"@fastify/under-pressure": "^9.0.0",
|
|
36
|
-
"@prisma/client": "^7.3.0",
|
|
37
36
|
"check-disk-space": "^3.4.0",
|
|
38
|
-
"fastify": "^5.1.0",
|
|
39
37
|
"fastify-bugsnag": "^5.0.0",
|
|
40
38
|
"fastify-plugin": "^5.0.0",
|
|
41
39
|
"uncrypto": "^0.1.3"
|
|
42
40
|
},
|
|
43
41
|
"peerDependencies": {
|
|
44
|
-
"fastify": "
|
|
42
|
+
"fastify": ">=5.0.0",
|
|
43
|
+
"@prisma/client": ">=5.0.0"
|
|
44
|
+
},
|
|
45
|
+
"peerDependenciesMeta": {
|
|
46
|
+
"@prisma/client": {
|
|
47
|
+
"optional": true
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public"
|
|
45
52
|
}
|
|
46
53
|
}
|