diff --git a/src/LayServer.js b/src/LayServer.js index f494505..a945680 100644 --- a/src/LayServer.js +++ b/src/LayServer.js @@ -10,20 +10,20 @@ import Logger from './Utils/Logger'; /** * Represents a LayServer instance that handles routing and server configuration. - * @todo add multi domain support * @class */ export default class LayServer extends BaseRouter { #controllers = new Map(); + #cookieHandle = undefined; #loaders = new Map(); #proc = null; #publicFiles; + #viewPaths = new Set(); #routing = null; #options = new Map([ ['layout', undefined], ['loaders', undefined], ['publicDir', undefined], - ['viewsPath', undefined], ['preferIndexFiles', false], ['discoverPublicFiles', false], ['enforceTrailingSlash', false], @@ -57,6 +57,21 @@ export default class LayServer extends BaseRouter { this.loaders = options.loaders; } } + + if(options.hasOwnProperty('viewPaths')) { + if(typeof(options.viewPaths) == 'string') { + this.#viewPaths.add(options.viewPaths); + } else if (Array.isArray(options.viewPaths) || options.viewPaths instanceof Set) { + this.#viewPaths = new Set([...this.#viewPaths, ...options.viewPaths]); + } + } + + if (options.hasOwnProperty('cookieHandle')) { + if(!options.cookieHandle.hasOwnProperty('read') || options.cookieHandle.hasOwnProperty('write')) { + Logger.debug('cookie handling offers no read/write methods'); + } + this.#cookieHandle = options.cookieHandle; + } } this.#routing = new LayRouting(this); @@ -77,10 +92,6 @@ export default class LayServer extends BaseRouter { this.#options.publicDir ) this.indexPublicFiles(this.#options.publicDir); - - if (!this.#options.viewsEngine && this.#options.viewsPath) { - this.#options.viewsEngine = new HtmlEngine(); - } } /** @@ -180,13 +191,27 @@ export default class LayServer extends BaseRouter { async handleRequest(req) { const url = new URL(req.url); + if(this.#cookieHandle) { + const cookie = this.#cookieHandle.read(req, { + Domain: url.hostname, + Path: '/', + SameSite: 'Strict', + Secure: url.protocol.indexOf('https') >= 0 + }); + /** + * Retrieves the layout of the LayServer instance. + * @returns {string|undefined} - The layout of the LayServer instance, or undefined if not set. + */ + cookie.set('visits', Number(cookie.get('visits') || '') + 1); + } + if ( !url.pathname.endsWith('/') && Array.isArray(this.#publicFiles) && this.#publicFiles.length > 0 ) { let path = this.#publicFiles.find( - (v) => url.pathname.substring(1) === v + (v) => v === url.pathname.substring(1) || v.endsWith(url.pathname.substring(1)) ); if (path) { try { @@ -208,12 +233,19 @@ export default class LayServer extends BaseRouter { } } + if (this.#options.get('publicDir')) { + // console.log('LayServer.js', 'publicDir', this.#options.get('publicDir')); + } + if (this.#options.enforceTrailingSlash && !url.pathname.endsWith('/')) { return Response.redirect(`${url.toString()}/`, 302); } let resp = await this.#routing.handle(req); - if (resp instanceof Response) return resp; + if (resp instanceof Response) { + if(this.#cookieHandle && cookie instanceof Map) this.#cookieHandle.write(resp, cookie); + return resp; + } return new Response('Not Found', { status: 404 }); } @@ -255,27 +287,12 @@ export default class LayServer extends BaseRouter { * @returns {Promise} - The path of the view file, or null if not found. */ async getViewPath(filepath) { - let path = this.#options.get('viewsPath'); - if (!path.endsWith('/')) path += '/'; - - const filename = filepath.split('/').pop().toString(); - const basedir = filepath.substring(0, filepath.indexOf(filename)); - path += basedir; - if (!path.endsWith('/')) path += '/'; - - const files = await readdir(path); - for (let file of files) { - Logger( - file, - file.substring(0, file.indexOf('.')), - filename.substring(0, filename.indexOf('.')) || filename - ); - if ( - (file.substring(0, file.indexOf('.')) || file) != - (filename.substring(0, filename.indexOf('.')) || filename) - ) - continue; - return `${path}${file}`; + for(const viewPath of this.#viewPaths) { + const realPath = resolvePath(__dirname, viewPath, filepath); + const file = Bun.file(realPath); + if(await file.exists()) { + return realPath; + } } return null; @@ -303,18 +320,35 @@ export default class LayServer extends BaseRouter { return new DefaultLoader(filepath); } + /** + * Adds a route to the LayServer instance. + * @param {string} path - The path of the route. + * @param {Function} cb - The callback function for the route. + */ add(path, cb) { this.#routing.add(...arguments) } + /** + * Adds a middleware to the LayServer instance. + * @param {Function} cb - The middleware function. + */ use (cb) { this.add('*', cb, arguments[1]); } + /** + * Checks if the LayServer instance has a layout. + * @returns {boolean} - True if the LayServer instance has a layout, false otherwise. + */ hasLayout() { return typeof(this.#options.get('layout')) == 'string' && this.#options.get('layout').length > 0; } + /** + * Retrieves the layout of the LayServer instance. + * @returns {string|undefined} - The layout of the LayServer instance, or undefined if not set. + */ getLayout() { if(!this.#options.has('layout')) return undefined;