clovie 0.1.26 → 0.1.28
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/dist/{LiveReload-OGN9VlKq.js → LiveReload-PORXKqL8.js} +2 -2
- package/dist/{LiveReload-OGN9VlKq.js.map → LiveReload-PORXKqL8.js.map} +1 -1
- package/dist/{Server-ChPACc2X.js → Server-BkZZGWiq.js} +2 -2
- package/dist/{Server-ChPACc2X.js.map → Server-BkZZGWiq.js.map} +1 -1
- package/dist/cjs/{LiveReload-B9fx9nCV.cjs → LiveReload-YaB3G8c8.cjs} +2 -2
- package/dist/cjs/{LiveReload-B9fx9nCV.cjs.map → LiveReload-YaB3G8c8.cjs.map} +1 -1
- package/dist/cjs/{Server-BaCoAz1f.cjs → Server-BqbjrDXw.cjs} +2 -2
- package/dist/cjs/{Server-BaCoAz1f.cjs.map → Server-BqbjrDXw.cjs.map} +1 -1
- package/dist/cjs/{createClovie-CKxeV_aK.cjs → createClovie-bhagLY-k.cjs} +40 -21
- package/dist/cjs/createClovie-bhagLY-k.cjs.map +1 -0
- package/dist/cjs/{index-CXdRvvQ8.cjs → index-D5kY4esA.cjs} +3 -3
- package/dist/cjs/{index-CXdRvvQ8.cjs.map → index-D5kY4esA.cjs.map} +1 -1
- package/dist/cjs/index.cjs +1 -1
- package/dist/{createClovie-BxgkSnM8.js → createClovie-ChsQoilz.js} +39 -20
- package/dist/createClovie-ChsQoilz.js.map +1 -0
- package/dist/{index-DUZoyjx2.js → index-CIb3KPoa.js} +2 -2
- package/dist/{index-DUZoyjx2.js.map → index-CIb3KPoa.js.map} +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/dist/cjs/createClovie-CKxeV_aK.cjs.map +0 -1
- package/dist/createClovie-BxgkSnM8.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Server } from "socket.io";
|
|
2
2
|
|
|
3
|
-
import { S as ServiceProvider, q as queueMacrotask } from "./createClovie-
|
|
3
|
+
import { S as ServiceProvider, q as queueMacrotask } from "./createClovie-ChsQoilz.js";
|
|
4
4
|
|
|
5
5
|
import "stream";
|
|
6
6
|
|
|
@@ -92,4 +92,4 @@ class LiveReload extends ServiceProvider {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
export { LiveReload };
|
|
95
|
-
//# sourceMappingURL=LiveReload-
|
|
95
|
+
//# sourceMappingURL=LiveReload-PORXKqL8.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LiveReload-
|
|
1
|
+
{"version":3,"file":"LiveReload-PORXKqL8.js","sources":["../lib/LiveReload.js"],"sourcesContent":["import { Server as SocketIOServer } from 'socket.io';\nimport { ServiceProvider } from '@brickworks/engine';\nimport { queueMacrotask } from './utils/tasks.js';\n\nexport class LiveReload extends ServiceProvider {\n static manifest = {\n name: 'Clovie LiveReload',\n namespace: 'liveReload',\n version: '1.0.0',\n };\n\n #io;\n #reloading = false;\n\n getter () {\n return {\n io: () => this.#io,\n }\n }\n\n actions() {\n return {\n initializeServer: async (server, opts) => {\n const log = this.useContext('log');\n if (opts.mode === 'development') {\n await this.#setupSocketIO(server, log);\n }\n },\n notifyReload: () => {\n if (this.#reloading) return;\n this.#reloading = true;\n \n queueMacrotask(() => {\n this.#reloading = false;\n if (this.#io) {\n this.#io.emit('reload')\n }\n });\n },\n injectLiveReloadScript: async (renderedContent, opts) => {\n const lastBodyIndex = renderedContent.lastIndexOf('</body>');\n if (lastBodyIndex !== -1) {\n const scriptConfig = { \n mode: opts.mode || 'development', \n port: opts.port || 3000 \n };\n \n try {\n // Import live reload script dynamically \n renderedContent = renderedContent.substring(0, lastBodyIndex) + \n this.#liveReloadScript(scriptConfig) + '\\n' + \n renderedContent.substring(lastBodyIndex);\n } catch (err) {\n console.warn('⚠️ Could not load live reload script:', err.message);\n }\n }\n return renderedContent;\n }\n }\n }\n\n async #setupSocketIO(server, log) {\n try {\n // Wait a bit for server to be fully initialized\n await new Promise(resolve => setTimeout(resolve, 100));\n\n log.debug('Setting up Socket.IO...');\n \n // Configure Socket.IO with proper CORS and options\n this.#io = new SocketIOServer(server, {\n cors: {\n origin: \"*\",\n methods: [\"GET\", \"POST\"]\n },\n transports: ['polling', 'websocket'],\n allowEIO3: true\n });\n\n this.#io.on('connection', (socket) => {\n log.debug(`Client connected: ${socket.id}`);\n \n socket.on('disconnect', (reason) => {\n log.debug(`Client disconnected: ${socket.id} - ${reason}`);\n });\n \n socket.on('error', (error) => {\n log.error('Socket error:', error);\n });\n });\n\n log.info('Socket.IO server ready');\n } catch (error) {\n log.error('Error setting up Socket.IO:', error);\n }\n }\n\n #liveReloadScript = (opts) => `<!-- Live Reload Script (Development Mode Only) -->\n<script src=\"https://cdn.socket.io/4.7.4/socket.io.min.js\"></script>\n<script>\n (function() {\n const opts = ${JSON.stringify(opts)};\n \n console.log('Initializing live reload with opts:', opts);\n \n // Configure Socket.IO client with proper options\n const socket = io({\n transports: ['polling', 'websocket'],\n timeout: 20000,\n forceNew: true\n });\n \n socket.on('reload', () => {\n console.log('Live reload triggered');\n window.location.reload();\n });\n \n socket.on('connect', () => {\n console.log('Connected to live reload server');\n });\n \n socket.on('disconnect', (reason) => {\n console.log('Disconnected from live reload server:', reason);\n });\n \n socket.on('connect_error', (error) => {\n console.error('Connection error:', error);\n console.log('Retrying connection in 3 seconds...');\n setTimeout(() => {\n socket.connect();\n }, 3000);\n });\n \n socket.on('error', (error) => {\n console.error('Socket error:', error);\n });\n \n // Add connection timeout\n setTimeout(() => {\n if (!socket.connected) {\n console.warn('Live reload connection timeout - server may not be running');\n }\n }, 5000);\n })();\n</script>`;\n}"],"names":["LiveReload","ServiceProvider","static","name","namespace","version","io","reloading","getter","this","actions","initializeServer","async","server","opts","log","useContext","mode","setupSocketIO","notifyReload","queueMacrotask","emit","injectLiveReloadScript","renderedContent","lastBodyIndex","lastIndexOf","scriptConfig","port","substring","liveReloadScript","err","console","warn","message","Promise","resolve","setTimeout","debug","SocketIOServer","cors","origin","methods","transports","allowEIO3","on","socket","id","reason","error","info","JSON","stringify"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIO,MAAMA,mBAAmBC;IAC9BC,gBAAkB;QAChBC,MAAM;QACNC,WAAW;QACXC,SAAS;;IAGXC;IACAC,YAAa;IAEb,MAAAC;QACE,OAAO;YACLF,IAAI,MAAMG,MAAKH;;AAEnB;IAEA,OAAAI;QACE,OAAO;YACLC,kBAAkBC,OAAOC,QAAQC;gBAC/B,MAAMC,MAAMN,KAAKO,WAAW;gBACV,kBAAdF,KAAKG,cACDR,MAAKS,cAAeL,QAAQE;;YAGtCI,cAAc;gBACRV,MAAKF,cACTE,MAAKF,aAAa,GAElBa,eAAe;oBACbX,MAAKF,aAAa,GACdE,MAAKH,MACPG,MAAKH,GAAIe,KAAK;;;YAIpBC,wBAAwBV,OAAOW,iBAAiBT;gBAC9C,MAAMU,gBAAgBD,gBAAgBE,YAAY;gBAClD,KAAsB,MAAlBD,eAAsB;oBACxB,MAAME,eAAe;wBACnBT,MAAMH,KAAKG,QAAQ;wBACnBU,MAAMb,KAAKa,QAAQ;;oBAGrB;wBAEEJ,kBAAkBA,gBAAgBK,UAAU,GAAGJ,iBAC/Bf,MAAKoB,iBAAkBH,gBAAgB,OACvCH,gBAAgBK,UAAUJ;AAC5C,sBAAE,OAAOM;wBACPC,QAAQC,KAAK,0CAA0CF,IAAIG;AAC7D;AACF;gBACA,OAAOV;;;AAGb;IAEA,oBAAML,CAAeL,QAAQE;QAC3B;kBAEQ,IAAImB,QAAQC,WAAWC,WAAWD,SAAS,OAEjDpB,IAAIsB,MAAM;YAGV5B,MAAKH,KAAM,IAAIgC,OAAezB,QAAQ;gBACpC0B,MAAM;oBACJC,QAAQ;oBACRC,SAAS,EAAC,OAAO;;gBAEnBC,YAAY,EAAC,WAAW;gBACxBC,YAAW;gBAGblC,MAAKH,GAAIsC,GAAG,cAAeC;gBACzB9B,IAAIsB,MAAM,qBAAqBQ,OAAOC,OAEtCD,OAAOD,GAAG,cAAeG;oBACvBhC,IAAIsB,MAAM,wBAAwBQ,OAAOC,QAAQC;oBAGnDF,OAAOD,GAAG,SAAUI;oBAClBjC,IAAIiC,MAAM,iBAAiBA;;gBAI/BjC,IAAIkC,KAAK;AACX,UAAE,OAAOD;YACPjC,IAAIiC,MAAM,+BAA+BA;AAC3C;AACF;IAEAnB,kBAAqBf,QAAS,iLAIboC,KAAKC,UAAUrC;;;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as compileRoute, a as chalk, S as ServiceProvider } from "./createClovie-
|
|
1
|
+
import { c as compileRoute, a as chalk, S as ServiceProvider } from "./createClovie-ChsQoilz.js";
|
|
2
2
|
|
|
3
3
|
import http from "node:http";
|
|
4
4
|
|
|
@@ -526,4 +526,4 @@ class Server extends ServiceProvider {
|
|
|
526
526
|
}
|
|
527
527
|
|
|
528
528
|
export { Server };
|
|
529
|
-
//# sourceMappingURL=Server-
|
|
529
|
+
//# sourceMappingURL=Server-BkZZGWiq.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Server-ChPACc2X.js","sources":["../lib/Server/Kernel.js","../lib/Server/utils/httpParsing.js","../lib/Server/adapters/AdapterInterface.js","../lib/Server/adapters/HttpAdapter.js","../lib/Server/utils/serverReady.js","../lib/Server/Server.js"],"sourcesContent":["import { compileRoute } from './utils/routeMatch.js';\n\n/**\n * Kernel handles route registration and matching\n * Separates routing logic from HTTP protocol handling\n */\nexport class Kernel {\n #routes = []; // { method, path, match, handler, mode, revalidate, ... }\n #hooks = { \n onRequest: null, \n preHandler: null, \n onSend: null, \n onError: null \n };\n #staticFallback = null;\n\n constructor() { \n }\n\n /**\n * Register multiple routes at once\n * @param {Array} rawRoutes - Array of route objects\n */\n registerRoutes(rawRoutes) {\n for (const r of rawRoutes) {\n this.registerRoute(r);\n }\n }\n\n /**\n * Register a single route\n * @param {Object} route - Route object with method, path, handler, etc.\n */\n registerRoute(route) {\n const compiledRoute = {\n ...route,\n match: compileRoute(route.path)\n };\n this.#routes.push(compiledRoute);\n }\n\n /**\n * Configure hooks\n * @param {Object} hooks - Hook functions\n */\n hooks(h) { \n Object.assign(this.#hooks, h); \n }\n\n /**\n * Set static file fallback handler\n * @param {string} outputDir - Directory to serve static files from\n * @param {Function} handler - Static file handler function\n */\n setStaticFallback(outputDir, handler) {\n this.#staticFallback = { outputDir, handler };\n }\n\n /**\n * Handle a request through the routing system\n * @param {Object} ctx - Request context\n * @returns {Object} Response object\n */\n async handle(ctx) {\n let response;\n try {\n // onRequest can short-circuit\n const onReqOut = await this.#hooks.onRequest?.(ctx);\n if (onReqOut) { response = onReqOut; return response; }\n\n // route match …\n let matchParams = null;\n const route = this.#routes.find(r => {\n if (r.method !== ctx.req.method) return false;\n const m = r.match(ctx.req.path);\n if (m) { matchParams = m; return true; }\n return false;\n });\n\n if (!route) {\n if (this.#staticFallback) {\n const staticResponse = await this.#staticFallback.handler(ctx, this.#staticFallback.outputDir);\n response = (staticResponse && staticResponse.status !== 404)\n ? staticResponse\n : ctx.respond.text('Not Found', 404);\n } else {\n response = ctx.respond.text('Not Found', 404);\n }\n return response;\n }\n\n ctx.req.params = matchParams || {};\n\n // preHandler can short-circuit\n const preOut = await this.#hooks.preHandler?.(ctx, route);\n if (preOut) { response = preOut; return response; }\n\n // route handler\n response = await route.handler(ctx);\n\n } catch (err) {\n response = (await this.#hooks.onError?.(ctx, err))\n ?? ctx.respond.text('Internal Server Error', 500);\n } finally {\n await this.#hooks.onSend?.(ctx, response);\n }\n return response ?? ctx.respond.text('', 204);\n}\n\n\n /**\n * Get all registered routes\n * @returns {Array} Array of registered routes\n */\n getRoutes() {\n return this.#routes.map(route => ({\n method: route.method,\n path: route.path,\n params: route.params || [],\n compiled: true\n }));\n }\n}\n","/**\n * HTTP parsing utilities for request body and query parameters\n */\n\n/**\n * Parse request body based on content type\n * @param {Object} req - Node.js request object\n * @returns {Object|null} Parsed body object or null\n */\nexport async function parseBody(req) {\n return new Promise((resolve) => {\n if (req.method === 'GET' || req.method === 'HEAD') {\n resolve(null);\n return;\n }\n\n const contentType = req.headers['content-type'] || '';\n let body = '';\n\n req.on('data', chunk => {\n body += chunk.toString();\n });\n\n req.on('end', () => {\n try {\n if (contentType.includes('application/json')) {\n resolve(body ? JSON.parse(body) : {});\n } else if (contentType.includes('application/x-www-form-urlencoded')) {\n resolve(parseUrlEncoded(body));\n } else if (contentType.includes('multipart/form-data')) {\n // For now, just return the raw body for multipart\n // Could be enhanced with proper multipart parsing\n resolve({ raw: body });\n } else {\n resolve(body || null);\n }\n } catch (error) {\n resolve(null);\n }\n });\n\n req.on('error', () => {\n resolve(null);\n });\n });\n}\n\n/**\n * Parse URL-encoded form data\n * @param {string} data - URL-encoded string\n * @returns {Object} Parsed object\n */\nfunction parseUrlEncoded(data) {\n const result = {};\n const pairs = data.split('&');\n \n for (const pair of pairs) {\n const [key, value] = pair.split('=');\n if (key) {\n const decodedKey = decodeURIComponent(key);\n const decodedValue = value ? decodeURIComponent(value) : '';\n \n // Handle arrays (key[] or key[0])\n if (decodedKey.endsWith('[]')) {\n const arrayKey = decodedKey.slice(0, -2);\n if (!result[arrayKey]) result[arrayKey] = [];\n result[arrayKey].push(decodedValue);\n } else {\n result[decodedKey] = decodedValue;\n }\n }\n }\n \n return result;\n}\n\n/**\n * Parse query parameters from URLSearchParams\n * @param {URLSearchParams} searchParams - URL search parameters\n * @returns {Object} Parsed query object with support for arrays\n */\nexport function parseQuery(searchParams) {\n const result = {};\n \n for (const [key, value] of searchParams.entries()) {\n // Handle array parameters (key[] or key[0])\n if (key.endsWith('[]') || /\\[\\d*\\]$/.test(key)) {\n const arrayKey = key.replace(/\\[\\d*\\]$/, '').replace('[]', '');\n if (!result[arrayKey]) result[arrayKey] = [];\n result[arrayKey].push(value);\n } else {\n result[key] = value;\n }\n }\n \n return result;\n}\n","/**\n * Clovie Adapter Interface\n * \n * This defines the contract that all HTTP server adapters must implement.\n * The Clovie kernel uses this interface to delegate HTTP handling to\n * any compatible adapter (Express, Fastify, Node HTTP, etc.)\n */\nimport { parseQuery } from '../utils/httpParsing.js';\n\n/**\n * Adapter Interface - All adapters must implement this\n */\nexport class AdapterInterface {\n static create(name) {\n return new this(name);\n }\n\n constructor(name) {\n this.name = name;\n this.server = null;\n this.kernel = null;\n this.log = null;\n this.hooks = null;\n }\n\n /**\n * Initialize the adapter with kernel and context\n * @param {Object} kernel - Clovie kernel instance\n * @param {Object} log - Clovie logger\n */\n async initialize(kernel, log) {\n this.kernel = kernel;\n this.log = log;\n }\n\n /**\n * Start the HTTP server\n * @param {Object} options - Server options (port, host, etc.)\n * @returns {Promise<Object>} - Server instance\n */\n async start(options) {\n throw new Error(`start() must be implemented by ${this.name} adapter`);\n }\n\n /**\n * Stop the HTTP server\n * @returns {Promise<void>}\n */\n async stop() {\n throw new Error(`stop() must be implemented by ${this.name} adapter`);\n }\n\n /**\n * Get the underlying HTTP server instance\n * Used by services like LiveReload for Socket.IO integration\n * @returns {Object|null} - HTTP server instance\n */\n getHttpServer() {\n return this.server;\n }\n\n /**\n * Check if the server is currently running\n * @returns {boolean}\n */\n isRunning() {\n return this.server !== null;\n }\n\n /**\n * Handle a request through the adapter\n * @param {Object} req - HTTP request\n * @param {Object} res - HTTP response\n * @returns {Promise<void>}\n */\n async handleRequest(req, res) {\n throw new Error(`handleRequest() must be implemented by ${this.name} adapter`);\n }\n\n /**\n * Create standardized context object from request\n * @param {Object} req - HTTP request\n * @param {Object} res - HTTP response\n * @returns {Object} - Standardized context object\n */\n createContext(req, res) {\n const url = new URL(req.url || req.originalUrl, `http://${req.headers.host}`);\n\n return {\n req: {\n method: req.method,\n url: url.toString(),\n path: url.pathname,\n headers: Object.fromEntries(\n Object.entries(req.headers).map(([k, v]) => [k.toLowerCase(), v])\n ),\n query: req.query || parseQuery(url.searchParams),\n body: req.body || null,\n raw: { req, res },\n params: {}\n },\n res,\n respond: new RespondHelpers()\n };\n }\n\n /**\n * Send response using standardized response format\n * @param {Object} res - HTTP response\n * @param {Object} response - Response object from route handler\n * @param {boolean} isHead - Whether this is a HEAD request\n * @returns {Promise<void>}\n */\n async sendResponse(res, response, isHead = false) {\n // Default to 204 if no response object was returned\n const resp = response ?? { type: 'text', status: 204, headers: {}, body: '' };\n\n if (res.headersSent) return; // defensive guard\n\n // Set status and headers (normalize keys)\n res.statusCode = resp.status ?? 200;\n if (resp.headers) {\n for (const [k, v] of Object.entries(resp.headers)) {\n res.setHeader(k.toLowerCase(), v);\n }\n }\n\n // Respect HEAD requests: send headers only\n if (isHead) {\n return res.end();\n }\n\n switch (resp.type) {\n case 'json': {\n if (!res.getHeader('content-type')) {\n res.setHeader('content-type', 'application/json; charset=utf-8');\n }\n return res.end(JSON.stringify(resp.body));\n }\n\n case 'text': {\n if (!res.getHeader('content-type')) {\n res.setHeader('content-type', 'text/plain; charset=utf-8');\n }\n return res.end(resp.body ?? '');\n }\n\n case 'html': {\n if (!res.getHeader('content-type')) {\n res.setHeader('content-type', 'text/html; charset=utf-8');\n }\n return res.end(resp.body ?? '');\n }\n\n case 'file': {\n return await this.serveFile(res, resp.path);\n }\n\n case 'stream': {\n const b = resp.body;\n if (!b) return res.end();\n // Node stream\n if (typeof b.pipe === 'function') return b.pipe(res);\n // AsyncIterable\n if (Symbol.asyncIterator in Object(b)) {\n for await (const chunk of b) {\n if (!res.write(chunk)) {\n await new Promise(r => res.once('drain', r));\n }\n }\n return res.end();\n }\n // Fallback\n return res.end(b);\n }\n\n default:\n return res.end('');\n }\n }\n\n /**\n * Serve static files with proper MIME types and streaming\n * @param {Object} res - HTTP response\n * @param {string} filePath - Path to file to serve\n * @returns {Promise<void>}\n */\n async serveFile(res, filePath) {\n const fs = await import('node:fs');\n const fsp = await import('node:fs/promises');\n const path = await import('node:path');\n const { pipeline } = await import('node:stream');\n const { promisify } = await import('node:util');\n \n const pipelineAsync = promisify(pipeline);\n\n const MIME = {\n '.html': 'text/html; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.js': 'application/javascript; charset=utf-8',\n '.mjs': 'application/javascript; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.ico': 'image/x-icon',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n '.eot': 'application/vnd.ms-fontobject'\n };\n\n try {\n const st = await fsp.stat(filePath);\n if (!st.isFile()) {\n res.statusCode = 404;\n res.setHeader('content-type', 'text/plain; charset=utf-8');\n return res.end('Not Found');\n }\n\n const ext = path.extname(filePath).toLowerCase();\n if (!res.getHeader('content-type')) {\n res.setHeader('content-type', MIME[ext] ?? 'application/octet-stream');\n }\n res.setHeader('content-length', String(st.size));\n\n const rs = fs.createReadStream(filePath);\n rs.on('error', () => {\n if (!res.headersSent) res.statusCode = 404;\n res.end('Not Found');\n });\n await pipelineAsync(rs, res); // backpressure-aware piping\n } catch {\n if (!res.headersSent) {\n res.statusCode = 404;\n res.setHeader('content-type', 'text/plain; charset=utf-8');\n }\n res.end('Not Found');\n }\n }\n\n /**\n * Handle request errors consistently\n * @param {Object} res - HTTP response\n * @param {Error} error - Error that occurred\n * @returns {Promise<void>}\n */\n async handleError(res, error) {\n this.log?.error?.('Request handling error:', error);\n if (!res.headersSent) {\n res.statusCode = 500;\n res.setHeader('content-type', 'text/plain; charset=utf-8');\n res.end('Internal Server Error');\n }\n }\n}\n\n/**\n * Route object structure that adapters receive from Clovie kernel\n */\nexport class ClovieRoute {\n constructor(method, path, handler, options = {}) {\n this.method = method.toUpperCase();\n this.path = path;\n this.handler = handler;\n this.options = options;\n this.params = options.params || [];\n }\n}\n\n/**\n * Hook object structure for lifecycle management\n */\nexport class ClovieHooks {\n constructor() {\n this.onRequest = null;\n this.preHandler = null;\n this.onSend = null;\n this.onError = null;\n }\n}\n\n/**\n * Context object passed to route handlers\n */\nexport class ClovieContext {\n constructor(req, res, state, stable) {\n this.req = req;\n this.res = res;\n this.state = state;\n this.stable = stable;\n this.respond = new RespondHelpers();\n }\n}\n\n/**\n * Response helpers for route handlers\n */\nexport class RespondHelpers {\n json(data, status = 200, headers = {}) {\n return { type: 'json', status, headers, body: data };\n }\n\n text(data, status = 200, headers = {}) {\n return { type: 'text', status, headers, body: data };\n }\n\n html(data, status = 200, headers = {}) {\n return { type: 'html', status, headers, body: data };\n }\n\n file(path, status = 200, headers = {}) {\n return { type: 'file', status, headers, path };\n }\n\n stream(body, status = 200, headers = {}) {\n return { type: 'stream', status, headers, body };\n }\n\n redirect(location, status = 302, headers = {}) {\n return { type:'text', status, headers: { ...headers, location }, body: '' };\n }\n}\n","/**\n * HTTP Adapter for Node.js native HTTP server\n * Thin I/O shim: normalize req/res, call kernel, send response\n */\nimport http from 'node:http';\nimport { AdapterInterface } from './AdapterInterface.js';\nimport { parseBody } from '../utils/httpParsing.js';\n\nexport class HttpAdapter extends AdapterInterface {\n #connections = new Set();\n\n constructor() {\n super('http');\n }\n\n async initialize(kernel, services, log) {\n await super.initialize(kernel, services, log);\n }\n\n async start({ port = 3000, host = '0.0.0.0' } = {}) {\n this.server = http.createServer(async (req, res) => {\n try {\n // Parse body for HTTP adapter (Express handles this differently)\n if (!req.body) {\n req.body = await parseBody(req);\n }\n\n const ctx = this.createContext(req, res);\n const out = await this.kernel.handle(ctx);\n await this.sendResponse(res, out, req.method === 'HEAD');\n } catch (error) {\n await this.handleError(res, error);\n }\n });\n\n // Track connections for clean shutdown\n this.server.on('connection', (conn) => {\n this.#connections.add(conn);\n conn.on('close', () => {\n this.#connections.delete(conn);\n });\n });\n\n await new Promise((resolve, reject) =>\n this.server.listen(port, host, err => (err ? reject(err) : resolve()))\n );\n\n this.log?.info?.(`HTTP Server listening on http://${host}:${port}`);\n return this.server;\n }\n\n async stop() {\n if (this.server) {\n // Destroy all active connections\n for (const conn of this.#connections) {\n conn.destroy();\n }\n this.#connections.clear();\n\n // Close the server\n await new Promise(resolve => this.server.close(() => resolve()));\n this.server = null;\n }\n }\n\n}\n","import chalk from 'chalk';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\n\nconst execAsync = promisify(exec);\n\n/**\n * Display a pretty server ready message with clickable URL\n * @param {object} options - Server options\n * @param {number} options.port - Server port\n * @param {string} options.host - Server host\n * @param {string} options.mode - Server mode (development/production)\n * @param {object} logger - Logger instance\n */\nexport async function displayServerReady({ port, host, mode }, logger) {\n const protocol = mode === 'development' ? 'http' : 'https';\n const url = `${protocol}://${host === '0.0.0.0' ? 'localhost' : host}:${port}`;\n \n // Create a nice banner\n const banner = [\n '',\n chalk.bold.blue('╔══════════════════════════════════════════════════════════════╗'),\n chalk.bold.blue('║') + chalk.bold.white(' 🚀 Clovie Server Ready! 🚀 ') + chalk.bold.blue('║'),\n chalk.bold.blue('╠══════════════════════════════════════════════════════════════╣'),\n chalk.bold.blue('║') + chalk.white(` Mode: ${chalk.green(mode.toUpperCase())} `) + chalk.bold.blue('║'),\n chalk.bold.blue('║') + chalk.white(` URL: ${chalk.cyan.underline(url)} `) + chalk.bold.blue('║'),\n chalk.bold.blue('║') + chalk.white(` Host: ${chalk.yellow(host)}:${chalk.yellow(port)} `) + chalk.bold.blue('║'),\n chalk.bold.blue('╚══════════════════════════════════════════════════════════════╝'),\n ''\n ];\n\n // Display the banner\n banner.forEach(line => logger.info(line));\n\n // Try to open browser automatically in development mode\n if (mode === 'development') {\n try {\n await openBrowser(url);\n logger.info(chalk.green('🌐 Browser opened automatically'));\n } catch (error) {\n logger.debug('Could not open browser automatically:', error.message);\n }\n }\n\n // Display helpful commands\n const commands = [\n '',\n chalk.gray('💡 Quick Commands:'),\n chalk.gray(` • Press ${chalk.yellow('Ctrl+C')} to stop the server`),\n chalk.gray(` • Visit ${chalk.cyan(url)} to view your site`),\n chalk.gray(` • Check the console for live reload updates`),\n ''\n ];\n\n commands.forEach(line => logger.info(line));\n}\n\n/**\n * Open browser with the given URL\n * @param {string} url - URL to open\n */\nasync function openBrowser(url) {\n const platform = process.platform;\n let command;\n\n switch (platform) {\n case 'darwin': // macOS\n command = `open \"${url}\"`;\n break;\n case 'win32': // Windows\n command = `start \"${url}\"`;\n break;\n default: // Linux and others\n command = `xdg-open \"${url}\"`;\n break;\n }\n\n try {\n await execAsync(command);\n } catch (error) {\n throw new Error(`Failed to open browser: ${error.message}`);\n }\n}","import { ServiceProvider } from '@brickworks/engine';\nimport { Kernel } from './Kernel.js';\nimport { HttpAdapter } from './adapters/HttpAdapter.js';\nimport { displayServerReady } from './utils/serverReady.js';\n\nexport class Server extends ServiceProvider {\n static manifest = {\n name: 'Clovie Server',\n namespace: 'server',\n version: '1.0.0'\n };\n\n #routes = [];\n #adapter = null;\n #hooks = {\n onRequest: null,\n preHandler: null,\n onSend: null,\n onError: null\n };\n\n actions(useContext) { \n return {\n // Add a route\n add: (method, path, handler, meta = {}) => {\n this.#routes.push({\n method: method.toUpperCase(),\n path,\n handler,\n meta\n });\n },\n\n // Set server adapter\n useAdapter: (adapter) => {\n this.#adapter = adapter;\n return this;\n },\n\n // Configure hooks\n hooks: (hooks) => {\n this.#hooks = { ...this.#hooks, ...hooks };\n return this;\n },\n\n // Start listening server\n listen: async (opts = {}) => {\n const relay = useContext('relay');\n const port = opts.port || 3000;\n const host = opts.host || '0.0.0.0';\n const log = useContext('log');\n \n // Create kernel with services\n const kernel = new Kernel({\n state: useContext('state'),\n stable: useContext('stable'),\n // Add other services as needed for ISR/static/SSR\n });\n\n // Configure kernel hooks\n kernel.hooks(this.#hooks);\n\n // 1) Register app routes first\n kernel.registerRoutes(this.#routes);\n\n // 2) Add system routes (won't shadow user routes)\n kernel.registerRoutes([\n {\n method: 'GET',\n path: '/health',\n handler: (ctx) => ctx.respond.json({\n status: 'ok',\n timestamp: new Date().toISOString(),\n mode: opts.mode || 'production'\n })\n },\n {\n method: 'GET',\n path: '/api/info',\n handler: (ctx) => ctx.respond.json({\n name: 'Clovie',\n version: '1.0.0',\n mode: opts.mode || 'production',\n routes: this.#routes.length\n })\n }\n ]);\n\n // 3) Configure static file serving as 404 fallback\n if (opts.outputDir) {\n kernel.setStaticFallback(opts.outputDir, (ctx, outputDir) => {\n return this.#serveStaticFile(ctx, outputDir);\n });\n }\n\n // 4) Boot adapter\n this.#adapter = this.#adapter ?? HttpAdapter.create();\n await this.#adapter.initialize(kernel, log);\n \n // Start the server and return the instance\n const server = await this.#adapter.start({ port, host });\n \n // Check for LiveReload service and initialize it if available\n try {\n const liveReload = useContext('liveReload');\n log.debug(`LiveReload service found: ${!!liveReload}, mode: ${opts.mode}`);\n if (liveReload && opts.mode === 'development') {\n log.info('Initializing LiveReload...');\n await liveReload.initializeServer(server, opts);\n log.info('LiveReload initialized successfully');\n }\n } catch (error) {\n log.debug('LiveReload not available:', error.message);\n }\n \n // Display pretty server ready message\n const actualPort = server.address()?.port || port;\n await displayServerReady({ \n port: actualPort, \n host, \n mode: opts.mode || 'production' \n }, log);\n \n // Broadcast server ready event\n relay.broadcast('server:ready', server);\n return server;\n },\n\n // Get all routes\n getRoutes: () => this.#routes,\n\n // Clear all routes (useful for testing)\n clearRoutes: () => {\n this.#routes = [];\n },\n\n // Stop the server\n stop: async () => {\n if (this.#adapter) {\n await this.#adapter.stop();\n }\n },\n\n // Check if server is running\n isRunning: () => this.#adapter && this.#adapter.isRunning(),\n\n // Get the underlying HTTP server (for Socket.IO integration)\n getHttpServer: () => {\n if (this.#adapter) {\n return this.#adapter.getHttpServer();\n }\n return null;\n }\n };\n }\n /**\n * Serve static files from the output directory\n * @private\n */\n async #serveStaticFile(context, outputDir) {\n const fs = await import('fs/promises');\n const path = await import('path');\n \n try {\n // Get the requested file path\n const requestPath = context.req.path === '/' ? '/index.html' : context.req.path;\n let filePath = path.join(outputDir, requestPath);\n let stats;\n \n try {\n // Try the path as-is first\n stats = await fs.stat(filePath);\n } catch (error) {\n // If it fails and has no extension, try adding .html\n const ext = path.extname(requestPath);\n if (!ext) {\n const htmlPath = path.join(outputDir, `${requestPath}.html`);\n try {\n stats = await fs.stat(htmlPath);\n filePath = htmlPath; // Use the .html version\n } catch (htmlError) {\n // Neither worked, return 404\n return context.respond.text('Not Found', 404);\n }\n } else {\n // Had an extension but file not found\n return context.respond.text('Not Found', 404);\n }\n }\n \n if (stats.isFile()) {\n // Determine content type\n const ext = path.extname(filePath);\n const contentType = this.#getContentType(ext);\n \n // Read and serve the file\n const content = await fs.readFile(filePath);\n \n // Serve with correct content type\n if (contentType === 'text/html') {\n return context.respond.html(content.toString(), 200);\n } else if (contentType === 'text/css') {\n return context.respond.text(content.toString(), 200, { 'Content-Type': 'text/css' });\n } else if (contentType === 'application/javascript') {\n return context.respond.text(content.toString(), 200, { 'Content-Type': 'application/javascript' });\n } else if (contentType.startsWith('text/')) {\n return context.respond.text(content.toString(), 200, { 'Content-Type': contentType });\n } else {\n // For binary files, send as file response\n return context.respond.file(filePath, 200, { 'Content-Type': contentType });\n }\n } else {\n return context.respond.text('Not Found', 404);\n }\n } catch (error) {\n return context.respond.text('Not Found', 404);\n }\n }\n\n /**\n * Get content type based on file extension\n * @private\n */\n #getContentType(ext) {\n const types = {\n '.html': 'text/html',\n '.css': 'text/css',\n '.js': 'application/javascript',\n '.json': 'application/json',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.ico': 'image/x-icon',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n '.eot': 'application/vnd.ms-fontobject'\n };\n \n return types[ext.toLowerCase()] || 'application/octet-stream';\n }\n}"],"names":["Kernel","routes","hooks","onRequest","preHandler","onSend","onError","staticFallback","constructor","registerRoutes","rawRoutes","r","this","registerRoute","route","compiledRoute","match","compileRoute","path","push","h","Object","assign","setStaticFallback","outputDir","handler","handle","ctx","response","onReqOut","matchParams","find","method","req","m","staticResponse","status","respond","text","params","preOut","err","getRoutes","map","compiled","async","parseBody","Promise","resolve","contentType","headers","body","on","chunk","toString","includes","JSON","parse","data","result","pairs","split","pair","key","value","decodedKey","decodeURIComponent","decodedValue","endsWith","arrayKey","slice","parseUrlEncoded","raw","error","parseQuery","searchParams","entries","test","replace","AdapterInterface","create","name","server","kernel","log","initialize","start","options","Error","stop","getHttpServer","isRunning","handleRequest","res","createContext","url","URL","originalUrl","host","pathname","fromEntries","k","v","toLowerCase","query","RespondHelpers","sendResponse","isHead","resp","type","headersSent","statusCode","setHeader","end","getHeader","stringify","serveFile","b","pipe","Symbol","asyncIterator","write","once","filePath","fs","import","fsp","pipeline","promisify","pipelineAsync","MIME","st","stat","isFile","ext","extname","String","size","rs","createReadStream","handleError","json","html","file","stream","redirect","location","HttpAdapter","connections","Set","super","services","port","http","createServer","out","conn","add","delete","reject","listen","info","destroy","clear","close","execAsync","exec","displayServerReady","mode","logger","chalk","bold","blue","white","green","toUpperCase","cyan","underline","yellow","forEach","line","command","process","platform","message","openBrowser","debug","gray","Server","ServiceProvider","static","namespace","version","adapter","actions","useContext","meta","useAdapter","opts","relay","state","stable","timestamp","Date","toISOString","length","serveStaticFile","liveReload","initializeServer","actualPort","address","broadcast","clearRoutes","context","requestPath","stats","join","htmlPath","htmlError","getContentType","content","readFile","startsWith"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMO,MAAMA;IACXC,QAAU;IACVC,OAAS;QACPC,WAAW;QACXC,YAAY;QACZC,QAAQ;QACRC,SAAS;;IAEXC,gBAAkB;IAElB,WAAAC,IACA;IAMA,cAAAC,CAAeC;QACb,KAAK,MAAMC,KAAKD,WACdE,KAAKC,cAAcF;AAEvB;IAMA,aAAAE,CAAcC;QACZ,MAAMC,gBAAgB;eACjBD;YACHE,OAAOC,aAAaH,MAAMI;;QAE5BN,MAAKX,OAAQkB,KAAKJ;AACpB;IAMA,KAAAb,CAAMkB;QACJC,OAAOC,OAAOV,MAAKV,OAAQkB;AAC7B;IAOA,iBAAAG,CAAkBC,WAAWC;QAC3Bb,MAAKL,iBAAkB;YAAEiB;YAAWC;;AACtC;IAOA,YAAMC,CAAOC;QACb,IAAIC;QACJ;YAEE,MAAMC,kBAAiBjB,MAAKV,MAAOC,YAAYwB;YAC/C,IAAIE,UAAiC,OAArBD,WAAWC,UAAiBD;YAG5C,IAAIE,cAAc;YAClB,MAAMhB,QAAQF,MAAKX,OAAQ8B,KAAKpB;gBAC9B,IAAIA,EAAEqB,WAAWL,IAAIM,IAAID,QAAQ,QAAO;gBACxC,MAAME,IAAIvB,EAAEK,MAAMW,IAAIM,IAAIf;gBAC1B,SAAIgB,MAAKJ,cAAcI,IAAU;;YAInC,KAAKpB,OAAO;gBACV,IAAIF,MAAKL,gBAAiB;oBACxB,MAAM4B,uBAAuBvB,MAAKL,eAAgBkB,QAAQE,KAAKf,MAAKL,eAAgBiB;oBACpFI,WAAYO,kBAA4C,QAA1BA,eAAeC,SACzCD,iBACAR,IAAIU,QAAQC,KAAK,aAAa;AACpC,uBACEV,WAAWD,IAAIU,QAAQC,KAAK,aAAa;gBAE3C,OAAOV;AACT;YAEAD,IAAIM,IAAIM,SAAST,eAAe,CAAA;YAGhC,MAAMU,gBAAe5B,MAAKV,MAAOE,aAAauB,KAAKb;YACnD,IAAI0B,QAA6B,OAAnBZ,WAAWY,QAAeZ;YAGxCA,iBAAiBd,MAAMW,QAAQE;AAEjC,UAAE,OAAOc;YACPb,kBAAkBhB,MAAKV,MAAOI,UAAUqB,KAAKc,SACxCd,IAAIU,QAAQC,KAAK,yBAAyB;AACjD,UAAC;mBACO1B,MAAKV,MAAOG,SAASsB,KAAKC;AAClC;QACA,OAAOA,YAAYD,IAAIU,QAAQC,KAAK,IAAI;AAC1C;IAOE,SAAAI;QACE,OAAO9B,MAAKX,OAAQ0C,IAAI7B,UAAK;YAC3BkB,QAAQlB,MAAMkB;YACdd,MAAMJ,MAAMI;YACZqB,QAAQzB,MAAMyB,UAAU;YACxBK,WAAU;;AAEd;;;AChHKC,eAAeC,UAAUb;IAC9B,OAAO,IAAIc,QAASC;QAClB,IAAmB,UAAff,IAAID,UAAmC,WAAfC,IAAID,QAE9B,YADAgB,QAAQ;QAIV,MAAMC,cAAchB,IAAIiB,QAAQ,mBAAmB;QACnD,IAAIC,OAAO;QAEXlB,IAAImB,GAAG,QAAQC;YACbF,QAAQE,MAAMC;YAGhBrB,IAAImB,GAAG,OAAO;YACZ;gBACMH,YAAYM,SAAS,sBACvBP,QAAQG,OAAOK,KAAKC,MAAMN,QAAQ,CAAA,KACzBF,YAAYM,SAAS,uCAC9BP,QAwBV,SAAyBU;oBACvB,MAAMC,SAAS,CAAA,GACTC,QAAQF,KAAKG,MAAM;oBAEzB,KAAK,MAAMC,QAAQF,OAAO;wBACxB,OAAOG,KAAKC,SAASF,KAAKD,MAAM;wBAChC,IAAIE,KAAK;4BACP,MAAME,aAAaC,mBAAmBH,MAChCI,eAAeH,QAAQE,mBAAmBF,SAAS;4BAGzD,IAAIC,WAAWG,SAAS,OAAO;gCAC7B,MAAMC,WAAWJ,WAAWK,MAAM,IAAG;gCAChCX,OAAOU,cAAWV,OAAOU,YAAY,KAC1CV,OAAOU,UAAUlD,KAAKgD;AACxB,mCACER,OAAOM,cAAcE;AAEzB;AACF;oBAEA,OAAOR;AACT,iBA9CkBY,CAAgBpB,SACfF,YAAYM,SAAS,yBAG9BP,QAAQ;oBAAEwB,KAAKrB;qBAEfH,QAAQG,QAAQ;AAEpB,cAAE,OAAOsB;gBACPzB,QAAQ;AACV;YAGFf,IAAImB,GAAG,SAAS;YACdJ,QAAQ;;;AAGd;;AAoCO,SAAS0B,WAAWC;IACzB,MAAMhB,SAAS,CAAA;IAEf,KAAK,OAAOI,KAAKC,UAAUW,aAAaC,WAEtC,IAAIb,IAAIK,SAAS,SAAS,WAAWS,KAAKd,MAAM;QAC9C,MAAMM,WAAWN,IAAIe,QAAQ,YAAY,IAAIA,QAAQ,MAAM;QACtDnB,OAAOU,cAAWV,OAAOU,YAAY,KAC1CV,OAAOU,UAAUlD,KAAK6C;AACxB,WACEL,OAAOI,OAAOC;IAIlB,OAAOL;AACT;;ACpFO,MAAMoB;IACX,aAAOC,CAAOC;QACZ,OAAO,IAAIrE,KAAKqE;AAClB;IAEA,WAAAzE,CAAYyE;QACVrE,KAAKqE,OAAOA,MACZrE,KAAKsE,SAAS,MACdtE,KAAKuE,SAAS,MACdvE,KAAKwE,MAAM,MACXxE,KAAKV,QAAQ;AACf;IAOA,gBAAMmF,CAAWF,QAAQC;QACvBxE,KAAKuE,SAASA,QACdvE,KAAKwE,MAAMA;AACb;IAOA,WAAME,CAAMC;QACV,MAAM,IAAIC,MAAM,kCAAkC5E,KAAKqE;AACzD;IAMA,UAAMQ;QACJ,MAAM,IAAID,MAAM,iCAAiC5E,KAAKqE;AACxD;IAOA,aAAAS;QACE,OAAO9E,KAAKsE;AACd;IAMA,SAAAS;QACE,OAAuB,SAAhB/E,KAAKsE;AACd;IAQA,mBAAMU,CAAc3D,KAAK4D;QACvB,MAAM,IAAIL,MAAM,0CAA0C5E,KAAKqE;AACjE;IAQA,aAAAa,CAAc7D,KAAK4D;QACjB,MAAME,MAAM,IAAIC,IAAI/D,IAAI8D,OAAO9D,IAAIgE,aAAa,UAAUhE,IAAIiB,QAAQgD;QAEtE,OAAO;YACLjE,KAAK;gBACHD,QAAQC,IAAID;gBACZ+D,KAAKA,IAAIzC;gBACTpC,MAAM6E,IAAII;gBACVjD,SAAS7B,OAAO+E,YACd/E,OAAOuD,QAAQ3C,IAAIiB,SAASP,IAAI,EAAE0D,GAAGC,OAAO,EAACD,EAAEE,eAAeD;gBAEhEE,OAAOvE,IAAIuE,SAAS9B,WAAWqB,IAAIpB;gBACnCxB,MAAMlB,IAAIkB,QAAQ;gBAClBqB,KAAK;oBAAEvC;oBAAK4D;;gBACZtD,QAAQ,CAAA;;YAEVsD;YACAxD,SAAS,IAAIoE;;AAEjB;IASA,kBAAMC,CAAab,KAAKjE,UAAU+E,UAAS;QAEzC,MAAMC,OAAOhF,YAAY;YAAEiF,MAAM;YAAQzE,QAAQ;YAAKc,SAAS;YAAIC,MAAM;;QAEzE,KAAI0C,IAAIiB,aAAR;YAIA,IADAjB,IAAIkB,aAAaH,KAAKxE,UAAU,KAC5BwE,KAAK1D,SACP,KAAK,OAAOmD,GAAGC,MAAMjF,OAAOuD,QAAQgC,KAAK1D,UACvC2C,IAAImB,UAAUX,EAAEE,eAAeD;YAKnC,IAAIK,QACF,OAAOd,IAAIoB;YAGb,QAAQL,KAAKC;cACX,KAAK;gBAIH,OAHKhB,IAAIqB,UAAU,mBACjBrB,IAAImB,UAAU,gBAAgB;gBAEzBnB,IAAIoB,IAAIzD,KAAK2D,UAAUP,KAAKzD;;cAGrC,KAAK;gBAIH,OAHK0C,IAAIqB,UAAU,mBACjBrB,IAAImB,UAAU,gBAAgB;gBAEzBnB,IAAIoB,IAAIL,KAAKzD,QAAQ;;cAG9B,KAAK;gBAIH,OAHK0C,IAAIqB,UAAU,mBACjBrB,IAAImB,UAAU,gBAAgB;gBAEzBnB,IAAIoB,IAAIL,KAAKzD,QAAQ;;cAG9B,KAAK;gBACH,aAAavC,KAAKwG,UAAUvB,KAAKe,KAAK1F;;cAGxC,KAAK;gBAAU;oBACb,MAAMmG,IAAIT,KAAKzD;oBACf,KAAKkE,GAAG,OAAOxB,IAAIoB;oBAEnB,IAAsB,qBAAXI,EAAEC,MAAqB,OAAOD,EAAEC,KAAKzB;oBAEhD,IAAI0B,OAAOC,iBAAiBnG,OAAOgG,IAAI;wBACrC,WAAW,MAAMhE,SAASgE,GACnBxB,IAAI4B,MAAMpE,gBACP,IAAIN,QAAQpC,KAAKkF,IAAI6B,KAAK,SAAS/G;wBAG7C,OAAOkF,IAAIoB;AACb;oBAEA,OAAOpB,IAAIoB,IAAII;AACjB;;cAEA;gBACE,OAAOxB,IAAIoB,IAAI;;AA5DE;AA8DvB;IAQA,eAAMG,CAAUvB,KAAK8B;QACnB,MAAMC,WAAWC,OAAO,YAClBC,YAAYD,OAAO,qBACnB3G,aAAa2G,OAAO,eACpBE,UAAEA,kBAAmBF,OAAO,iBAC5BG,WAAEA,mBAAoBH,OAAO,cAE7BI,gBAAgBD,UAAUD,WAE1BG,OAAO;YACX,SAAS;YACT,QAAQ;YACR,OAAO;YACP,QAAQ;YACR,SAAS;YACT,QAAQ;YACR,QAAQ;YACR,QAAQ;YACR,SAAS;YACT,QAAQ;YACR,QAAQ;YACR,SAAS;YACT,UAAU;YACV,QAAQ;YACR,QAAQ;;QAGV;YACE,MAAMC,WAAWL,IAAIM,KAAKT;YAC1B,KAAKQ,GAAGE,UAGN,OAFAxC,IAAIkB,aAAa,KACjBlB,IAAImB,UAAU,gBAAgB;YACvBnB,IAAIoB,IAAI;YAGjB,MAAMqB,MAAMpH,KAAKqH,QAAQZ,UAAUpB;YAC9BV,IAAIqB,UAAU,mBACjBrB,IAAImB,UAAU,gBAAgBkB,KAAKI,QAAQ;YAE7CzC,IAAImB,UAAU,kBAAkBwB,OAAOL,GAAGM;YAE1C,MAAMC,KAAKd,GAAGe,iBAAiBhB;YAC/Be,GAAGtF,GAAG,SAAS;gBACRyC,IAAIiB,gBAAajB,IAAIkB,aAAa,MACvClB,IAAIoB,IAAI;sBAEJgB,cAAcS,IAAI7C;AAC1B,UAAE;YACKA,IAAIiB,gBACPjB,IAAIkB,aAAa,KACjBlB,IAAImB,UAAU,gBAAgB;YAEhCnB,IAAIoB,IAAI;AACV;AACF;IAQA,iBAAM2B,CAAY/C,KAAKpB;QACrB7D,KAAKwE,KAAKX,QAAQ,2BAA2BA,QACxCoB,IAAIiB,gBACPjB,IAAIkB,aAAa;QACjBlB,IAAImB,UAAU,gBAAgB,8BAC9BnB,IAAIoB,IAAI;AAEZ;;;AA4CK,MAAMR;IACX,IAAAoC,CAAKnF,MAAMtB,SAAS,KAAKc,UAAU,CAAA;QACjC,OAAO;YAAE2D,MAAM;YAAQzE;YAAQc;YAASC,MAAMO;;AAChD;IAEA,IAAApB,CAAKoB,MAAMtB,SAAS,KAAKc,UAAU,CAAA;QACjC,OAAO;YAAE2D,MAAM;YAAQzE;YAAQc;YAASC,MAAMO;;AAChD;IAEA,IAAAoF,CAAKpF,MAAMtB,SAAS,KAAKc,UAAU,CAAA;QACjC,OAAO;YAAE2D,MAAM;YAAQzE;YAAQc;YAASC,MAAMO;;AAChD;IAEA,IAAAqF,CAAK7H,MAAMkB,SAAS,KAAKc,UAAU,CAAA;QACjC,OAAO;YAAE2D,MAAM;YAAQzE;YAAQc;YAAShC;;AAC1C;IAEA,MAAA8H,CAAO7F,MAAMf,SAAS,KAAKc,UAAU,CAAA;QACnC,OAAO;YAAE2D,MAAM;YAAUzE;YAAQc;YAASC;;AAC5C;IAEA,QAAA8F,CAASC,UAAU9G,SAAS,KAAKc,UAAU,CAAA;QACzC,OAAO;YAAE2D,MAAK;YAAQzE;YAAQc,SAAS;mBAAKA;gBAASgG;;YAAY/F,MAAM;;AACzE;;;AC3TK,MAAMgG,oBAAoBpE;IAC/BqE,aAAe,IAAIC;IAEnB,WAAA7I;QACE8I,MAAM;AACR;IAEA,gBAAMjE,CAAWF,QAAQoE,UAAUnE;cAC3BkE,MAAMjE,WAAWF,QAAQoE,UAAUnE;AAC3C;IAEA,WAAME,EAAMkE,MAAEA,OAAO,KAAItD,MAAEA,OAAO,aAAc;QA6B9C,OA5BAtF,KAAKsE,SAASuE,KAAKC,aAAa7G,OAAOZ,KAAK4D;YAC1C;gBAEO5D,IAAIkB,SACPlB,IAAIkB,aAAaL,UAAUb;gBAG7B,MAAMN,MAAMf,KAAKkF,cAAc7D,KAAK4D,MAC9B8D,YAAY/I,KAAKuE,OAAOzD,OAAOC;sBAC/Bf,KAAK8F,aAAab,KAAK8D,KAAoB,WAAf1H,IAAID;AACxC,cAAE,OAAOyC;sBACD7D,KAAKgI,YAAY/C,KAAKpB;AAC9B;YAIF7D,KAAKsE,OAAO9B,GAAG,cAAewG;YAC5BhJ,MAAKwI,YAAaS,IAAID,OACtBA,KAAKxG,GAAG,SAAS;gBACfxC,MAAKwI,YAAaU,OAAOF;;kBAIvB,IAAI7G,QAAQ,CAACC,SAAS+G,WAC1BnJ,KAAKsE,OAAO8E,OAAOR,MAAMtD,MAAMzD,OAAQA,MAAMsH,OAAOtH,OAAOO;QAG7DpC,KAAKwE,KAAK6E,OAAO,mCAAmC/D,QAAQsD,SACrD5I,KAAKsE;AACd;IAEA,UAAMO;QACJ,IAAI7E,KAAKsE,QAAQ;YAEf,KAAK,MAAM0E,QAAQhJ,MAAKwI,aACtBQ,KAAKM;YAEPtJ,MAAKwI,YAAae,eAGZ,IAAIpH,QAAQC,WAAWpC,KAAKsE,OAAOkF,MAAM,MAAMpH;YACrDpC,KAAKsE,SAAS;AAChB;AACF;;;AC3DF,MAAMmF,YAAYrC,UAAUsC;;AAUrBzH,eAAe0H,oBAAmBf,MAAEA,MAAItD,MAAEA,MAAIsE,MAAEA,OAAQC;IAC7D,MACM1E,MAAM,GADc,kBAATyE,OAAyB,SAAS,aACb,cAATtE,OAAqB,cAAcA,QAAQsD;IAmBxE,IAhBe,EACb,IACAkB,MAAMC,KAAKC,KAAK,qEAChBF,MAAMC,KAAKC,KAAK,OAAOF,MAAMC,KAAKE,MAAM,wEAAwEH,MAAMC,KAAKC,KAAK,MAChIF,MAAMC,KAAKC,KAAK,qEAChBF,MAAMC,KAAKC,KAAK,OAAOF,MAAMG,MAAM,eAAeH,MAAMI,MAAMN,KAAKO,wDAAwDL,MAAMC,KAAKC,KAAK,MAC3IF,MAAMC,KAAKC,KAAK,OAAOF,MAAMG,MAAM,eAAeH,MAAMM,KAAKC,UAAUlF,8BAA8B2E,MAAMC,KAAKC,KAAK,MACrHF,MAAMC,KAAKC,KAAK,OAAOF,MAAMG,MAAM,eAAeH,MAAMQ,OAAOhF,SAASwE,MAAMQ,OAAO1B,+CAA+CkB,MAAMC,KAAKC,KAAK,MACpJF,MAAMC,KAAKC,KAAK,qEAChB,KAIKO,QAAQC,QAAQX,OAAOR,KAAKmB;IAGtB,kBAATZ,MACF;cAyBJ3H,eAA2BkD;YAEzB,IAAIsF;YAEJ,QAHiBC,QAAQC;cAIvB,KAAK;gBACHF,UAAU,SAAStF;gBACnB;;cACF,KAAK;gBACHsF,UAAU,UAAUtF;gBACpB;;cACF;gBACEsF,UAAU,aAAatF;;YAI3B;sBACQsE,UAAUgB;AAClB,cAAE,OAAO5G;gBACP,MAAM,IAAIe,MAAM,2BAA2Bf,MAAM+G;AACnD;AACF,SA7CYC,CAAY1F,MAClB0E,OAAOR,KAAKS,MAAMI,MAAM;AAC1B,MAAE,OAAOrG;QACPgG,OAAOiB,MAAM,yCAAyCjH,MAAM+G;AAC9D;IAIe,EACf,IACAd,MAAMiB,KAAK,uBACXjB,MAAMiB,KAAK,cAAcjB,MAAMQ,OAAO,iCACtCR,MAAMiB,KAAK,cAAcjB,MAAMM,KAAKjF,2BACpC2E,MAAMiB,KAAK,mDACX,KAGOR,QAAQC,QAAQX,OAAOR,KAAKmB;AACvC;;AClDO,MAAMQ,eAAeC;IAC1BC,gBAAkB;QAChB7G,MAAM;QACN8G,WAAW;QACXC,SAAS;;IAGX/L,QAAU;IACVgM,SAAW;IACX/L,OAAS;QACPC,WAAW;QACXC,YAAY;QACZC,QAAQ;QACRC,SAAS;;IAGX,OAAA4L,CAAQC;QACN,OAAO;YAELtC,KAAK,CAAC7H,QAAQd,MAAMO,SAAS2K,OAAO,CAAA;gBAClCxL,MAAKX,OAAQkB,KAAK;oBAChBa,QAAQA,OAAO+I;oBACf7J;oBACAO;oBACA2K;;;YAKJC,YAAaJ,YACXrL,MAAKqL,UAAWA,SACTrL;YAITV,OAAQA,UACNU,MAAKV,QAAS;mBAAKU,MAAKV;mBAAWA;eAC5BU;YAIToJ,QAAQnH,OAAOyJ,OAAO;gBACpB,MAAMC,QAAQJ,WAAW,UACnB3C,OAAO8C,KAAK9C,QAAQ,KACpBtD,OAAOoG,KAAKpG,QAAQ,WACpBd,MAAM+G,WAAW,QAGjBhH,SAAS,IAAInF,OAAO;oBACxBwM,OAAOL,WAAW;oBAClBM,QAAQN,WAAW;;gBAKrBhH,OAAOjF,MAAMU,MAAKV,QAGlBiF,OAAO1E,eAAeG,MAAKX,SAG3BkF,OAAO1E,eAAe,EACpB;oBACEuB,QAAQ;oBACRd,MAAM;oBACNO,SAAUE,OAAQA,IAAIU,QAAQwG,KAAK;wBACjCzG,QAAQ;wBACRsK,YAAW,IAAIC,MAAOC;wBACtBpC,MAAM8B,KAAK9B,QAAQ;;mBAGvB;oBACExI,QAAQ;oBACRd,MAAM;oBACNO,SAAUE,OAAQA,IAAIU,QAAQwG,KAAK;wBACjC5D,MAAM;wBACN+G,SAAS;wBACTxB,MAAM8B,KAAK9B,QAAQ;wBACnBvK,QAAQW,MAAKX,OAAQ4M;;sBAMvBP,KAAK9K,aACP2D,OAAO5D,kBAAkB+K,KAAK9K,WAAW,CAACG,KAAKH,cACtCZ,MAAKkM,gBAAiBnL,KAAKH;gBAKtCZ,MAAKqL,UAAWrL,MAAKqL,WAAY9C,YAAYnE,gBACvCpE,MAAKqL,QAAS5G,WAAWF,QAAQC;gBAGvC,MAAMF,eAAetE,MAAKqL,QAAS3G,MAAM;oBAAEkE;oBAAMtD;;gBAGjD;oBACE,MAAM6G,aAAaZ,WAAW;oBAC9B/G,IAAIsG,MAAM,+BAA+BqB,qBAAqBT,KAAK9B,SAC/DuC,cAA4B,kBAAdT,KAAK9B,SACrBpF,IAAI6E,KAAK;0BACH8C,WAAWC,iBAAiB9H,QAAQoH,OAC1ClH,IAAI6E,KAAK;AAEb,kBAAE,OAAOxF;oBACPW,IAAIsG,MAAM,6BAA6BjH,MAAM+G;AAC/C;gBAGA,MAAMyB,aAAa/H,OAAOgI,WAAW1D,QAAQA;gBAS7C,aARMe,mBAAmB;oBACvBf,MAAMyD;oBACN/G;oBACAsE,MAAM8B,KAAK9B,QAAQ;mBAClBpF,MAGHmH,MAAMY,UAAU,gBAAgBjI,SACzBA;;YAITxC,WAAW,MAAM9B,MAAKX;YAGtBmN,aAAa;gBACXxM,MAAKX,SAAU;;YAIjBwF,MAAM5C;gBACAjC,MAAKqL,iBACDrL,MAAKqL,QAASxG;;YAKxBE,WAAW,MAAM/E,MAAKqL,WAAYrL,MAAKqL,QAAStG;YAGhDD,eAAe,MACT9E,MAAKqL,UACArL,MAAKqL,QAASvG,kBAEhB;;AAGb;IAKA,sBAAMoH,CAAiBO,SAAS7L;QAC9B,MAAMoG,WAAWC,OAAO,gBAClB3G,aAAa2G,OAAO;QAE1B;YAEE,MAAMyF,cAAmC,QAArBD,QAAQpL,IAAIf,OAAe,gBAAgBmM,QAAQpL,IAAIf;YAC3E,IACIqM,OADA5F,WAAWzG,KAAKsM,KAAKhM,WAAW8L;YAGpC;gBAEEC,cAAc3F,GAAGQ,KAAKT;AACxB,cAAE,OAAOlD;gBAGP,IADYvD,KAAKqH,QAAQ+E,cAYvB,OAAOD,QAAQhL,QAAQC,KAAK,aAAa;gBAXjC;oBACR,MAAMmL,WAAWvM,KAAKsM,KAAKhM,WAAW,GAAG8L;oBACzC;wBACEC,cAAc3F,GAAGQ,KAAKqF,WACtB9F,WAAW8F;AACb,sBAAE,OAAOC;wBAEP,OAAOL,QAAQhL,QAAQC,KAAK,aAAa;AAC3C;AACF;AAIF;YAEA,IAAIiL,MAAMlF,UAAU;gBAElB,MAAMC,MAAMpH,KAAKqH,QAAQZ,WACnB1E,cAAcrC,MAAK+M,eAAgBrF,MAGnCsF,gBAAgBhG,GAAGiG,SAASlG;gBAGlC,OAAoB,gBAAhB1E,cACKoK,QAAQhL,QAAQyG,KAAK8E,QAAQtK,YAAY,OACvB,eAAhBL,cACFoK,QAAQhL,QAAQC,KAAKsL,QAAQtK,YAAY,KAAK;oBAAE,gBAAgB;qBAC9C,6BAAhBL,cACFoK,QAAQhL,QAAQC,KAAKsL,QAAQtK,YAAY,KAAK;oBAAE,gBAAgB;qBAC9DL,YAAY6K,WAAW,WACzBT,QAAQhL,QAAQC,KAAKsL,QAAQtK,YAAY,KAAK;oBAAE,gBAAgBL;qBAGhEoK,QAAQhL,QAAQ0G,KAAKpB,UAAU,KAAK;oBAAE,gBAAgB1E;;AAEjE;YACE,OAAOoK,QAAQhL,QAAQC,KAAK,aAAa;AAE7C,UAAE,OAAOmC;YACP,OAAO4I,QAAQhL,QAAQC,KAAK,aAAa;AAC3C;AACF;IAMA,eAAAqL,CAAgBrF;QAkBd,OAjBc;YACZ,SAAS;YACT,QAAQ;YACR,OAAO;YACP,SAAS;YACT,QAAQ;YACR,QAAQ;YACR,SAAS;YACT,QAAQ;YACR,QAAQ;YACR,QAAQ;YACR,SAAS;YACT,UAAU;YACV,QAAQ;YACR,QAAQ;UAGGA,IAAI/B,kBAAkB;AACrC;;;"}
|
|
1
|
+
{"version":3,"file":"Server-BkZZGWiq.js","sources":["../lib/Server/Kernel.js","../lib/Server/utils/httpParsing.js","../lib/Server/adapters/AdapterInterface.js","../lib/Server/adapters/HttpAdapter.js","../lib/Server/utils/serverReady.js","../lib/Server/Server.js"],"sourcesContent":["import { compileRoute } from './utils/routeMatch.js';\n\n/**\n * Kernel handles route registration and matching\n * Separates routing logic from HTTP protocol handling\n */\nexport class Kernel {\n #routes = []; // { method, path, match, handler, mode, revalidate, ... }\n #hooks = { \n onRequest: null, \n preHandler: null, \n onSend: null, \n onError: null \n };\n #staticFallback = null;\n\n constructor() { \n }\n\n /**\n * Register multiple routes at once\n * @param {Array} rawRoutes - Array of route objects\n */\n registerRoutes(rawRoutes) {\n for (const r of rawRoutes) {\n this.registerRoute(r);\n }\n }\n\n /**\n * Register a single route\n * @param {Object} route - Route object with method, path, handler, etc.\n */\n registerRoute(route) {\n const compiledRoute = {\n ...route,\n match: compileRoute(route.path)\n };\n this.#routes.push(compiledRoute);\n }\n\n /**\n * Configure hooks\n * @param {Object} hooks - Hook functions\n */\n hooks(h) { \n Object.assign(this.#hooks, h); \n }\n\n /**\n * Set static file fallback handler\n * @param {string} outputDir - Directory to serve static files from\n * @param {Function} handler - Static file handler function\n */\n setStaticFallback(outputDir, handler) {\n this.#staticFallback = { outputDir, handler };\n }\n\n /**\n * Handle a request through the routing system\n * @param {Object} ctx - Request context\n * @returns {Object} Response object\n */\n async handle(ctx) {\n let response;\n try {\n // onRequest can short-circuit\n const onReqOut = await this.#hooks.onRequest?.(ctx);\n if (onReqOut) { response = onReqOut; return response; }\n\n // route match …\n let matchParams = null;\n const route = this.#routes.find(r => {\n if (r.method !== ctx.req.method) return false;\n const m = r.match(ctx.req.path);\n if (m) { matchParams = m; return true; }\n return false;\n });\n\n if (!route) {\n if (this.#staticFallback) {\n const staticResponse = await this.#staticFallback.handler(ctx, this.#staticFallback.outputDir);\n response = (staticResponse && staticResponse.status !== 404)\n ? staticResponse\n : ctx.respond.text('Not Found', 404);\n } else {\n response = ctx.respond.text('Not Found', 404);\n }\n return response;\n }\n\n ctx.req.params = matchParams || {};\n\n // preHandler can short-circuit\n const preOut = await this.#hooks.preHandler?.(ctx, route);\n if (preOut) { response = preOut; return response; }\n\n // route handler\n response = await route.handler(ctx);\n\n } catch (err) {\n response = (await this.#hooks.onError?.(ctx, err))\n ?? ctx.respond.text('Internal Server Error', 500);\n } finally {\n await this.#hooks.onSend?.(ctx, response);\n }\n return response ?? ctx.respond.text('', 204);\n}\n\n\n /**\n * Get all registered routes\n * @returns {Array} Array of registered routes\n */\n getRoutes() {\n return this.#routes.map(route => ({\n method: route.method,\n path: route.path,\n params: route.params || [],\n compiled: true\n }));\n }\n}\n","/**\n * HTTP parsing utilities for request body and query parameters\n */\n\n/**\n * Parse request body based on content type\n * @param {Object} req - Node.js request object\n * @returns {Object|null} Parsed body object or null\n */\nexport async function parseBody(req) {\n return new Promise((resolve) => {\n if (req.method === 'GET' || req.method === 'HEAD') {\n resolve(null);\n return;\n }\n\n const contentType = req.headers['content-type'] || '';\n let body = '';\n\n req.on('data', chunk => {\n body += chunk.toString();\n });\n\n req.on('end', () => {\n try {\n if (contentType.includes('application/json')) {\n resolve(body ? JSON.parse(body) : {});\n } else if (contentType.includes('application/x-www-form-urlencoded')) {\n resolve(parseUrlEncoded(body));\n } else if (contentType.includes('multipart/form-data')) {\n // For now, just return the raw body for multipart\n // Could be enhanced with proper multipart parsing\n resolve({ raw: body });\n } else {\n resolve(body || null);\n }\n } catch (error) {\n resolve(null);\n }\n });\n\n req.on('error', () => {\n resolve(null);\n });\n });\n}\n\n/**\n * Parse URL-encoded form data\n * @param {string} data - URL-encoded string\n * @returns {Object} Parsed object\n */\nfunction parseUrlEncoded(data) {\n const result = {};\n const pairs = data.split('&');\n \n for (const pair of pairs) {\n const [key, value] = pair.split('=');\n if (key) {\n const decodedKey = decodeURIComponent(key);\n const decodedValue = value ? decodeURIComponent(value) : '';\n \n // Handle arrays (key[] or key[0])\n if (decodedKey.endsWith('[]')) {\n const arrayKey = decodedKey.slice(0, -2);\n if (!result[arrayKey]) result[arrayKey] = [];\n result[arrayKey].push(decodedValue);\n } else {\n result[decodedKey] = decodedValue;\n }\n }\n }\n \n return result;\n}\n\n/**\n * Parse query parameters from URLSearchParams\n * @param {URLSearchParams} searchParams - URL search parameters\n * @returns {Object} Parsed query object with support for arrays\n */\nexport function parseQuery(searchParams) {\n const result = {};\n \n for (const [key, value] of searchParams.entries()) {\n // Handle array parameters (key[] or key[0])\n if (key.endsWith('[]') || /\\[\\d*\\]$/.test(key)) {\n const arrayKey = key.replace(/\\[\\d*\\]$/, '').replace('[]', '');\n if (!result[arrayKey]) result[arrayKey] = [];\n result[arrayKey].push(value);\n } else {\n result[key] = value;\n }\n }\n \n return result;\n}\n","/**\n * Clovie Adapter Interface\n * \n * This defines the contract that all HTTP server adapters must implement.\n * The Clovie kernel uses this interface to delegate HTTP handling to\n * any compatible adapter (Express, Fastify, Node HTTP, etc.)\n */\nimport { parseQuery } from '../utils/httpParsing.js';\n\n/**\n * Adapter Interface - All adapters must implement this\n */\nexport class AdapterInterface {\n static create(name) {\n return new this(name);\n }\n\n constructor(name) {\n this.name = name;\n this.server = null;\n this.kernel = null;\n this.log = null;\n this.hooks = null;\n }\n\n /**\n * Initialize the adapter with kernel and context\n * @param {Object} kernel - Clovie kernel instance\n * @param {Object} log - Clovie logger\n */\n async initialize(kernel, log) {\n this.kernel = kernel;\n this.log = log;\n }\n\n /**\n * Start the HTTP server\n * @param {Object} options - Server options (port, host, etc.)\n * @returns {Promise<Object>} - Server instance\n */\n async start(options) {\n throw new Error(`start() must be implemented by ${this.name} adapter`);\n }\n\n /**\n * Stop the HTTP server\n * @returns {Promise<void>}\n */\n async stop() {\n throw new Error(`stop() must be implemented by ${this.name} adapter`);\n }\n\n /**\n * Get the underlying HTTP server instance\n * Used by services like LiveReload for Socket.IO integration\n * @returns {Object|null} - HTTP server instance\n */\n getHttpServer() {\n return this.server;\n }\n\n /**\n * Check if the server is currently running\n * @returns {boolean}\n */\n isRunning() {\n return this.server !== null;\n }\n\n /**\n * Handle a request through the adapter\n * @param {Object} req - HTTP request\n * @param {Object} res - HTTP response\n * @returns {Promise<void>}\n */\n async handleRequest(req, res) {\n throw new Error(`handleRequest() must be implemented by ${this.name} adapter`);\n }\n\n /**\n * Create standardized context object from request\n * @param {Object} req - HTTP request\n * @param {Object} res - HTTP response\n * @returns {Object} - Standardized context object\n */\n createContext(req, res) {\n const url = new URL(req.url || req.originalUrl, `http://${req.headers.host}`);\n\n return {\n req: {\n method: req.method,\n url: url.toString(),\n path: url.pathname,\n headers: Object.fromEntries(\n Object.entries(req.headers).map(([k, v]) => [k.toLowerCase(), v])\n ),\n query: req.query || parseQuery(url.searchParams),\n body: req.body || null,\n raw: { req, res },\n params: {}\n },\n res,\n respond: new RespondHelpers()\n };\n }\n\n /**\n * Send response using standardized response format\n * @param {Object} res - HTTP response\n * @param {Object} response - Response object from route handler\n * @param {boolean} isHead - Whether this is a HEAD request\n * @returns {Promise<void>}\n */\n async sendResponse(res, response, isHead = false) {\n // Default to 204 if no response object was returned\n const resp = response ?? { type: 'text', status: 204, headers: {}, body: '' };\n\n if (res.headersSent) return; // defensive guard\n\n // Set status and headers (normalize keys)\n res.statusCode = resp.status ?? 200;\n if (resp.headers) {\n for (const [k, v] of Object.entries(resp.headers)) {\n res.setHeader(k.toLowerCase(), v);\n }\n }\n\n // Respect HEAD requests: send headers only\n if (isHead) {\n return res.end();\n }\n\n switch (resp.type) {\n case 'json': {\n if (!res.getHeader('content-type')) {\n res.setHeader('content-type', 'application/json; charset=utf-8');\n }\n return res.end(JSON.stringify(resp.body));\n }\n\n case 'text': {\n if (!res.getHeader('content-type')) {\n res.setHeader('content-type', 'text/plain; charset=utf-8');\n }\n return res.end(resp.body ?? '');\n }\n\n case 'html': {\n if (!res.getHeader('content-type')) {\n res.setHeader('content-type', 'text/html; charset=utf-8');\n }\n return res.end(resp.body ?? '');\n }\n\n case 'file': {\n return await this.serveFile(res, resp.path);\n }\n\n case 'stream': {\n const b = resp.body;\n if (!b) return res.end();\n // Node stream\n if (typeof b.pipe === 'function') return b.pipe(res);\n // AsyncIterable\n if (Symbol.asyncIterator in Object(b)) {\n for await (const chunk of b) {\n if (!res.write(chunk)) {\n await new Promise(r => res.once('drain', r));\n }\n }\n return res.end();\n }\n // Fallback\n return res.end(b);\n }\n\n default:\n return res.end('');\n }\n }\n\n /**\n * Serve static files with proper MIME types and streaming\n * @param {Object} res - HTTP response\n * @param {string} filePath - Path to file to serve\n * @returns {Promise<void>}\n */\n async serveFile(res, filePath) {\n const fs = await import('node:fs');\n const fsp = await import('node:fs/promises');\n const path = await import('node:path');\n const { pipeline } = await import('node:stream');\n const { promisify } = await import('node:util');\n \n const pipelineAsync = promisify(pipeline);\n\n const MIME = {\n '.html': 'text/html; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.js': 'application/javascript; charset=utf-8',\n '.mjs': 'application/javascript; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.ico': 'image/x-icon',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n '.eot': 'application/vnd.ms-fontobject'\n };\n\n try {\n const st = await fsp.stat(filePath);\n if (!st.isFile()) {\n res.statusCode = 404;\n res.setHeader('content-type', 'text/plain; charset=utf-8');\n return res.end('Not Found');\n }\n\n const ext = path.extname(filePath).toLowerCase();\n if (!res.getHeader('content-type')) {\n res.setHeader('content-type', MIME[ext] ?? 'application/octet-stream');\n }\n res.setHeader('content-length', String(st.size));\n\n const rs = fs.createReadStream(filePath);\n rs.on('error', () => {\n if (!res.headersSent) res.statusCode = 404;\n res.end('Not Found');\n });\n await pipelineAsync(rs, res); // backpressure-aware piping\n } catch {\n if (!res.headersSent) {\n res.statusCode = 404;\n res.setHeader('content-type', 'text/plain; charset=utf-8');\n }\n res.end('Not Found');\n }\n }\n\n /**\n * Handle request errors consistently\n * @param {Object} res - HTTP response\n * @param {Error} error - Error that occurred\n * @returns {Promise<void>}\n */\n async handleError(res, error) {\n this.log?.error?.('Request handling error:', error);\n if (!res.headersSent) {\n res.statusCode = 500;\n res.setHeader('content-type', 'text/plain; charset=utf-8');\n res.end('Internal Server Error');\n }\n }\n}\n\n/**\n * Route object structure that adapters receive from Clovie kernel\n */\nexport class ClovieRoute {\n constructor(method, path, handler, options = {}) {\n this.method = method.toUpperCase();\n this.path = path;\n this.handler = handler;\n this.options = options;\n this.params = options.params || [];\n }\n}\n\n/**\n * Hook object structure for lifecycle management\n */\nexport class ClovieHooks {\n constructor() {\n this.onRequest = null;\n this.preHandler = null;\n this.onSend = null;\n this.onError = null;\n }\n}\n\n/**\n * Context object passed to route handlers\n */\nexport class ClovieContext {\n constructor(req, res, state, stable) {\n this.req = req;\n this.res = res;\n this.state = state;\n this.stable = stable;\n this.respond = new RespondHelpers();\n }\n}\n\n/**\n * Response helpers for route handlers\n */\nexport class RespondHelpers {\n json(data, status = 200, headers = {}) {\n return { type: 'json', status, headers, body: data };\n }\n\n text(data, status = 200, headers = {}) {\n return { type: 'text', status, headers, body: data };\n }\n\n html(data, status = 200, headers = {}) {\n return { type: 'html', status, headers, body: data };\n }\n\n file(path, status = 200, headers = {}) {\n return { type: 'file', status, headers, path };\n }\n\n stream(body, status = 200, headers = {}) {\n return { type: 'stream', status, headers, body };\n }\n\n redirect(location, status = 302, headers = {}) {\n return { type:'text', status, headers: { ...headers, location }, body: '' };\n }\n}\n","/**\n * HTTP Adapter for Node.js native HTTP server\n * Thin I/O shim: normalize req/res, call kernel, send response\n */\nimport http from 'node:http';\nimport { AdapterInterface } from './AdapterInterface.js';\nimport { parseBody } from '../utils/httpParsing.js';\n\nexport class HttpAdapter extends AdapterInterface {\n #connections = new Set();\n\n constructor() {\n super('http');\n }\n\n async initialize(kernel, services, log) {\n await super.initialize(kernel, services, log);\n }\n\n async start({ port = 3000, host = '0.0.0.0' } = {}) {\n this.server = http.createServer(async (req, res) => {\n try {\n // Parse body for HTTP adapter (Express handles this differently)\n if (!req.body) {\n req.body = await parseBody(req);\n }\n\n const ctx = this.createContext(req, res);\n const out = await this.kernel.handle(ctx);\n await this.sendResponse(res, out, req.method === 'HEAD');\n } catch (error) {\n await this.handleError(res, error);\n }\n });\n\n // Track connections for clean shutdown\n this.server.on('connection', (conn) => {\n this.#connections.add(conn);\n conn.on('close', () => {\n this.#connections.delete(conn);\n });\n });\n\n await new Promise((resolve, reject) =>\n this.server.listen(port, host, err => (err ? reject(err) : resolve()))\n );\n\n this.log?.info?.(`HTTP Server listening on http://${host}:${port}`);\n return this.server;\n }\n\n async stop() {\n if (this.server) {\n // Destroy all active connections\n for (const conn of this.#connections) {\n conn.destroy();\n }\n this.#connections.clear();\n\n // Close the server\n await new Promise(resolve => this.server.close(() => resolve()));\n this.server = null;\n }\n }\n\n}\n","import chalk from 'chalk';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\n\nconst execAsync = promisify(exec);\n\n/**\n * Display a pretty server ready message with clickable URL\n * @param {object} options - Server options\n * @param {number} options.port - Server port\n * @param {string} options.host - Server host\n * @param {string} options.mode - Server mode (development/production)\n * @param {object} logger - Logger instance\n */\nexport async function displayServerReady({ port, host, mode }, logger) {\n const protocol = mode === 'development' ? 'http' : 'https';\n const url = `${protocol}://${host === '0.0.0.0' ? 'localhost' : host}:${port}`;\n \n // Create a nice banner\n const banner = [\n '',\n chalk.bold.blue('╔══════════════════════════════════════════════════════════════╗'),\n chalk.bold.blue('║') + chalk.bold.white(' 🚀 Clovie Server Ready! 🚀 ') + chalk.bold.blue('║'),\n chalk.bold.blue('╠══════════════════════════════════════════════════════════════╣'),\n chalk.bold.blue('║') + chalk.white(` Mode: ${chalk.green(mode.toUpperCase())} `) + chalk.bold.blue('║'),\n chalk.bold.blue('║') + chalk.white(` URL: ${chalk.cyan.underline(url)} `) + chalk.bold.blue('║'),\n chalk.bold.blue('║') + chalk.white(` Host: ${chalk.yellow(host)}:${chalk.yellow(port)} `) + chalk.bold.blue('║'),\n chalk.bold.blue('╚══════════════════════════════════════════════════════════════╝'),\n ''\n ];\n\n // Display the banner\n banner.forEach(line => logger.info(line));\n\n // Try to open browser automatically in development mode\n if (mode === 'development') {\n try {\n await openBrowser(url);\n logger.info(chalk.green('🌐 Browser opened automatically'));\n } catch (error) {\n logger.debug('Could not open browser automatically:', error.message);\n }\n }\n\n // Display helpful commands\n const commands = [\n '',\n chalk.gray('💡 Quick Commands:'),\n chalk.gray(` • Press ${chalk.yellow('Ctrl+C')} to stop the server`),\n chalk.gray(` • Visit ${chalk.cyan(url)} to view your site`),\n chalk.gray(` • Check the console for live reload updates`),\n ''\n ];\n\n commands.forEach(line => logger.info(line));\n}\n\n/**\n * Open browser with the given URL\n * @param {string} url - URL to open\n */\nasync function openBrowser(url) {\n const platform = process.platform;\n let command;\n\n switch (platform) {\n case 'darwin': // macOS\n command = `open \"${url}\"`;\n break;\n case 'win32': // Windows\n command = `start \"${url}\"`;\n break;\n default: // Linux and others\n command = `xdg-open \"${url}\"`;\n break;\n }\n\n try {\n await execAsync(command);\n } catch (error) {\n throw new Error(`Failed to open browser: ${error.message}`);\n }\n}","import { ServiceProvider } from '@brickworks/engine';\nimport { Kernel } from './Kernel.js';\nimport { HttpAdapter } from './adapters/HttpAdapter.js';\nimport { displayServerReady } from './utils/serverReady.js';\n\nexport class Server extends ServiceProvider {\n static manifest = {\n name: 'Clovie Server',\n namespace: 'server',\n version: '1.0.0'\n };\n\n #routes = [];\n #adapter = null;\n #hooks = {\n onRequest: null,\n preHandler: null,\n onSend: null,\n onError: null\n };\n\n actions(useContext) { \n return {\n // Add a route\n add: (method, path, handler, meta = {}) => {\n this.#routes.push({\n method: method.toUpperCase(),\n path,\n handler,\n meta\n });\n },\n\n // Set server adapter\n useAdapter: (adapter) => {\n this.#adapter = adapter;\n return this;\n },\n\n // Configure hooks\n hooks: (hooks) => {\n this.#hooks = { ...this.#hooks, ...hooks };\n return this;\n },\n\n // Start listening server\n listen: async (opts = {}) => {\n const relay = useContext('relay');\n const port = opts.port || 3000;\n const host = opts.host || '0.0.0.0';\n const log = useContext('log');\n \n // Create kernel with services\n const kernel = new Kernel({\n state: useContext('state'),\n stable: useContext('stable'),\n // Add other services as needed for ISR/static/SSR\n });\n\n // Configure kernel hooks\n kernel.hooks(this.#hooks);\n\n // 1) Register app routes first\n kernel.registerRoutes(this.#routes);\n\n // 2) Add system routes (won't shadow user routes)\n kernel.registerRoutes([\n {\n method: 'GET',\n path: '/health',\n handler: (ctx) => ctx.respond.json({\n status: 'ok',\n timestamp: new Date().toISOString(),\n mode: opts.mode || 'production'\n })\n },\n {\n method: 'GET',\n path: '/api/info',\n handler: (ctx) => ctx.respond.json({\n name: 'Clovie',\n version: '1.0.0',\n mode: opts.mode || 'production',\n routes: this.#routes.length\n })\n }\n ]);\n\n // 3) Configure static file serving as 404 fallback\n if (opts.outputDir) {\n kernel.setStaticFallback(opts.outputDir, (ctx, outputDir) => {\n return this.#serveStaticFile(ctx, outputDir);\n });\n }\n\n // 4) Boot adapter\n this.#adapter = this.#adapter ?? HttpAdapter.create();\n await this.#adapter.initialize(kernel, log);\n \n // Start the server and return the instance\n const server = await this.#adapter.start({ port, host });\n \n // Check for LiveReload service and initialize it if available\n try {\n const liveReload = useContext('liveReload');\n log.debug(`LiveReload service found: ${!!liveReload}, mode: ${opts.mode}`);\n if (liveReload && opts.mode === 'development') {\n log.info('Initializing LiveReload...');\n await liveReload.initializeServer(server, opts);\n log.info('LiveReload initialized successfully');\n }\n } catch (error) {\n log.debug('LiveReload not available:', error.message);\n }\n \n // Display pretty server ready message\n const actualPort = server.address()?.port || port;\n await displayServerReady({ \n port: actualPort, \n host, \n mode: opts.mode || 'production' \n }, log);\n \n // Broadcast server ready event\n relay.broadcast('server:ready', server);\n return server;\n },\n\n // Get all routes\n getRoutes: () => this.#routes,\n\n // Clear all routes (useful for testing)\n clearRoutes: () => {\n this.#routes = [];\n },\n\n // Stop the server\n stop: async () => {\n if (this.#adapter) {\n await this.#adapter.stop();\n }\n },\n\n // Check if server is running\n isRunning: () => this.#adapter && this.#adapter.isRunning(),\n\n // Get the underlying HTTP server (for Socket.IO integration)\n getHttpServer: () => {\n if (this.#adapter) {\n return this.#adapter.getHttpServer();\n }\n return null;\n }\n };\n }\n /**\n * Serve static files from the output directory\n * @private\n */\n async #serveStaticFile(context, outputDir) {\n const fs = await import('fs/promises');\n const path = await import('path');\n \n try {\n // Get the requested file path\n const requestPath = context.req.path === '/' ? '/index.html' : context.req.path;\n let filePath = path.join(outputDir, requestPath);\n let stats;\n \n try {\n // Try the path as-is first\n stats = await fs.stat(filePath);\n } catch (error) {\n // If it fails and has no extension, try adding .html\n const ext = path.extname(requestPath);\n if (!ext) {\n const htmlPath = path.join(outputDir, `${requestPath}.html`);\n try {\n stats = await fs.stat(htmlPath);\n filePath = htmlPath; // Use the .html version\n } catch (htmlError) {\n // Neither worked, return 404\n return context.respond.text('Not Found', 404);\n }\n } else {\n // Had an extension but file not found\n return context.respond.text('Not Found', 404);\n }\n }\n \n if (stats.isFile()) {\n // Determine content type\n const ext = path.extname(filePath);\n const contentType = this.#getContentType(ext);\n \n // Read and serve the file\n const content = await fs.readFile(filePath);\n \n // Serve with correct content type\n if (contentType === 'text/html') {\n return context.respond.html(content.toString(), 200);\n } else if (contentType === 'text/css') {\n return context.respond.text(content.toString(), 200, { 'Content-Type': 'text/css' });\n } else if (contentType === 'application/javascript') {\n return context.respond.text(content.toString(), 200, { 'Content-Type': 'application/javascript' });\n } else if (contentType.startsWith('text/')) {\n return context.respond.text(content.toString(), 200, { 'Content-Type': contentType });\n } else {\n // For binary files, send as file response\n return context.respond.file(filePath, 200, { 'Content-Type': contentType });\n }\n } else {\n return context.respond.text('Not Found', 404);\n }\n } catch (error) {\n return context.respond.text('Not Found', 404);\n }\n }\n\n /**\n * Get content type based on file extension\n * @private\n */\n #getContentType(ext) {\n const types = {\n '.html': 'text/html',\n '.css': 'text/css',\n '.js': 'application/javascript',\n '.json': 'application/json',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.ico': 'image/x-icon',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n '.eot': 'application/vnd.ms-fontobject'\n };\n \n return types[ext.toLowerCase()] || 'application/octet-stream';\n }\n}"],"names":["Kernel","routes","hooks","onRequest","preHandler","onSend","onError","staticFallback","constructor","registerRoutes","rawRoutes","r","this","registerRoute","route","compiledRoute","match","compileRoute","path","push","h","Object","assign","setStaticFallback","outputDir","handler","handle","ctx","response","onReqOut","matchParams","find","method","req","m","staticResponse","status","respond","text","params","preOut","err","getRoutes","map","compiled","async","parseBody","Promise","resolve","contentType","headers","body","on","chunk","toString","includes","JSON","parse","data","result","pairs","split","pair","key","value","decodedKey","decodeURIComponent","decodedValue","endsWith","arrayKey","slice","parseUrlEncoded","raw","error","parseQuery","searchParams","entries","test","replace","AdapterInterface","create","name","server","kernel","log","initialize","start","options","Error","stop","getHttpServer","isRunning","handleRequest","res","createContext","url","URL","originalUrl","host","pathname","fromEntries","k","v","toLowerCase","query","RespondHelpers","sendResponse","isHead","resp","type","headersSent","statusCode","setHeader","end","getHeader","stringify","serveFile","b","pipe","Symbol","asyncIterator","write","once","filePath","fs","import","fsp","pipeline","promisify","pipelineAsync","MIME","st","stat","isFile","ext","extname","String","size","rs","createReadStream","handleError","json","html","file","stream","redirect","location","HttpAdapter","connections","Set","super","services","port","http","createServer","out","conn","add","delete","reject","listen","info","destroy","clear","close","execAsync","exec","displayServerReady","mode","logger","chalk","bold","blue","white","green","toUpperCase","cyan","underline","yellow","forEach","line","command","process","platform","message","openBrowser","debug","gray","Server","ServiceProvider","static","namespace","version","adapter","actions","useContext","meta","useAdapter","opts","relay","state","stable","timestamp","Date","toISOString","length","serveStaticFile","liveReload","initializeServer","actualPort","address","broadcast","clearRoutes","context","requestPath","stats","join","htmlPath","htmlError","getContentType","content","readFile","startsWith"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var socket_io = require("socket.io"), createClovie = require("./createClovie-
|
|
3
|
+
var socket_io = require("socket.io"), createClovie = require("./createClovie-bhagLY-k.cjs");
|
|
4
4
|
|
|
5
5
|
require("stream"), require("module"), require("path"), require("crypto"), require("fs"),
|
|
6
6
|
require("istextorbinary"), require("chokidar"), require("readline"), require("events"),
|
|
@@ -72,4 +72,4 @@ class LiveReload extends createClovie.ServiceProvider {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
exports.LiveReload = LiveReload;
|
|
75
|
-
//# sourceMappingURL=LiveReload-
|
|
75
|
+
//# sourceMappingURL=LiveReload-YaB3G8c8.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LiveReload-
|
|
1
|
+
{"version":3,"file":"LiveReload-YaB3G8c8.cjs","sources":["../../lib/LiveReload.js"],"sourcesContent":["import { Server as SocketIOServer } from 'socket.io';\nimport { ServiceProvider } from '@brickworks/engine';\nimport { queueMacrotask } from './utils/tasks.js';\n\nexport class LiveReload extends ServiceProvider {\n static manifest = {\n name: 'Clovie LiveReload',\n namespace: 'liveReload',\n version: '1.0.0',\n };\n\n #io;\n #reloading = false;\n\n getter () {\n return {\n io: () => this.#io,\n }\n }\n\n actions() {\n return {\n initializeServer: async (server, opts) => {\n const log = this.useContext('log');\n if (opts.mode === 'development') {\n await this.#setupSocketIO(server, log);\n }\n },\n notifyReload: () => {\n if (this.#reloading) return;\n this.#reloading = true;\n \n queueMacrotask(() => {\n this.#reloading = false;\n if (this.#io) {\n this.#io.emit('reload')\n }\n });\n },\n injectLiveReloadScript: async (renderedContent, opts) => {\n const lastBodyIndex = renderedContent.lastIndexOf('</body>');\n if (lastBodyIndex !== -1) {\n const scriptConfig = { \n mode: opts.mode || 'development', \n port: opts.port || 3000 \n };\n \n try {\n // Import live reload script dynamically \n renderedContent = renderedContent.substring(0, lastBodyIndex) + \n this.#liveReloadScript(scriptConfig) + '\\n' + \n renderedContent.substring(lastBodyIndex);\n } catch (err) {\n console.warn('⚠️ Could not load live reload script:', err.message);\n }\n }\n return renderedContent;\n }\n }\n }\n\n async #setupSocketIO(server, log) {\n try {\n // Wait a bit for server to be fully initialized\n await new Promise(resolve => setTimeout(resolve, 100));\n\n log.debug('Setting up Socket.IO...');\n \n // Configure Socket.IO with proper CORS and options\n this.#io = new SocketIOServer(server, {\n cors: {\n origin: \"*\",\n methods: [\"GET\", \"POST\"]\n },\n transports: ['polling', 'websocket'],\n allowEIO3: true\n });\n\n this.#io.on('connection', (socket) => {\n log.debug(`Client connected: ${socket.id}`);\n \n socket.on('disconnect', (reason) => {\n log.debug(`Client disconnected: ${socket.id} - ${reason}`);\n });\n \n socket.on('error', (error) => {\n log.error('Socket error:', error);\n });\n });\n\n log.info('Socket.IO server ready');\n } catch (error) {\n log.error('Error setting up Socket.IO:', error);\n }\n }\n\n #liveReloadScript = (opts) => `<!-- Live Reload Script (Development Mode Only) -->\n<script src=\"https://cdn.socket.io/4.7.4/socket.io.min.js\"></script>\n<script>\n (function() {\n const opts = ${JSON.stringify(opts)};\n \n console.log('Initializing live reload with opts:', opts);\n \n // Configure Socket.IO client with proper options\n const socket = io({\n transports: ['polling', 'websocket'],\n timeout: 20000,\n forceNew: true\n });\n \n socket.on('reload', () => {\n console.log('Live reload triggered');\n window.location.reload();\n });\n \n socket.on('connect', () => {\n console.log('Connected to live reload server');\n });\n \n socket.on('disconnect', (reason) => {\n console.log('Disconnected from live reload server:', reason);\n });\n \n socket.on('connect_error', (error) => {\n console.error('Connection error:', error);\n console.log('Retrying connection in 3 seconds...');\n setTimeout(() => {\n socket.connect();\n }, 3000);\n });\n \n socket.on('error', (error) => {\n console.error('Socket error:', error);\n });\n \n // Add connection timeout\n setTimeout(() => {\n if (!socket.connected) {\n console.warn('Live reload connection timeout - server may not be running');\n }\n }, 5000);\n })();\n</script>`;\n}"],"names":["LiveReload","ServiceProvider","static","name","namespace","version","io","reloading","getter","this","actions","initializeServer","async","server","opts","log","useContext","mode","setupSocketIO","notifyReload","queueMacrotask","emit","injectLiveReloadScript","renderedContent","lastBodyIndex","lastIndexOf","scriptConfig","port","substring","liveReloadScript","err","console","warn","message","Promise","resolve","setTimeout","debug","SocketIOServer","cors","origin","methods","transports","allowEIO3","on","socket","id","reason","error","info","JSON","stringify"],"mappings":";;;;;;;;AAIO,MAAMA,mBAAmBC,aAAAA;IAC9BC,gBAAkB;QAChBC,MAAM;QACNC,WAAW;QACXC,SAAS;;IAGXC;IACAC,YAAa;IAEb,MAAAC;QACE,OAAO;YACLF,IAAI,MAAMG,MAAKH;;AAEnB;IAEA,OAAAI;QACE,OAAO;YACLC,kBAAkBC,OAAOC,QAAQC;gBAC/B,MAAMC,MAAMN,KAAKO,WAAW;gBACV,kBAAdF,KAAKG,cACDR,MAAKS,cAAeL,QAAQE;;YAGtCI,cAAc;gBACRV,MAAKF,cACTE,MAAKF,aAAa,GAElBa,aAAAA,eAAe;oBACbX,MAAKF,aAAa,GACdE,MAAKH,MACPG,MAAKH,GAAIe,KAAK;;;YAIpBC,wBAAwBV,OAAOW,iBAAiBT;gBAC9C,MAAMU,gBAAgBD,gBAAgBE,YAAY;gBAClD,KAAsB,MAAlBD,eAAsB;oBACxB,MAAME,eAAe;wBACnBT,MAAMH,KAAKG,QAAQ;wBACnBU,MAAMb,KAAKa,QAAQ;;oBAGrB;wBAEEJ,kBAAkBA,gBAAgBK,UAAU,GAAGJ,iBAC/Bf,MAAKoB,iBAAkBH,gBAAgB,OACvCH,gBAAgBK,UAAUJ;AAC5C,sBAAE,OAAOM;wBACPC,QAAQC,KAAK,0CAA0CF,IAAIG;AAC7D;AACF;gBACA,OAAOV;;;AAGb;IAEA,oBAAML,CAAeL,QAAQE;QAC3B;kBAEQ,IAAImB,QAAQC,WAAWC,WAAWD,SAAS,OAEjDpB,IAAIsB,MAAM;YAGV5B,MAAKH,KAAM,IAAIgC,UAAAA,OAAezB,QAAQ;gBACpC0B,MAAM;oBACJC,QAAQ;oBACRC,SAAS,EAAC,OAAO;;gBAEnBC,YAAY,EAAC,WAAW;gBACxBC,YAAW;gBAGblC,MAAKH,GAAIsC,GAAG,cAAeC;gBACzB9B,IAAIsB,MAAM,qBAAqBQ,OAAOC,OAEtCD,OAAOD,GAAG,cAAeG;oBACvBhC,IAAIsB,MAAM,wBAAwBQ,OAAOC,QAAQC;oBAGnDF,OAAOD,GAAG,SAAUI;oBAClBjC,IAAIiC,MAAM,iBAAiBA;;gBAI/BjC,IAAIkC,KAAK;AACX,UAAE,OAAOD;YACPjC,IAAIiC,MAAM,+BAA+BA;AAC3C;AACF;IAEAnB,kBAAqBf,QAAS,iLAIboC,KAAKC,UAAUrC;;;"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var createClovie = require("./createClovie-
|
|
3
|
+
var createClovie = require("./createClovie-bhagLY-k.cjs"), http = require("node:http"), child_process = require("child_process"), util = require("util");
|
|
4
4
|
|
|
5
5
|
require("stream"), require("module"), require("path"), require("crypto"), require("fs"),
|
|
6
6
|
require("istextorbinary"), require("chokidar"), require("readline"), require("events"),
|
|
@@ -502,4 +502,4 @@ class Server extends createClovie.ServiceProvider {
|
|
|
502
502
|
}
|
|
503
503
|
|
|
504
504
|
exports.Server = Server;
|
|
505
|
-
//# sourceMappingURL=Server-
|
|
505
|
+
//# sourceMappingURL=Server-BqbjrDXw.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Server-BaCoAz1f.cjs","sources":["../../lib/Server/Kernel.js","../../lib/Server/utils/httpParsing.js","../../lib/Server/adapters/AdapterInterface.js","../../lib/Server/adapters/HttpAdapter.js","../../lib/Server/utils/serverReady.js","../../lib/Server/Server.js"],"sourcesContent":["import { compileRoute } from './utils/routeMatch.js';\n\n/**\n * Kernel handles route registration and matching\n * Separates routing logic from HTTP protocol handling\n */\nexport class Kernel {\n #routes = []; // { method, path, match, handler, mode, revalidate, ... }\n #hooks = { \n onRequest: null, \n preHandler: null, \n onSend: null, \n onError: null \n };\n #staticFallback = null;\n\n constructor() { \n }\n\n /**\n * Register multiple routes at once\n * @param {Array} rawRoutes - Array of route objects\n */\n registerRoutes(rawRoutes) {\n for (const r of rawRoutes) {\n this.registerRoute(r);\n }\n }\n\n /**\n * Register a single route\n * @param {Object} route - Route object with method, path, handler, etc.\n */\n registerRoute(route) {\n const compiledRoute = {\n ...route,\n match: compileRoute(route.path)\n };\n this.#routes.push(compiledRoute);\n }\n\n /**\n * Configure hooks\n * @param {Object} hooks - Hook functions\n */\n hooks(h) { \n Object.assign(this.#hooks, h); \n }\n\n /**\n * Set static file fallback handler\n * @param {string} outputDir - Directory to serve static files from\n * @param {Function} handler - Static file handler function\n */\n setStaticFallback(outputDir, handler) {\n this.#staticFallback = { outputDir, handler };\n }\n\n /**\n * Handle a request through the routing system\n * @param {Object} ctx - Request context\n * @returns {Object} Response object\n */\n async handle(ctx) {\n let response;\n try {\n // onRequest can short-circuit\n const onReqOut = await this.#hooks.onRequest?.(ctx);\n if (onReqOut) { response = onReqOut; return response; }\n\n // route match …\n let matchParams = null;\n const route = this.#routes.find(r => {\n if (r.method !== ctx.req.method) return false;\n const m = r.match(ctx.req.path);\n if (m) { matchParams = m; return true; }\n return false;\n });\n\n if (!route) {\n if (this.#staticFallback) {\n const staticResponse = await this.#staticFallback.handler(ctx, this.#staticFallback.outputDir);\n response = (staticResponse && staticResponse.status !== 404)\n ? staticResponse\n : ctx.respond.text('Not Found', 404);\n } else {\n response = ctx.respond.text('Not Found', 404);\n }\n return response;\n }\n\n ctx.req.params = matchParams || {};\n\n // preHandler can short-circuit\n const preOut = await this.#hooks.preHandler?.(ctx, route);\n if (preOut) { response = preOut; return response; }\n\n // route handler\n response = await route.handler(ctx);\n\n } catch (err) {\n response = (await this.#hooks.onError?.(ctx, err))\n ?? ctx.respond.text('Internal Server Error', 500);\n } finally {\n await this.#hooks.onSend?.(ctx, response);\n }\n return response ?? ctx.respond.text('', 204);\n}\n\n\n /**\n * Get all registered routes\n * @returns {Array} Array of registered routes\n */\n getRoutes() {\n return this.#routes.map(route => ({\n method: route.method,\n path: route.path,\n params: route.params || [],\n compiled: true\n }));\n }\n}\n","/**\n * HTTP parsing utilities for request body and query parameters\n */\n\n/**\n * Parse request body based on content type\n * @param {Object} req - Node.js request object\n * @returns {Object|null} Parsed body object or null\n */\nexport async function parseBody(req) {\n return new Promise((resolve) => {\n if (req.method === 'GET' || req.method === 'HEAD') {\n resolve(null);\n return;\n }\n\n const contentType = req.headers['content-type'] || '';\n let body = '';\n\n req.on('data', chunk => {\n body += chunk.toString();\n });\n\n req.on('end', () => {\n try {\n if (contentType.includes('application/json')) {\n resolve(body ? JSON.parse(body) : {});\n } else if (contentType.includes('application/x-www-form-urlencoded')) {\n resolve(parseUrlEncoded(body));\n } else if (contentType.includes('multipart/form-data')) {\n // For now, just return the raw body for multipart\n // Could be enhanced with proper multipart parsing\n resolve({ raw: body });\n } else {\n resolve(body || null);\n }\n } catch (error) {\n resolve(null);\n }\n });\n\n req.on('error', () => {\n resolve(null);\n });\n });\n}\n\n/**\n * Parse URL-encoded form data\n * @param {string} data - URL-encoded string\n * @returns {Object} Parsed object\n */\nfunction parseUrlEncoded(data) {\n const result = {};\n const pairs = data.split('&');\n \n for (const pair of pairs) {\n const [key, value] = pair.split('=');\n if (key) {\n const decodedKey = decodeURIComponent(key);\n const decodedValue = value ? decodeURIComponent(value) : '';\n \n // Handle arrays (key[] or key[0])\n if (decodedKey.endsWith('[]')) {\n const arrayKey = decodedKey.slice(0, -2);\n if (!result[arrayKey]) result[arrayKey] = [];\n result[arrayKey].push(decodedValue);\n } else {\n result[decodedKey] = decodedValue;\n }\n }\n }\n \n return result;\n}\n\n/**\n * Parse query parameters from URLSearchParams\n * @param {URLSearchParams} searchParams - URL search parameters\n * @returns {Object} Parsed query object with support for arrays\n */\nexport function parseQuery(searchParams) {\n const result = {};\n \n for (const [key, value] of searchParams.entries()) {\n // Handle array parameters (key[] or key[0])\n if (key.endsWith('[]') || /\\[\\d*\\]$/.test(key)) {\n const arrayKey = key.replace(/\\[\\d*\\]$/, '').replace('[]', '');\n if (!result[arrayKey]) result[arrayKey] = [];\n result[arrayKey].push(value);\n } else {\n result[key] = value;\n }\n }\n \n return result;\n}\n","/**\n * Clovie Adapter Interface\n * \n * This defines the contract that all HTTP server adapters must implement.\n * The Clovie kernel uses this interface to delegate HTTP handling to\n * any compatible adapter (Express, Fastify, Node HTTP, etc.)\n */\nimport { parseQuery } from '../utils/httpParsing.js';\n\n/**\n * Adapter Interface - All adapters must implement this\n */\nexport class AdapterInterface {\n static create(name) {\n return new this(name);\n }\n\n constructor(name) {\n this.name = name;\n this.server = null;\n this.kernel = null;\n this.log = null;\n this.hooks = null;\n }\n\n /**\n * Initialize the adapter with kernel and context\n * @param {Object} kernel - Clovie kernel instance\n * @param {Object} log - Clovie logger\n */\n async initialize(kernel, log) {\n this.kernel = kernel;\n this.log = log;\n }\n\n /**\n * Start the HTTP server\n * @param {Object} options - Server options (port, host, etc.)\n * @returns {Promise<Object>} - Server instance\n */\n async start(options) {\n throw new Error(`start() must be implemented by ${this.name} adapter`);\n }\n\n /**\n * Stop the HTTP server\n * @returns {Promise<void>}\n */\n async stop() {\n throw new Error(`stop() must be implemented by ${this.name} adapter`);\n }\n\n /**\n * Get the underlying HTTP server instance\n * Used by services like LiveReload for Socket.IO integration\n * @returns {Object|null} - HTTP server instance\n */\n getHttpServer() {\n return this.server;\n }\n\n /**\n * Check if the server is currently running\n * @returns {boolean}\n */\n isRunning() {\n return this.server !== null;\n }\n\n /**\n * Handle a request through the adapter\n * @param {Object} req - HTTP request\n * @param {Object} res - HTTP response\n * @returns {Promise<void>}\n */\n async handleRequest(req, res) {\n throw new Error(`handleRequest() must be implemented by ${this.name} adapter`);\n }\n\n /**\n * Create standardized context object from request\n * @param {Object} req - HTTP request\n * @param {Object} res - HTTP response\n * @returns {Object} - Standardized context object\n */\n createContext(req, res) {\n const url = new URL(req.url || req.originalUrl, `http://${req.headers.host}`);\n\n return {\n req: {\n method: req.method,\n url: url.toString(),\n path: url.pathname,\n headers: Object.fromEntries(\n Object.entries(req.headers).map(([k, v]) => [k.toLowerCase(), v])\n ),\n query: req.query || parseQuery(url.searchParams),\n body: req.body || null,\n raw: { req, res },\n params: {}\n },\n res,\n respond: new RespondHelpers()\n };\n }\n\n /**\n * Send response using standardized response format\n * @param {Object} res - HTTP response\n * @param {Object} response - Response object from route handler\n * @param {boolean} isHead - Whether this is a HEAD request\n * @returns {Promise<void>}\n */\n async sendResponse(res, response, isHead = false) {\n // Default to 204 if no response object was returned\n const resp = response ?? { type: 'text', status: 204, headers: {}, body: '' };\n\n if (res.headersSent) return; // defensive guard\n\n // Set status and headers (normalize keys)\n res.statusCode = resp.status ?? 200;\n if (resp.headers) {\n for (const [k, v] of Object.entries(resp.headers)) {\n res.setHeader(k.toLowerCase(), v);\n }\n }\n\n // Respect HEAD requests: send headers only\n if (isHead) {\n return res.end();\n }\n\n switch (resp.type) {\n case 'json': {\n if (!res.getHeader('content-type')) {\n res.setHeader('content-type', 'application/json; charset=utf-8');\n }\n return res.end(JSON.stringify(resp.body));\n }\n\n case 'text': {\n if (!res.getHeader('content-type')) {\n res.setHeader('content-type', 'text/plain; charset=utf-8');\n }\n return res.end(resp.body ?? '');\n }\n\n case 'html': {\n if (!res.getHeader('content-type')) {\n res.setHeader('content-type', 'text/html; charset=utf-8');\n }\n return res.end(resp.body ?? '');\n }\n\n case 'file': {\n return await this.serveFile(res, resp.path);\n }\n\n case 'stream': {\n const b = resp.body;\n if (!b) return res.end();\n // Node stream\n if (typeof b.pipe === 'function') return b.pipe(res);\n // AsyncIterable\n if (Symbol.asyncIterator in Object(b)) {\n for await (const chunk of b) {\n if (!res.write(chunk)) {\n await new Promise(r => res.once('drain', r));\n }\n }\n return res.end();\n }\n // Fallback\n return res.end(b);\n }\n\n default:\n return res.end('');\n }\n }\n\n /**\n * Serve static files with proper MIME types and streaming\n * @param {Object} res - HTTP response\n * @param {string} filePath - Path to file to serve\n * @returns {Promise<void>}\n */\n async serveFile(res, filePath) {\n const fs = await import('node:fs');\n const fsp = await import('node:fs/promises');\n const path = await import('node:path');\n const { pipeline } = await import('node:stream');\n const { promisify } = await import('node:util');\n \n const pipelineAsync = promisify(pipeline);\n\n const MIME = {\n '.html': 'text/html; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.js': 'application/javascript; charset=utf-8',\n '.mjs': 'application/javascript; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.ico': 'image/x-icon',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n '.eot': 'application/vnd.ms-fontobject'\n };\n\n try {\n const st = await fsp.stat(filePath);\n if (!st.isFile()) {\n res.statusCode = 404;\n res.setHeader('content-type', 'text/plain; charset=utf-8');\n return res.end('Not Found');\n }\n\n const ext = path.extname(filePath).toLowerCase();\n if (!res.getHeader('content-type')) {\n res.setHeader('content-type', MIME[ext] ?? 'application/octet-stream');\n }\n res.setHeader('content-length', String(st.size));\n\n const rs = fs.createReadStream(filePath);\n rs.on('error', () => {\n if (!res.headersSent) res.statusCode = 404;\n res.end('Not Found');\n });\n await pipelineAsync(rs, res); // backpressure-aware piping\n } catch {\n if (!res.headersSent) {\n res.statusCode = 404;\n res.setHeader('content-type', 'text/plain; charset=utf-8');\n }\n res.end('Not Found');\n }\n }\n\n /**\n * Handle request errors consistently\n * @param {Object} res - HTTP response\n * @param {Error} error - Error that occurred\n * @returns {Promise<void>}\n */\n async handleError(res, error) {\n this.log?.error?.('Request handling error:', error);\n if (!res.headersSent) {\n res.statusCode = 500;\n res.setHeader('content-type', 'text/plain; charset=utf-8');\n res.end('Internal Server Error');\n }\n }\n}\n\n/**\n * Route object structure that adapters receive from Clovie kernel\n */\nexport class ClovieRoute {\n constructor(method, path, handler, options = {}) {\n this.method = method.toUpperCase();\n this.path = path;\n this.handler = handler;\n this.options = options;\n this.params = options.params || [];\n }\n}\n\n/**\n * Hook object structure for lifecycle management\n */\nexport class ClovieHooks {\n constructor() {\n this.onRequest = null;\n this.preHandler = null;\n this.onSend = null;\n this.onError = null;\n }\n}\n\n/**\n * Context object passed to route handlers\n */\nexport class ClovieContext {\n constructor(req, res, state, stable) {\n this.req = req;\n this.res = res;\n this.state = state;\n this.stable = stable;\n this.respond = new RespondHelpers();\n }\n}\n\n/**\n * Response helpers for route handlers\n */\nexport class RespondHelpers {\n json(data, status = 200, headers = {}) {\n return { type: 'json', status, headers, body: data };\n }\n\n text(data, status = 200, headers = {}) {\n return { type: 'text', status, headers, body: data };\n }\n\n html(data, status = 200, headers = {}) {\n return { type: 'html', status, headers, body: data };\n }\n\n file(path, status = 200, headers = {}) {\n return { type: 'file', status, headers, path };\n }\n\n stream(body, status = 200, headers = {}) {\n return { type: 'stream', status, headers, body };\n }\n\n redirect(location, status = 302, headers = {}) {\n return { type:'text', status, headers: { ...headers, location }, body: '' };\n }\n}\n","/**\n * HTTP Adapter for Node.js native HTTP server\n * Thin I/O shim: normalize req/res, call kernel, send response\n */\nimport http from 'node:http';\nimport { AdapterInterface } from './AdapterInterface.js';\nimport { parseBody } from '../utils/httpParsing.js';\n\nexport class HttpAdapter extends AdapterInterface {\n #connections = new Set();\n\n constructor() {\n super('http');\n }\n\n async initialize(kernel, services, log) {\n await super.initialize(kernel, services, log);\n }\n\n async start({ port = 3000, host = '0.0.0.0' } = {}) {\n this.server = http.createServer(async (req, res) => {\n try {\n // Parse body for HTTP adapter (Express handles this differently)\n if (!req.body) {\n req.body = await parseBody(req);\n }\n\n const ctx = this.createContext(req, res);\n const out = await this.kernel.handle(ctx);\n await this.sendResponse(res, out, req.method === 'HEAD');\n } catch (error) {\n await this.handleError(res, error);\n }\n });\n\n // Track connections for clean shutdown\n this.server.on('connection', (conn) => {\n this.#connections.add(conn);\n conn.on('close', () => {\n this.#connections.delete(conn);\n });\n });\n\n await new Promise((resolve, reject) =>\n this.server.listen(port, host, err => (err ? reject(err) : resolve()))\n );\n\n this.log?.info?.(`HTTP Server listening on http://${host}:${port}`);\n return this.server;\n }\n\n async stop() {\n if (this.server) {\n // Destroy all active connections\n for (const conn of this.#connections) {\n conn.destroy();\n }\n this.#connections.clear();\n\n // Close the server\n await new Promise(resolve => this.server.close(() => resolve()));\n this.server = null;\n }\n }\n\n}\n","import chalk from 'chalk';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\n\nconst execAsync = promisify(exec);\n\n/**\n * Display a pretty server ready message with clickable URL\n * @param {object} options - Server options\n * @param {number} options.port - Server port\n * @param {string} options.host - Server host\n * @param {string} options.mode - Server mode (development/production)\n * @param {object} logger - Logger instance\n */\nexport async function displayServerReady({ port, host, mode }, logger) {\n const protocol = mode === 'development' ? 'http' : 'https';\n const url = `${protocol}://${host === '0.0.0.0' ? 'localhost' : host}:${port}`;\n \n // Create a nice banner\n const banner = [\n '',\n chalk.bold.blue('╔══════════════════════════════════════════════════════════════╗'),\n chalk.bold.blue('║') + chalk.bold.white(' 🚀 Clovie Server Ready! 🚀 ') + chalk.bold.blue('║'),\n chalk.bold.blue('╠══════════════════════════════════════════════════════════════╣'),\n chalk.bold.blue('║') + chalk.white(` Mode: ${chalk.green(mode.toUpperCase())} `) + chalk.bold.blue('║'),\n chalk.bold.blue('║') + chalk.white(` URL: ${chalk.cyan.underline(url)} `) + chalk.bold.blue('║'),\n chalk.bold.blue('║') + chalk.white(` Host: ${chalk.yellow(host)}:${chalk.yellow(port)} `) + chalk.bold.blue('║'),\n chalk.bold.blue('╚══════════════════════════════════════════════════════════════╝'),\n ''\n ];\n\n // Display the banner\n banner.forEach(line => logger.info(line));\n\n // Try to open browser automatically in development mode\n if (mode === 'development') {\n try {\n await openBrowser(url);\n logger.info(chalk.green('🌐 Browser opened automatically'));\n } catch (error) {\n logger.debug('Could not open browser automatically:', error.message);\n }\n }\n\n // Display helpful commands\n const commands = [\n '',\n chalk.gray('💡 Quick Commands:'),\n chalk.gray(` • Press ${chalk.yellow('Ctrl+C')} to stop the server`),\n chalk.gray(` • Visit ${chalk.cyan(url)} to view your site`),\n chalk.gray(` • Check the console for live reload updates`),\n ''\n ];\n\n commands.forEach(line => logger.info(line));\n}\n\n/**\n * Open browser with the given URL\n * @param {string} url - URL to open\n */\nasync function openBrowser(url) {\n const platform = process.platform;\n let command;\n\n switch (platform) {\n case 'darwin': // macOS\n command = `open \"${url}\"`;\n break;\n case 'win32': // Windows\n command = `start \"${url}\"`;\n break;\n default: // Linux and others\n command = `xdg-open \"${url}\"`;\n break;\n }\n\n try {\n await execAsync(command);\n } catch (error) {\n throw new Error(`Failed to open browser: ${error.message}`);\n }\n}","import { ServiceProvider } from '@brickworks/engine';\nimport { Kernel } from './Kernel.js';\nimport { HttpAdapter } from './adapters/HttpAdapter.js';\nimport { displayServerReady } from './utils/serverReady.js';\n\nexport class Server extends ServiceProvider {\n static manifest = {\n name: 'Clovie Server',\n namespace: 'server',\n version: '1.0.0'\n };\n\n #routes = [];\n #adapter = null;\n #hooks = {\n onRequest: null,\n preHandler: null,\n onSend: null,\n onError: null\n };\n\n actions(useContext) { \n return {\n // Add a route\n add: (method, path, handler, meta = {}) => {\n this.#routes.push({\n method: method.toUpperCase(),\n path,\n handler,\n meta\n });\n },\n\n // Set server adapter\n useAdapter: (adapter) => {\n this.#adapter = adapter;\n return this;\n },\n\n // Configure hooks\n hooks: (hooks) => {\n this.#hooks = { ...this.#hooks, ...hooks };\n return this;\n },\n\n // Start listening server\n listen: async (opts = {}) => {\n const relay = useContext('relay');\n const port = opts.port || 3000;\n const host = opts.host || '0.0.0.0';\n const log = useContext('log');\n \n // Create kernel with services\n const kernel = new Kernel({\n state: useContext('state'),\n stable: useContext('stable'),\n // Add other services as needed for ISR/static/SSR\n });\n\n // Configure kernel hooks\n kernel.hooks(this.#hooks);\n\n // 1) Register app routes first\n kernel.registerRoutes(this.#routes);\n\n // 2) Add system routes (won't shadow user routes)\n kernel.registerRoutes([\n {\n method: 'GET',\n path: '/health',\n handler: (ctx) => ctx.respond.json({\n status: 'ok',\n timestamp: new Date().toISOString(),\n mode: opts.mode || 'production'\n })\n },\n {\n method: 'GET',\n path: '/api/info',\n handler: (ctx) => ctx.respond.json({\n name: 'Clovie',\n version: '1.0.0',\n mode: opts.mode || 'production',\n routes: this.#routes.length\n })\n }\n ]);\n\n // 3) Configure static file serving as 404 fallback\n if (opts.outputDir) {\n kernel.setStaticFallback(opts.outputDir, (ctx, outputDir) => {\n return this.#serveStaticFile(ctx, outputDir);\n });\n }\n\n // 4) Boot adapter\n this.#adapter = this.#adapter ?? HttpAdapter.create();\n await this.#adapter.initialize(kernel, log);\n \n // Start the server and return the instance\n const server = await this.#adapter.start({ port, host });\n \n // Check for LiveReload service and initialize it if available\n try {\n const liveReload = useContext('liveReload');\n log.debug(`LiveReload service found: ${!!liveReload}, mode: ${opts.mode}`);\n if (liveReload && opts.mode === 'development') {\n log.info('Initializing LiveReload...');\n await liveReload.initializeServer(server, opts);\n log.info('LiveReload initialized successfully');\n }\n } catch (error) {\n log.debug('LiveReload not available:', error.message);\n }\n \n // Display pretty server ready message\n const actualPort = server.address()?.port || port;\n await displayServerReady({ \n port: actualPort, \n host, \n mode: opts.mode || 'production' \n }, log);\n \n // Broadcast server ready event\n relay.broadcast('server:ready', server);\n return server;\n },\n\n // Get all routes\n getRoutes: () => this.#routes,\n\n // Clear all routes (useful for testing)\n clearRoutes: () => {\n this.#routes = [];\n },\n\n // Stop the server\n stop: async () => {\n if (this.#adapter) {\n await this.#adapter.stop();\n }\n },\n\n // Check if server is running\n isRunning: () => this.#adapter && this.#adapter.isRunning(),\n\n // Get the underlying HTTP server (for Socket.IO integration)\n getHttpServer: () => {\n if (this.#adapter) {\n return this.#adapter.getHttpServer();\n }\n return null;\n }\n };\n }\n /**\n * Serve static files from the output directory\n * @private\n */\n async #serveStaticFile(context, outputDir) {\n const fs = await import('fs/promises');\n const path = await import('path');\n \n try {\n // Get the requested file path\n const requestPath = context.req.path === '/' ? '/index.html' : context.req.path;\n let filePath = path.join(outputDir, requestPath);\n let stats;\n \n try {\n // Try the path as-is first\n stats = await fs.stat(filePath);\n } catch (error) {\n // If it fails and has no extension, try adding .html\n const ext = path.extname(requestPath);\n if (!ext) {\n const htmlPath = path.join(outputDir, `${requestPath}.html`);\n try {\n stats = await fs.stat(htmlPath);\n filePath = htmlPath; // Use the .html version\n } catch (htmlError) {\n // Neither worked, return 404\n return context.respond.text('Not Found', 404);\n }\n } else {\n // Had an extension but file not found\n return context.respond.text('Not Found', 404);\n }\n }\n \n if (stats.isFile()) {\n // Determine content type\n const ext = path.extname(filePath);\n const contentType = this.#getContentType(ext);\n \n // Read and serve the file\n const content = await fs.readFile(filePath);\n \n // Serve with correct content type\n if (contentType === 'text/html') {\n return context.respond.html(content.toString(), 200);\n } else if (contentType === 'text/css') {\n return context.respond.text(content.toString(), 200, { 'Content-Type': 'text/css' });\n } else if (contentType === 'application/javascript') {\n return context.respond.text(content.toString(), 200, { 'Content-Type': 'application/javascript' });\n } else if (contentType.startsWith('text/')) {\n return context.respond.text(content.toString(), 200, { 'Content-Type': contentType });\n } else {\n // For binary files, send as file response\n return context.respond.file(filePath, 200, { 'Content-Type': contentType });\n }\n } else {\n return context.respond.text('Not Found', 404);\n }\n } catch (error) {\n return context.respond.text('Not Found', 404);\n }\n }\n\n /**\n * Get content type based on file extension\n * @private\n */\n #getContentType(ext) {\n const types = {\n '.html': 'text/html',\n '.css': 'text/css',\n '.js': 'application/javascript',\n '.json': 'application/json',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.ico': 'image/x-icon',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n '.eot': 'application/vnd.ms-fontobject'\n };\n \n return types[ext.toLowerCase()] || 'application/octet-stream';\n }\n}"],"names":["Kernel","routes","hooks","onRequest","preHandler","onSend","onError","staticFallback","constructor","registerRoutes","rawRoutes","r","this","registerRoute","route","compiledRoute","match","compileRoute","path","push","h","Object","assign","setStaticFallback","outputDir","handler","handle","ctx","response","onReqOut","matchParams","find","method","req","m","staticResponse","status","respond","text","params","preOut","err","getRoutes","map","compiled","async","parseBody","Promise","resolve","contentType","headers","body","on","chunk","toString","includes","JSON","parse","data","result","pairs","split","pair","key","value","decodedKey","decodeURIComponent","decodedValue","endsWith","arrayKey","slice","parseUrlEncoded","raw","error","parseQuery","searchParams","entries","test","replace","AdapterInterface","create","name","server","kernel","log","initialize","start","options","Error","stop","getHttpServer","isRunning","handleRequest","res","createContext","url","URL","originalUrl","host","pathname","fromEntries","k","v","toLowerCase","query","RespondHelpers","sendResponse","isHead","resp","type","headersSent","statusCode","setHeader","end","getHeader","stringify","serveFile","b","pipe","Symbol","asyncIterator","write","once","filePath","fs","import","fsp","pipeline","promisify","pipelineAsync","MIME","st","stat","isFile","ext","extname","String","size","rs","createReadStream","handleError","json","html","file","stream","redirect","location","HttpAdapter","connections","Set","super","services","port","http","createServer","out","conn","add","delete","reject","listen","info","destroy","clear","close","execAsync","exec","displayServerReady","mode","logger","chalk","bold","blue","white","green","toUpperCase","cyan","underline","yellow","forEach","line","command","process","platform","message","openBrowser","debug","gray","Server","ServiceProvider","static","namespace","version","adapter","actions","useContext","meta","useAdapter","opts","relay","state","stable","timestamp","Date","toISOString","length","serveStaticFile","liveReload","initializeServer","actualPort","address","broadcast","clearRoutes","context","requestPath","stats","join","htmlPath","htmlError","getContentType","content","readFile","startsWith"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Server-BqbjrDXw.cjs","sources":["../../lib/Server/Kernel.js","../../lib/Server/utils/httpParsing.js","../../lib/Server/adapters/AdapterInterface.js","../../lib/Server/adapters/HttpAdapter.js","../../lib/Server/utils/serverReady.js","../../lib/Server/Server.js"],"sourcesContent":["import { compileRoute } from './utils/routeMatch.js';\n\n/**\n * Kernel handles route registration and matching\n * Separates routing logic from HTTP protocol handling\n */\nexport class Kernel {\n #routes = []; // { method, path, match, handler, mode, revalidate, ... }\n #hooks = { \n onRequest: null, \n preHandler: null, \n onSend: null, \n onError: null \n };\n #staticFallback = null;\n\n constructor() { \n }\n\n /**\n * Register multiple routes at once\n * @param {Array} rawRoutes - Array of route objects\n */\n registerRoutes(rawRoutes) {\n for (const r of rawRoutes) {\n this.registerRoute(r);\n }\n }\n\n /**\n * Register a single route\n * @param {Object} route - Route object with method, path, handler, etc.\n */\n registerRoute(route) {\n const compiledRoute = {\n ...route,\n match: compileRoute(route.path)\n };\n this.#routes.push(compiledRoute);\n }\n\n /**\n * Configure hooks\n * @param {Object} hooks - Hook functions\n */\n hooks(h) { \n Object.assign(this.#hooks, h); \n }\n\n /**\n * Set static file fallback handler\n * @param {string} outputDir - Directory to serve static files from\n * @param {Function} handler - Static file handler function\n */\n setStaticFallback(outputDir, handler) {\n this.#staticFallback = { outputDir, handler };\n }\n\n /**\n * Handle a request through the routing system\n * @param {Object} ctx - Request context\n * @returns {Object} Response object\n */\n async handle(ctx) {\n let response;\n try {\n // onRequest can short-circuit\n const onReqOut = await this.#hooks.onRequest?.(ctx);\n if (onReqOut) { response = onReqOut; return response; }\n\n // route match …\n let matchParams = null;\n const route = this.#routes.find(r => {\n if (r.method !== ctx.req.method) return false;\n const m = r.match(ctx.req.path);\n if (m) { matchParams = m; return true; }\n return false;\n });\n\n if (!route) {\n if (this.#staticFallback) {\n const staticResponse = await this.#staticFallback.handler(ctx, this.#staticFallback.outputDir);\n response = (staticResponse && staticResponse.status !== 404)\n ? staticResponse\n : ctx.respond.text('Not Found', 404);\n } else {\n response = ctx.respond.text('Not Found', 404);\n }\n return response;\n }\n\n ctx.req.params = matchParams || {};\n\n // preHandler can short-circuit\n const preOut = await this.#hooks.preHandler?.(ctx, route);\n if (preOut) { response = preOut; return response; }\n\n // route handler\n response = await route.handler(ctx);\n\n } catch (err) {\n response = (await this.#hooks.onError?.(ctx, err))\n ?? ctx.respond.text('Internal Server Error', 500);\n } finally {\n await this.#hooks.onSend?.(ctx, response);\n }\n return response ?? ctx.respond.text('', 204);\n}\n\n\n /**\n * Get all registered routes\n * @returns {Array} Array of registered routes\n */\n getRoutes() {\n return this.#routes.map(route => ({\n method: route.method,\n path: route.path,\n params: route.params || [],\n compiled: true\n }));\n }\n}\n","/**\n * HTTP parsing utilities for request body and query parameters\n */\n\n/**\n * Parse request body based on content type\n * @param {Object} req - Node.js request object\n * @returns {Object|null} Parsed body object or null\n */\nexport async function parseBody(req) {\n return new Promise((resolve) => {\n if (req.method === 'GET' || req.method === 'HEAD') {\n resolve(null);\n return;\n }\n\n const contentType = req.headers['content-type'] || '';\n let body = '';\n\n req.on('data', chunk => {\n body += chunk.toString();\n });\n\n req.on('end', () => {\n try {\n if (contentType.includes('application/json')) {\n resolve(body ? JSON.parse(body) : {});\n } else if (contentType.includes('application/x-www-form-urlencoded')) {\n resolve(parseUrlEncoded(body));\n } else if (contentType.includes('multipart/form-data')) {\n // For now, just return the raw body for multipart\n // Could be enhanced with proper multipart parsing\n resolve({ raw: body });\n } else {\n resolve(body || null);\n }\n } catch (error) {\n resolve(null);\n }\n });\n\n req.on('error', () => {\n resolve(null);\n });\n });\n}\n\n/**\n * Parse URL-encoded form data\n * @param {string} data - URL-encoded string\n * @returns {Object} Parsed object\n */\nfunction parseUrlEncoded(data) {\n const result = {};\n const pairs = data.split('&');\n \n for (const pair of pairs) {\n const [key, value] = pair.split('=');\n if (key) {\n const decodedKey = decodeURIComponent(key);\n const decodedValue = value ? decodeURIComponent(value) : '';\n \n // Handle arrays (key[] or key[0])\n if (decodedKey.endsWith('[]')) {\n const arrayKey = decodedKey.slice(0, -2);\n if (!result[arrayKey]) result[arrayKey] = [];\n result[arrayKey].push(decodedValue);\n } else {\n result[decodedKey] = decodedValue;\n }\n }\n }\n \n return result;\n}\n\n/**\n * Parse query parameters from URLSearchParams\n * @param {URLSearchParams} searchParams - URL search parameters\n * @returns {Object} Parsed query object with support for arrays\n */\nexport function parseQuery(searchParams) {\n const result = {};\n \n for (const [key, value] of searchParams.entries()) {\n // Handle array parameters (key[] or key[0])\n if (key.endsWith('[]') || /\\[\\d*\\]$/.test(key)) {\n const arrayKey = key.replace(/\\[\\d*\\]$/, '').replace('[]', '');\n if (!result[arrayKey]) result[arrayKey] = [];\n result[arrayKey].push(value);\n } else {\n result[key] = value;\n }\n }\n \n return result;\n}\n","/**\n * Clovie Adapter Interface\n * \n * This defines the contract that all HTTP server adapters must implement.\n * The Clovie kernel uses this interface to delegate HTTP handling to\n * any compatible adapter (Express, Fastify, Node HTTP, etc.)\n */\nimport { parseQuery } from '../utils/httpParsing.js';\n\n/**\n * Adapter Interface - All adapters must implement this\n */\nexport class AdapterInterface {\n static create(name) {\n return new this(name);\n }\n\n constructor(name) {\n this.name = name;\n this.server = null;\n this.kernel = null;\n this.log = null;\n this.hooks = null;\n }\n\n /**\n * Initialize the adapter with kernel and context\n * @param {Object} kernel - Clovie kernel instance\n * @param {Object} log - Clovie logger\n */\n async initialize(kernel, log) {\n this.kernel = kernel;\n this.log = log;\n }\n\n /**\n * Start the HTTP server\n * @param {Object} options - Server options (port, host, etc.)\n * @returns {Promise<Object>} - Server instance\n */\n async start(options) {\n throw new Error(`start() must be implemented by ${this.name} adapter`);\n }\n\n /**\n * Stop the HTTP server\n * @returns {Promise<void>}\n */\n async stop() {\n throw new Error(`stop() must be implemented by ${this.name} adapter`);\n }\n\n /**\n * Get the underlying HTTP server instance\n * Used by services like LiveReload for Socket.IO integration\n * @returns {Object|null} - HTTP server instance\n */\n getHttpServer() {\n return this.server;\n }\n\n /**\n * Check if the server is currently running\n * @returns {boolean}\n */\n isRunning() {\n return this.server !== null;\n }\n\n /**\n * Handle a request through the adapter\n * @param {Object} req - HTTP request\n * @param {Object} res - HTTP response\n * @returns {Promise<void>}\n */\n async handleRequest(req, res) {\n throw new Error(`handleRequest() must be implemented by ${this.name} adapter`);\n }\n\n /**\n * Create standardized context object from request\n * @param {Object} req - HTTP request\n * @param {Object} res - HTTP response\n * @returns {Object} - Standardized context object\n */\n createContext(req, res) {\n const url = new URL(req.url || req.originalUrl, `http://${req.headers.host}`);\n\n return {\n req: {\n method: req.method,\n url: url.toString(),\n path: url.pathname,\n headers: Object.fromEntries(\n Object.entries(req.headers).map(([k, v]) => [k.toLowerCase(), v])\n ),\n query: req.query || parseQuery(url.searchParams),\n body: req.body || null,\n raw: { req, res },\n params: {}\n },\n res,\n respond: new RespondHelpers()\n };\n }\n\n /**\n * Send response using standardized response format\n * @param {Object} res - HTTP response\n * @param {Object} response - Response object from route handler\n * @param {boolean} isHead - Whether this is a HEAD request\n * @returns {Promise<void>}\n */\n async sendResponse(res, response, isHead = false) {\n // Default to 204 if no response object was returned\n const resp = response ?? { type: 'text', status: 204, headers: {}, body: '' };\n\n if (res.headersSent) return; // defensive guard\n\n // Set status and headers (normalize keys)\n res.statusCode = resp.status ?? 200;\n if (resp.headers) {\n for (const [k, v] of Object.entries(resp.headers)) {\n res.setHeader(k.toLowerCase(), v);\n }\n }\n\n // Respect HEAD requests: send headers only\n if (isHead) {\n return res.end();\n }\n\n switch (resp.type) {\n case 'json': {\n if (!res.getHeader('content-type')) {\n res.setHeader('content-type', 'application/json; charset=utf-8');\n }\n return res.end(JSON.stringify(resp.body));\n }\n\n case 'text': {\n if (!res.getHeader('content-type')) {\n res.setHeader('content-type', 'text/plain; charset=utf-8');\n }\n return res.end(resp.body ?? '');\n }\n\n case 'html': {\n if (!res.getHeader('content-type')) {\n res.setHeader('content-type', 'text/html; charset=utf-8');\n }\n return res.end(resp.body ?? '');\n }\n\n case 'file': {\n return await this.serveFile(res, resp.path);\n }\n\n case 'stream': {\n const b = resp.body;\n if (!b) return res.end();\n // Node stream\n if (typeof b.pipe === 'function') return b.pipe(res);\n // AsyncIterable\n if (Symbol.asyncIterator in Object(b)) {\n for await (const chunk of b) {\n if (!res.write(chunk)) {\n await new Promise(r => res.once('drain', r));\n }\n }\n return res.end();\n }\n // Fallback\n return res.end(b);\n }\n\n default:\n return res.end('');\n }\n }\n\n /**\n * Serve static files with proper MIME types and streaming\n * @param {Object} res - HTTP response\n * @param {string} filePath - Path to file to serve\n * @returns {Promise<void>}\n */\n async serveFile(res, filePath) {\n const fs = await import('node:fs');\n const fsp = await import('node:fs/promises');\n const path = await import('node:path');\n const { pipeline } = await import('node:stream');\n const { promisify } = await import('node:util');\n \n const pipelineAsync = promisify(pipeline);\n\n const MIME = {\n '.html': 'text/html; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.js': 'application/javascript; charset=utf-8',\n '.mjs': 'application/javascript; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.ico': 'image/x-icon',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n '.eot': 'application/vnd.ms-fontobject'\n };\n\n try {\n const st = await fsp.stat(filePath);\n if (!st.isFile()) {\n res.statusCode = 404;\n res.setHeader('content-type', 'text/plain; charset=utf-8');\n return res.end('Not Found');\n }\n\n const ext = path.extname(filePath).toLowerCase();\n if (!res.getHeader('content-type')) {\n res.setHeader('content-type', MIME[ext] ?? 'application/octet-stream');\n }\n res.setHeader('content-length', String(st.size));\n\n const rs = fs.createReadStream(filePath);\n rs.on('error', () => {\n if (!res.headersSent) res.statusCode = 404;\n res.end('Not Found');\n });\n await pipelineAsync(rs, res); // backpressure-aware piping\n } catch {\n if (!res.headersSent) {\n res.statusCode = 404;\n res.setHeader('content-type', 'text/plain; charset=utf-8');\n }\n res.end('Not Found');\n }\n }\n\n /**\n * Handle request errors consistently\n * @param {Object} res - HTTP response\n * @param {Error} error - Error that occurred\n * @returns {Promise<void>}\n */\n async handleError(res, error) {\n this.log?.error?.('Request handling error:', error);\n if (!res.headersSent) {\n res.statusCode = 500;\n res.setHeader('content-type', 'text/plain; charset=utf-8');\n res.end('Internal Server Error');\n }\n }\n}\n\n/**\n * Route object structure that adapters receive from Clovie kernel\n */\nexport class ClovieRoute {\n constructor(method, path, handler, options = {}) {\n this.method = method.toUpperCase();\n this.path = path;\n this.handler = handler;\n this.options = options;\n this.params = options.params || [];\n }\n}\n\n/**\n * Hook object structure for lifecycle management\n */\nexport class ClovieHooks {\n constructor() {\n this.onRequest = null;\n this.preHandler = null;\n this.onSend = null;\n this.onError = null;\n }\n}\n\n/**\n * Context object passed to route handlers\n */\nexport class ClovieContext {\n constructor(req, res, state, stable) {\n this.req = req;\n this.res = res;\n this.state = state;\n this.stable = stable;\n this.respond = new RespondHelpers();\n }\n}\n\n/**\n * Response helpers for route handlers\n */\nexport class RespondHelpers {\n json(data, status = 200, headers = {}) {\n return { type: 'json', status, headers, body: data };\n }\n\n text(data, status = 200, headers = {}) {\n return { type: 'text', status, headers, body: data };\n }\n\n html(data, status = 200, headers = {}) {\n return { type: 'html', status, headers, body: data };\n }\n\n file(path, status = 200, headers = {}) {\n return { type: 'file', status, headers, path };\n }\n\n stream(body, status = 200, headers = {}) {\n return { type: 'stream', status, headers, body };\n }\n\n redirect(location, status = 302, headers = {}) {\n return { type:'text', status, headers: { ...headers, location }, body: '' };\n }\n}\n","/**\n * HTTP Adapter for Node.js native HTTP server\n * Thin I/O shim: normalize req/res, call kernel, send response\n */\nimport http from 'node:http';\nimport { AdapterInterface } from './AdapterInterface.js';\nimport { parseBody } from '../utils/httpParsing.js';\n\nexport class HttpAdapter extends AdapterInterface {\n #connections = new Set();\n\n constructor() {\n super('http');\n }\n\n async initialize(kernel, services, log) {\n await super.initialize(kernel, services, log);\n }\n\n async start({ port = 3000, host = '0.0.0.0' } = {}) {\n this.server = http.createServer(async (req, res) => {\n try {\n // Parse body for HTTP adapter (Express handles this differently)\n if (!req.body) {\n req.body = await parseBody(req);\n }\n\n const ctx = this.createContext(req, res);\n const out = await this.kernel.handle(ctx);\n await this.sendResponse(res, out, req.method === 'HEAD');\n } catch (error) {\n await this.handleError(res, error);\n }\n });\n\n // Track connections for clean shutdown\n this.server.on('connection', (conn) => {\n this.#connections.add(conn);\n conn.on('close', () => {\n this.#connections.delete(conn);\n });\n });\n\n await new Promise((resolve, reject) =>\n this.server.listen(port, host, err => (err ? reject(err) : resolve()))\n );\n\n this.log?.info?.(`HTTP Server listening on http://${host}:${port}`);\n return this.server;\n }\n\n async stop() {\n if (this.server) {\n // Destroy all active connections\n for (const conn of this.#connections) {\n conn.destroy();\n }\n this.#connections.clear();\n\n // Close the server\n await new Promise(resolve => this.server.close(() => resolve()));\n this.server = null;\n }\n }\n\n}\n","import chalk from 'chalk';\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\n\nconst execAsync = promisify(exec);\n\n/**\n * Display a pretty server ready message with clickable URL\n * @param {object} options - Server options\n * @param {number} options.port - Server port\n * @param {string} options.host - Server host\n * @param {string} options.mode - Server mode (development/production)\n * @param {object} logger - Logger instance\n */\nexport async function displayServerReady({ port, host, mode }, logger) {\n const protocol = mode === 'development' ? 'http' : 'https';\n const url = `${protocol}://${host === '0.0.0.0' ? 'localhost' : host}:${port}`;\n \n // Create a nice banner\n const banner = [\n '',\n chalk.bold.blue('╔══════════════════════════════════════════════════════════════╗'),\n chalk.bold.blue('║') + chalk.bold.white(' 🚀 Clovie Server Ready! 🚀 ') + chalk.bold.blue('║'),\n chalk.bold.blue('╠══════════════════════════════════════════════════════════════╣'),\n chalk.bold.blue('║') + chalk.white(` Mode: ${chalk.green(mode.toUpperCase())} `) + chalk.bold.blue('║'),\n chalk.bold.blue('║') + chalk.white(` URL: ${chalk.cyan.underline(url)} `) + chalk.bold.blue('║'),\n chalk.bold.blue('║') + chalk.white(` Host: ${chalk.yellow(host)}:${chalk.yellow(port)} `) + chalk.bold.blue('║'),\n chalk.bold.blue('╚══════════════════════════════════════════════════════════════╝'),\n ''\n ];\n\n // Display the banner\n banner.forEach(line => logger.info(line));\n\n // Try to open browser automatically in development mode\n if (mode === 'development') {\n try {\n await openBrowser(url);\n logger.info(chalk.green('🌐 Browser opened automatically'));\n } catch (error) {\n logger.debug('Could not open browser automatically:', error.message);\n }\n }\n\n // Display helpful commands\n const commands = [\n '',\n chalk.gray('💡 Quick Commands:'),\n chalk.gray(` • Press ${chalk.yellow('Ctrl+C')} to stop the server`),\n chalk.gray(` • Visit ${chalk.cyan(url)} to view your site`),\n chalk.gray(` • Check the console for live reload updates`),\n ''\n ];\n\n commands.forEach(line => logger.info(line));\n}\n\n/**\n * Open browser with the given URL\n * @param {string} url - URL to open\n */\nasync function openBrowser(url) {\n const platform = process.platform;\n let command;\n\n switch (platform) {\n case 'darwin': // macOS\n command = `open \"${url}\"`;\n break;\n case 'win32': // Windows\n command = `start \"${url}\"`;\n break;\n default: // Linux and others\n command = `xdg-open \"${url}\"`;\n break;\n }\n\n try {\n await execAsync(command);\n } catch (error) {\n throw new Error(`Failed to open browser: ${error.message}`);\n }\n}","import { ServiceProvider } from '@brickworks/engine';\nimport { Kernel } from './Kernel.js';\nimport { HttpAdapter } from './adapters/HttpAdapter.js';\nimport { displayServerReady } from './utils/serverReady.js';\n\nexport class Server extends ServiceProvider {\n static manifest = {\n name: 'Clovie Server',\n namespace: 'server',\n version: '1.0.0'\n };\n\n #routes = [];\n #adapter = null;\n #hooks = {\n onRequest: null,\n preHandler: null,\n onSend: null,\n onError: null\n };\n\n actions(useContext) { \n return {\n // Add a route\n add: (method, path, handler, meta = {}) => {\n this.#routes.push({\n method: method.toUpperCase(),\n path,\n handler,\n meta\n });\n },\n\n // Set server adapter\n useAdapter: (adapter) => {\n this.#adapter = adapter;\n return this;\n },\n\n // Configure hooks\n hooks: (hooks) => {\n this.#hooks = { ...this.#hooks, ...hooks };\n return this;\n },\n\n // Start listening server\n listen: async (opts = {}) => {\n const relay = useContext('relay');\n const port = opts.port || 3000;\n const host = opts.host || '0.0.0.0';\n const log = useContext('log');\n \n // Create kernel with services\n const kernel = new Kernel({\n state: useContext('state'),\n stable: useContext('stable'),\n // Add other services as needed for ISR/static/SSR\n });\n\n // Configure kernel hooks\n kernel.hooks(this.#hooks);\n\n // 1) Register app routes first\n kernel.registerRoutes(this.#routes);\n\n // 2) Add system routes (won't shadow user routes)\n kernel.registerRoutes([\n {\n method: 'GET',\n path: '/health',\n handler: (ctx) => ctx.respond.json({\n status: 'ok',\n timestamp: new Date().toISOString(),\n mode: opts.mode || 'production'\n })\n },\n {\n method: 'GET',\n path: '/api/info',\n handler: (ctx) => ctx.respond.json({\n name: 'Clovie',\n version: '1.0.0',\n mode: opts.mode || 'production',\n routes: this.#routes.length\n })\n }\n ]);\n\n // 3) Configure static file serving as 404 fallback\n if (opts.outputDir) {\n kernel.setStaticFallback(opts.outputDir, (ctx, outputDir) => {\n return this.#serveStaticFile(ctx, outputDir);\n });\n }\n\n // 4) Boot adapter\n this.#adapter = this.#adapter ?? HttpAdapter.create();\n await this.#adapter.initialize(kernel, log);\n \n // Start the server and return the instance\n const server = await this.#adapter.start({ port, host });\n \n // Check for LiveReload service and initialize it if available\n try {\n const liveReload = useContext('liveReload');\n log.debug(`LiveReload service found: ${!!liveReload}, mode: ${opts.mode}`);\n if (liveReload && opts.mode === 'development') {\n log.info('Initializing LiveReload...');\n await liveReload.initializeServer(server, opts);\n log.info('LiveReload initialized successfully');\n }\n } catch (error) {\n log.debug('LiveReload not available:', error.message);\n }\n \n // Display pretty server ready message\n const actualPort = server.address()?.port || port;\n await displayServerReady({ \n port: actualPort, \n host, \n mode: opts.mode || 'production' \n }, log);\n \n // Broadcast server ready event\n relay.broadcast('server:ready', server);\n return server;\n },\n\n // Get all routes\n getRoutes: () => this.#routes,\n\n // Clear all routes (useful for testing)\n clearRoutes: () => {\n this.#routes = [];\n },\n\n // Stop the server\n stop: async () => {\n if (this.#adapter) {\n await this.#adapter.stop();\n }\n },\n\n // Check if server is running\n isRunning: () => this.#adapter && this.#adapter.isRunning(),\n\n // Get the underlying HTTP server (for Socket.IO integration)\n getHttpServer: () => {\n if (this.#adapter) {\n return this.#adapter.getHttpServer();\n }\n return null;\n }\n };\n }\n /**\n * Serve static files from the output directory\n * @private\n */\n async #serveStaticFile(context, outputDir) {\n const fs = await import('fs/promises');\n const path = await import('path');\n \n try {\n // Get the requested file path\n const requestPath = context.req.path === '/' ? '/index.html' : context.req.path;\n let filePath = path.join(outputDir, requestPath);\n let stats;\n \n try {\n // Try the path as-is first\n stats = await fs.stat(filePath);\n } catch (error) {\n // If it fails and has no extension, try adding .html\n const ext = path.extname(requestPath);\n if (!ext) {\n const htmlPath = path.join(outputDir, `${requestPath}.html`);\n try {\n stats = await fs.stat(htmlPath);\n filePath = htmlPath; // Use the .html version\n } catch (htmlError) {\n // Neither worked, return 404\n return context.respond.text('Not Found', 404);\n }\n } else {\n // Had an extension but file not found\n return context.respond.text('Not Found', 404);\n }\n }\n \n if (stats.isFile()) {\n // Determine content type\n const ext = path.extname(filePath);\n const contentType = this.#getContentType(ext);\n \n // Read and serve the file\n const content = await fs.readFile(filePath);\n \n // Serve with correct content type\n if (contentType === 'text/html') {\n return context.respond.html(content.toString(), 200);\n } else if (contentType === 'text/css') {\n return context.respond.text(content.toString(), 200, { 'Content-Type': 'text/css' });\n } else if (contentType === 'application/javascript') {\n return context.respond.text(content.toString(), 200, { 'Content-Type': 'application/javascript' });\n } else if (contentType.startsWith('text/')) {\n return context.respond.text(content.toString(), 200, { 'Content-Type': contentType });\n } else {\n // For binary files, send as file response\n return context.respond.file(filePath, 200, { 'Content-Type': contentType });\n }\n } else {\n return context.respond.text('Not Found', 404);\n }\n } catch (error) {\n return context.respond.text('Not Found', 404);\n }\n }\n\n /**\n * Get content type based on file extension\n * @private\n */\n #getContentType(ext) {\n const types = {\n '.html': 'text/html',\n '.css': 'text/css',\n '.js': 'application/javascript',\n '.json': 'application/json',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.ico': 'image/x-icon',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n '.eot': 'application/vnd.ms-fontobject'\n };\n \n return types[ext.toLowerCase()] || 'application/octet-stream';\n }\n}"],"names":["Kernel","routes","hooks","onRequest","preHandler","onSend","onError","staticFallback","constructor","registerRoutes","rawRoutes","r","this","registerRoute","route","compiledRoute","match","compileRoute","path","push","h","Object","assign","setStaticFallback","outputDir","handler","handle","ctx","response","onReqOut","matchParams","find","method","req","m","staticResponse","status","respond","text","params","preOut","err","getRoutes","map","compiled","async","parseBody","Promise","resolve","contentType","headers","body","on","chunk","toString","includes","JSON","parse","data","result","pairs","split","pair","key","value","decodedKey","decodeURIComponent","decodedValue","endsWith","arrayKey","slice","parseUrlEncoded","raw","error","parseQuery","searchParams","entries","test","replace","AdapterInterface","create","name","server","kernel","log","initialize","start","options","Error","stop","getHttpServer","isRunning","handleRequest","res","createContext","url","URL","originalUrl","host","pathname","fromEntries","k","v","toLowerCase","query","RespondHelpers","sendResponse","isHead","resp","type","headersSent","statusCode","setHeader","end","getHeader","stringify","serveFile","b","pipe","Symbol","asyncIterator","write","once","filePath","fs","import","fsp","pipeline","promisify","pipelineAsync","MIME","st","stat","isFile","ext","extname","String","size","rs","createReadStream","handleError","json","html","file","stream","redirect","location","HttpAdapter","connections","Set","super","services","port","http","createServer","out","conn","add","delete","reject","listen","info","destroy","clear","close","execAsync","exec","displayServerReady","mode","logger","chalk","bold","blue","white","green","toUpperCase","cyan","underline","yellow","forEach","line","command","process","platform","message","openBrowser","debug","gray","Server","ServiceProvider","static","namespace","version","adapter","actions","useContext","meta","useAdapter","opts","relay","state","stable","timestamp","Date","toISOString","length","serveStaticFile","liveReload","initializeServer","actualPort","address","broadcast","clearRoutes","context","requestPath","stats","join","htmlPath","htmlError","getContentType","content","readFile","startsWith"],"mappings":"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"}
|