@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
|
@@ -1,24 +1,20 @@
|
|
|
1
1
|
export async function setupPrisma(fastify, options) {
|
|
2
|
-
if (options.active
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
21
|
-
await fastify.prisma.$disconnect();
|
|
22
|
-
}
|
|
16
|
+
await fastify.prisma.$disconnect();
|
|
23
17
|
});
|
|
18
|
+
|
|
19
|
+
fastify.log.info("[xConfig] Prisma enabled");
|
|
24
20
|
}
|
|
@@ -1,27 +1,16 @@
|
|
|
1
|
-
// src/lifecycle/xFastifyAfter.js
|
|
2
1
|
import { printRoutes } from "../utils/colorize.js";
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
|
|
3
|
+
export function xFastifyAfter(fastify, options) {
|
|
5
4
|
fastify.addHook("onClose", () => {
|
|
6
|
-
|
|
5
|
+
fastify.log.info("Server shutting down... Goodbye");
|
|
7
6
|
});
|
|
8
7
|
|
|
9
|
-
/*
|
|
10
|
-
===== LIST ROUTES AFTER ALL PLUGINS =====
|
|
11
|
-
Use the after() method to ensure this runs after all plugins are registered.
|
|
12
|
-
*/
|
|
13
8
|
fastify.after(() => {
|
|
14
9
|
if (options.professional !== true) {
|
|
15
|
-
console.info(" ✅ Listing Routes:");
|
|
16
10
|
fastify.ready(() => {
|
|
17
11
|
printRoutes(options.routes, options.colors !== false);
|
|
18
|
-
|
|
19
|
-
console.info(
|
|
20
|
-
`🚀 Server is ready on port ${process.env.PORT || 3000}\n\n`
|
|
21
|
-
);
|
|
12
|
+
fastify.log.info(`Server is ready on port ${process.env.PORT || 3000}`);
|
|
22
13
|
});
|
|
23
14
|
}
|
|
24
15
|
});
|
|
25
|
-
|
|
26
|
-
|
|
27
16
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export async function setupBugsnag(fastify, options) {
|
|
2
|
-
if (options.active
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
fastify.register(import("fastify-bugsnag"), {
|
|
6
|
-
apiKey: options.apiKey,
|
|
7
|
-
});
|
|
8
|
-
console.info(" ✅ BugSnag Enabled");
|
|
2
|
+
if (options.active === false) return;
|
|
3
|
+
if (!options.apiKey || typeof options.apiKey !== 'string') {
|
|
4
|
+
throw new Error("[xConfig] bugsnag.apiKey is required and must be a string");
|
|
9
5
|
}
|
|
6
|
+
fastify.register(import("fastify-bugsnag"), {
|
|
7
|
+
apiKey: options.apiKey,
|
|
8
|
+
});
|
|
9
|
+
fastify.log.info("[xConfig] Bugsnag enabled");
|
|
10
10
|
}
|
package/src/middleware/cors.js
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
export async function setupCors(fastify, options) {
|
|
2
|
-
if (options.active
|
|
3
|
-
// Extract active flag and pass all other options directly to the CORS plugin
|
|
4
|
-
const { active, ...corsOptions } = options;
|
|
2
|
+
if (options.active === false) return;
|
|
5
3
|
|
|
6
|
-
|
|
7
|
-
const defaultOrigins = process.env.NODE_ENV === 'production'
|
|
8
|
-
? ["https://getx.io"] // Production: only allow production domain
|
|
9
|
-
: ["http://localhost:3000", "http://localhost:3001"]; // Development: allow localhost
|
|
4
|
+
const { active, ...corsOptions } = options;
|
|
10
5
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
6
|
+
const defaultOrigins = process.env.NODE_ENV === 'production'
|
|
7
|
+
? (process.env.CORS_ORIGIN ? process.env.CORS_ORIGIN.split(',').map(s => s.trim()) : true)
|
|
8
|
+
: ["http://localhost:3000", "http://localhost:3001"];
|
|
9
|
+
|
|
10
|
+
await fastify.register(await import("@fastify/cors"), {
|
|
11
|
+
origin: corsOptions.origin || defaultOrigins,
|
|
12
|
+
credentials: corsOptions.credentials !== undefined ? corsOptions.credentials : true,
|
|
13
|
+
methods: corsOptions.methods || ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
|
14
|
+
...corsOptions,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
fastify.log.info("[xConfig] CORS enabled");
|
|
19
18
|
}
|
|
@@ -1,26 +1,21 @@
|
|
|
1
|
-
export
|
|
1
|
+
export function setupFancyErrors(fastify, enabled) {
|
|
2
|
+
if (enabled === false) return;
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
status: statusCode,
|
|
11
|
-
message: error.message || "Internal Server Error",
|
|
12
|
-
// Only show stack in development mode
|
|
13
|
-
stack: process.env.NODE_ENV === "development" ? error.stack : undefined,
|
|
14
|
-
};
|
|
4
|
+
fastify.setErrorHandler((error, request, reply) => {
|
|
5
|
+
const statusCode = error.statusCode || 500;
|
|
6
|
+
const response = {
|
|
7
|
+
status: statusCode,
|
|
8
|
+
message: error.message || "Internal Server Error",
|
|
9
|
+
stack: process.env.NODE_ENV !== "production" ? error.stack : undefined,
|
|
10
|
+
};
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
12
|
+
if (fastify.bugsnag && typeof fastify.bugsnag.notify === 'function') {
|
|
13
|
+
fastify.bugsnag.notify(error);
|
|
14
|
+
}
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
fastify.log.error(response);
|
|
17
|
+
reply.status(statusCode).send(response);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
fastify.log.info("[xConfig] Fancy errors enabled");
|
|
26
21
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export async function setupMultipart(fastify, options) {
|
|
2
|
-
if (options.active
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
if (options.active === false) return;
|
|
3
|
+
const { active, ...multipartOptions } = options;
|
|
4
|
+
fastify.register(import("@fastify/multipart"), multipartOptions);
|
|
5
|
+
fastify.log.info("[xConfig] Multipart enabled");
|
|
6
6
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export async function setupRateLimit(fastify, options) {
|
|
2
|
-
if (options.active
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
if (options.active === false) return;
|
|
3
|
+
const { active, ...rateLimitOptions } = options;
|
|
4
|
+
fastify.register(import("@fastify/rate-limit"), rateLimitOptions);
|
|
5
|
+
fastify.log.info("[xConfig] Rate limiting enabled");
|
|
6
6
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export async function setupUnderPressure(fastify, options) {
|
|
2
|
-
if (options.active
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
if (options.active === false) return;
|
|
3
|
+
const { active, ...underPressureOptions } = options;
|
|
4
|
+
fastify.register(import("@fastify/under-pressure"), underPressureOptions);
|
|
5
|
+
fastify.log.info("[xConfig] Under pressure enabled");
|
|
6
6
|
}
|
package/src/utils/formatBytes.js
CHANGED
package/src/utils/health.js
CHANGED
|
@@ -1,42 +1,29 @@
|
|
|
1
|
-
// Import necessary modules
|
|
2
1
|
import os from "os";
|
|
3
2
|
import process from "process";
|
|
4
|
-
import fs from "fs";
|
|
5
|
-
import util from "util";
|
|
6
3
|
|
|
7
|
-
|
|
8
|
-
// Promisify fs functions
|
|
9
|
-
const statAsync = util.promisify(fs.stat);
|
|
10
|
-
|
|
11
|
-
// Record the server start time
|
|
12
|
-
const serverStartTime = Date.now();
|
|
13
|
-
|
|
14
|
-
// Helper function to format bytes into human-readable format
|
|
15
4
|
function formatBytes(bytes, decimals = 2) {
|
|
16
5
|
if (bytes === 0) return "0 Bytes";
|
|
17
6
|
const k = 1024;
|
|
18
7
|
const dm = decimals < 0 ? 0 : decimals;
|
|
19
8
|
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB"];
|
|
20
9
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
21
|
-
|
|
22
|
-
return `${formattedNumber} ${sizes[i]}`;
|
|
10
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
|
|
23
11
|
}
|
|
24
12
|
|
|
25
|
-
export async function setupHealth(fastify
|
|
13
|
+
export async function setupHealth(fastify) {
|
|
26
14
|
fastify.get("/health", async (request, reply) => {
|
|
27
15
|
const status = {
|
|
28
16
|
status: "healthy",
|
|
29
17
|
timestamp: new Date().toISOString(),
|
|
30
|
-
uptime: process.uptime(),
|
|
31
|
-
version: "1.0.0", // Fetch dynamically if possible
|
|
18
|
+
uptime: process.uptime(),
|
|
32
19
|
environment: process.env.NODE_ENV || "development",
|
|
33
20
|
dependencies: {},
|
|
34
21
|
resources: {},
|
|
35
22
|
details: {},
|
|
36
23
|
};
|
|
37
24
|
|
|
25
|
+
// Database connectivity check
|
|
38
26
|
try {
|
|
39
|
-
// Database connectivity check
|
|
40
27
|
if (fastify.prisma) {
|
|
41
28
|
await fastify.prisma.$queryRaw`SELECT 1`;
|
|
42
29
|
status.dependencies.database = "up";
|
|
@@ -49,8 +36,8 @@ export async function setupHealth(fastify, options) {
|
|
|
49
36
|
status.details.databaseError = error.message;
|
|
50
37
|
}
|
|
51
38
|
|
|
39
|
+
// Redis connectivity check
|
|
52
40
|
try {
|
|
53
|
-
// Redis connectivity check
|
|
54
41
|
if (fastify.redis) {
|
|
55
42
|
await fastify.redis.ping();
|
|
56
43
|
status.dependencies.redis = "up";
|
|
@@ -65,8 +52,6 @@ export async function setupHealth(fastify, options) {
|
|
|
65
52
|
|
|
66
53
|
// Resource usage
|
|
67
54
|
const memoryUsage = process.memoryUsage();
|
|
68
|
-
const loadAverage = os.loadavg();
|
|
69
|
-
|
|
70
55
|
status.resources.memory = {
|
|
71
56
|
rss: formatBytes(memoryUsage.rss),
|
|
72
57
|
heapTotal: formatBytes(memoryUsage.heapTotal),
|
|
@@ -76,16 +61,14 @@ export async function setupHealth(fastify, options) {
|
|
|
76
61
|
};
|
|
77
62
|
|
|
78
63
|
status.resources.cpu = {
|
|
79
|
-
loadAverage
|
|
64
|
+
loadAverage: os.loadavg(),
|
|
80
65
|
cpus: os.cpus().length,
|
|
81
66
|
};
|
|
82
67
|
|
|
83
68
|
// Disk space availability
|
|
84
69
|
try {
|
|
85
|
-
// Implement disk space check using 'check-disk-space' package
|
|
86
|
-
// Install it via 'npm install check-disk-space'
|
|
87
70
|
const checkDiskSpace = (await import("check-disk-space")).default;
|
|
88
|
-
const diskSpace = await checkDiskSpace("/");
|
|
71
|
+
const diskSpace = await checkDiskSpace("/");
|
|
89
72
|
status.resources.disk = {
|
|
90
73
|
free: formatBytes(diskSpace.free),
|
|
91
74
|
size: formatBytes(diskSpace.size),
|
|
@@ -95,15 +78,7 @@ export async function setupHealth(fastify, options) {
|
|
|
95
78
|
status.details.diskError = error.message;
|
|
96
79
|
}
|
|
97
80
|
|
|
98
|
-
//
|
|
99
|
-
// Example: Check if a scheduled job is running
|
|
100
|
-
if (typeof isJobRunning === "function" && !isJobRunning()) {
|
|
101
|
-
status.status = "degraded";
|
|
102
|
-
status.details.jobStatus = "Scheduled job is not running";
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Configuration validation
|
|
106
|
-
// Only check required env vars if Prisma is enabled
|
|
81
|
+
// Configuration validation — only if Prisma is enabled
|
|
107
82
|
if (fastify.prisma) {
|
|
108
83
|
const requiredEnvVars = ["DATABASE_URL"];
|
|
109
84
|
const missingEnvVars = requiredEnvVars.filter(
|
|
@@ -115,11 +90,10 @@ export async function setupHealth(fastify, options) {
|
|
|
115
90
|
}
|
|
116
91
|
}
|
|
117
92
|
|
|
118
|
-
// Determine overall health
|
|
119
93
|
if (status.status === "healthy") {
|
|
120
94
|
reply.send(status);
|
|
121
95
|
} else {
|
|
122
|
-
reply.status(
|
|
96
|
+
reply.status(503).send(status);
|
|
123
97
|
}
|
|
124
98
|
});
|
|
125
|
-
}
|
|
99
|
+
}
|
package/src/xConfig.js
CHANGED
|
@@ -1,36 +1,28 @@
|
|
|
1
|
-
// src/xConfig.js
|
|
2
1
|
import fp from "fastify-plugin";
|
|
3
|
-
const isProduction = process.env.NODE_ENV === 'production';
|
|
4
2
|
|
|
5
|
-
/*
|
|
6
|
-
* Integrations
|
|
7
|
-
*/
|
|
8
3
|
import { setupPrisma } from "./integrations/prisma.js";
|
|
9
|
-
|
|
10
|
-
/*
|
|
11
|
-
* Lifecycle
|
|
12
|
-
*/
|
|
13
4
|
import { xFastifyAfter } from "./lifecycle/xFastifyAfter.js";
|
|
14
|
-
|
|
15
|
-
/*
|
|
16
|
-
* Middleware
|
|
17
|
-
*/
|
|
18
5
|
import { setupCors } from './middleware/cors.js';
|
|
19
6
|
import { setupUnderPressure } from './middleware/underPressure.js';
|
|
20
7
|
import { setupRateLimit } from './middleware/rateLimit.js';
|
|
21
8
|
import { setupMultipart } from './middleware/multipart.js';
|
|
22
9
|
import { setupBugsnag } from './middleware/bugsnag.js';
|
|
23
|
-
import { setupFancyErrors } from './middleware/fancyErrors.js'
|
|
24
|
-
|
|
25
|
-
/*
|
|
26
|
-
* Utils
|
|
27
|
-
*/
|
|
10
|
+
import { setupFancyErrors } from './middleware/fancyErrors.js';
|
|
28
11
|
import xEcho from "./utils/xEcho.js";
|
|
29
12
|
import { setupHealth } from "./utils/health.js";
|
|
30
13
|
import xSlugify from "./utils/xSlugify.js";
|
|
31
14
|
import xUUID from "./utils/xUUID.js";
|
|
15
|
+
import xFormatBytes from "./utils/formatBytes.js";
|
|
32
16
|
|
|
33
17
|
async function xConfig(fastify, options) {
|
|
18
|
+
// Validate top-level options
|
|
19
|
+
if (options.professional !== undefined && typeof options.professional !== 'boolean') {
|
|
20
|
+
throw new Error("[xConfig] professional must be a boolean");
|
|
21
|
+
}
|
|
22
|
+
if (options.fancyErrors !== undefined && typeof options.fancyErrors !== 'boolean') {
|
|
23
|
+
throw new Error("[xConfig] fancyErrors must be a boolean");
|
|
24
|
+
}
|
|
25
|
+
|
|
34
26
|
const {
|
|
35
27
|
professional = false,
|
|
36
28
|
fancyErrors = true,
|
|
@@ -42,46 +34,36 @@ async function xConfig(fastify, options) {
|
|
|
42
34
|
rateLimit: rateLimitOptions = {},
|
|
43
35
|
} = options;
|
|
44
36
|
|
|
45
|
-
|
|
46
|
-
console.info("\n 🌮 Starting xConfig...\n");
|
|
37
|
+
fastify.log.info("[xConfig] Starting...");
|
|
47
38
|
|
|
48
|
-
|
|
49
|
-
===== LIST ROUTES =====
|
|
50
|
-
Moved the onRoute hook to the top to capture all routes.
|
|
51
|
-
*/
|
|
39
|
+
// Capture all registered routes for listing
|
|
52
40
|
const routes = [];
|
|
53
41
|
fastify.addHook("onRoute", (r) => routes.push(r));
|
|
54
42
|
|
|
55
|
-
|
|
56
|
-
* Integrations
|
|
57
|
-
*/
|
|
43
|
+
// Integrations
|
|
58
44
|
await setupPrisma(fastify, prismaOptions);
|
|
59
45
|
|
|
60
|
-
|
|
61
|
-
* Middleware
|
|
62
|
-
*/
|
|
46
|
+
// Middleware
|
|
63
47
|
await setupCors(fastify, corsOptions);
|
|
64
48
|
await setupUnderPressure(fastify, underPressureOptions);
|
|
65
49
|
await setupRateLimit(fastify, rateLimitOptions);
|
|
66
50
|
await setupMultipart(fastify, multipartOptions);
|
|
67
51
|
await setupBugsnag(fastify, bugsnagOptions);
|
|
68
|
-
|
|
69
|
-
fastify.register(import('@fastify/sensible'))
|
|
70
|
-
|
|
71
|
-
/*
|
|
72
|
-
* Utils
|
|
73
|
-
*/
|
|
52
|
+
setupFancyErrors(fastify, fancyErrors);
|
|
53
|
+
fastify.register(import('@fastify/sensible'));
|
|
74
54
|
|
|
55
|
+
// Utils
|
|
75
56
|
fastify.register(xEcho);
|
|
76
57
|
fastify.register(xSlugify);
|
|
77
58
|
fastify.register(xUUID);
|
|
59
|
+
fastify.register(xFormatBytes);
|
|
78
60
|
await setupHealth(fastify);
|
|
79
61
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
62
|
+
// Lifecycle — route listing after all plugins
|
|
63
|
+
xFastifyAfter(fastify, { professional, routes });
|
|
83
64
|
}
|
|
84
65
|
|
|
85
66
|
export default fp(xConfig, {
|
|
86
67
|
name: "xConfig",
|
|
68
|
+
fastify: ">=5.0.0",
|
|
87
69
|
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function setupCloudinary(fastify: any, cloudinaryOptions: any): Promise<void>;
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { v2 as Cloudinary } from "cloudinary";
|
|
2
|
-
export async function setupCloudinary(fastify, cloudinaryOptions) {
|
|
3
|
-
if (cloudinaryOptions.active !== false) {
|
|
4
|
-
Cloudinary.config({
|
|
5
|
-
cloud_name: cloudinaryOptions.cloudName,
|
|
6
|
-
api_key: cloudinaryOptions.apiKey,
|
|
7
|
-
api_secret: cloudinaryOptions.apiSecret,
|
|
8
|
-
});
|
|
9
|
-
fastify.decorate("cloudinary", {
|
|
10
|
-
async upload(fileStream, options = {}) {
|
|
11
|
-
return new Promise((resolve, reject) => {
|
|
12
|
-
const uploadStream = Cloudinary.uploader.upload_stream(options, (error, result) => {
|
|
13
|
-
if (error)
|
|
14
|
-
reject(error);
|
|
15
|
-
else
|
|
16
|
-
resolve(result);
|
|
17
|
-
});
|
|
18
|
-
fileStream.pipe(uploadStream);
|
|
19
|
-
});
|
|
20
|
-
},
|
|
21
|
-
});
|
|
22
|
-
console.info(" ✅ Cloudinary Enabled");
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
//# sourceMappingURL=cloudinary.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cloudinary.js","sourceRoot":"","sources":["../../src/integrations/cloudinary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,IAAI,UAAU,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAY,EAAE,iBAAsB;IACxE,IAAI,iBAAiB,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QACvC,UAAU,CAAC,MAAM,CAAC;YAChB,UAAU,EAAE,iBAAiB,CAAC,SAAS;YACvC,OAAO,EAAE,iBAAiB,CAAC,MAAM;YACjC,UAAU,EAAE,iBAAiB,CAAC,SAAS;SACxC,CAAC,CAAC;QACH,OAAO,CAAC,QAAQ,CAAC,YAAY,EAAE;YAC7B,KAAK,CAAC,MAAM,CAAC,UAAe,EAAE,OAAO,GAAG,EAAE;gBACxC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;oBACrC,MAAM,YAAY,GAAG,UAAU,CAAC,QAAQ,CAAC,aAAa,CACpD,OAAO,EACP,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;wBAChB,IAAI,KAAK;4BAAE,MAAM,CAAC,KAAK,CAAC,CAAC;;4BACpB,OAAO,CAAC,MAAM,CAAC,CAAC;oBACvB,CAAC,CACF,CAAC;oBACF,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBAChC,CAAC,CAAC,CAAC;YACL,CAAC;SACF,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function setupPrisma(fastify: any, prismaOptions: any): Promise<void>;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { PrismaClient } from "@prisma/client";
|
|
2
|
-
export async function setupPrisma(fastify, prismaOptions) {
|
|
3
|
-
if (prismaOptions.active !== false) {
|
|
4
|
-
const prisma = new PrismaClient(prismaOptions);
|
|
5
|
-
await prisma.$connect();
|
|
6
|
-
fastify.decorate("prisma", prisma);
|
|
7
|
-
fastify.addHook("onClose", async () => {
|
|
8
|
-
await fastify.prisma.$disconnect();
|
|
9
|
-
});
|
|
10
|
-
console.info(" ✅ Prisma Enabled");
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
//# sourceMappingURL=prisma.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prisma.js","sourceRoot":"","sources":["../../src/integrations/prisma.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAY,EAAE,aAAkB;IAChE,IAAI,aAAa,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,aAAa,CAAC,CAAC;QAC/C,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACnC,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;YACpC,MAAM,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACrC,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IACtC,CAAC;AACH,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function setupSendGrid(fastify: any, sendGridOptions: any): Promise<void>;
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import Sendgrid from "@sendgrid/mail";
|
|
2
|
-
export async function setupSendGrid(fastify, sendGridOptions) {
|
|
3
|
-
if (sendGridOptions.active !== false) {
|
|
4
|
-
if (!sendGridOptions.apiKey)
|
|
5
|
-
throw new Error("SendGrid API key must be provided.");
|
|
6
|
-
Sendgrid.setApiKey(sendGridOptions.apiKey);
|
|
7
|
-
fastify.decorate("sendgrid", {
|
|
8
|
-
async sendEmail(to, subject, templateId, dynamicTemplateData) {
|
|
9
|
-
const msg = {
|
|
10
|
-
to,
|
|
11
|
-
from: sendGridOptions.fromEmail,
|
|
12
|
-
subject,
|
|
13
|
-
templateId,
|
|
14
|
-
dynamicTemplateData,
|
|
15
|
-
};
|
|
16
|
-
await Sendgrid.send(msg);
|
|
17
|
-
},
|
|
18
|
-
});
|
|
19
|
-
console.info(" ✅ SendGrid Enabled");
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
//# sourceMappingURL=sendgrid.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sendgrid.js","sourceRoot":"","sources":["../../src/integrations/sendgrid.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAEtC,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAY,EAAE,eAAoB;IACpE,IAAI,eAAe,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QACrC,IAAI,CAAC,eAAe,CAAC,MAAM;YACzB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACxD,QAAQ,CAAC,SAAS,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QAC3C,OAAO,CAAC,QAAQ,CAAC,UAAU,EAAE;YAC3B,KAAK,CAAC,SAAS,CACb,EAAU,EACV,OAAe,EACf,UAAkB,EAClB,mBAAwB;gBAExB,MAAM,GAAG,GAAG;oBACV,EAAE;oBACF,IAAI,EAAE,eAAe,CAAC,SAAS;oBAC/B,OAAO;oBACP,UAAU;oBACV,mBAAmB;iBACpB,CAAC;gBACF,MAAM,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC3B,CAAC;SACF,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IACxC,CAAC;AACH,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function setupStripe(fastify: any, stripeOptions: any): Promise<void>;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import Stripe from "stripe";
|
|
2
|
-
export async function setupStripe(fastify, stripeOptions) {
|
|
3
|
-
if (stripeOptions.active !== false) {
|
|
4
|
-
const stripeClient = new Stripe(stripeOptions.apiKey, {
|
|
5
|
-
apiVersion: "2024-06-20",
|
|
6
|
-
});
|
|
7
|
-
fastify.decorate("stripe", {
|
|
8
|
-
async createPaymentIntent(amount, currency = "usd") {
|
|
9
|
-
return await stripeClient.paymentIntents.create({ amount, currency });
|
|
10
|
-
},
|
|
11
|
-
});
|
|
12
|
-
console.info(" ✅ Stripe Enabled");
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
//# sourceMappingURL=stripe.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"stripe.js","sourceRoot":"","sources":["../../src/integrations/stripe.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAY,EAAE,aAAkB;IAChE,IAAI,aAAa,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QACnC,MAAM,YAAY,GAAG,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE;YACpD,UAAU,EAAE,YAAY;SACzB,CAAC,CAAC;QACH,OAAO,CAAC,QAAQ,CAAC,QAAQ,EAAE;YACzB,KAAK,CAAC,mBAAmB,CAAC,MAAc,EAAE,QAAQ,GAAG,KAAK;gBACxD,OAAO,MAAM,YAAY,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;YACxE,CAAC;SACF,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IACtC,CAAC;AACH,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function setupTwilio(fastify: any, twilioOptions: any): Promise<void>;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import Twilio from "twilio";
|
|
2
|
-
export async function setupTwilio(fastify, twilioOptions) {
|
|
3
|
-
if (twilioOptions.active !== false) {
|
|
4
|
-
const twilioClient = Twilio(twilioOptions.accountSid, twilioOptions.authToken);
|
|
5
|
-
fastify.decorate("twilio", {
|
|
6
|
-
async sendSMS(to, body) {
|
|
7
|
-
return await twilioClient.messages.create({
|
|
8
|
-
body,
|
|
9
|
-
to,
|
|
10
|
-
from: twilioOptions.phoneNumber,
|
|
11
|
-
});
|
|
12
|
-
},
|
|
13
|
-
});
|
|
14
|
-
console.info(" ✅ Twilio Enabled");
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
//# sourceMappingURL=twilio.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"twilio.js","sourceRoot":"","sources":["../../src/integrations/twilio.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAY,EAAE,aAAkB;IAChE,IAAI,aAAa,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QACnC,MAAM,YAAY,GAAG,MAAM,CACzB,aAAa,CAAC,UAAU,EACxB,aAAa,CAAC,SAAS,CACxB,CAAC;QACF,OAAO,CAAC,QAAQ,CAAC,QAAQ,EAAE;YACzB,KAAK,CAAC,OAAO,CAAC,EAAU,EAAE,IAAY;gBACpC,OAAO,MAAM,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC;oBACxC,IAAI;oBACJ,EAAE;oBACF,IAAI,EAAE,aAAa,CAAC,WAAW;iBAChC,CAAC,CAAC;YACL,CAAC;SACF,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IACtC,CAAC;AACH,CAAC"}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export async function setupBugsnag(fastify, options) {
|
|
2
|
-
if (options.active !== false && options.apiKey) {
|
|
3
|
-
await fastify.register(import("fastify-bugsnag"), {
|
|
4
|
-
apiKey: options.apiKey,
|
|
5
|
-
});
|
|
6
|
-
console.info(" ✅ Bugsnag Enabled");
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
//# sourceMappingURL=bugsnag.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bugsnag.js","sourceRoot":"","sources":["../../src/middleware/bugsnag.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAwB,EAAE,OAAY;IACvE,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QAC/C,MAAM,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,iBAAiB,CAAC,EAAE;YAChD,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACvC,CAAC;AACH,CAAC"}
|
package/dist/middleware/cors.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export async function setupCors(fastify, options) {
|
|
2
|
-
if (options.active !== false) {
|
|
3
|
-
await fastify.register(import("@fastify/cors"), {
|
|
4
|
-
origin: options.origin || ["https://getx.io", "http://localhost:3000"],
|
|
5
|
-
credentials: options.credentials !== undefined ? options.credentials : true,
|
|
6
|
-
methods: options.methods || ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
|
7
|
-
});
|
|
8
|
-
console.info(" ✅ CORS Enabled");
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
//# sourceMappingURL=cors.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cors.js","sourceRoot":"","sources":["../../src/middleware/cors.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAwB,EAAE,OAAY;IACpE,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QAC7B,MAAM,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE;YAC9C,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,CAAC,iBAAiB,EAAE,uBAAuB,CAAC;YACtE,WAAW,EACT,OAAO,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI;YAChE,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC;SACxE,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IACpC,CAAC;AACH,CAAC"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export async function setupErrorHandler(fastify, fancyErrors) {
|
|
2
|
-
if (fancyErrors !== false) {
|
|
3
|
-
fastify.setErrorHandler((error, request, reply) => {
|
|
4
|
-
const statusCode = error.statusCode || 500;
|
|
5
|
-
const response = {
|
|
6
|
-
status: statusCode,
|
|
7
|
-
message: error.message || "Internal Server Error",
|
|
8
|
-
stack: process.env.NODE_ENV === "development" ? error.stack : undefined,
|
|
9
|
-
};
|
|
10
|
-
// Optional Bugsnag error reporting
|
|
11
|
-
if (fastify.bugsnag)
|
|
12
|
-
fastify.bugsnag.notify(error);
|
|
13
|
-
fastify.log.error(response);
|
|
14
|
-
reply.status(statusCode).send(response);
|
|
15
|
-
});
|
|
16
|
-
console.info(" ✅ Fancy Errors Enabled");
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
//# sourceMappingURL=errorHandler.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errorHandler.js","sourceRoot":"","sources":["../../src/middleware/errorHandler.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,OAAwB,EACxB,WAAoB;IAEpB,IAAI,WAAW,KAAK,KAAK,EAAE,CAAC;QAC1B,OAAO,CAAC,eAAe,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;YAChD,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,IAAI,GAAG,CAAC;YAC3C,MAAM,QAAQ,GAAG;gBACf,MAAM,EAAE,UAAU;gBAClB,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,uBAAuB;gBACjD,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;aACxE,CAAC;YAEF,mCAAmC;YACnC,IAAI,OAAO,CAAC,OAAO;gBAAE,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAEnD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC5B,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC"}
|