@xenterprises/fastify-xconfig 1.0.0 → 1.0.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/.github/workflows/ci.yml +19 -0
- package/.taprc +3 -0
- package/README.md +18 -171
- package/index.d.ts +13 -0
- package/index.js +9 -0
- package/package.json +33 -39
- package/test/index.test-d.ts +13 -0
- package/test/index.test.js +14 -0
- package/test/xConfig.js +115 -0
- package/tsconfig.json +9 -0
- 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/server/app.js +0 -85
- package/src/auth/admin.js +0 -181
- package/src/auth/portal.js +0 -177
- package/src/integrations/cloudinary.js +0 -98
- package/src/integrations/geocode.js +0 -43
- package/src/integrations/prisma.js +0 -30
- package/src/integrations/sendgrid.js +0 -58
- package/src/integrations/twilio.js +0 -146
- package/src/lifecycle/xFastifyAfter.js +0 -27
- package/src/middleware/bugsnag.js +0 -10
- package/src/middleware/cors.js +0 -10
- package/src/middleware/fancyErrors.js +0 -26
- package/src/middleware/multipart.js +0 -6
- package/src/middleware/rateLimit.js +0 -6
- package/src/middleware/underPressure.js +0 -6
- package/src/utils/colorize.js +0 -37
- package/src/utils/cookie.js +0 -5
- package/src/utils/formatBytes.js +0 -16
- package/src/utils/health.js +0 -126
- package/src/utils/xEcho.js +0 -12
- package/src/utils/xSlugify.js +0 -20
- package/src/utils/xUUID.js +0 -14
- package/src/xConfig.js +0 -117
- package/test/index.js +0 -17
- 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/xConfigReference.js +0 -1526
- package/xConfigWorkingList.js +0 -720
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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"multipart.js","sourceRoot":"","sources":["../../src/middleware/multipart.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAwB,EAAE,OAAY;IACzE,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QAC7B,MAAM,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IACzC,CAAC;AACH,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rateLimit.js","sourceRoot":"","sources":["../../src/middleware/rateLimit.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAwB,EAAE,OAAY;IACzE,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QAC7B,MAAM,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC,CAAC;QAC/D,OAAO,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"underPressure.js","sourceRoot":"","sources":["../../src/middleware/underPressure.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAwB,EACxB,OAAY;IAEZ,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QAC7B,MAAM,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,yBAAyB,CAAC,EAAE,OAAO,CAAC,CAAC;QACnE,OAAO,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC"}
|
package/dist/utils/colorize.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { FastifyInstance, RouteOptions } from "fastify";
|
|
2
|
-
export declare function colorize(method: string, text: string): string;
|
|
3
|
-
export declare function printRoutes(routes: RouteOptions[], colors?: boolean): void;
|
|
4
|
-
export declare function captureRoutes(fastify: FastifyInstance): RouteOptions[];
|
package/dist/utils/colorize.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
const COLORS = {
|
|
2
|
-
POST: 33,
|
|
3
|
-
GET: 32,
|
|
4
|
-
PUT: 34,
|
|
5
|
-
DELETE: 31,
|
|
6
|
-
PATCH: 90,
|
|
7
|
-
clear: 39,
|
|
8
|
-
};
|
|
9
|
-
// Function to colorize method and path names
|
|
10
|
-
export function colorize(method, text) {
|
|
11
|
-
const colorCode = COLORS[method] || COLORS.clear;
|
|
12
|
-
return `\u001b[${colorCode}m${text}\u001b[${COLORS.clear}m`;
|
|
13
|
-
}
|
|
14
|
-
// Function to print the collected routes
|
|
15
|
-
export function printRoutes(routes, colors = true) {
|
|
16
|
-
routes
|
|
17
|
-
.sort((a, b) => a.url.localeCompare(b.url))
|
|
18
|
-
.forEach(({ method, url }) => {
|
|
19
|
-
const methodsArray = Array.isArray(method) ? method : [method];
|
|
20
|
-
methodsArray
|
|
21
|
-
.filter((m) => m !== "HEAD")
|
|
22
|
-
.forEach((m) => console.info(`${colors ? colorize(m, m) : m}\t${colors ? colorize(m, url) : url}`));
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
// Helper function to capture all registered routes
|
|
26
|
-
export function captureRoutes(fastify) {
|
|
27
|
-
const routes = [];
|
|
28
|
-
fastify.addHook("onRoute", (routeOptions) => {
|
|
29
|
-
routes.push(routeOptions);
|
|
30
|
-
});
|
|
31
|
-
return routes;
|
|
32
|
-
}
|
|
33
|
-
//# sourceMappingURL=colorize.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"colorize.js","sourceRoot":"","sources":["../../src/utils/colorize.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,GAA+B;IACzC,IAAI,EAAE,EAAE;IACR,GAAG,EAAE,EAAE;IACP,GAAG,EAAE,EAAE;IACP,MAAM,EAAE,EAAE;IACV,KAAK,EAAE,EAAE;IACT,KAAK,EAAE,EAAE;CACV,CAAC;AAEF,6CAA6C;AAC7C,MAAM,UAAU,QAAQ,CAAC,MAAc,EAAE,IAAY;IACnD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAoB,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC;IAC/D,OAAO,UAAU,SAAS,IAAI,IAAI,UAAU,MAAM,CAAC,KAAK,GAAG,CAAC;AAC9D,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,WAAW,CAAC,MAAsB,EAAE,MAAM,GAAG,IAAI;IAC/D,MAAM;SACH,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;SAC1C,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE;QAC3B,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC/D,YAAY;aACT,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC;aAC3B,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CACb,OAAO,CAAC,IAAI,CACV,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CACrE,CACF,CAAC;IACN,CAAC,CAAC,CAAC;AACP,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,aAAa,CAAC,OAAwB;IACpD,MAAM,MAAM,GAAmB,EAAE,CAAC;IAElC,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,YAAY,EAAE,EAAE;QAC1C,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function formatBytes(bytes: number, decimals?: number): string;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export function formatBytes(bytes, decimals = 2) {
|
|
2
|
-
if (bytes === 0)
|
|
3
|
-
return "0 Bytes";
|
|
4
|
-
const k = 1024;
|
|
5
|
-
const dm = decimals < 0 ? 0 : decimals;
|
|
6
|
-
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB"];
|
|
7
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
8
|
-
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
|
|
9
|
-
}
|
|
10
|
-
//# sourceMappingURL=formatBytes.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"formatBytes.js","sourceRoot":"","sources":["../../src/utils/formatBytes.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,QAAQ,GAAG,CAAC;IACrD,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAClC,MAAM,CAAC,GAAG,IAAI,CAAC;IACf,MAAM,EAAE,GAAG,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IACvC,MAAM,KAAK,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACtD,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,OAAO,GAAG,UAAU,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAC3E,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const generateUUID: any;
|
package/dist/utils/randomUUID.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"randomUUID.js","sourceRoot":"","sources":["../../src/utils/randomUUID.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAAC"}
|
package/dist/utils/statAsync.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"statAsync.js","sourceRoot":"","sources":["../../src/utils/statAsync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC"}
|
package/dist/xConfig.d.ts
DELETED
package/dist/xConfig.js
DELETED
package/dist/xConfig.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"xConfig.js","sourceRoot":"","sources":["../src/xConfig.ts"],"names":[],"mappings":"AAAA,gBAAgB;AAChB,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEhC,KAAK,UAAU,OAAO,CAAC,OAAO,EAAE,OAAO;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,2BAA2B,CAAC,CAAC;AAC/D,CAAC;AAED,eAAe,EAAE,CAAC,OAAO,EAAE;IACzB,IAAI,EAAE,SAAS;CAChB,CAAC,CAAC"}
|
package/server/app.js
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
// server/app.js
|
|
2
|
-
import Fastify from 'fastify';
|
|
3
|
-
import xConfig from '../src/xConfig.js'; // Import your plugin correctly
|
|
4
|
-
|
|
5
|
-
const fastify = Fastify();
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export default async function (fastify, opts) {
|
|
9
|
-
fastify.register(xConfig, {
|
|
10
|
-
professional: false,
|
|
11
|
-
fancyErrors: true,
|
|
12
|
-
prisma: {
|
|
13
|
-
active: false,
|
|
14
|
-
},
|
|
15
|
-
bugsnag: {
|
|
16
|
-
apiKey: process.env.BUGSNAG_API_KEY
|
|
17
|
-
},
|
|
18
|
-
rateLimit: {
|
|
19
|
-
max: process.env.RATE_LIMIT_MAX || 100,
|
|
20
|
-
timeWindow: process.env.RATE_LIMIT_TIME_WINDOW || '1 minute'
|
|
21
|
-
},
|
|
22
|
-
stripe: {
|
|
23
|
-
active: false,
|
|
24
|
-
apiKey: process.env.STRIPE_API_KEY
|
|
25
|
-
},
|
|
26
|
-
sendGrid: {
|
|
27
|
-
active: true,
|
|
28
|
-
apiKey: process.env.SENDGRID_API_KEY,
|
|
29
|
-
apiKeyEmailValidation: process.env.SENDGRID_API_EMAIL_VALIDATION_KEY,
|
|
30
|
-
fromEmail: process.env.SENDGRID_FROM_EMAIL || 'ops@getx.io',
|
|
31
|
-
},
|
|
32
|
-
twilio: {
|
|
33
|
-
active: true,
|
|
34
|
-
accountSid: process.env.TWILIO_ACCOUNT_SID,
|
|
35
|
-
authToken: process.env.TWILIO_AUTH_TOKEN,
|
|
36
|
-
phoneNumber: process.env.TWILIO_PHONE_NUMBER
|
|
37
|
-
},
|
|
38
|
-
cloudinary: {
|
|
39
|
-
active: false,
|
|
40
|
-
cloudName: process.env.CLOUDINARY_CLOUD_NAME,
|
|
41
|
-
apiKey: process.env.CLOUDINARY_API_KEY,
|
|
42
|
-
apiSecret: process.env.CLOUDINARY_API_SECRET,
|
|
43
|
-
basePath: process.env.CLOUDINARY_BASE_PATH || 'basepath'
|
|
44
|
-
},
|
|
45
|
-
cors: {
|
|
46
|
-
active: true,
|
|
47
|
-
origin: process.env.CORS_ORIGIN || ['http://localhost:3000', 'https://app.bandmate.io'],
|
|
48
|
-
credentials: true
|
|
49
|
-
},
|
|
50
|
-
auth: {
|
|
51
|
-
excludedPaths: ['/public', '/portal/auth/register'],
|
|
52
|
-
admin: {
|
|
53
|
-
active: true,
|
|
54
|
-
secret: process.env.ADMIN_JWT_SECRET,
|
|
55
|
-
expiresIn: '1h',
|
|
56
|
-
cookieOptions: {
|
|
57
|
-
name: 'adminToken',
|
|
58
|
-
httpOnly: true,
|
|
59
|
-
secure: true, // Set to false if not using HTTPS
|
|
60
|
-
sameSite: 'strict', // Can be 'lax', 'strict', or 'none'
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
user: {
|
|
64
|
-
active: true,
|
|
65
|
-
portalStackProjectId: process.env.STACK_PROJECT_ID,
|
|
66
|
-
me: {
|
|
67
|
-
isOnboarded: true
|
|
68
|
-
},
|
|
69
|
-
registerEmail: {
|
|
70
|
-
subject: 'Welcome to Bandmate!',
|
|
71
|
-
templateId: ''
|
|
72
|
-
}
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
geocode: {
|
|
76
|
-
active: true,
|
|
77
|
-
apiKey: process.env.GEOCODIO_API_KEY
|
|
78
|
-
}
|
|
79
|
-
}); // Register the default export, which should be a function
|
|
80
|
-
fastify.get('/', async (request, reply) => {
|
|
81
|
-
console.log(fastify.xEcho())
|
|
82
|
-
return { status: fastify.xEcho() }
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
};
|
package/src/auth/admin.js
DELETED
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import * as jose from "jose";
|
|
2
|
-
const isProduction = process.env.NODE_ENV === 'production';
|
|
3
|
-
|
|
4
|
-
export async function setupAdminAuth(fastify, options) {
|
|
5
|
-
if (options.admin?.active !== false) {
|
|
6
|
-
// Get configuration
|
|
7
|
-
const projectId = options.admin.stackProjectId || process.env.ADMIN_STACK_PROJECT_ID;
|
|
8
|
-
const publishableKey = options.admin.publishableKey || process.env.ADMIN_STACK_PUBLISHABLE_CLIENT_KEY;
|
|
9
|
-
const secretKey = options.admin.secretKey || process.env.ADMIN_STACK_SECRET_SERVER_KEY;
|
|
10
|
-
|
|
11
|
-
if (!projectId) {
|
|
12
|
-
throw new Error("Stack Auth admin project ID is required");
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (!publishableKey || !secretKey) {
|
|
16
|
-
throw new Error("Stack Auth admin publishable and secret keys are required");
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const adminExcludedPaths = options.admin.excludedPaths || [
|
|
20
|
-
"/admin/auth/login",
|
|
21
|
-
"/admin/auth/logout",
|
|
22
|
-
];
|
|
23
|
-
|
|
24
|
-
// Base URL for Stack Auth API
|
|
25
|
-
const stackAuthBaseUrl = `https://api.stack-auth.com/api/v1`;
|
|
26
|
-
const jwksUrl = `${stackAuthBaseUrl}/projects/${projectId}/.well-known/jwks.json`;
|
|
27
|
-
|
|
28
|
-
// Create JWKS for token verification
|
|
29
|
-
const jwks = jose.createRemoteJWKSet(new URL(jwksUrl));
|
|
30
|
-
|
|
31
|
-
// Helper for Stack Auth API headers
|
|
32
|
-
fastify.decorate('getAdminStackAuthHeaders', function (accessType = "server") {
|
|
33
|
-
const headers = {
|
|
34
|
-
'Content-Type': 'application/json',
|
|
35
|
-
'Accept': 'application/json',
|
|
36
|
-
'X-Stack-Access-Type': accessType,
|
|
37
|
-
'X-Stack-Project-Id': projectId,
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
if (accessType === "client") {
|
|
41
|
-
headers['X-Stack-Publishable-Client-Key'] = publishableKey;
|
|
42
|
-
} else if (accessType === "server") {
|
|
43
|
-
headers['X-Stack-Secret-Server-Key'] = secretKey;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return headers;
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
// JWT verification helper
|
|
50
|
-
fastify.decorate('verifyAdminStackJWT', async function (accessToken) {
|
|
51
|
-
try {
|
|
52
|
-
// Add validation to ensure accessToken is a valid string
|
|
53
|
-
if (!accessToken || typeof accessToken !== 'string') {
|
|
54
|
-
fastify.log.error('Invalid admin token format: token must be a non-empty string');
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const { payload } = await jose.jwtVerify(accessToken, jwks);
|
|
59
|
-
|
|
60
|
-
// Verify the payload has expected properties
|
|
61
|
-
if (!payload || !payload.sub) {
|
|
62
|
-
fastify.log.error('Invalid admin token payload: missing required claims');
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return payload;
|
|
67
|
-
} catch (error) {
|
|
68
|
-
fastify.log.error(error);
|
|
69
|
-
return null;
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
// Admin authentication hook
|
|
74
|
-
fastify.addHook("onRequest", async (request, reply) => {
|
|
75
|
-
const url = request.url;
|
|
76
|
-
|
|
77
|
-
// Skip authentication for excluded paths
|
|
78
|
-
if (adminExcludedPaths.some((path) => url.startsWith(path))) {
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (url.startsWith("/admin")) {
|
|
83
|
-
try {
|
|
84
|
-
// Get token from header
|
|
85
|
-
const authHeader = request.headers.authorization;
|
|
86
|
-
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
87
|
-
return reply.code(401).send({ error: "Admin access token required" });
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Verify token
|
|
91
|
-
const token = authHeader.slice(7);
|
|
92
|
-
const payload = await fastify.verifyAdminStackJWT(token);
|
|
93
|
-
|
|
94
|
-
if (!payload) {
|
|
95
|
-
return reply.code(401).send({ error: "Invalid admin token" });
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Set admin info on request
|
|
99
|
-
request.admin = payload;
|
|
100
|
-
request.adminAuth = { id: payload.sub };
|
|
101
|
-
} catch (err) {
|
|
102
|
-
return reply.code(401).send({ error: "Admin authentication failed" });
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
// Admin login endpoint
|
|
108
|
-
fastify.post("/admin/auth/login", async (req, reply) => {
|
|
109
|
-
try {
|
|
110
|
-
const { email, password } = req.body;
|
|
111
|
-
|
|
112
|
-
if (!email || !password) {
|
|
113
|
-
return reply.code(400).send({ error: "Email and password required" });
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Call Stack Auth API for password sign-in
|
|
117
|
-
const response = await fetch(
|
|
118
|
-
`${stackAuthBaseUrl}/auth/password/sign-in`,
|
|
119
|
-
{
|
|
120
|
-
method: 'POST',
|
|
121
|
-
headers: fastify.getAdminStackAuthHeaders("server"),
|
|
122
|
-
body: JSON.stringify({ email, password })
|
|
123
|
-
}
|
|
124
|
-
);
|
|
125
|
-
|
|
126
|
-
const data = await response.json().catch(() => ({}));
|
|
127
|
-
|
|
128
|
-
if (!response.ok) {
|
|
129
|
-
return reply.code(response.status || 400).send({
|
|
130
|
-
error: data.message || "Authentication failed"
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Check if we have the expected response properties
|
|
135
|
-
if (!data.access_token || !data.refresh_token || !data.user_id) {
|
|
136
|
-
return reply.code(500).send({ error: "Invalid response from authentication service" });
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Verify token
|
|
140
|
-
const payload = await fastify.verifyAdminStackJWT(data.access_token);
|
|
141
|
-
if (!payload) {
|
|
142
|
-
return reply.code(401).send({ error: "Invalid token received" });
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
reply.send({
|
|
146
|
-
accessToken: data.access_token,
|
|
147
|
-
refreshToken: data.refresh_token,
|
|
148
|
-
admin: payload,
|
|
149
|
-
adminId: data.user_id
|
|
150
|
-
});
|
|
151
|
-
} catch (err) {
|
|
152
|
-
fastify.log.error(err);
|
|
153
|
-
reply.code(500).send({ error: "Internal server error" });
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
// Admin info endpoint
|
|
158
|
-
fastify.get("/admin/auth/me", async (req, reply) => {
|
|
159
|
-
reply.send(req.admin || { authenticated: false });
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
// Token verification endpoint
|
|
163
|
-
fastify.post("/admin/auth/verify", async (req, reply) => {
|
|
164
|
-
const { token } = req.body;
|
|
165
|
-
|
|
166
|
-
if (!token) {
|
|
167
|
-
return reply.code(400).send({ error: "Token required" });
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const payload = await fastify.verifyAdminStackJWT(token);
|
|
171
|
-
|
|
172
|
-
if (!payload) {
|
|
173
|
-
return reply.code(401).send({ valid: false });
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
reply.send({ valid: true, admin: payload });
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
console.info(" ✅ Auth Admin Enabled");
|
|
180
|
-
}
|
|
181
|
-
}
|
package/src/auth/portal.js
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import * as jose from "jose";
|
|
2
|
-
import fetch from "node-fetch";
|
|
3
|
-
|
|
4
|
-
export async function setupAuth(fastify, options) {
|
|
5
|
-
if (options.user?.active !== false) {
|
|
6
|
-
// Get configuration
|
|
7
|
-
const projectId = options.user.portalStackProjectId || process.env.STACK_PROJECT_ID;
|
|
8
|
-
const publishableKey = options.user.publishableKey || process.env.STACK_PUBLISHABLE_CLIENT_KEY;
|
|
9
|
-
const secretKey = options.user.secretKey || process.env.STACK_SECRET_SERVER_KEY;
|
|
10
|
-
|
|
11
|
-
if (!projectId) {
|
|
12
|
-
throw new Error("Stack Auth project ID is required");
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (!publishableKey || !secretKey) {
|
|
16
|
-
throw new Error("Stack Auth publishable and secret keys are required");
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const userExcludedPaths = options.user.excludedPaths || [
|
|
20
|
-
"/portal/auth/login",
|
|
21
|
-
"/portal/auth/logout",
|
|
22
|
-
"/portal/auth/register",
|
|
23
|
-
"/portal/auth/forgot-password",
|
|
24
|
-
"/portal/auth/reset-password"
|
|
25
|
-
];
|
|
26
|
-
|
|
27
|
-
// Base URL for Stack Auth API
|
|
28
|
-
const stackAuthBaseUrl = `https://api.stack-auth.com/api/v1`;
|
|
29
|
-
const jwksUrl = `${stackAuthBaseUrl}/projects/${projectId}/.well-known/jwks.json`;
|
|
30
|
-
|
|
31
|
-
// Create JWKS for token verification
|
|
32
|
-
const jwks = jose.createRemoteJWKSet(new URL(jwksUrl));
|
|
33
|
-
|
|
34
|
-
// Helper for Stack Auth API headers
|
|
35
|
-
fastify.decorate('getStackAuthHeaders', function (accessType = "server") {
|
|
36
|
-
const headers = {
|
|
37
|
-
'Content-Type': 'application/json',
|
|
38
|
-
'Accept': 'application/json',
|
|
39
|
-
'X-Stack-Access-Type': accessType,
|
|
40
|
-
'X-Stack-Project-Id': projectId,
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
if (accessType === "client") {
|
|
44
|
-
headers['X-Stack-Publishable-Client-Key'] = publishableKey;
|
|
45
|
-
} else if (accessType === "server") {
|
|
46
|
-
headers['X-Stack-Secret-Server-Key'] = secretKey;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return headers;
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// JWT verification helper
|
|
53
|
-
fastify.decorate('verifyStackJWT', async function (accessToken) {
|
|
54
|
-
try {
|
|
55
|
-
const { payload } = await jose.jwtVerify(accessToken, jwks);
|
|
56
|
-
return payload;
|
|
57
|
-
} catch (error) {
|
|
58
|
-
fastify.log.error(error);
|
|
59
|
-
return null;
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// API URL helper
|
|
64
|
-
fastify.decorate('getStackAuthApiUrl', function () {
|
|
65
|
-
return stackAuthBaseUrl;
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
// Authentication middleware
|
|
69
|
-
fastify.addHook("onRequest", async (request, reply) => {
|
|
70
|
-
const url = request.url;
|
|
71
|
-
|
|
72
|
-
// Skip excluded paths
|
|
73
|
-
if (userExcludedPaths.some(path => url.startsWith(path))) {
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (url.startsWith("/portal")) {
|
|
78
|
-
try {
|
|
79
|
-
// Get token from header
|
|
80
|
-
const authHeader = request.headers.authorization;
|
|
81
|
-
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
82
|
-
return reply.code(401).send({ error: "Access token required" });
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Verify token
|
|
86
|
-
const token = authHeader.slice(7);
|
|
87
|
-
const payload = await fastify.verifyStackJWT(token);
|
|
88
|
-
|
|
89
|
-
if (!payload) {
|
|
90
|
-
return reply.code(401).send({ error: "Invalid token" });
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Set user info on request
|
|
94
|
-
request.user = payload;
|
|
95
|
-
request.userAuth = { id: payload.sub };
|
|
96
|
-
} catch (err) {
|
|
97
|
-
return reply.code(401).send({ error: "Authentication failed" });
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
// Login endpoint
|
|
103
|
-
fastify.post("/portal/auth/login", async (req, reply) => {
|
|
104
|
-
try {
|
|
105
|
-
const { email, password } = req.body;
|
|
106
|
-
|
|
107
|
-
if (!email || !password) {
|
|
108
|
-
return reply.code(400).send({ error: "Email and password required" });
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Call Stack Auth API for password sign-in
|
|
112
|
-
const response = await fetch(
|
|
113
|
-
`${stackAuthBaseUrl}/auth/password/sign-in`,
|
|
114
|
-
{
|
|
115
|
-
method: 'POST',
|
|
116
|
-
headers: fastify.getStackAuthHeaders("server"),
|
|
117
|
-
body: JSON.stringify({ email, password })
|
|
118
|
-
}
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
const data = await response.json().catch(() => ({}));
|
|
122
|
-
|
|
123
|
-
if (!response.ok) {
|
|
124
|
-
return reply.code(response.status || 400).send({
|
|
125
|
-
error: data.message || "Authentication failed"
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Check if we have the expected response properties
|
|
130
|
-
if (!data.access_token || !data.refresh_token || !data.user_id) {
|
|
131
|
-
return reply.code(500).send({ error: "Invalid response from authentication service" });
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Verify token
|
|
135
|
-
const payload = await fastify.verifyStackJWT(data.access_token);
|
|
136
|
-
if (!payload) {
|
|
137
|
-
return reply.code(401).send({ error: "Invalid token received" });
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
reply.send({
|
|
141
|
-
accessToken: data.access_token,
|
|
142
|
-
refreshToken: data.refresh_token,
|
|
143
|
-
user: payload,
|
|
144
|
-
userId: data.user_id
|
|
145
|
-
});
|
|
146
|
-
} catch (err) {
|
|
147
|
-
fastify.log.error(err);
|
|
148
|
-
reply.code(500).send({ error: "Internal server error" });
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
// User info endpoint
|
|
154
|
-
fastify.get("/portal/auth/me", async (req, reply) => {
|
|
155
|
-
reply.send(req.user || { authenticated: false });
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
// Token verification endpoint
|
|
159
|
-
fastify.post("/portal/auth/verify", async (req, reply) => {
|
|
160
|
-
const { token } = req.body;
|
|
161
|
-
|
|
162
|
-
if (!token) {
|
|
163
|
-
return reply.code(400).send({ error: "Token required" });
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const payload = await fastify.verifyStackJWT(token);
|
|
167
|
-
|
|
168
|
-
if (!payload) {
|
|
169
|
-
return reply.code(401).send({ valid: false });
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
reply.send({ valid: true, user: payload });
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
console.info(" ✅ Auth User Enabled");
|
|
176
|
-
}
|
|
177
|
-
}
|