rjweb-server
Version:
Easy and Robust Way to create a Web Server with Many Easy-to-use Features in NodeJS
336 lines (335 loc) • 11.1 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var path_exports = {};
__export(path_exports, {
default: () => RoutePath
});
module.exports = __toCommonJS(path_exports);
var import_path = __toESM(require("../path"));
var import_types = require("util/types");
var import_parsePath = __toESM(require("../../functions/parsePath"));
var import_path2 = __toESM(require("path"));
var import_fs = __toESM(require("fs"));
var import_ws = __toESM(require("./ws"));
var import_http2 = __toESM(require("./http"));
var import_defaultHeaders = __toESM(require("./defaultHeaders"));
class RoutePath {
/** Generate Route Block */
constructor(path2, validations, headers, contexts) {
this.hasCalledGet = false;
this.httpPath = (0, import_parsePath.default)(path2);
this.routes = [];
this.statics = [];
this.webSockets = [];
this.loadPaths = [];
this.parsedHeaders = {};
this.validations = validations || [];
this.headers = headers || {};
this.externals = [];
if (Object.keys(this.headers).length > 0) {
const routeDefaultHeaders = new import_defaultHeaders.default();
this.externals.push({ object: routeDefaultHeaders });
for (const [key, value] of Object.entries(this.headers)) {
routeDefaultHeaders.add(key, value);
}
}
}
/**
* Add a Validation
* @example
* ```
* // The /api route will automatically check for correct credentials
* // Obviously still putting the prefix (in this case / from the RoutePath in front)
* const controller = new Server({ })
*
* controller.path('/api', (path) => path
* .validate(async(ctr, end) => {
* if (!ctr.headers.has('Authorization')) return end(ctr.status(401).print('Unauthorized'))
* if (ctr.headers.get('Authorization') !== 'key123 or db request ig') return end(ctr.status(401).print('Unauthorized'))
* })
* .redirect('/pics', 'https://google.com/search?q=devil')
* )
* ```
* @since 3.2.1
*/
validate(code) {
this.validations.push(code);
return this;
}
/**
* Add a HTTP Route
* @example
* ```
* controller.path('/', (path) => path
* .http('GET', '/hello', (ws) => ws
* .onRequest(async(ctr) => {
* ctr.print('Hello bro!')
* })
* )
* )
* ```
* @since 6.0.0
*/
http(method, path2, callback) {
if (this.routes.some((obj) => (0, import_types.isRegExp)(obj.path) ? false : obj.path.path === (0, import_parsePath.default)(path2)))
return this;
const routeHTTP = new import_http2.default(path2, method, this.validations, this.parsedHeaders);
this.externals.push({ object: routeHTTP, addPrefix: this.httpPath });
callback(routeHTTP);
return this;
}
/**
* Add a Websocket Route
* @example
* ```
* controller.path('/', (path) => path
* .ws('/uptime', (ws) => ws
* .onConnect(async(ctr) => {
* console.log('Connected to ws!')
* })
* .onMessage((ctr) => {
* console.log('Received message', ctr.message)
* })
* .onClose((ctr) => {
* console.log('Disconnected from ws!')
* })
* )
* )
* ```
* @since 5.4.0
*/
ws(path2, callback) {
if (this.webSockets.some((obj) => (0, import_types.isRegExp)(obj.path) ? false : obj.path.path === (0, import_parsePath.default)(path2)))
return this;
const routeWS = new import_ws.default(path2, this.validations, this.parsedHeaders);
this.externals.push({ object: routeWS, addPrefix: this.httpPath });
callback(routeWS);
return this;
}
/**
* Add Default Headers
* @example
* ```
* controller.path('/', (path) => path
* .defaultHeaders((dH) => dH
* .add('X-Api-Version', '1.0.0')
* )
* )
* ```
* @since 6.0.0
*/
defaultHeaders(callback) {
const routeDefaultHeaders = new import_defaultHeaders.default();
this.externals.push({ object: routeDefaultHeaders });
callback(routeDefaultHeaders);
this.headers = Object.assign(this.headers, routeDefaultHeaders["defaultHeaders"]);
return this;
}
/**
* Add a Redirect
* @example
* ```
* // The /devil route will automatically redirect to google.com
* // Obviously still putting the prefix (in this case / from the RoutePath in front)
* const controller = new Server({ })
*
* controller.path('/', (path) => path
* .redirect('/devil', 'https://google.com')
* .redirect('/devilpics', 'https://google.com/search?q=devil')
* )
* ```
* @since 3.1.0
*/
redirect(request, redirect) {
this.routes.push({
type: "http",
method: "GET",
path: new import_path.default("GET", (0, import_parsePath.default)([this.httpPath, request])),
onRequest: (ctr) => ctr.redirect(redirect),
data: {
validations: this.validations,
headers: this.parsedHeaders
},
context: { data: {}, keep: true }
});
return this;
}
/**
* Serve Static Files
* @example
* ```
* // All Files in "./static" will be served dynamically so they wont be loaded as routes by default
* // Due to the hideHTML Option being on files will be served differently, /index.html -> /; /about.html -> /about; /contributors/index.html -> /contributors
* const controller = new Server({ })
*
* controller.path('/', (path) => path
* .static('./static', {
* hideHTML: true, // If enabled will remove .html ending from files
* addTypes: true, // If enabled will automatically add content-types to some file endings (including the custom ones defined in the main config)
* })
* )
* ```
* @since 3.1.0
*/
static(folder, options = {}) {
const addTypes = options?.addTypes ?? true;
const compress = options?.compress ?? true;
const hideHTML = options?.hideHTML ?? false;
this.statics.push({
type: "static",
path: new import_path.default("GET", (0, import_parsePath.default)(this.httpPath)),
location: folder,
data: {
doCompress: compress,
addTypes,
hideHTML,
validations: this.validations,
headers: this.parsedHeaders
}
});
return this;
}
/**
* Load CJS Route Files
* @example
* ```
* // All Files in "./routes" ending with .js will be loaded as routes
* const controller = new Server({ })
*
* controller.path('/', (path) => path
* .loadCJS('./routes')
* )
* ```
* @since 3.1.0
*/
loadCJS(folder, options = {}) {
const fileBasedRouting = options?.fileBasedRouting ?? false;
if (!import_fs.default.existsSync(import_path2.default.resolve(folder)))
throw Error("The CJS Function folder wasnt found!");
this.loadPaths.push({
path: import_path2.default.resolve(folder),
prefix: this.httpPath,
type: "cjs",
validations: this.validations,
fileBasedRouting,
headers: this.parsedHeaders
});
return this;
}
/**
* Load ESM Route Files
* @example
* ```
* // All Files in "./routes" ending with .js will be loaded as routes
* const controller = new Server({ })
*
* controller.path('/', (path) => path
* .loadESM('./routes')
* )
* ```
* @since 4.0.0
*/
loadESM(folder, options = {}) {
const fileBasedRouting = options?.fileBasedRouting ?? false;
if (!import_fs.default.existsSync(import_path2.default.resolve(folder)))
throw Error("The ESM Function folder wasnt found!");
this.loadPaths.push({
path: import_path2.default.resolve(folder),
prefix: this.httpPath,
type: "esm",
validations: this.validations,
fileBasedRouting,
headers: this.parsedHeaders
});
return this;
}
/**
* Add a new Block of Routes with a Prefix
* @example
* ```
* const controller = new Server({ })
*
* controller.path('/', (path) => path
* .http('GET', '/cool', (http) => http
* .onRequest((ctr) => {
* ctr.print('cool!')
* })
* )
* .path('/api', (path) => path
* .context({
* version: '1.0.0'
* })
* .http('GET', '/', (http) => http
* .onRequest((ctr) => {
* ctr.print(`Welcome to the API!, Version ${ctr["@"].version}`)
* })
* )
* )
* )
* ```
* @since 5.0.0
*/
path(prefix, router) {
if ("getData" in router) {
this.externals.push({ object: router, addPrefix: (0, import_parsePath.default)([this.httpPath, prefix]) });
} else {
const routePath = new RoutePath((0, import_parsePath.default)([this.httpPath, prefix]), [...this.validations], Object.assign({}, this.headers));
this.externals.push({ object: routePath });
router(routePath);
}
return this;
}
/**
* Internal Method for Generating Routes Object
* @since 6.0.0
*/
async getData() {
if (!this.hasCalledGet)
for (const external of this.externals) {
const result = await external.object.getData(external.addPrefix ?? "/");
if ("routes" in result && result.routes.length > 0)
this.routes.push(...result.routes);
if ("webSockets" in result && result.webSockets.length > 0)
this.webSockets.push(...result.webSockets);
if ("statics" in result && result.statics.length > 0)
this.statics.push(...result.statics);
if ("loadPaths" in result && result.loadPaths.length > 0)
this.loadPaths.push(...result.loadPaths);
if ("defaultHeaders" in result)
this.parsedHeaders = Object.assign(this.parsedHeaders, result.defaultHeaders);
}
this.hasCalledGet = true;
return {
routes: this.routes,
webSockets: this.webSockets,
statics: this.statics,
loadPaths: this.loadPaths
};
}
}