@xenterprises/fastify-xconfig 2.1.4 → 2.2.0

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 (82) hide show
  1. package/LICENSE +60 -0
  2. package/README.md +140 -141
  3. package/examples/.env.example +17 -0
  4. package/examples/basic.js +127 -0
  5. package/index.d.ts +75 -0
  6. package/package.json +9 -5
  7. package/src/integrations/prisma.js +13 -17
  8. package/src/lifecycle/xFastifyAfter.js +4 -15
  9. package/src/middleware/bugsnag.js +7 -7
  10. package/src/middleware/cors.js +14 -15
  11. package/src/middleware/fancyErrors.js +17 -22
  12. package/src/middleware/multipart.js +4 -4
  13. package/src/middleware/rateLimit.js +4 -4
  14. package/src/middleware/underPressure.js +4 -4
  15. package/src/utils/formatBytes.js +3 -1
  16. package/src/utils/health.js +10 -36
  17. package/src/xConfig.js +21 -39
  18. package/dist/integrations/cloudinary.d.ts +0 -1
  19. package/dist/integrations/cloudinary.js +0 -25
  20. package/dist/integrations/cloudinary.js.map +0 -1
  21. package/dist/integrations/prisma.d.ts +0 -1
  22. package/dist/integrations/prisma.js +0 -13
  23. package/dist/integrations/prisma.js.map +0 -1
  24. package/dist/integrations/sendgrid.d.ts +0 -1
  25. package/dist/integrations/sendgrid.js +0 -22
  26. package/dist/integrations/sendgrid.js.map +0 -1
  27. package/dist/integrations/stripe.d.ts +0 -1
  28. package/dist/integrations/stripe.js +0 -15
  29. package/dist/integrations/stripe.js.map +0 -1
  30. package/dist/integrations/twilio.d.ts +0 -1
  31. package/dist/integrations/twilio.js +0 -17
  32. package/dist/integrations/twilio.js.map +0 -1
  33. package/dist/middleware/bugsnag.d.ts +0 -2
  34. package/dist/middleware/bugsnag.js +0 -9
  35. package/dist/middleware/bugsnag.js.map +0 -1
  36. package/dist/middleware/cors.d.ts +0 -2
  37. package/dist/middleware/cors.js +0 -11
  38. package/dist/middleware/cors.js.map +0 -1
  39. package/dist/middleware/errorHandler.d.ts +0 -2
  40. package/dist/middleware/errorHandler.js +0 -19
  41. package/dist/middleware/errorHandler.js.map +0 -1
  42. package/dist/middleware/multipart.d.ts +0 -2
  43. package/dist/middleware/multipart.js +0 -7
  44. package/dist/middleware/multipart.js.map +0 -1
  45. package/dist/middleware/rateLimit.d.ts +0 -2
  46. package/dist/middleware/rateLimit.js +0 -7
  47. package/dist/middleware/rateLimit.js.map +0 -1
  48. package/dist/middleware/underPressure.d.ts +0 -2
  49. package/dist/middleware/underPressure.js +0 -7
  50. package/dist/middleware/underPressure.js.map +0 -1
  51. package/dist/utils/colorize.d.ts +0 -4
  52. package/dist/utils/colorize.js +0 -33
  53. package/dist/utils/colorize.js.map +0 -1
  54. package/dist/utils/formatBytes.d.ts +0 -1
  55. package/dist/utils/formatBytes.js +0 -10
  56. package/dist/utils/formatBytes.js.map +0 -1
  57. package/dist/utils/randomUUID.d.ts +0 -1
  58. package/dist/utils/randomUUID.js +0 -3
  59. package/dist/utils/randomUUID.js.map +0 -1
  60. package/dist/utils/statAsync.d.ts +0 -2
  61. package/dist/utils/statAsync.js +0 -4
  62. package/dist/utils/statAsync.js.map +0 -1
  63. package/dist/xConfig.d.ts +0 -3
  64. package/dist/xConfig.js +0 -9
  65. package/dist/xConfig.js.map +0 -1
  66. package/ts-reference/integrations/cloudinary.ts +0 -26
  67. package/ts-reference/integrations/prisma.ts +0 -13
  68. package/ts-reference/integrations/sendgrid.ts +0 -27
  69. package/ts-reference/integrations/stripe.ts +0 -15
  70. package/ts-reference/integrations/twilio.ts +0 -20
  71. package/ts-reference/middleware/bugsnag.ts +0 -10
  72. package/ts-reference/middleware/cors.ts +0 -13
  73. package/ts-reference/middleware/errorHandler.ts +0 -24
  74. package/ts-reference/middleware/multipart.ts +0 -8
  75. package/ts-reference/middleware/rateLimit.ts +0 -8
  76. package/ts-reference/middleware/underPressure.ts +0 -11
  77. package/ts-reference/utils/colorize.ts +0 -45
  78. package/ts-reference/utils/formatBytes.ts +0 -8
  79. package/ts-reference/utils/randomUUID.ts +0 -3
  80. package/ts-reference/utils/statAsync.ts +0 -4
  81. package/tsconfig.json +0 -14
  82. package/xConfigReference.js +0 -119
package/LICENSE ADDED
@@ -0,0 +1,60 @@
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.
8
+
9
+ TERMS AND CONDITIONS
10
+
11
+ 1. OWNERSHIP
12
+ All rights, title, and interest in and to the Software, including all
13
+ intellectual property rights, are and shall remain the exclusive property
14
+ of X Enterprises LLC.
15
+
16
+ 2. RESTRICTIONS
17
+ Without the prior written consent of X Enterprises LLC, you may not:
18
+ - Copy, modify, or distribute the Software
19
+ - Reverse engineer, decompile, or disassemble the Software
20
+ - Sublicense, sell, lease, or otherwise transfer the Software
21
+ - Remove or alter any proprietary notices or labels
22
+
23
+ 3. AUTHORIZED USE
24
+ Use of this Software is limited to authorized employees, contractors, and
25
+ agents of X Enterprises LLC, solely for purposes approved by X Enterprises
26
+ LLC.
27
+
28
+ 4. NO WARRANTY
29
+ THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31
+ FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL
32
+ X ENTERPRISES LLC BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY,
33
+ WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF,
34
+ OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35
+ SOFTWARE.
36
+
37
+ 5. LIMITATION OF LIABILITY
38
+ IN NO EVENT SHALL X ENTERPRISES LLC BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
39
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
40
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
41
+ OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
42
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
43
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
44
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45
+
46
+ 6. GOVERNING LAW
47
+ This license shall be governed by and construed in accordance with the laws
48
+ of the State of Washington, United States, without regard to its conflict
49
+ of law provisions.
50
+
51
+ 7. TERMINATION
52
+ This license is effective until terminated. X Enterprises LLC may terminate
53
+ this license at any time without notice. Upon termination, you must destroy
54
+ all copies of the Software in your possession.
55
+
56
+ For licensing inquiries, contact: legal@x.enterprises
57
+
58
+ ---
59
+ X Enterprises LLC
60
+ Bothell, Washington, United States
package/README.md CHANGED
@@ -1,18 +1,8 @@
1
- # xConfig Plugin
1
+ # @xenterprises/fastify-xconfig
2
2
 
3
- A Fastify plugin that provides core configuration, middleware setup, and foundational services for Fastify applications.
3
+ Fastify plugin for centralized middleware orchestration, health checks, and utility decorators.
4
4
 
5
- ## Overview
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: {}, // Prisma client configuration
33
- cors: {
34
- active: true,
35
- origin: ['http://localhost:3000'],
36
- credentials: true
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
- await fastify.listen({ port: 3000 });
48
- ```
49
-
50
- ## Configuration Options
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
- ### Middleware Options
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
- ## Environment Variables
88
-
89
- The plugin reads these environment variables:
90
-
91
- ```bash
92
- # Database
93
- DATABASE_URL=postgresql://user:password@localhost:5432/dbname?sslmode=require
94
-
95
- # Server
96
- NODE_ENV=development
97
- PORT=3002
98
- FASTIFY_ADDRESS=0.0.0.0
99
-
100
- # Observability
101
- BUGSNAG_API_KEY=your-bugsnag-api-key
102
-
103
- # CORS
104
- CORS_ORIGIN=http://localhost:3000,https://example.com
105
- RATE_LIMIT_MAX=100
106
- RATE_LIMIT_TIME_WINDOW=1 minute
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
- ## Service Separation
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
- ```bash
126
- npm test
127
- ```
128
-
129
- ### Starting Development Server
119
+ ## Environment Variables
130
120
 
131
- ```bash
132
- npm run dev
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 development server watches for file changes and auto-restarts.
154
+ The `stack` field is only included when `NODE_ENV !== "production"`.
136
155
 
137
- ### Starting Production Server
156
+ ## How It Works
138
157
 
139
- ```bash
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
- ## Dependencies
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
- - `fastify` (^5.0.0) - Web framework
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
- ISC
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",
4
+ "version": "2.2.0",
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": "ISC",
13
+ "license": "UNLICENSED",
14
14
  "repository": {
15
15
  "type": "git",
16
16
  "url": "https://gitlab.com/x-enterprises/fastify-plugins/fastify-x-config"
@@ -33,14 +33,18 @@
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": "^5.0.0"
42
+ "fastify": ">=5.0.0",
43
+ "@prisma/client": ">=5.0.0"
44
+ },
45
+ "peerDependenciesMeta": {
46
+ "@prisma/client": {
47
+ "optional": true
48
+ }
45
49
  }
46
50
  }
@@ -1,24 +1,20 @@
1
1
  export async function setupPrisma(fastify, options) {
2
- if (options.active !== false) {
3
- const { client: PrismaClient, active, ...prismaOptions } = options;
4
- if (!PrismaClient) {
5
- throw new Error("prisma.client is required - pass your PrismaClient class from your generated client");
6
- }
2
+ if (options.active === false) return;
7
3
 
8
- const prisma = new PrismaClient(prismaOptions);
9
-
10
- fastify.decorate("prisma", prisma);
11
-
12
- fastify.addHook("onClose", async () => {
13
- await fastify.prisma.$disconnect();
14
- });
15
-
16
- console.info(" ✅ Prisma Enabled");
4
+ const { client: PrismaClient, active, ...prismaOptions } = options;
5
+ if (!PrismaClient) {
6
+ throw new Error("[xConfig] prisma.client is required - pass your PrismaClient class from your generated client");
17
7
  }
8
+ if (typeof PrismaClient !== 'function') {
9
+ throw new Error("[xConfig] prisma.client must be a PrismaClient constructor");
10
+ }
11
+
12
+ const prisma = new PrismaClient(prismaOptions);
13
+ fastify.decorate("prisma", prisma);
18
14
 
19
15
  fastify.addHook("onClose", async () => {
20
- if (fastify.prisma) {
21
- await fastify.prisma.$disconnect();
22
- }
16
+ await fastify.prisma.$disconnect();
23
17
  });
18
+
19
+ fastify.log.info("[xConfig] Prisma enabled");
24
20
  }