clovie 0.1.13 → 0.1.15

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/bin/cli.js CHANGED
@@ -8,6 +8,7 @@ const __filename = fileURLToPath(import.meta.url);
8
8
  const __dirname = dirname(__filename);
9
9
 
10
10
  // Local - import from compiled dist for published package
11
+ // import { createClovie } from "../lib/createClovie.js";
11
12
  import { createClovie } from "../dist/index.js";
12
13
 
13
14
  // Check for create command first (before any argument parsing)
@@ -1,6 +1,6 @@
1
1
  import { Server } from "socket.io";
2
2
 
3
- import { S as ServiceProvider, q as queueMacrotask } from "./createClovie-1_zYoNTN.js";
3
+ import { S as ServiceProvider, q as queueMacrotask } from "./createClovie-DffOfE7b.js";
4
4
 
5
5
  import "stream";
6
6
 
@@ -47,7 +47,7 @@ class LiveReload extends ServiceProvider {
47
47
  },
48
48
  notifyReload: () => {
49
49
  this.#reloading || (this.#reloading = !0, queueMacrotask(() => {
50
- this.#reloading = !1, this.#io.emit("reload");
50
+ this.#reloading = !1, this.#io && this.#io.emit("reload");
51
51
  }));
52
52
  },
53
53
  injectLiveReloadScript: async (renderedContent, config) => {
@@ -92,4 +92,4 @@ class LiveReload extends ServiceProvider {
92
92
  }
93
93
 
94
94
  export { LiveReload };
95
- //# sourceMappingURL=LiveReload-CGbacq3U.js.map
95
+ //# sourceMappingURL=LiveReload-BYADGncf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LiveReload-BYADGncf.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) => {\n const log = this.useContext('log');\n if (this.config?.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, config) => {\n const lastBodyIndex = renderedContent.lastIndexOf('</body>');\n if (lastBodyIndex !== -1) {\n const scriptConfig = { \n mode: config.mode || 'development', \n port: config.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 = (config) => `<!-- 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 config = ${JSON.stringify(config)};\n \n console.log('Initializing live reload with config:', config);\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","log","useContext","config","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,MAAOC;gBACvB,MAAMC,MAAML,KAAKM,WAAW;gBACF,kBAAtBN,KAAKO,QAAQC,cACTR,MAAKS,cAAeL,QAAQC;;YAGtCK,cAAc;gBACRV,MAAKF,cACTE,MAAKF,aAAa,GAElBa,eAAe;oBACbX,MAAKF,aAAa,GACdE,MAAKH,MACPG,MAAKH,GAAIe,KAAK;;;YAIpBC,wBAAwBV,OAAOW,iBAAiBP;gBAC9C,MAAMQ,gBAAgBD,gBAAgBE,YAAY;gBAClD,KAAsB,MAAlBD,eAAsB;oBACxB,MAAME,eAAe;wBACnBT,MAAMD,OAAOC,QAAQ;wBACrBU,MAAMX,OAAOW,QAAQ;;oBAGvB;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,QAAQC;QAC3B;kBAEQ,IAAIoB,QAAQC,WAAWC,WAAWD,SAAS,OAEjDrB,IAAIuB,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;gBACzB/B,IAAIuB,MAAM,qBAAqBQ,OAAOC,OAEtCD,OAAOD,GAAG,cAAeG;oBACvBjC,IAAIuB,MAAM,wBAAwBQ,OAAOC,QAAQC;oBAGnDF,OAAOD,GAAG,SAAUI;oBAClBlC,IAAIkC,MAAM,iBAAiBA;;gBAI/BlC,IAAImC,KAAK;AACX,UAAE,OAAOD;YACPlC,IAAIkC,MAAM,+BAA+BA;AAC3C;AACF;IAEAnB,kBAAqBb,UAAW,mLAIbkC,KAAKC,UAAUnC;;;"}
@@ -1,4 +1,4 @@
1
- import { m as matchRoute, c as chalk, S as ServiceProvider, p as parseRouteParams } from "./createClovie-1_zYoNTN.js";
1
+ import { m as matchRoute, c as chalk, S as ServiceProvider, p as parseRouteParams } from "./createClovie-DffOfE7b.js";
2
2
 
3
3
  import http from "node:http";
4
4
 
@@ -372,4 +372,4 @@ class Server extends ServiceProvider {
372
372
  }
373
373
 
374
374
  export { Server };
375
- //# sourceMappingURL=Server-B7CJgUcU.js.map
375
+ //# sourceMappingURL=Server-D0dT9bUg.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Server-B7CJgUcU.js","sources":["../lib/adapters/AdapterInterface.js","../lib/adapters/http.js","../lib/utils/serverReady.js","../lib/Server.js"],"sourcesContent":["/**\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 */\n\n/**\n * Adapter Interface - All adapters must implement this\n */\nexport class AdapterInterface {\n constructor(name) {\n this.name = name;\n this.server = null;\n this.routes = [];\n this.hooks = null;\n }\n\n /**\n * Initialize the adapter with routes, hooks, and useContext\n * @param {Array} routes - Array of route objects from Clovie kernel\n * @param {Object} hooks - Lifecycle hooks from Clovie kernel\n * @param {Function} useContext - Engine context accessor\n */\n async initialize(routes, hooks, useContext) {\n throw new Error(`initialize() must be implemented by ${this.name} adapter`);\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/**\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","/**\n * Built-in HTTP adapter for Clovie kernel\n */\nimport http from 'node:http';\nimport { AdapterInterface, ClovieRoute, ClovieHooks, ClovieContext } from './AdapterInterface.js';\nimport { matchRoute } from '../utils/routeParams.js';\n\nexport class HttpAdapter extends AdapterInterface {\n constructor() {\n super('http');\n this.logger = null;\n }\n\n async initialize(routes, hooks, useContext) {\n this.routes = routes;\n this.hooks = hooks || {};\n this.useContext = useContext;\n this.logger = useContext('log');\n }\n\n async start(opts) {\n const { port = 3000, host = '0.0.0.0' } = opts;\n \n this.server = http.createServer((req, res) => this.handleRequest(req, res));\n \n return new Promise((resolve, reject) => {\n this.server.listen(port, host, (err) => {\n if (err) {\n reject(err);\n } else {\n this.logger?.info(`HTTP Server listening on http://${host}:${port}`);\n resolve(this.server); // Return the server instance\n }\n });\n });\n }\n\n async stop() {\n if (this.server) {\n return new Promise((resolve) => {\n this.server.close(() => {\n this.logger?.info('HTTP Server stopped');\n this.server = null;\n resolve();\n });\n });\n }\n }\n\n async handleRequest(req, res) {\n let context;\n try {\n // Get state and stable from useContext\n const [state, stable] = this.useContext('state', 'stable');\n \n // Create context from Node.js request\n context = this.createContext(req, res, state, stable);\n \n // Parse URL to get pathname\n const url = new URL(req.url, `http://${req.headers.host}`);\n \n // Find matching route using pathname (not full URL)\n const route = this.findRoute(req.method, url.pathname);\n \n if (!route) {\n res.statusCode = 404;\n res.end('Not Found');\n return;\n }\n\n // Extract route parameters and update context\n const params = this.extractParams(route.path, url.pathname);\n context.req.params = params;\n\n // Execute hooks\n await this.hooks.onRequest?.(context);\n await this.hooks.preHandler?.(context);\n\n // Execute route handler\n const response = await route.handler(context);\n \n // Execute onSend hook\n await this.hooks.onSend?.(context, response);\n\n // Send response\n this.sendResponse(res, response);\n\n } catch (error) {\n const errorResponse = await this.hooks.onError?.(context, error) || {\n type: 'text',\n status: 500,\n body: 'Internal Server Error'\n };\n \n if (!res.headersSent) {\n this.sendResponse(res, errorResponse);\n }\n }\n }\n\n createContext(req, res, state, stable) {\n const url = new URL(req.url, `http://${req.headers.host}`);\n \n const clovieReq = {\n method: req.method,\n url: url.toString(),\n path: url.pathname,\n params: {}, // Will be populated by route matching\n query: Object.fromEntries(url.searchParams),\n headers: req.headers,\n body: req.body,\n raw: { req, res }\n };\n \n return new ClovieContext(clovieReq, res, state, stable);\n }\n\n findRoute(method, pathname) {\n for (const route of this.routes) {\n if (route.method === method && this.matchPath(route.path, pathname)) {\n return route;\n }\n }\n return null;\n }\n\n matchPath(routePath, urlPath) {\n // Use the existing route matching logic\n const match = matchRoute(routePath, urlPath);\n return match !== null;\n }\n\n extractParams(routePath, urlPath) {\n // Use the existing route matching logic to extract parameters\n const match = matchRoute(routePath, urlPath);\n return match ? match.params : {};\n }\n\n sendResponse(res, response) {\n if (!response) return;\n\n // Set headers\n if (response.headers) {\n for (const [key, value] of Object.entries(response.headers)) {\n res.setHeader(key, value);\n }\n }\n\n // Set status\n res.statusCode = response.status || 200;\n\n // Send body based on type\n switch (response.type) {\n case 'json':\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify(response.body));\n break;\n case 'text':\n // Set Content-Type header if not already provided\n const hasContentType = response.headers && response.headers['Content-Type'];\n if (!hasContentType) {\n res.setHeader('Content-Type', 'text/plain');\n }\n res.end(response.body);\n break;\n case 'html':\n res.setHeader('Content-Type', 'text/html');\n res.end(response.body);\n break;\n case 'file':\n // For file responses, you'd typically use res.sendFile() or similar\n res.end('File response not implemented in HTTP adapter');\n break;\n case 'stream':\n res.end(response.body);\n break;\n default:\n res.end(response.body || '');\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 { parseRouteParams } from './utils/routeParams.js';\nimport { HttpAdapter } from './adapters/http.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 initialize(_, config) {\n this.#routes.push({\n method: 'GET',\n path: '/health',\n handler: async (context) => {\n return context.respond.json({\n status: 'ok',\n timestamp: new Date().toISOString(),\n mode: config.mode || 'production'\n });\n },\n params: []\n });\n\n // Add API info endpoint\n this.#routes.push({\n method: 'GET',\n path: '/api/info',\n handler: async (context) => {\n return context.respond.json({\n name: 'Clovie',\n version: '1.0.0',\n mode: config.mode || 'production',\n routes: this.#routes.length\n });\n },\n params: []\n });\n\n // Serve static files from outputDir (wildcard route last)\n if (config.outputDir) {\n this.#routes.push({\n method: 'GET',\n path: '/*',\n handler: async (context) => {\n return this.#serveStaticFile(context, config.outputDir);\n },\n params: [{ name: 'wild', type: 'string' }]\n });\n }\n }\n\n actions(useContext) { \n return {\n // Add a route\n add: (method, path, handler, options = {}) => {\n // Parse route parameters for validation and documentation\n const params = parseRouteParams(path);\n \n this.#routes.push({ \n method: method.toUpperCase(), \n path, \n handler: async (context) => {\n // Inject engine context into handler\n context.useContext = useContext;\n return await handler(context);\n },\n params,\n ...options // Allow additional options like paramTypes, validation, etc.\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 Object.assign(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 || opts || 3000;\n const host = opts.host || '0.0.0.0';\n const log = useContext('log');\n \n // Use HTTP adapter by default if none set\n if (!this.#adapter) {\n this.#adapter = new HttpAdapter();\n }\n\n // Initialize adapter with routes, hooks, and useContext\n await this.#adapter.initialize(this.#routes, this.#hooks, useContext);\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: ${this.config?.mode}`);\n if (liveReload && this.config?.mode === 'development') {\n log.info('Initializing LiveReload...');\n await liveReload.initializeServer(server);\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: this.config.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 // 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 // Legacy support for direct HTTP handling\n handle: async (req, res) => {\n // Create a temporary HTTP adapter for legacy support\n const tempAdapter = new HttpAdapter();\n await tempAdapter.initialize(this.#routes, this.#hooks, useContext);\n return tempAdapter.handleRequest(req, res);\n }\n };\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 const filePath = path.join(outputDir, requestPath);\n \n // Check if file exists\n const stats = await fs.stat(filePath);\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\n}\n"],"names":["AdapterInterface","constructor","name","this","server","routes","hooks","initialize","useContext","Error","start","options","stop","getHttpServer","isRunning","handleRequest","req","res","ClovieContext","state","stable","respond","RespondHelpers","json","data","status","headers","type","body","text","html","file","path","stream","HttpAdapter","super","logger","opts","port","host","http","createServer","Promise","resolve","reject","listen","err","info","close","context","createContext","url","URL","route","findRoute","method","pathname","statusCode","end","params","extractParams","onRequest","preHandler","response","handler","onSend","sendResponse","error","errorResponse","onError","headersSent","clovieReq","toString","query","Object","fromEntries","searchParams","raw","matchPath","routePath","urlPath","matchRoute","match","key","value","entries","setHeader","JSON","stringify","execAsync","promisify","exec","async","displayServerReady","mode","chalk","bold","blue","white","green","toUpperCase","cyan","underline","yellow","forEach","line","command","process","platform","message","openBrowser","debug","gray","Server","ServiceProvider","static","namespace","version","adapter","_","config","push","timestamp","Date","toISOString","length","outputDir","serveStaticFile","actions","add","parseRouteParams","useAdapter","assign","relay","log","liveReload","initializeServer","actualPort","address","broadcast","getRoutes","handle","tempAdapter","fs","import","requestPath","filePath","join","stat","isFile","ext","extname","contentType","getContentType","content","readFile","startsWith","toLowerCase"],"mappings":"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"}
1
+ {"version":3,"file":"Server-D0dT9bUg.js","sources":["../lib/adapters/AdapterInterface.js","../lib/adapters/http.js","../lib/utils/serverReady.js","../lib/Server.js"],"sourcesContent":["/**\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 */\n\n/**\n * Adapter Interface - All adapters must implement this\n */\nexport class AdapterInterface {\n constructor(name) {\n this.name = name;\n this.server = null;\n this.routes = [];\n this.hooks = null;\n }\n\n /**\n * Initialize the adapter with routes, hooks, and useContext\n * @param {Array} routes - Array of route objects from Clovie kernel\n * @param {Object} hooks - Lifecycle hooks from Clovie kernel\n * @param {Function} useContext - Engine context accessor\n */\n async initialize(routes, hooks, useContext) {\n throw new Error(`initialize() must be implemented by ${this.name} adapter`);\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/**\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","/**\n * Built-in HTTP adapter for Clovie kernel\n */\nimport http from 'node:http';\nimport { AdapterInterface, ClovieRoute, ClovieHooks, ClovieContext } from './AdapterInterface.js';\nimport { matchRoute } from '../utils/routeParams.js';\n\nexport class HttpAdapter extends AdapterInterface {\n constructor() {\n super('http');\n this.logger = null;\n }\n\n async initialize(routes, hooks, useContext) {\n this.routes = routes;\n this.hooks = hooks || {};\n this.useContext = useContext;\n this.logger = useContext('log');\n }\n\n async start(opts) {\n const { port = 3000, host = '0.0.0.0' } = opts;\n \n this.server = http.createServer((req, res) => this.handleRequest(req, res));\n \n return new Promise((resolve, reject) => {\n this.server.listen(port, host, (err) => {\n if (err) {\n reject(err);\n } else {\n this.logger?.info(`HTTP Server listening on http://${host}:${port}`);\n resolve(this.server); // Return the server instance\n }\n });\n });\n }\n\n async stop() {\n if (this.server) {\n return new Promise((resolve) => {\n this.server.close(() => {\n this.logger?.info('HTTP Server stopped');\n this.server = null;\n resolve();\n });\n });\n }\n }\n\n async handleRequest(req, res) {\n let context;\n try {\n // Get state and stable from useContext\n const [state, stable] = this.useContext('state', 'stable');\n \n // Create context from Node.js request\n context = this.createContext(req, res, state, stable);\n \n // Parse URL to get pathname\n const url = new URL(req.url, `http://${req.headers.host}`);\n \n // Find matching route using pathname (not full URL)\n const route = this.findRoute(req.method, url.pathname);\n \n if (!route) {\n res.statusCode = 404;\n res.end('Not Found');\n return;\n }\n\n // Extract route parameters and update context\n const params = this.extractParams(route.path, url.pathname);\n context.req.params = params;\n\n // Execute hooks\n await this.hooks.onRequest?.(context);\n await this.hooks.preHandler?.(context);\n\n // Execute route handler\n const response = await route.handler(context);\n \n // Execute onSend hook\n await this.hooks.onSend?.(context, response);\n\n // Send response\n this.sendResponse(res, response);\n\n } catch (error) {\n const errorResponse = await this.hooks.onError?.(context, error) || {\n type: 'text',\n status: 500,\n body: 'Internal Server Error'\n };\n \n if (!res.headersSent) {\n this.sendResponse(res, errorResponse);\n }\n }\n }\n\n createContext(req, res, state, stable) {\n const url = new URL(req.url, `http://${req.headers.host}`);\n \n const clovieReq = {\n method: req.method,\n url: url.toString(),\n path: url.pathname,\n params: {}, // Will be populated by route matching\n query: Object.fromEntries(url.searchParams),\n headers: req.headers,\n body: req.body,\n raw: { req, res }\n };\n \n return new ClovieContext(clovieReq, res, state, stable);\n }\n\n findRoute(method, pathname) {\n for (const route of this.routes) {\n if (route.method === method && this.matchPath(route.path, pathname)) {\n return route;\n }\n }\n return null;\n }\n\n matchPath(routePath, urlPath) {\n // Use the existing route matching logic\n const match = matchRoute(routePath, urlPath);\n return match !== null;\n }\n\n extractParams(routePath, urlPath) {\n // Use the existing route matching logic to extract parameters\n const match = matchRoute(routePath, urlPath);\n return match ? match.params : {};\n }\n\n sendResponse(res, response) {\n if (!response) return;\n\n // Set headers\n if (response.headers) {\n for (const [key, value] of Object.entries(response.headers)) {\n res.setHeader(key, value);\n }\n }\n\n // Set status\n res.statusCode = response.status || 200;\n\n // Send body based on type\n switch (response.type) {\n case 'json':\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify(response.body));\n break;\n case 'text':\n // Set Content-Type header if not already provided\n const hasContentType = response.headers && response.headers['Content-Type'];\n if (!hasContentType) {\n res.setHeader('Content-Type', 'text/plain');\n }\n res.end(response.body);\n break;\n case 'html':\n res.setHeader('Content-Type', 'text/html');\n res.end(response.body);\n break;\n case 'file':\n // For file responses, you'd typically use res.sendFile() or similar\n res.end('File response not implemented in HTTP adapter');\n break;\n case 'stream':\n res.end(response.body);\n break;\n default:\n res.end(response.body || '');\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 { parseRouteParams } from './utils/routeParams.js';\nimport { HttpAdapter } from './adapters/http.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 initialize(_, config) {\n this.#routes.push({\n method: 'GET',\n path: '/health',\n handler: async (context) => {\n return context.respond.json({\n status: 'ok',\n timestamp: new Date().toISOString(),\n mode: config.mode || 'production'\n });\n },\n params: []\n });\n\n // Add API info endpoint\n this.#routes.push({\n method: 'GET',\n path: '/api/info',\n handler: async (context) => {\n return context.respond.json({\n name: 'Clovie',\n version: '1.0.0',\n mode: config.mode || 'production',\n routes: this.#routes.length\n });\n },\n params: []\n });\n\n // Serve static files from outputDir (wildcard route last)\n if (config.outputDir) {\n this.#routes.push({\n method: 'GET',\n path: '/*',\n handler: async (context) => {\n return this.#serveStaticFile(context, config.outputDir);\n },\n params: [{ name: 'wild', type: 'string' }]\n });\n }\n }\n\n actions(useContext) { \n return {\n // Add a route\n add: (method, path, handler, options = {}) => {\n // Parse route parameters for validation and documentation\n const params = parseRouteParams(path);\n \n this.#routes.push({ \n method: method.toUpperCase(), \n path, \n handler: async (context) => {\n // Inject engine context into handler\n context.useContext = useContext;\n return await handler(context);\n },\n params,\n ...options // Allow additional options like paramTypes, validation, etc.\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 Object.assign(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 || opts || 3000;\n const host = opts.host || '0.0.0.0';\n const log = useContext('log');\n \n // Use HTTP adapter by default if none set\n if (!this.#adapter) {\n this.#adapter = new HttpAdapter();\n }\n\n // Initialize adapter with routes, hooks, and useContext\n await this.#adapter.initialize(this.#routes, this.#hooks, useContext);\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: ${this.config?.mode}`);\n if (liveReload && this.config?.mode === 'development') {\n log.info('Initializing LiveReload...');\n await liveReload.initializeServer(server);\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: this.config.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 // 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 // Legacy support for direct HTTP handling\n handle: async (req, res) => {\n // Create a temporary HTTP adapter for legacy support\n const tempAdapter = new HttpAdapter();\n await tempAdapter.initialize(this.#routes, this.#hooks, useContext);\n return tempAdapter.handleRequest(req, res);\n }\n };\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 const filePath = path.join(outputDir, requestPath);\n \n // Check if file exists\n const stats = await fs.stat(filePath);\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\n}\n"],"names":["AdapterInterface","constructor","name","this","server","routes","hooks","initialize","useContext","Error","start","options","stop","getHttpServer","isRunning","handleRequest","req","res","ClovieContext","state","stable","respond","RespondHelpers","json","data","status","headers","type","body","text","html","file","path","stream","HttpAdapter","super","logger","opts","port","host","http","createServer","Promise","resolve","reject","listen","err","info","close","context","createContext","url","URL","route","findRoute","method","pathname","statusCode","end","params","extractParams","onRequest","preHandler","response","handler","onSend","sendResponse","error","errorResponse","onError","headersSent","clovieReq","toString","query","Object","fromEntries","searchParams","raw","matchPath","routePath","urlPath","matchRoute","match","key","value","entries","setHeader","JSON","stringify","execAsync","promisify","exec","async","displayServerReady","mode","chalk","bold","blue","white","green","toUpperCase","cyan","underline","yellow","forEach","line","command","process","platform","message","openBrowser","debug","gray","Server","ServiceProvider","static","namespace","version","adapter","_","config","push","timestamp","Date","toISOString","length","outputDir","serveStaticFile","actions","add","parseRouteParams","useAdapter","assign","relay","log","liveReload","initializeServer","actualPort","address","broadcast","getRoutes","handle","tempAdapter","fs","import","requestPath","filePath","join","stat","isFile","ext","extname","contentType","getContentType","content","readFile","startsWith","toLowerCase"],"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-CHAONNH5.cjs");
3
+ var socket_io = require("socket.io"), createClovie = require("./createClovie-2MdHaYuu.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"),
@@ -27,7 +27,7 @@ class LiveReload extends createClovie.ServiceProvider {
27
27
  },
28
28
  notifyReload: () => {
29
29
  this.#reloading || (this.#reloading = !0, createClovie.queueMacrotask(() => {
30
- this.#reloading = !1, this.#io.emit("reload");
30
+ this.#reloading = !1, this.#io && this.#io.emit("reload");
31
31
  }));
32
32
  },
33
33
  injectLiveReloadScript: async (renderedContent, config) => {
@@ -72,4 +72,4 @@ class LiveReload extends createClovie.ServiceProvider {
72
72
  }
73
73
 
74
74
  exports.LiveReload = LiveReload;
75
- //# sourceMappingURL=LiveReload-B2laUnHe.cjs.map
75
+ //# sourceMappingURL=LiveReload-_50RxFF7.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LiveReload-_50RxFF7.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) => {\n const log = this.useContext('log');\n if (this.config?.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, config) => {\n const lastBodyIndex = renderedContent.lastIndexOf('</body>');\n if (lastBodyIndex !== -1) {\n const scriptConfig = { \n mode: config.mode || 'development', \n port: config.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 = (config) => `<!-- 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 config = ${JSON.stringify(config)};\n \n console.log('Initializing live reload with config:', config);\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","log","useContext","config","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,MAAOC;gBACvB,MAAMC,MAAML,KAAKM,WAAW;gBACF,kBAAtBN,KAAKO,QAAQC,cACTR,MAAKS,cAAeL,QAAQC;;YAGtCK,cAAc;gBACRV,MAAKF,cACTE,MAAKF,aAAa,GAElBa,aAAAA,eAAe;oBACbX,MAAKF,aAAa,GACdE,MAAKH,MACPG,MAAKH,GAAIe,KAAK;;;YAIpBC,wBAAwBV,OAAOW,iBAAiBP;gBAC9C,MAAMQ,gBAAgBD,gBAAgBE,YAAY;gBAClD,KAAsB,MAAlBD,eAAsB;oBACxB,MAAME,eAAe;wBACnBT,MAAMD,OAAOC,QAAQ;wBACrBU,MAAMX,OAAOW,QAAQ;;oBAGvB;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,QAAQC;QAC3B;kBAEQ,IAAIoB,QAAQC,WAAWC,WAAWD,SAAS,OAEjDrB,IAAIuB,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;gBACzB/B,IAAIuB,MAAM,qBAAqBQ,OAAOC,OAEtCD,OAAOD,GAAG,cAAeG;oBACvBjC,IAAIuB,MAAM,wBAAwBQ,OAAOC,QAAQC;oBAGnDF,OAAOD,GAAG,SAAUI;oBAClBlC,IAAIkC,MAAM,iBAAiBA;;gBAI/BlC,IAAImC,KAAK;AACX,UAAE,OAAOD;YACPlC,IAAIkC,MAAM,+BAA+BA;AAC3C;AACF;IAEAnB,kBAAqBb,UAAW,mLAIbkC,KAAKC,UAAUnC;;;"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
 
3
- var createClovie = require("./createClovie-CHAONNH5.cjs"), http = require("node:http"), child_process = require("child_process"), util = require("util");
3
+ var createClovie = require("./createClovie-2MdHaYuu.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"),
@@ -348,4 +348,4 @@ class Server extends createClovie.ServiceProvider {
348
348
  }
349
349
 
350
350
  exports.Server = Server;
351
- //# sourceMappingURL=Server-BUMt6MLA.cjs.map
351
+ //# sourceMappingURL=Server-LHBZNNWv.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Server-BUMt6MLA.cjs","sources":["../../lib/adapters/AdapterInterface.js","../../lib/adapters/http.js","../../lib/utils/serverReady.js","../../lib/Server.js"],"sourcesContent":["/**\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 */\n\n/**\n * Adapter Interface - All adapters must implement this\n */\nexport class AdapterInterface {\n constructor(name) {\n this.name = name;\n this.server = null;\n this.routes = [];\n this.hooks = null;\n }\n\n /**\n * Initialize the adapter with routes, hooks, and useContext\n * @param {Array} routes - Array of route objects from Clovie kernel\n * @param {Object} hooks - Lifecycle hooks from Clovie kernel\n * @param {Function} useContext - Engine context accessor\n */\n async initialize(routes, hooks, useContext) {\n throw new Error(`initialize() must be implemented by ${this.name} adapter`);\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/**\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","/**\n * Built-in HTTP adapter for Clovie kernel\n */\nimport http from 'node:http';\nimport { AdapterInterface, ClovieRoute, ClovieHooks, ClovieContext } from './AdapterInterface.js';\nimport { matchRoute } from '../utils/routeParams.js';\n\nexport class HttpAdapter extends AdapterInterface {\n constructor() {\n super('http');\n this.logger = null;\n }\n\n async initialize(routes, hooks, useContext) {\n this.routes = routes;\n this.hooks = hooks || {};\n this.useContext = useContext;\n this.logger = useContext('log');\n }\n\n async start(opts) {\n const { port = 3000, host = '0.0.0.0' } = opts;\n \n this.server = http.createServer((req, res) => this.handleRequest(req, res));\n \n return new Promise((resolve, reject) => {\n this.server.listen(port, host, (err) => {\n if (err) {\n reject(err);\n } else {\n this.logger?.info(`HTTP Server listening on http://${host}:${port}`);\n resolve(this.server); // Return the server instance\n }\n });\n });\n }\n\n async stop() {\n if (this.server) {\n return new Promise((resolve) => {\n this.server.close(() => {\n this.logger?.info('HTTP Server stopped');\n this.server = null;\n resolve();\n });\n });\n }\n }\n\n async handleRequest(req, res) {\n let context;\n try {\n // Get state and stable from useContext\n const [state, stable] = this.useContext('state', 'stable');\n \n // Create context from Node.js request\n context = this.createContext(req, res, state, stable);\n \n // Parse URL to get pathname\n const url = new URL(req.url, `http://${req.headers.host}`);\n \n // Find matching route using pathname (not full URL)\n const route = this.findRoute(req.method, url.pathname);\n \n if (!route) {\n res.statusCode = 404;\n res.end('Not Found');\n return;\n }\n\n // Extract route parameters and update context\n const params = this.extractParams(route.path, url.pathname);\n context.req.params = params;\n\n // Execute hooks\n await this.hooks.onRequest?.(context);\n await this.hooks.preHandler?.(context);\n\n // Execute route handler\n const response = await route.handler(context);\n \n // Execute onSend hook\n await this.hooks.onSend?.(context, response);\n\n // Send response\n this.sendResponse(res, response);\n\n } catch (error) {\n const errorResponse = await this.hooks.onError?.(context, error) || {\n type: 'text',\n status: 500,\n body: 'Internal Server Error'\n };\n \n if (!res.headersSent) {\n this.sendResponse(res, errorResponse);\n }\n }\n }\n\n createContext(req, res, state, stable) {\n const url = new URL(req.url, `http://${req.headers.host}`);\n \n const clovieReq = {\n method: req.method,\n url: url.toString(),\n path: url.pathname,\n params: {}, // Will be populated by route matching\n query: Object.fromEntries(url.searchParams),\n headers: req.headers,\n body: req.body,\n raw: { req, res }\n };\n \n return new ClovieContext(clovieReq, res, state, stable);\n }\n\n findRoute(method, pathname) {\n for (const route of this.routes) {\n if (route.method === method && this.matchPath(route.path, pathname)) {\n return route;\n }\n }\n return null;\n }\n\n matchPath(routePath, urlPath) {\n // Use the existing route matching logic\n const match = matchRoute(routePath, urlPath);\n return match !== null;\n }\n\n extractParams(routePath, urlPath) {\n // Use the existing route matching logic to extract parameters\n const match = matchRoute(routePath, urlPath);\n return match ? match.params : {};\n }\n\n sendResponse(res, response) {\n if (!response) return;\n\n // Set headers\n if (response.headers) {\n for (const [key, value] of Object.entries(response.headers)) {\n res.setHeader(key, value);\n }\n }\n\n // Set status\n res.statusCode = response.status || 200;\n\n // Send body based on type\n switch (response.type) {\n case 'json':\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify(response.body));\n break;\n case 'text':\n // Set Content-Type header if not already provided\n const hasContentType = response.headers && response.headers['Content-Type'];\n if (!hasContentType) {\n res.setHeader('Content-Type', 'text/plain');\n }\n res.end(response.body);\n break;\n case 'html':\n res.setHeader('Content-Type', 'text/html');\n res.end(response.body);\n break;\n case 'file':\n // For file responses, you'd typically use res.sendFile() or similar\n res.end('File response not implemented in HTTP adapter');\n break;\n case 'stream':\n res.end(response.body);\n break;\n default:\n res.end(response.body || '');\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 { parseRouteParams } from './utils/routeParams.js';\nimport { HttpAdapter } from './adapters/http.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 initialize(_, config) {\n this.#routes.push({\n method: 'GET',\n path: '/health',\n handler: async (context) => {\n return context.respond.json({\n status: 'ok',\n timestamp: new Date().toISOString(),\n mode: config.mode || 'production'\n });\n },\n params: []\n });\n\n // Add API info endpoint\n this.#routes.push({\n method: 'GET',\n path: '/api/info',\n handler: async (context) => {\n return context.respond.json({\n name: 'Clovie',\n version: '1.0.0',\n mode: config.mode || 'production',\n routes: this.#routes.length\n });\n },\n params: []\n });\n\n // Serve static files from outputDir (wildcard route last)\n if (config.outputDir) {\n this.#routes.push({\n method: 'GET',\n path: '/*',\n handler: async (context) => {\n return this.#serveStaticFile(context, config.outputDir);\n },\n params: [{ name: 'wild', type: 'string' }]\n });\n }\n }\n\n actions(useContext) { \n return {\n // Add a route\n add: (method, path, handler, options = {}) => {\n // Parse route parameters for validation and documentation\n const params = parseRouteParams(path);\n \n this.#routes.push({ \n method: method.toUpperCase(), \n path, \n handler: async (context) => {\n // Inject engine context into handler\n context.useContext = useContext;\n return await handler(context);\n },\n params,\n ...options // Allow additional options like paramTypes, validation, etc.\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 Object.assign(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 || opts || 3000;\n const host = opts.host || '0.0.0.0';\n const log = useContext('log');\n \n // Use HTTP adapter by default if none set\n if (!this.#adapter) {\n this.#adapter = new HttpAdapter();\n }\n\n // Initialize adapter with routes, hooks, and useContext\n await this.#adapter.initialize(this.#routes, this.#hooks, useContext);\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: ${this.config?.mode}`);\n if (liveReload && this.config?.mode === 'development') {\n log.info('Initializing LiveReload...');\n await liveReload.initializeServer(server);\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: this.config.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 // 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 // Legacy support for direct HTTP handling\n handle: async (req, res) => {\n // Create a temporary HTTP adapter for legacy support\n const tempAdapter = new HttpAdapter();\n await tempAdapter.initialize(this.#routes, this.#hooks, useContext);\n return tempAdapter.handleRequest(req, res);\n }\n };\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 const filePath = path.join(outputDir, requestPath);\n \n // Check if file exists\n const stats = await fs.stat(filePath);\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\n}\n"],"names":["AdapterInterface","constructor","name","this","server","routes","hooks","initialize","useContext","Error","start","options","stop","getHttpServer","isRunning","handleRequest","req","res","ClovieContext","state","stable","respond","RespondHelpers","json","data","status","headers","type","body","text","html","file","path","stream","HttpAdapter","super","logger","opts","port","host","http","createServer","Promise","resolve","reject","listen","err","info","close","context","createContext","url","URL","route","findRoute","method","pathname","statusCode","end","params","extractParams","onRequest","preHandler","response","handler","onSend","sendResponse","error","errorResponse","onError","headersSent","clovieReq","toString","query","Object","fromEntries","searchParams","raw","matchPath","routePath","urlPath","matchRoute","match","key","value","entries","setHeader","JSON","stringify","execAsync","promisify","exec","async","displayServerReady","mode","chalk","bold","blue","white","green","toUpperCase","cyan","underline","yellow","forEach","line","command","process","platform","message","openBrowser","debug","gray","Server","ServiceProvider","static","namespace","version","adapter","_","config","push","timestamp","Date","toISOString","length","outputDir","serveStaticFile","actions","add","parseRouteParams","useAdapter","assign","relay","log","liveReload","initializeServer","actualPort","address","broadcast","getRoutes","handle","tempAdapter","fs","import","requestPath","filePath","join","stat","isFile","ext","extname","contentType","getContentType","content","readFile","startsWith","toLowerCase"],"mappings":"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"}
1
+ {"version":3,"file":"Server-LHBZNNWv.cjs","sources":["../../lib/adapters/AdapterInterface.js","../../lib/adapters/http.js","../../lib/utils/serverReady.js","../../lib/Server.js"],"sourcesContent":["/**\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 */\n\n/**\n * Adapter Interface - All adapters must implement this\n */\nexport class AdapterInterface {\n constructor(name) {\n this.name = name;\n this.server = null;\n this.routes = [];\n this.hooks = null;\n }\n\n /**\n * Initialize the adapter with routes, hooks, and useContext\n * @param {Array} routes - Array of route objects from Clovie kernel\n * @param {Object} hooks - Lifecycle hooks from Clovie kernel\n * @param {Function} useContext - Engine context accessor\n */\n async initialize(routes, hooks, useContext) {\n throw new Error(`initialize() must be implemented by ${this.name} adapter`);\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/**\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","/**\n * Built-in HTTP adapter for Clovie kernel\n */\nimport http from 'node:http';\nimport { AdapterInterface, ClovieRoute, ClovieHooks, ClovieContext } from './AdapterInterface.js';\nimport { matchRoute } from '../utils/routeParams.js';\n\nexport class HttpAdapter extends AdapterInterface {\n constructor() {\n super('http');\n this.logger = null;\n }\n\n async initialize(routes, hooks, useContext) {\n this.routes = routes;\n this.hooks = hooks || {};\n this.useContext = useContext;\n this.logger = useContext('log');\n }\n\n async start(opts) {\n const { port = 3000, host = '0.0.0.0' } = opts;\n \n this.server = http.createServer((req, res) => this.handleRequest(req, res));\n \n return new Promise((resolve, reject) => {\n this.server.listen(port, host, (err) => {\n if (err) {\n reject(err);\n } else {\n this.logger?.info(`HTTP Server listening on http://${host}:${port}`);\n resolve(this.server); // Return the server instance\n }\n });\n });\n }\n\n async stop() {\n if (this.server) {\n return new Promise((resolve) => {\n this.server.close(() => {\n this.logger?.info('HTTP Server stopped');\n this.server = null;\n resolve();\n });\n });\n }\n }\n\n async handleRequest(req, res) {\n let context;\n try {\n // Get state and stable from useContext\n const [state, stable] = this.useContext('state', 'stable');\n \n // Create context from Node.js request\n context = this.createContext(req, res, state, stable);\n \n // Parse URL to get pathname\n const url = new URL(req.url, `http://${req.headers.host}`);\n \n // Find matching route using pathname (not full URL)\n const route = this.findRoute(req.method, url.pathname);\n \n if (!route) {\n res.statusCode = 404;\n res.end('Not Found');\n return;\n }\n\n // Extract route parameters and update context\n const params = this.extractParams(route.path, url.pathname);\n context.req.params = params;\n\n // Execute hooks\n await this.hooks.onRequest?.(context);\n await this.hooks.preHandler?.(context);\n\n // Execute route handler\n const response = await route.handler(context);\n \n // Execute onSend hook\n await this.hooks.onSend?.(context, response);\n\n // Send response\n this.sendResponse(res, response);\n\n } catch (error) {\n const errorResponse = await this.hooks.onError?.(context, error) || {\n type: 'text',\n status: 500,\n body: 'Internal Server Error'\n };\n \n if (!res.headersSent) {\n this.sendResponse(res, errorResponse);\n }\n }\n }\n\n createContext(req, res, state, stable) {\n const url = new URL(req.url, `http://${req.headers.host}`);\n \n const clovieReq = {\n method: req.method,\n url: url.toString(),\n path: url.pathname,\n params: {}, // Will be populated by route matching\n query: Object.fromEntries(url.searchParams),\n headers: req.headers,\n body: req.body,\n raw: { req, res }\n };\n \n return new ClovieContext(clovieReq, res, state, stable);\n }\n\n findRoute(method, pathname) {\n for (const route of this.routes) {\n if (route.method === method && this.matchPath(route.path, pathname)) {\n return route;\n }\n }\n return null;\n }\n\n matchPath(routePath, urlPath) {\n // Use the existing route matching logic\n const match = matchRoute(routePath, urlPath);\n return match !== null;\n }\n\n extractParams(routePath, urlPath) {\n // Use the existing route matching logic to extract parameters\n const match = matchRoute(routePath, urlPath);\n return match ? match.params : {};\n }\n\n sendResponse(res, response) {\n if (!response) return;\n\n // Set headers\n if (response.headers) {\n for (const [key, value] of Object.entries(response.headers)) {\n res.setHeader(key, value);\n }\n }\n\n // Set status\n res.statusCode = response.status || 200;\n\n // Send body based on type\n switch (response.type) {\n case 'json':\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify(response.body));\n break;\n case 'text':\n // Set Content-Type header if not already provided\n const hasContentType = response.headers && response.headers['Content-Type'];\n if (!hasContentType) {\n res.setHeader('Content-Type', 'text/plain');\n }\n res.end(response.body);\n break;\n case 'html':\n res.setHeader('Content-Type', 'text/html');\n res.end(response.body);\n break;\n case 'file':\n // For file responses, you'd typically use res.sendFile() or similar\n res.end('File response not implemented in HTTP adapter');\n break;\n case 'stream':\n res.end(response.body);\n break;\n default:\n res.end(response.body || '');\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 { parseRouteParams } from './utils/routeParams.js';\nimport { HttpAdapter } from './adapters/http.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 initialize(_, config) {\n this.#routes.push({\n method: 'GET',\n path: '/health',\n handler: async (context) => {\n return context.respond.json({\n status: 'ok',\n timestamp: new Date().toISOString(),\n mode: config.mode || 'production'\n });\n },\n params: []\n });\n\n // Add API info endpoint\n this.#routes.push({\n method: 'GET',\n path: '/api/info',\n handler: async (context) => {\n return context.respond.json({\n name: 'Clovie',\n version: '1.0.0',\n mode: config.mode || 'production',\n routes: this.#routes.length\n });\n },\n params: []\n });\n\n // Serve static files from outputDir (wildcard route last)\n if (config.outputDir) {\n this.#routes.push({\n method: 'GET',\n path: '/*',\n handler: async (context) => {\n return this.#serveStaticFile(context, config.outputDir);\n },\n params: [{ name: 'wild', type: 'string' }]\n });\n }\n }\n\n actions(useContext) { \n return {\n // Add a route\n add: (method, path, handler, options = {}) => {\n // Parse route parameters for validation and documentation\n const params = parseRouteParams(path);\n \n this.#routes.push({ \n method: method.toUpperCase(), \n path, \n handler: async (context) => {\n // Inject engine context into handler\n context.useContext = useContext;\n return await handler(context);\n },\n params,\n ...options // Allow additional options like paramTypes, validation, etc.\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 Object.assign(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 || opts || 3000;\n const host = opts.host || '0.0.0.0';\n const log = useContext('log');\n \n // Use HTTP adapter by default if none set\n if (!this.#adapter) {\n this.#adapter = new HttpAdapter();\n }\n\n // Initialize adapter with routes, hooks, and useContext\n await this.#adapter.initialize(this.#routes, this.#hooks, useContext);\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: ${this.config?.mode}`);\n if (liveReload && this.config?.mode === 'development') {\n log.info('Initializing LiveReload...');\n await liveReload.initializeServer(server);\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: this.config.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 // 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 // Legacy support for direct HTTP handling\n handle: async (req, res) => {\n // Create a temporary HTTP adapter for legacy support\n const tempAdapter = new HttpAdapter();\n await tempAdapter.initialize(this.#routes, this.#hooks, useContext);\n return tempAdapter.handleRequest(req, res);\n }\n };\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 const filePath = path.join(outputDir, requestPath);\n \n // Check if file exists\n const stats = await fs.stat(filePath);\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\n}\n"],"names":["AdapterInterface","constructor","name","this","server","routes","hooks","initialize","useContext","Error","start","options","stop","getHttpServer","isRunning","handleRequest","req","res","ClovieContext","state","stable","respond","RespondHelpers","json","data","status","headers","type","body","text","html","file","path","stream","HttpAdapter","super","logger","opts","port","host","http","createServer","Promise","resolve","reject","listen","err","info","close","context","createContext","url","URL","route","findRoute","method","pathname","statusCode","end","params","extractParams","onRequest","preHandler","response","handler","onSend","sendResponse","error","errorResponse","onError","headersSent","clovieReq","toString","query","Object","fromEntries","searchParams","raw","matchPath","routePath","urlPath","matchRoute","match","key","value","entries","setHeader","JSON","stringify","execAsync","promisify","exec","async","displayServerReady","mode","chalk","bold","blue","white","green","toUpperCase","cyan","underline","yellow","forEach","line","command","process","platform","message","openBrowser","debug","gray","Server","ServiceProvider","static","namespace","version","adapter","_","config","push","timestamp","Date","toISOString","length","outputDir","serveStaticFile","actions","add","parseRouteParams","useAdapter","assign","relay","log","liveReload","initializeServer","actualPort","address","broadcast","getRoutes","handle","tempAdapter","fs","import","requestPath","filePath","join","stat","isFile","ext","extname","contentType","getContentType","content","readFile","startsWith","toLowerCase"],"mappings":"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"}