enh(general) BaseRouter docs; unified Storage; implement Cookies

This commit is contained in:
gh0sTedBuddy
2024-04-01 22:22:37 +01:00
parent 4c23fdbc37
commit 548cfb02e0
3 changed files with 212 additions and 1 deletions

View File

@@ -1,49 +1,112 @@
import Logger from '../Utils/Logger';
/**
* @class BaseRouter
* @description Base class for creating routers
*/
export default class BaseRouter {
/**
* Add a route with the specified path, callback, and options.
* @param {string} path - The route path.
* @param {function} cb - The callback function to handle the route.
* @param {object} [options={}] - Additional options for the route.
*/
add(path, cb, options = {}) {
Logger.error('add method not implemented');
throw new Error('add method not implemented!')
}
/**
* Add a route that matches any HTTP method.
* @param {string} path - The route path.
* @param {function} cb - The callback function to handle the route.
*/
any(path, cb) {
this.all(path, cb);
}
/**
* Add a route that matches all HTTP methods.
* @param {string} path - The route path.
* @param {function} cb - The callback function to handle the route.
* @returns {BaseRouter} The current instance of BaseRouter for chaining.
*/
all(path, cb) {
this.add(path, cb, { ...(arguments[2] || {}), method: 'all' });
return this;
}
/**
* Add a route that matches the GET HTTP method.
* @param {string} path - The route path.
* @param {function} cb - The callback function to handle the route.
* @returns {BaseRouter} The current instance of BaseRouter for chaining.
*/
get(path, cb) {
this.add(path, cb, { ...(arguments[2] || {}), method: 'get' });
return this;
}
/**
* Add a route that matches the POST HTTP method.
* @param {string} path - The route path.
* @param {function} cb - The callback function to handle the route.
* @returns {BaseRouter} The current instance of BaseRouter for chaining.
*/
post(path, cb) {
this.add(path, cb, { ...(arguments[2] || {}), method: 'post' });
return this;
}
/**
* Add a route that matches the PUT HTTP method.
* @param {string} path - The route path.
* @param {function} cb - The callback function to handle the route.
* @returns {BaseRouter} The current instance of BaseRouter for chaining.
*/
put(path, cb) {
this.add(path, cb, { ...(arguments[2] || {}), method: 'put' });
return this;
}
/**
* Add a route that matches the PATCH HTTP method.
* @param {string} path - The route path.
* @param {function} cb - The callback function to handle the route.
* @returns {BaseRouter} The current instance of BaseRouter for chaining.
*/
patch(path, cb) {
this.add(path, cb, { ...(arguments[2] || {}), method: 'patch' });
return this;
}
/**
* Add a route that matches the DELETE HTTP method.
* @param {string} path - The route path.
* @param {function} cb - The callback function to handle the route.
* @returns {BaseRouter} The current instance of BaseRouter for chaining.
*/
delete(path, cb) {
this.add(path, cb, { ...(arguments[2] || {}), method: 'delete' });
return this;
}
/**
* Add a route that matches the HEAD HTTP method.
* @param {string} path - The route path.
* @param {function} cb - The callback function to handle the route.
* @returns {BaseRouter} The current instance of BaseRouter for chaining.
*/
head(path, cb) {
this.add(path, cb, { ...(arguments[2] || {}), method: 'head' });
return this;
}
/**
* Add a route that matches the OPTIONS HTTP method.
* @param {string} path - The route path.
* @param {function} cb - The callback function to handle the route.
* @returns {BaseRouter} The current instance of BaseRouter for chaining.
*/
options(path, cb) {
this.add(path, cb, { ...(arguments[2] || {}), method: 'options' });
return this;

74
src/Utils/Cookie.js Normal file
View File

@@ -0,0 +1,74 @@
export default class Cookie {
/**
* Reads cookies from a Request object and returns a Map of cookie values.
* @param {Request} request - The Request object to read cookies from.
* @returns {Map} - A Map containing the cookie values.
*/
static read(request, settings = {}) {
const cookie = new Map();
if (request.headers.has('Cookie')) {
const cookiePairs = request.headers.get('Cookie').toString().split('; ');
for (const pair of cookiePairs) {
const [name, value] = pair.split('=');
cookie.set(name, decodeURIComponent(value));
}
}
Object.keys(settings).forEach(k => cookie.set(k, settings[k]));
return cookie;
}
/**
* Writes a Map of cookie values to a Response object's headers.
* @param {Response} response - The Response object to write cookies to.
* @param {object} cookies - An object containing cookie values.
* @param {object} [settings={}] - Additional cookie settings (e.g., expires, path, domain).
*/
static write(response, data, settings = {}) {
const cookiePairs = [];
for (const [name, value] of [...data]) {
const encodedValue = encodeURIComponent(value);
cookiePairs.push(`${name}=${encodedValue}`);
}
const cookieString = cookiePairs.join('; ');
let cookie = `${cookieString}`;
// Append additional cookie settings if present
for (const [settingName, settingValue] of Object.entries(settings)) {
cookie += `; ${settingName}`;
if (settingValue !== true) {
cookie += `=${settingValue}`;
}
}
response.headers.set('Set-Cookie', cookie);
}
/**
* Sets a cookie value with the specified name and optional settings.
* @param {Response} response - The Response object to set the cookie on.
* @param {string} name - The name of the cookie.
* @param {string} value - The value of the cookie.
* @param {object} [settings={}] - Additional cookie settings (e.g., expires, path, domain).
*/
static set(response, name, value, settings = {}) {
const cookies = CookieHandler.read(response.request);
cookies[name] = value;
CookieHandler.write(response, cookies, settings);
}
/**
* Deletes a cookie with the specified name by setting its expiration to a past date.
* @param {Response} response - The Response object to delete the cookie from.
* @param {string} name - The name of the cookie to delete.
*/
static delete(response, name) {
const cookies = CookieHandler.read(response.request);
delete cookies[name];
CookieHandler.write(response, cookies, { expires: new Date(0) });
}
}

74
src/Utils/Storage.js Normal file
View File

@@ -0,0 +1,74 @@
import { resolve } from 'path';
import { mkdir, exists, readdir } from 'fs/promises';
/**
* Storage class for handling file operations.
*/
export default class Storage {
#options = new Map([
['baseDir', undefined],
]);
/**
* Constructor for the Storage class.
* @param {Object|Map} options - Configuration options for the Storage instance.
*/
constructor(options) {
if(typeof options == 'object' && options.constructor?.name == 'Object') {
options = new Map(Object.entries(options));
}
for(const k of this.#options.keys()) {
if(!options.has(k)) continue;
this.#options.set(k, options.get(k));
}
}
/**
* Ensures that a directory exists at the specified path.
* @param {string} path - The path of the directory to ensure.
* @returns {Promise<void>}
*/
async ensureDir(path) {
if(!path || typeof(path) != 'string') return;
path = this.resolve(path);
if(!(await exists(path))) {
await mkdir(path, { recursive: true });
}
}
/**
* Resolves a relative path to an absolute path based on the configured base directory.
* @param {string} path - The relative path to resolve.
* @returns {string} The resolved absolute path.
*/
resolve(path) {
return resolve(this.#options.get('baseDir'), path);
}
/**
* Writes data to a file at the specified path.
* @param {string} path - The path of the file to write.
* @param {string|Buffer} data - The data to write to the file.
* @returns {Promise<void>}
*/
async write(path, data) {
path = this.resolve(path);
const file = Bun.file(path);
return await Bun.write(file, data);
}
/**
* Reads the contents of a file at the specified path.
* @param {string} path - The path of the file to read.
* @returns {Promise<string>} The contents of the file as a string.
* @throws {Error} If the file does not exist.
*/
async read(path) {
path = this.resolve(path);
const file = Bun.file(path);
if(!(await file.exists())) throw new Error('file does not exist');
return await file.text();
}
}