baraqex
Version:
A powerful full-stack framework for modern web development
1,554 lines (1,545 loc) • 66.5 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
}) : x)(function(x) {
if (typeof require !== "undefined")
return require.apply(this, arguments);
throw Error('Dynamic require of "' + x + '" is not supported');
});
var __esm = (fn, res) => function __init() {
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
// node_modules/frontend-hamroun/dist/index.mjs
function batchUpdates(fn) {
if (isBatching) {
queue.push(fn);
return;
}
isBatching = true;
try {
fn();
while (queue.length > 0) {
const nextFn = queue.shift();
nextFn == null ? void 0 : nextFn();
}
} finally {
isBatching = false;
}
}
function setRenderCallback(callback, element, container) {
globalRenderCallback = callback;
globalContainer = container;
currentElement = element;
}
function prepareRender() {
currentRender++;
stateIndices.set(currentRender, 0);
return currentRender;
}
function finishRender() {
if (isServer) {
serverStates.delete(currentRender);
}
currentRender = 0;
}
function useState(initial) {
if (!currentRender) {
throw new Error("useState must be called within a render");
}
if (isServer) {
if (!serverStates.has(currentRender)) {
serverStates.set(currentRender, /* @__PURE__ */ new Map());
}
const componentState = serverStates.get(currentRender);
const index2 = stateIndices.get(currentRender) || 0;
if (!componentState.has(index2)) {
componentState.set(index2, initial);
}
const state2 = componentState.get(index2);
const setState2 = (newValue) => {
};
stateIndices.set(currentRender, index2 + 1);
return [state2, setState2];
}
if (!states.has(currentRender)) {
states.set(currentRender, []);
}
const componentStates = states.get(currentRender);
const index = stateIndices.get(currentRender);
if (index >= componentStates.length) {
componentStates.push(initial);
}
const state = componentStates[index];
const setState = (newValue) => {
const nextValue = typeof newValue === "function" ? newValue(componentStates[index]) : newValue;
if (componentStates[index] === nextValue)
return;
componentStates[index] = nextValue;
if (isBatching) {
batchUpdates(() => rerender(currentRender));
} else {
rerender(currentRender);
}
};
stateIndices.set(currentRender, index + 1);
return [state, setState];
}
function useEffect(callback, deps) {
if (!currentRender)
throw new Error("useEffect must be called within a render");
const effectIndex = stateIndices.get(currentRender);
if (!effects.has(currentRender)) {
effects.set(currentRender, []);
}
const componentEffects = effects.get(currentRender);
const prevEffect = componentEffects[effectIndex];
if (!prevEffect || !deps || !prevEffect.deps || deps.some((dep, i) => dep !== prevEffect.deps[i])) {
if (prevEffect == null ? void 0 : prevEffect.cleanup) {
prevEffect.cleanup();
}
queueMicrotask(() => {
const cleanup = callback() || void 0;
componentEffects[effectIndex] = { cleanup, deps };
});
}
stateIndices.set(currentRender, effectIndex + 1);
}
function useMemo(factory, deps) {
if (!currentRender)
throw new Error("useMemo must be called within a render");
const memoIndex = stateIndices.get(currentRender);
if (!memos.has(currentRender)) {
memos.set(currentRender, []);
}
const componentMemos = memos.get(currentRender);
const prevMemo = componentMemos[memoIndex];
if (!prevMemo || deps && deps.some((dep, i) => !Object.is(dep, prevMemo.deps[i]))) {
const value = factory();
componentMemos[memoIndex] = { value, deps };
stateIndices.set(currentRender, memoIndex + 1);
return value;
}
stateIndices.set(currentRender, memoIndex + 1);
return prevMemo.value;
}
function useRef(initial) {
if (!currentRender)
throw new Error("useRef must be called within a render");
const refIndex = stateIndices.get(currentRender);
if (!refs.has(currentRender)) {
refs.set(currentRender, []);
}
const componentRefs = refs.get(currentRender);
if (refIndex >= componentRefs.length) {
const ref2 = { current: initial };
componentRefs.push(ref2);
stateIndices.set(currentRender, refIndex + 1);
return ref2;
}
const ref = componentRefs[refIndex];
stateIndices.set(currentRender, refIndex + 1);
return ref;
}
async function rerender(rendererId) {
try {
const componentEffects = effects.get(rendererId);
if (componentEffects) {
componentEffects.forEach((effect) => {
if (effect.cleanup)
effect.cleanup();
});
effects.set(rendererId, []);
}
if (globalRenderCallback && globalContainer && currentElement) {
await globalRenderCallback(currentElement, globalContainer);
}
} catch (error) {
console.error("Error during rerender:", error);
}
}
function useErrorBoundary() {
const [error, setError] = useState(null);
return [error, () => setError(null)];
}
function createContext(defaultValue) {
const context = {
Provider: ({ value, children }) => {
return children;
},
Consumer: ({ children }) => {
return children(defaultValue);
},
_id: Symbol(),
useSelector: (selector) => {
return selector(defaultValue);
}
};
return context;
}
function useContext(context) {
return context;
}
function jsx(type, props) {
console.log("JSX Transform:", { type, props });
const processedProps = { ...props };
if (arguments.length > 2) {
processedProps.children = Array.prototype.slice.call(arguments, 2);
}
return { type, props: processedProps };
}
async function createElement(vnode) {
var _a;
console.log("Creating element from:", vnode);
if (vnode == null) {
return document.createTextNode("");
}
if (typeof vnode === "boolean") {
return document.createTextNode("");
}
if (typeof vnode === "number" || typeof vnode === "string") {
return document.createTextNode(String(vnode));
}
if (Array.isArray(vnode)) {
const fragment = document.createDocumentFragment();
for (const child of vnode) {
const node = await createElement(child);
fragment.appendChild(node);
}
return fragment;
}
if ("type" in vnode && vnode.props !== void 0) {
const { type, props } = vnode;
if (typeof type === "function") {
try {
const result = await type(props || {});
const node = await createElement(result);
if (node instanceof Element) {
node.setAttribute("data-component-id", type.name || type.toString());
}
return node;
} catch (error) {
console.error("Error rendering component:", error);
return document.createTextNode("");
}
}
const element = document.createElement(type);
for (const [key, value] of Object.entries(props || {})) {
if (key === "children")
continue;
if (key.startsWith("on") && typeof value === "function") {
const eventName = key.toLowerCase().slice(2);
const existingHandler = (_a = element.__events) == null ? void 0 : _a[eventName];
if (existingHandler) {
element.removeEventListener(eventName, existingHandler);
}
element.addEventListener(eventName, value);
if (!element.__events) {
element.__events = {};
}
element.__events[eventName] = value;
} else if (key === "style" && typeof value === "object") {
Object.assign(element.style, value);
} else if (key === "className") {
element.setAttribute("class", String(value));
} else if (key !== "key" && key !== "ref") {
element.setAttribute(key, String(value));
}
}
const children = props == null ? void 0 : props.children;
if (children != null) {
const childArray = Array.isArray(children) ? children.flat() : [children];
for (const child of childArray) {
const childNode = await createElement(child);
element.appendChild(childNode);
}
}
return element;
}
return document.createTextNode(String(vnode));
}
async function hydrate(element, container) {
isHydrating = true;
try {
await render(element, container);
} finally {
isHydrating = false;
}
}
async function render(element, container) {
console.log("Rendering to:", container.id);
batchUpdates(async () => {
const rendererId = prepareRender();
try {
setRenderCallback(render, element, container);
const domNode = await createElement(element);
if (!isHydrating) {
container.innerHTML = "";
}
container.appendChild(domNode);
} finally {
finishRender();
}
});
}
function renderToString(vnode) {
prepareRender();
const html = renderNodeToString(vnode);
finishRender();
return html;
}
function renderNodeToString(vnode) {
var _a, _b, _c;
if (vnode === null || vnode === void 0)
return "";
if (typeof vnode === "boolean")
return "";
if (typeof vnode === "number" || typeof vnode === "string")
return escapeHtml(String(vnode));
if (typeof vnode.type === "function") {
const Component2 = vnode.type;
const renderedNode = Component2(vnode.props || {});
return renderNodeToString(renderedNode);
}
if (typeof vnode.type === "string") {
const tag = vnode.type;
let attrs = "";
let children = "";
if (vnode.props) {
for (const [key, value] of Object.entries(vnode.props)) {
if (key === "children")
continue;
if (key.startsWith("on"))
continue;
if (key === "className") {
attrs += ` class="${escapeHtml(value)}"`;
continue;
}
if (typeof value === "string" || typeof value === "number") {
attrs += ` ${key}="${escapeHtml(String(value))}"`;
} else if (value === true) {
attrs += ` ${key}`;
}
}
}
const childrenArray = ((_a = vnode.props) == null ? void 0 : _a.children) ? Array.isArray(vnode.props.children) ? vnode.props.children : [vnode.props.children] : [];
for (const child of childrenArray) {
children += renderNodeToString(child);
}
const selfClosing = [
"area",
"base",
"br",
"col",
"embed",
"hr",
"img",
"input",
"link",
"meta",
"param",
"source",
"track",
"wbr"
];
if (selfClosing.includes(tag)) {
return `<${tag}${attrs}/>`;
}
return `<${tag}${attrs}>${children}</${tag}>`;
}
if (vnode.type === Symbol.for("react.fragment")) {
let fragmentOutput = "";
const children = Array.isArray((_b = vnode.props) == null ? void 0 : _b.children) ? vnode.props.children : ((_c = vnode.props) == null ? void 0 : _c.children) ? [vnode.props.children] : [];
for (const child of children) {
fragmentOutput += renderNodeToString(child);
}
return fragmentOutput;
}
console.warn("Unknown vnode type:", vnode.type);
return "";
}
function escapeHtml(text) {
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
}
var isBatching, queue, currentRender, states, stateIndices, effects, memos, refs, globalRenderCallback, globalContainer, currentElement, isServer, serverStates, Fragment, isHydrating, server;
var init_dist = __esm({
"node_modules/frontend-hamroun/dist/index.mjs"() {
isBatching = false;
queue = [];
currentRender = 0;
states = /* @__PURE__ */ new Map();
stateIndices = /* @__PURE__ */ new Map();
effects = /* @__PURE__ */ new Map();
memos = /* @__PURE__ */ new Map();
refs = /* @__PURE__ */ new Map();
globalRenderCallback = null;
globalContainer = null;
currentElement = null;
isServer = typeof window === "undefined";
serverStates = /* @__PURE__ */ new Map();
Fragment = ({ children }) => children;
isHydrating = false;
server = {
async getServer() {
throw new Error("Server module can only be used in Node.js environment");
}
};
}
});
// src/server/database.ts
var Database;
var init_database = __esm({
"src/server/database.ts"() {
"use strict";
Database = class {
constructor(config) {
this.mongoClient = null;
this.mongoDb = null;
this.mysqlPool = null;
this.pgPool = null;
this.config = config;
}
async connect() {
switch (this.config.type) {
case "mongodb":
await this.connectMongo();
break;
case "mysql":
await this.connectMysql();
break;
case "postgres":
await this.connectPostgres();
break;
default:
throw new Error(`Unsupported database type: ${this.config.type}`);
}
}
async connectMongo() {
try {
const { MongoClient } = await import("mongodb");
this.mongoClient = new MongoClient(this.config.url);
await this.mongoClient.connect();
this.mongoDb = this.mongoClient.db();
console.log("Connected to MongoDB");
} catch (error) {
if (error.code === "MODULE_NOT_FOUND") {
throw new Error("MongoDB driver not installed. Run: npm install mongodb");
}
console.error("MongoDB connection error:", error);
throw error;
}
}
async connectMysql() {
try {
const mysql = await import("mysql2/promise");
this.mysqlPool = mysql.createPool(this.config.url);
await this.mysqlPool.getConnection();
console.log("Connected to MySQL");
} catch (error) {
if (error.code === "MODULE_NOT_FOUND") {
throw new Error("MySQL driver not installed. Run: npm install mysql2");
}
console.error("MySQL connection error:", error);
throw error;
}
}
async connectPostgres() {
try {
const pg = await import("pg");
this.pgPool = new pg.Pool({ connectionString: this.config.url });
const client = await this.pgPool.connect();
client.release();
console.log("Connected to PostgreSQL");
} catch (error) {
if (error.code === "MODULE_NOT_FOUND") {
throw new Error("PostgreSQL driver not installed. Run: npm install pg @types/pg");
}
console.error("PostgreSQL connection error:", error);
throw error;
}
}
async disconnect() {
if (this.mongoClient) {
await this.mongoClient.close();
this.mongoClient = null;
this.mongoDb = null;
}
if (this.mysqlPool) {
await this.mysqlPool.end();
this.mysqlPool = null;
}
if (this.pgPool) {
await this.pgPool.end();
this.pgPool = null;
}
}
// Database-specific methods
getMongoDb() {
return this.mongoDb;
}
getMysqlPool() {
return this.mysqlPool;
}
getPgPool() {
return this.pgPool;
}
// Generic query method
async query(sql, values) {
switch (this.config.type) {
case "mongodb":
throw new Error("For MongoDB, use getMongoDb() instead of query()");
case "mysql":
if (!this.mysqlPool)
throw new Error("MySQL not connected");
const [rows] = await this.mysqlPool.execute(sql, values || []);
return rows;
case "postgres":
if (!this.pgPool)
throw new Error("PostgreSQL not connected");
const result = await this.pgPool.query(sql, values || []);
return result.rows;
default:
throw new Error(`Unsupported database type: ${this.config.type}`);
}
}
};
}
});
// src/server/auth.ts
var AuthService;
var init_auth = __esm({
"src/server/auth.ts"() {
"use strict";
AuthService = class {
constructor(config) {
this.config = {
expiresIn: "24h",
...config
};
}
async hashPassword(password) {
try {
const bcrypt = await import("bcryptjs");
return bcrypt.hash(password, 10);
} catch (error) {
if (error.code === "MODULE_NOT_FOUND") {
throw new Error("bcryptjs not installed. Run: npm install bcryptjs @types/bcryptjs");
}
throw error;
}
}
async comparePasswords(password, hashedPassword) {
try {
const bcrypt = await import("bcryptjs");
return bcrypt.compare(password, hashedPassword);
} catch (error) {
if (error.code === "MODULE_NOT_FOUND") {
throw new Error("bcryptjs not installed. Run: npm install bcryptjs @types/bcryptjs");
}
throw error;
}
}
generateToken(user) {
try {
const jwt = __require("jsonwebtoken");
const options = {};
if (this.config.expiresIn) {
options.expiresIn = this.config.expiresIn;
}
return jwt.sign(
{ id: user.id, username: user.username, roles: user.roles || [] },
this.config.secret,
options
);
} catch (error) {
if (error.code === "MODULE_NOT_FOUND") {
throw new Error("jsonwebtoken not installed. Run: npm install jsonwebtoken @types/jsonwebtoken");
}
throw error;
}
}
verifyToken(token) {
try {
const jwt = __require("jsonwebtoken");
return jwt.verify(token, this.config.secret);
} catch (error) {
if (error.code === "MODULE_NOT_FOUND") {
throw new Error("jsonwebtoken not installed. Run: npm install jsonwebtoken @types/jsonwebtoken");
}
return null;
}
}
// Express middleware for authentication
initialize() {
return (req, res, next) => {
const token = this.extractToken(req);
if (token) {
const decoded = this.verifyToken(token);
if (decoded) {
req.user = decoded;
}
}
next();
};
}
// Express middleware for requiring authentication
requireAuth() {
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({ message: "Unauthorized" });
}
return next();
};
}
// Express middleware for requiring specific roles
requireRoles(roles) {
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({ message: "Unauthorized" });
}
const userRoles = req.user.roles || [];
const hasRequiredRole = roles.some((role) => userRoles.includes(role));
if (!hasRequiredRole) {
return res.status(403).json({ message: "Forbidden" });
}
return next();
};
}
extractToken(req) {
if (req.headers.authorization && req.headers.authorization.startsWith("Bearer ")) {
return req.headers.authorization.substring(7);
}
return null;
}
};
}
});
// src/server/api-router.ts
import path from "path";
import fs from "fs";
import { pathToFileURL } from "url";
var ApiRouter;
var init_api_router = __esm({
"src/server/api-router.ts"() {
"use strict";
ApiRouter = class {
constructor(apiDir, auth = null) {
this.router = null;
this.initialized = false;
this.apiDir = path.resolve(process.cwd(), apiDir);
this.auth = auth;
}
async initialize() {
if (this.initialized && this.router)
return;
try {
const express = await import("express");
this.router = express.default.Router();
this.setupRoutes();
this.initialized = true;
console.log("\u2705 API Router initialized successfully");
} catch (error) {
console.error("\u274C Failed to initialize API Router:", error);
if (error.code === "MODULE_NOT_FOUND") {
throw new Error("Express not installed. Run: npm install express @types/express");
}
throw error;
}
}
isInitialized() {
return this.initialized && this.router !== null;
}
setupRoutes() {
if (!fs.existsSync(this.apiDir)) {
console.log(`API directory not found: ${this.apiDir}`);
return;
}
this.scanDirectory(this.apiDir, "");
}
scanDirectory(dirPath, routePrefix) {
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dirPath, entry.name);
if (entry.isDirectory()) {
this.scanDirectory(fullPath, `${routePrefix}/${entry.name}`);
} else if (this.isRouteFile(entry.name)) {
const routePath = this.getRoutePath(entry.name, routePrefix);
this.registerRoute(fullPath, routePath);
}
}
}
isRouteFile(filename) {
return filename.endsWith(".js") || filename.endsWith(".ts") || filename.endsWith(".mjs");
}
getRoutePath(filename, routePrefix) {
const baseName = path.basename(filename, path.extname(filename));
if (baseName === "index") {
return routePrefix || "/";
}
const paramMatch = baseName.match(/^\[(.+)\]$/);
if (paramMatch) {
return `${routePrefix}/:${paramMatch[1]}`;
}
return `${routePrefix}/${baseName}`;
}
async registerRoute(filePath, routePath) {
try {
const absolutePath = path.isAbsolute(filePath) ? filePath : path.resolve(filePath);
const fileUrl = pathToFileURL(absolutePath).href;
const urlWithTimestamp = `${fileUrl}?t=${Date.now()}`;
const routeModule = await import(urlWithTimestamp);
if (!this.isValidRouteModule(routeModule)) {
console.warn(`Invalid route module: ${filePath}`);
return;
}
console.log(`Registering API route: ${routePath}`);
const middleware = routeModule.middleware || [];
for (const method of ["get", "post", "put", "delete", "patch", "options"]) {
const handler = routeModule[method];
if (typeof handler === "function") {
const routerMethod = this.router[method];
routerMethod.call(
this.router,
routePath,
...middleware,
this.wrapHandler(handler)
);
}
}
} catch (error) {
console.error(`Error registering route (${filePath}):`, error);
}
}
isValidRouteModule(module) {
if (!module)
return false;
return ["get", "post", "put", "delete", "patch", "options"].some((method) => typeof module[method] === "function");
}
wrapHandler(handler) {
return async (req, res, next) => {
try {
await handler(req, res, next);
} catch (error) {
next(error);
}
};
}
};
}
});
// src/server/middleware.ts
function rateLimit(options) {
const requests = /* @__PURE__ */ new Map();
return (req, res, next) => {
const ip = req.ip || req.socket.remoteAddress || "unknown";
const now = Date.now();
const reqTimes = (requests.get(ip) || []).filter((time) => now - time < options.windowMs);
reqTimes.push(now);
requests.set(ip, reqTimes);
if (reqTimes.length > options.max) {
return res.status(429).json({
error: {
message: "Too Many Requests",
retryAfter: Math.ceil(options.windowMs / 1e3)
}
});
}
return next();
};
}
var requestLogger, errorHandler, notFoundHandler;
var init_middleware = __esm({
"src/server/middleware.ts"() {
"use strict";
requestLogger = (req, res, next) => {
console.log(`${(/* @__PURE__ */ new Date()).toISOString()} - ${req.method} ${req.url}`);
next();
};
errorHandler = (err, req, res, next) => {
console.error(err.stack);
res.status(500).json({
error: {
message: "Internal Server Error",
...process.env.NODE_ENV !== "production" ? { details: err.message, stack: err.stack } : {}
}
});
};
notFoundHandler = (req, res) => {
res.status(404).json({
error: {
message: `Not Found - ${req.method} ${req.url}`
}
});
};
}
});
// src/server/utils.ts
var utils_exports = {};
__export(utils_exports, {
ensureDirectory: () => ensureDirectory,
generateToken: () => generateToken,
getEnvironmentInfo: () => getEnvironmentInfo,
getPagination: () => getPagination,
hashString: () => hashString,
isDirectoryEmpty: () => isDirectoryEmpty,
readJsonFile: () => readJsonFile,
safeJsonParse: () => safeJsonParse,
sendError: () => sendError,
sendSuccess: () => sendSuccess,
validateFields: () => validateFields,
validateFileUpload: () => validateFileUpload,
writeJsonFile: () => writeJsonFile
});
import crypto2 from "crypto";
import fs2 from "fs/promises";
import path2 from "path";
function safeJsonParse(json, fallback) {
try {
return JSON.parse(json);
} catch (error) {
return fallback;
}
}
function generateToken(length = 32) {
return crypto2.randomBytes(length).toString("hex");
}
function hashString(input, salt = "") {
return crypto2.createHash("sha256").update(input + salt).digest("hex");
}
function getPagination(req) {
const page = Math.max(1, parseInt(req.query.page) || 1);
const rawLimit = parseInt(req.query.limit);
let limit;
if (isNaN(rawLimit) || rawLimit <= 0) {
limit = 20;
} else {
limit = Math.max(1, Math.min(100, rawLimit));
}
const skip = (page - 1) * limit;
return { page, limit, skip };
}
function sendSuccess(res, data, message = "Success") {
return res.json({
success: true,
message,
data
});
}
function sendError(res, message = "An error occurred", statusCode = 400, errors) {
return res.status(statusCode).json({
success: false,
message,
errors: errors || void 0
});
}
function validateFields(req, requiredFields) {
const missing = requiredFields.filter((field) => {
const value = req.body[field];
return value === void 0 || value === null || value === "";
});
return {
valid: missing.length === 0,
missing
};
}
function validateFileUpload(file, options = {}) {
if (!file) {
return { valid: false, error: "No file provided" };
}
if (options.maxSize && file.size > options.maxSize) {
return {
valid: false,
error: `File too large. Maximum size allowed is ${options.maxSize / 1024 / 1024}MB`
};
}
if (options.allowedTypes && options.allowedTypes.length > 0) {
const fileType = file.mimetype;
if (!options.allowedTypes.includes(fileType)) {
return {
valid: false,
error: `Invalid file type. Allowed types: ${options.allowedTypes.join(", ")}`
};
}
}
return { valid: true };
}
function getEnvironmentInfo() {
return {
nodeVersion: process.version,
platform: process.platform,
arch: process.arch,
memory: process.memoryUsage(),
uptime: process.uptime(),
env: process.env.NODE_ENV || "development"
};
}
async function isDirectoryEmpty(dirPath) {
try {
const files = await fs2.readdir(dirPath);
return files.length === 0;
} catch (error) {
return true;
}
}
async function ensureDirectory(dirPath) {
try {
await fs2.access(dirPath);
} catch (error) {
await fs2.mkdir(dirPath, { recursive: true });
}
}
async function writeJsonFile(filePath, data) {
await ensureDirectory(path2.dirname(filePath));
await fs2.writeFile(filePath, JSON.stringify(data, null, 2), "utf8");
}
async function readJsonFile(filePath, defaultValue) {
try {
const data = await fs2.readFile(filePath, "utf8");
return safeJsonParse(data, defaultValue);
} catch (error) {
return defaultValue;
}
}
var init_utils = __esm({
"src/server/utils.ts"() {
"use strict";
}
});
// src/server/templates.ts
var templates_exports = {};
__export(templates_exports, {
generateDocument: () => generateDocument,
generateErrorPage: () => generateErrorPage,
generateLoadingPage: () => generateLoadingPage
});
function generateDocument(content, options = {}) {
const {
title = "Frontend Hamroun App",
description = "",
lang = "en",
charset = "UTF-8",
viewport = "width=device-width, initial-scale=1.0",
scripts = [],
styles = [],
meta = {},
bodyClasses = "",
htmlAttrs = {},
bodyAttrs = {},
initialData = {},
componentName = ""
} = options;
const htmlAttributes = Object.entries(htmlAttrs).map(([key, value]) => `${key}="${escapeHtml2(value)}"`).join(" ");
const bodyAttributes = Object.entries(bodyAttrs).map(([key, value]) => `${key}="${escapeHtml2(value)}"`).join(" ");
const metaTags = [
`<meta charset="${charset}">`,
`<meta name="viewport" content="${viewport}">`,
description ? `<meta name="description" content="${escapeHtml2(description)}">` : ""
];
Object.entries(meta).forEach(([name, content2]) => {
metaTags.push(`<meta name="${escapeHtml2(name)}" content="${escapeHtml2(content2)}">`);
});
const scriptTags = scripts.map((src) => {
if (src.startsWith("<script")) {
return src;
}
return `<script src="${escapeHtml2(src)}" ${src.endsWith(".js") ? 'type="module"' : ""} defer></script>`;
});
const styleTags = styles.map((href) => {
if (href.startsWith("<style")) {
return href;
}
return `<link rel="stylesheet" href="${escapeHtml2(href)}">`;
});
const initialDataScript = Object.keys(initialData).length > 0 ? `<script id="__APP_DATA__" type="application/json">${escapeHtml2(JSON.stringify(initialData))}</script>` : "";
return `<!DOCTYPE html>
<html lang="${lang}" ${htmlAttributes}>
<head>
${metaTags.filter(Boolean).join("\n ")}
<title>${escapeHtml2(title)}</title>
${styleTags.join("\n ")}
</head>
<body class="${bodyClasses}" ${bodyAttributes}>
<div id="app-root" data-ssr-root${componentName ? ` data-component="${escapeHtml2(componentName)}"` : ""}>${content}</div>
${initialDataScript}
${scriptTags.join("\n ")}
</body>
</html>`;
}
function generateErrorPage(statusCode, message, error) {
const errorMessages = {
400: "Bad Request",
401: "Unauthorized",
403: "Forbidden",
404: "Not Found",
500: "Internal Server Error"
};
const title = `${statusCode} - ${errorMessages[statusCode] || "Error"}`;
const isDev = process.env.NODE_ENV !== "production";
const errorDetails = isDev && error ? `
<div class="error-details">
<pre>${escapeHtml2(error.stack || error.message)}</pre>
</div>
` : "";
const content = `
<div class="error-container">
<h1>${statusCode}</h1>
<h2>${escapeHtml2(errorMessages[statusCode] || "Error")}</h2>
<p>${escapeHtml2(message)}</p>
${errorDetails}
<a href="/" class="home-link">Back to Home</a>
</div>
`;
const styles = [`<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
background-color: #f7f7f7;
color: #333;
}
.error-container {
text-align: center;
padding: 2rem;
border-radius: 8px;
background-color: white;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
max-width: 600px;
width: 100%;
}
h1 {
font-size: 6rem;
margin: 0;
color: #e74c3c;
}
h2 {
margin-top: 0;
margin-bottom: 1rem;
color: #333;
}
.error-details {
text-align: left;
margin: 2rem 0;
padding: 1rem;
background-color: #f8f8f8;
border-radius: 4px;
overflow: auto;
}
pre {
margin: 0;
font-family: monospace;
font-size: 0.85rem;
white-space: pre-wrap;
}
.home-link {
display: inline-block;
margin-top: 1.5rem;
padding: 0.75rem 1.5rem;
background-color: #3498db;
color: white;
text-decoration: none;
border-radius: 4px;
transition: background-color 0.2s;
}
.home-link:hover {
background-color: #2980b9;
}
</style>`];
return generateDocument(content, {
title,
description: `Error ${statusCode}: ${errorMessages[statusCode] || "Error"}`,
bodyClasses: "error-page",
styles
});
}
function generateLoadingPage(message = "Loading...") {
const content = `
<div class="loading-container">
<div class="spinner"></div>
<p>${escapeHtml2(message)}</p>
</div>
`;
const styles = [`<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
background-color: #f7f7f7;
color: #333;
}
.loading-container {
text-align: center;
}
.spinner {
width: 50px;
height: 50px;
border: 5px solid rgba(0, 0, 0, 0.1);
border-radius: 50%;
border-top-color: #3498db;
animation: spin 1s ease-in-out infinite;
margin: 0 auto 20px;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
</style>`];
return generateDocument(content, {
title: "Loading",
bodyClasses: "loading-page",
styles
});
}
function escapeHtml2(text) {
return String(text).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
}
var init_templates = __esm({
"src/server/templates.ts"() {
"use strict";
}
});
// src/server/wasm.ts
import fs3 from "fs/promises";
import path3 from "path";
import { pathToFileURL as pathToFileURL2 } from "url";
async function initNodeWasm() {
if (initialized)
return;
try {
globalThis.TextEncoder = globalThis.TextEncoder || TextEncoder;
globalThis.TextDecoder = globalThis.TextDecoder || TextDecoder;
initialized = true;
} catch (error) {
console.error("[WASM] Failed to initialize Node.js WASM environment:", error);
throw error;
}
}
async function loadGoRuntime(goWasmPath) {
if (typeof globalThis.Go === "function") {
return globalThis.Go;
}
const possiblePaths = [
goWasmPath,
"./wasm_exec.cjs",
"./wasm_exec.js",
"./public/wasm_exec.cjs",
"./public/wasm_exec.js",
"./src/wasm_exec.cjs",
"./src/wasm_exec.js",
path3.join(process.cwd(), "wasm_exec.cjs"),
path3.join(process.cwd(), "wasm_exec.js"),
path3.join(process.cwd(), "public", "wasm_exec.cjs"),
path3.join(process.cwd(), "public", "wasm_exec.js"),
path3.join(process.cwd(), "src", "wasm_exec.cjs"),
path3.join(process.cwd(), "src", "wasm_exec.js")
].filter(Boolean);
for (const wasmExecPath of possiblePaths) {
try {
const resolvedPath = path3.resolve(wasmExecPath);
try {
const stats = await fs3.stat(resolvedPath);
if (!stats.isFile()) {
continue;
}
} catch (statError) {
continue;
}
const wasmExecUrl = pathToFileURL2(resolvedPath).href;
if (globalThis.Go) {
delete globalThis.Go;
}
await import(wasmExecUrl);
if (typeof globalThis.Go === "function") {
console.log(`[WASM] Loaded Go runtime from: ${resolvedPath}`);
return globalThis.Go;
} else {
console.warn(`[WASM] File found but Go class not exported: ${resolvedPath}`);
}
} catch (error) {
console.warn(`[WASM] Error loading from ${wasmExecPath}:`, error.message);
continue;
}
}
throw new Error(
`[WASM] Could not find wasm_exec.js. Please ensure you have the Go WASM runtime file available.
You can get it from: https://github.com/golang/go/blob/master/misc/wasm/wasm_exec.js
Searched paths: ${possiblePaths.join(", ")}`
);
}
async function loadGoWasmFromFile(wasmFilePath, options = {}) {
try {
await initNodeWasm();
if (options.debug) {
console.log("[WASM] Loading WASM from file:", wasmFilePath);
}
const GoRuntime = await loadGoRuntime(options.goWasmPath);
const go = new GoRuntime();
const wasmBuffer = await fs3.readFile(wasmFilePath);
const wasmModule = await WebAssembly.compile(wasmBuffer);
const baseImports = go.importObject;
const finalImportObject = {
...baseImports,
...options.importObject
};
if (options.debug) {
console.log("[WASM] Available import modules:", Object.keys(finalImportObject));
for (const [moduleName, moduleExports] of Object.entries(finalImportObject)) {
if (typeof moduleExports === "object" && moduleExports !== null) {
const exportNames = Object.keys(moduleExports);
console.log(`[WASM] ${moduleName} import functions:`, exportNames);
}
}
}
const instance = await WebAssembly.instantiate(wasmModule, finalImportObject);
if (options.debug) {
console.log("[WASM] WASM instance created, starting Go runtime...");
}
const runPromise = go.run(instance);
if (options.debug) {
console.log("[WASM] Go runtime started, waiting for initialization...");
}
await new Promise((resolve) => setTimeout(resolve, 2e3));
if (options.debug) {
console.log("[WASM] Scanning global object for Go functions...");
}
const functions = {};
const globalObj = globalThis;
const allKeys = Object.getOwnPropertyNames(globalObj);
const goKeys = allKeys.filter((key) => key.startsWith("go"));
if (options.debug) {
console.log('[WASM] All keys starting with "go":', goKeys);
}
for (const key of goKeys) {
if (typeof globalObj[key] === "function") {
functions[key] = globalObj[key];
if (options.debug) {
console.log(`[WASM] Found function: ${key}`);
}
}
}
const wasmInstance = {
instance,
module: wasmModule,
exports: instance.exports,
functions
};
if (options.onLoad) {
options.onLoad(wasmInstance);
}
if (options.debug) {
console.log(`[WASM] Module loaded successfully with ${Object.keys(functions).length} functions`);
console.log("[WASM] Final function list:", Object.keys(functions));
}
runPromise.catch((error) => {
if (options.debug) {
console.log("[WASM] Go program finished with error:", error);
}
});
return wasmInstance;
} catch (error) {
console.error("[WASM] Failed to load Go WASM module:", error);
throw error;
}
}
var initialized;
var init_wasm = __esm({
"src/server/wasm.ts"() {
"use strict";
initialized = false;
}
});
// src/server/index.ts
var server_exports = {};
__export(server_exports, {
ApiRouter: () => ApiRouter,
AuthService: () => AuthService,
Database: () => Database,
Server: () => Server,
createDevServer: () => createDevServer,
createProductionServer: () => createProductionServer,
createServer: () => createServer,
default: () => server_default,
ensureDirectory: () => ensureDirectory,
errorHandler: () => errorHandler,
generateDocument: () => generateDocument,
generateErrorPage: () => generateErrorPage,
generateLoadingPage: () => generateLoadingPage,
generateToken: () => generateToken,
getEnvironmentInfo: () => getEnvironmentInfo,
getPagination: () => getPagination,
getRequestIp: () => getRequestIp,
hashString: () => hashString,
initNodeWasm: () => initNodeWasm,
isDirectoryEmpty: () => isDirectoryEmpty,
loadGoWasmFromFile: () => loadGoWasmFromFile,
notFoundHandler: () => notFoundHandler,
parseCookies: () => parseCookies,
rateLimit: () => rateLimit,
readJsonFile: () => readJsonFile,
renderComponent: () => renderComponent,
renderToString: () => renderToString,
requestLogger: () => requestLogger,
safeJsonParse: () => safeJsonParse,
sendError: () => sendError,
sendSuccess: () => sendSuccess,
validateFields: () => validateFields,
validateFileUpload: () => validateFileUpload,
writeJsonFile: () => writeJsonFile
});
import path4 from "path";
import fs4 from "fs";
import { pathToFileURL as pathToFileURL3 } from "url";
function getComponentName(filePath, pagesDir) {
try {
const relativePath = path4.relative(pagesDir, filePath);
const withoutExt = relativePath.replace(/\.[^/.]+$/, "");
const cleanPath = withoutExt.replace(/\/index$/, "");
return `/pages/${cleanPath}`;
} catch (e) {
return "";
}
}
function createServer(config = {}) {
return new Server(config);
}
function createDevServer(options = {}) {
return new Server({
port: options.port || 3e3,
enableCors: options.enableCors !== false,
apiDir: "./src/api",
pagesDir: "./src/pages",
staticDir: "./public"
});
}
function createProductionServer(config) {
const server2 = new Server({
...config,
// Fix the PORT parsing
port: config.port || (process.env.PORT ? parseInt(process.env.PORT) : 8080)
});
server2.addShutdownHandler();
return server2;
}
function getRequestIp(req) {
return req.ip || req.headers["x-forwarded-for"]?.split(",")[0].trim() || req.socket.remoteAddress || "";
}
function parseCookies(req) {
const cookies = {};
const cookieHeader = req.headers.cookie;
if (cookieHeader) {
cookieHeader.split(";").forEach((cookie) => {
const [name, value] = cookie.split("=").map((c) => c.trim());
cookies[name] = value;
});
}
return cookies;
}
var Server, renderComponent, server_default;
var init_server = __esm({
"src/server/index.ts"() {
"use strict";
init_dist();
init_database();
init_auth();
init_api_router();
init_middleware();
init_utils();
init_templates();
init_wasm();
init_wasm();
init_utils();
init_templates();
init_database();
init_auth();
init_api_router();
init_middleware();
Server = class {
constructor(config = {}) {
this.server = null;
this.db = null;
this.auth = null;
this.initialized = false;
this.config = {
port: 3e3,
apiDir: "./api",
pagesDir: "./pages",
staticDir: "./public",
enableCors: true,
...config
};
}
async initializeApp() {
if (this.initialized)
return;
try {
const express = await import("express");
this.app = express.default();
this.app.use(express.default.json());
this.app.use(express.default.urlencoded({ extended: true }));
if (this.config.enableCors) {
try {
const cors = await import("cors");
this.app.use(cors.default(this.config.corsOptions));
} catch (error) {
console.warn("CORS not available - install with: npm install cors @types/cors");
}
}
if (this.config.db) {
this.db = new Database(this.config.db);
}
if (this.config.auth) {
this.auth = new AuthService({
secret: this.config.auth.secret,
expiresIn: this.config.auth.expiresIn
});
this.app.use(this.auth.initialize());
}
const staticPath = path4.resolve(process.cwd(), this.config.staticDir);
if (fs4.existsSync(staticPath)) {
this.app.use(express.default.static(staticPath));
}
this.setupApiRoutes();
this.setupPageRoutes();
this.app.use(notFoundHandler);
this.app.use(errorHandler);
this.initialized = true;
} catch (error) {
if (error.code === "MODULE_NOT_FOUND" && error.message.includes("express")) {
throw new Error("Express not installed. Run: npm install express @types/express");
}
throw error;
}
}
async setupApiRoutes() {
const apiRouter = new ApiRouter(this.config.apiDir, this.auth);
await apiRouter.initialize();
if (!apiRouter.isInitialized() || !apiRouter.router) {
console.warn("\u26A0\uFE0F API router not initialized properly - skipping API routes");
return;
}
console.log("\u2705 Setting up API routes...");
this.app.use("/api", requestLogger, apiRouter.router);
this.app.get("/api-docs", (req, res) => {
const apiDocs = this.generateApiDocs();
res.json(apiDocs);
});
}
generateApiDocs() {
const apiDir = path4.resolve(process.cwd(), this.config.apiDir);
const docs = { endpoints: [] };
if (fs4.existsSync(apiDir)) {
this.scanApiDirectory(apiDir, "", docs.endpoints);
}
return docs;
}
scanApiDirectory(dirPath, routePrefix, endpoints) {
const entries = fs4.readdirSync(dirPath, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path4.join(dirPath, entry.name);
if (entry.isDirectory()) {
this.scanApiDirectory(fullPath, `${routePrefix}/${entry.name}`, endpoints);
} else if (entry.name.endsWith(".js") || entry.name.endsWith(".ts")) {
const routePath = this.getRoutePath(entry.name, routePrefix);
endpoints.push({
path: routePath,
file: path4.relative(process.cwd(), fullPath),
methods: this.detectApiMethods(fullPath)
});
}
}
}
getRoutePath(filename, routePrefix) {
const baseName = path4.basename(filename, path4.extname(filename));
if (baseName === "index") {
return routePrefix || "/";
}
const paramMatch = baseName.match(/^\[(.+)\]$/);
if (paramMatch) {
return `${routePrefix}/:${paramMatch[1]}`;
}
return `${routePrefix}/${baseName}`;
}
detectApiMethods(filePath) {
try {
const content = fs4.readFileSync(filePath, "utf8");
const methods = ["get", "post", "put", "delete", "patch", "options"];
return methods.filter(
(method) => new RegExp(`export (async )?function ${method}\\s*\\(`).test(content) || new RegExp(`export const ${method}\\s*=`).test(content)
);
} catch (error) {
return [];
}
}
setupPageRoutes() {
const pagesPath = path4.resolve(process.cwd(), this.config.pagesDir);
if (!fs4.existsSync(pagesPath)) {
return;
}
this.app.get("*", async (req, res) => {
try {
const { html, statusCode } = await this.renderPage(req.path);
res.status(statusCode || 200).send(html);
} catch (error) {
console.error("Error rendering page:", error);
const errorHtml = generateErrorPage(500, "Server Error");
res.status(500).send(errorHtml);
}
});
}
async renderPage(routePath) {
try {
const pagesDir = this.config.pagesDir ? path4.resolve(process.cwd(), this.config.pagesDir) : "";
if (!pagesDir || !fs4.existsSync(pagesDir)) {
return {
html: generateErrorPage(404, "Pages directory not found"),
statusCode: 404
};
}
let normalizedPath = routePath;
if (!normalizedPath.startsWith("/")) {
normalizedPath = "/" + normalizedPath;
}
if (normalizedPath === "/") {
normalizedPath = "/index";
}
let pagePath = "";
const possiblePaths = [
path4.join(pagesDir, `${normalizedPath}.js`),
path4.join(pagesDir, `${normalizedPath}.ts`),
path4.join(pagesDir, `${normalizedPath}.jsx`),
path4.join(pagesDir, `${normalizedPath}.tsx`),
path4.join(pagesDir, `${normalizedPath}/index.js`),
path4.join(pagesDir, `${normalizedPath}/index.ts`),
path4.join(pagesDir, `${normalizedPath}/index.jsx`),
path4.join(pagesDir, `${normalizedPath}/index.tsx`)
];
for (const p of possiblePaths) {
if (fs4.existsSync(p)) {
pagePath = p;
break;
}
}
if (!pagePath) {
return {
html: generateErrorPage(404, `Page not found: ${normalizedPath}`),
statusCode: 404
};
}
try {
const absolutePath = path4.isAbsolute(pagePath) ? pagePath : path4.resolve(pagePath);
const fileUrl = pathToFileURL3(absolutePath).href;
const urlWithTimestamp = `${fileUrl}?t=${Date.now()}`;
const pageModule = await import(urlWithTimestamp);
if (!pageModule || !pageModule.default) {
throw new Error(`No default export found in ${pagePath}`);
}
const PageComponent = pageModule.default;
const initial