UNPKG

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
"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 }; } }