frontend-hamroun 1.2.5 → 1.2.7

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.
@@ -1,31 +1,31 @@
1
- (function(c,b){typeof exports=="object"&&typeof module<"u"?b(exports,require("express"),require("path"),require("compression"),require("helmet"),require("morgan"),require("mongoose"),require("fs"),require("jsonwebtoken"),require("bcrypt"),require("crypto")):typeof define=="function"&&define.amd?define(["exports","express","path","compression","helmet","morgan","mongoose","fs","jsonwebtoken","bcrypt","crypto"],b):(c=typeof globalThis<"u"?globalThis:c||self,b(c["frontend-hamroun"]={},c.express,c.path,c.compression,c.helmet,c.morgan,c.mongoose,c.fs,c.jwt,c.bcrypt,c.crypto))})(this,function(c,b,ye,Fe,Le,Be,_,He,Z,qe,Ve){"use strict";function We(r){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const e in r)if(e!=="default"){const n=Object.getOwnPropertyDescriptor(r,e);Object.defineProperty(t,e,n.get?n:{enumerable:!0,get:()=>r[e]})}}return t.default=r,Object.freeze(t)}const me=We(qe),ge=globalThis||void 0||self;function Ue(r){return r&&r.__esModule&&Object.prototype.hasOwnProperty.call(r,"default")?r.default:r}var we={exports:{}},y=we.exports={},v,A;function K(){throw new Error("setTimeout has not been defined")}function ee(){throw new Error("clearTimeout has not been defined")}(function(){try{typeof setTimeout=="function"?v=setTimeout:v=K}catch{v=K}try{typeof clearTimeout=="function"?A=clearTimeout:A=ee}catch{A=ee}})();function Ee(r){if(v===setTimeout)return setTimeout(r,0);if((v===K||!v)&&setTimeout)return v=setTimeout,setTimeout(r,0);try{return v(r,0)}catch{try{return v.call(null,r,0)}catch{return v.call(this,r,0)}}}function Ge(r){if(A===clearTimeout)return clearTimeout(r);if((A===ee||!A)&&clearTimeout)return A=clearTimeout,clearTimeout(r);try{return A(r)}catch{try{return A.call(null,r)}catch{return A.call(this,r)}}}var j=[],P=!1,I,V=-1;function Je(){!P||!I||(P=!1,I.length?j=I.concat(j):V=-1,j.length&&be())}function be(){if(!P){var r=Ee(Je);P=!0;for(var t=j.length;t;){for(I=j,j=[];++V<t;)I&&I[V].run();V=-1,t=j.length}I=null,P=!1,Ge(r)}}y.nextTick=function(r){var t=new Array(arguments.length-1);if(arguments.length>1)for(var e=1;e<arguments.length;e++)t[e-1]=arguments[e];j.push(new Te(r,t)),j.length===1&&!P&&Ee(be)};function Te(r,t){this.fun=r,this.array=t}Te.prototype.run=function(){this.fun.apply(null,this.array)},y.title="browser",y.browser=!0,y.env={},y.argv=[],y.version="",y.versions={};function C(){}y.on=C,y.addListener=C,y.once=C,y.off=C,y.removeListener=C,y.removeAllListeners=C,y.emit=C,y.prependListener=C,y.prependOnceListener=C,y.listeners=function(r){return[]},y.binding=function(r){throw new Error("process.binding is not supported")},y.cwd=function(){return"/"},y.chdir=function(r){throw new Error("process.chdir is not supported")},y.umask=function(){return 0};var ze=we.exports;const E=Ue(ze),O=typeof window<"u"?window:typeof ge<"u"?ge:{};function W(r,t,e){return{type:r,props:t||{},key:e}}function te(r,t,e){return W(r,t,e)}function U(r){if(typeof r=="string"||typeof r=="number")return document.createTextNode(String(r));if(typeof r.type=="function"){const e=r.type(r.props);return U(e)}const t=document.createElement(r.type);return Object.entries(r.props||{}).forEach(([e,n])=>{if(e==="children")(Array.isArray(n)?n:[n]).forEach(i=>{if(i!=null){const o=U(i);E.env.NODE_ENV==="test"&&typeof window<"u"&&(O.__renderStats||(O.__renderStats={elementsCreated:0,textNodesCreated:0,eventsAttached:0,renderTime:0},typeof afterAll=="function"&&afterAll(()=>{try{const a=require("fs"),f=require("path").resolve(E.cwd(),"jsx-runtime-stats.json");a.writeFileSync(f,JSON.stringify(O.__renderStats,null,2)),console.log(`JSX runtime stats written to ${f}`)}catch(a){console.error("Failed to write stats file:",a)}})),o instanceof Text?O.__renderStats.textNodesCreated++:O.__renderStats.elementsCreated++),t.appendChild(o)}});else if(e.startsWith("on")){const s=e.toLowerCase().substring(2);t.addEventListener(s,n),E.env.NODE_ENV==="test"&&typeof window<"u"&&O.__renderStats&&O.__renderStats.eventsAttached++}else e==="className"?t.setAttribute("class",n):e==="style"&&typeof n=="object"?Object.entries(n).forEach(([s,i])=>{t.style[s]=String(i)}):t.setAttribute(e,n)}),t}const re=Symbol("Fragment");typeof window<"u"&&(window.jsx=W,window.jsxs=te,window.Fragment=re);const Qe=typeof window<"u"&&typeof document<"u";async function R(r){var t;if(console.log("Creating element from:",r),!Qe){if(r==null)return{nodeType:3,textContent:""};if(typeof r=="boolean")return{nodeType:3,textContent:""};if(typeof r=="number"||typeof r=="string")return{nodeType:3,textContent:String(r)};if(Array.isArray(r)){const e={nodeType:11,childNodes:[]};for(const n of r){const s=await R(n);e.childNodes.push(s)}return e}if("type"in r&&r.props!==void 0){const{type:e,props:n}=r;if(typeof e=="function")try{const o=await e(n||{});return await R(o)}catch(o){return console.error("Error rendering component:",o),{nodeType:3,textContent:""}}const s={nodeType:1,tagName:e,attributes:{},style:{},childNodes:[],setAttribute:function(o,a){this.attributes[o]=a},appendChild:function(o){this.childNodes.push(o)}};for(const[o,a]of Object.entries(n||{}))if(o!=="children")if(o.startsWith("on")&&typeof a=="function"){const u=o.toLowerCase().slice(2);s.__events||(s.__events={}),s.__events[u]=a}else o==="style"&&typeof a=="object"?Object.assign(s.style,a):o==="className"?s.setAttribute("class",String(a)):o!=="key"&&o!=="ref"&&s.setAttribute(o,String(a));const i=n==null?void 0:n.children;if(i!=null){const o=Array.isArray(i)?i.flat():[i];for(const a of o){const u=await R(a);s.appendChild(u)}}return s}return{nodeType:3,textContent:String(r)}}if(r==null||typeof r=="boolean")return document.createTextNode("");if(typeof r=="number"||typeof r=="string")return document.createTextNode(String(r));if(Array.isArray(r)){const e=document.createDocumentFragment();for(const n of r){const s=await R(n);e.appendChild(s)}return e}if("type"in r&&r.props!==void 0){const{type:e,props:n}=r;if(typeof e=="function")try{const o=await e(n||{}),a=await R(o);return a instanceof Element&&a.setAttribute("data-component-id",e.name||e.toString()),a}catch(o){return console.error("Error rendering component:",o),document.createTextNode("")}const s=document.createElement(e);for(const[o,a]of Object.entries(n||{}))if(o!=="children")if(o.startsWith("on")&&typeof a=="function"){const u=o.toLowerCase().slice(2),f=(t=s.__events)==null?void 0:t[u];f&&s.removeEventListener(u,f),s.addEventListener(u,a),s.__events||(s.__events={}),s.__events[u]=a}else o==="style"&&typeof a=="object"?Object.assign(s.style,a):o==="className"?s.setAttribute("class",String(a)):o!=="key"&&o!=="ref"&&s.setAttribute(o,String(a));const i=n==null?void 0:n.children;if(i!=null){const o=Array.isArray(i)?i.flat():[i];for(const a of o){const u=await R(a);s.appendChild(u)}}return s}return document.createTextNode(String(r))}class Se{constructor(t={}){this.state={},this.element=null,this._mounted=!1,this.props=t}componentDidMount(){}async setState(t){const e={...this.state};this.state={...e,...t},console.log(`${this.constructor.name} state updated:`,{prev:e,next:this.state}),await Promise.resolve(),this._mounted?await this.update():await this.update()}_replayEvents(t,e){const n=t.__events||{};Object.entries(n).forEach(([s,i])=>{e.addEventListener(s,i)}),e.__events=n}_deepCloneWithEvents(t){const e=t.cloneNode(!1),n=t.__events||{};return e.__events=n,Object.entries(n).forEach(([s,i])=>{e.addEventListener(s,i)}),Array.from(t.childNodes).forEach(s=>{s instanceof HTMLElement?e.appendChild(this._deepCloneWithEvents(s)):e.appendChild(s.cloneNode(!0))}),e}async update(){const t=this.render();if(!t)return document.createTextNode("");const e=await R(t);if(e instanceof HTMLElement)return this._updateElement(e);const n=document.createElement("div");return n.appendChild(e),this._updateElement(n)}async _updateElement(t){const e=this._deepCloneWithEvents(t);return e.__instance=this,this.element?this.element.parentNode&&(this.element.parentNode.replaceChild(e,this.element),this.element=e):(this.element=e,this._mounted||(this._mounted=!0,queueMicrotask(()=>this.componentDidMount()))),this.element}render(){throw new Error("Component must implement render() method")}}let G=!1;const ne=[];function J(r){if(G){ne.push(r);return}G=!0;try{for(r();ne.length>0;){const t=ne.shift();t==null||t()}}finally{G=!1}}let l=0;const se=new Map,S=new Map,L=new Map,oe=new Map,ie=new Map;let ae=null,ce=null,ue=null;const ke=typeof window>"u",z=new Map;function ve(r,t,e){ae=r,ce=e,ue=t}function B(){return l++,S.set(l,0),l}function H(){ke&&z.delete(l),l=0}function le(r){if(!l)throw new Error("useState must be called within a render");if(ke){z.has(l)||z.set(l,new Map);const i=z.get(l),o=S.get(l)||0;i.has(o)||i.set(o,r);const a=i.get(o),u=f=>{};return S.set(l,o+1),[a,u]}se.has(l)||se.set(l,[]);const t=se.get(l),e=S.get(l);e>=t.length&&t.push(r);const n=t[e],s=i=>{const o=typeof i=="function"?i(t[e]):i;t[e]!==o&&(t[e]=o,G?J(()=>$e(l)):$e(l))};return S.set(l,e+1),[n,s]}function Ae(r,t){if(!l)throw new Error("useEffect must be called within a render");const e=S.get(l);L.has(l)||L.set(l,[]);const n=L.get(l),s=n[e];(!s||!t||!s.deps||t.some((i,o)=>i!==s.deps[o]))&&(s!=null&&s.cleanup&&s.cleanup(),queueMicrotask(()=>{const i=r()||void 0;n[e]={cleanup:i,deps:t}})),S.set(l,e+1)}function je(r,t){if(!l)throw new Error("useMemo must be called within a render");const e=S.get(l);oe.has(l)||oe.set(l,[]);const n=oe.get(l),s=n[e];if(!s||t&&t.some((i,o)=>!Object.is(i,s.deps[o]))){const i=r();return n[e]={value:i,deps:t},S.set(l,e+1),i}return S.set(l,e+1),s.value}function Ce(r){if(!l)throw new Error("useRef must be called within a render");const t=S.get(l);ie.has(l)||ie.set(l,[]);const e=ie.get(l);if(t>=e.length){const s={current:r};return e.push(s),S.set(l,t+1),s}const n=e[t];return S.set(l,t+1),n}async function $e(r){try{const t=L.get(r);t&&(t.forEach(e=>{e.cleanup&&e.cleanup()}),L.set(r,[])),ae&&ce&&ue&&await ae(ue,ce)}catch(t){console.error("Error during rerender:",t)}}function _e(){const[r,t]=le(null);return[r,()=>t(null)]}let Q=!1;async function Re(r,t){Q=!0;try{await Y(r,t)}finally{Q=!1}}async function Y(r,t){console.log("Rendering to:",t.id||"unnamed-container"),J(async()=>{const e=B();try{ve(Y,r,t);const n=await R(r);Q||(t.innerHTML=""),Q&&t.firstChild?console.log("Hydrating existing DOM"):t.appendChild(n)}finally{H()}})}async function N(r){B(),ve(()=>{},r,null);try{if(r==null||typeof r=="boolean")return"";if(typeof r=="number"||typeof r=="string")return X(String(r));if(Array.isArray(r))return(await Promise.all(r.map(N))).join("");if("type"in r&&r.props!==void 0){const{type:t,props:e}=r;if(typeof t=="function")try{B();const i=await t(e||{}),o=await N(i);return H(),o}catch(i){return console.error("Error rendering component:",i),""}if(t===Symbol.for("react.fragment")||t.name==="Fragment"){if(e.children){const i=Array.isArray(e.children)?e.children:[e.children];return(await Promise.all(i.map(N))).join("")}return""}let n=`<${t}`;for(const[i,o]of Object.entries(e||{}))i==="children"||i==="key"||(i==="className"?n+=` class="${X(String(o))}"`:i==="style"&&typeof o=="object"?n+=` style="${Ye(o||{})}"`:i.startsWith("on")||(n+=` ${i}="${X(String(o))}"`));if(new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]).has(t))return n+"/>";if(n+=">",e!=null&&e.children){const i=Array.isArray(e.children)?e.children:[e.children];for(const o of i)n+=await N(o)}return n+`</${t}>`}return X(String(r))}finally{H()}}function X(r){return r.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function Ye(r){return Object.entries(r).map(([t,e])=>`${Xe(t)}:${e}`).join(";")}function Xe(r){return r.replace(/[A-Z]/g,t=>"-"+t.toLowerCase())}class Ie{constructor(t){this.connection=null,this._connected=!1,this.options={retryAttempts:3,retryDelay:1e3,connectionTimeout:1e4,autoIndex:!0,...t}}async connect(){try{if(this._connected&&this.connection)return this.connection;_.set("strictQuery",!0);let t=0;for(;t<(this.options.retryAttempts||3);)try{await _.connect(this.options.uri,{dbName:this.options.name,connectTimeoutMS:this.options.connectionTimeout,autoIndex:this.options.autoIndex,...this.options.options});break}catch(e){if(t++,t>=(this.options.retryAttempts||3))throw e;console.log(`Connection attempt ${t} failed. Retrying in ${this.options.retryDelay}ms...`),await new Promise(n=>setTimeout(n,this.options.retryDelay))}return this.connection=_.connection,this._connected=!0,console.log(`Connected to MongoDB at ${this.options.uri}/${this.options.name}`),this.connection.on("error",e=>{console.error("MongoDB connection error:",e),this._connected=!1}),this.connection.on("disconnected",()=>{console.log("MongoDB disconnected"),this._connected=!1}),this.connection}catch(t){throw console.error("Failed to connect to MongoDB:",t),t}}async disconnect(){this.connection&&(await _.disconnect(),this._connected=!1,this.connection=null,console.log("Disconnected from MongoDB"))}isConnected(){return this._connected}getConnection(){return this.connection}}function Oe(r={}){const t=b(),{port:e=3e3,staticDir:n="public",enableCors:s=!0,apiPrefix:i="/api",ssrEnabled:o=!0,middlewares:a=[],enableCompression:u=!0,enableHelmet:f=!0,logFormat:p="dev",trustProxy:T=!1,showErrorDetails:$=E.env.NODE_ENV!=="production"}=r;if(T&&t.set("trust proxy",T),t.use(b.json()),t.use(b.urlencoded({extended:!0})),u&&t.use(Fe()),f&&t.use(Le({contentSecurityPolicy:r.disableCSP?!1:void 0})),p&&t.use(Be(p)),s&&t.use((d,m,h)=>{if(m.header("Access-Control-Allow-Origin","*"),m.header("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, PATCH, OPTIONS"),m.header("Access-Control-Allow-Headers","Origin, X-Requested-With, Content-Type, Accept, Authorization"),d.method==="OPTIONS")return m.sendStatus(200);h()}),a.forEach(d=>t.use(d)),n){const d=ye.resolve(E.cwd(),n);He.existsSync(d)?(t.use(b.static(d,{maxAge:r.staticCacheAge||"1d",etag:!0})),console.log(`📂 Serving static files from: ${d}`)):console.warn(`⚠️ Static directory not found: ${d}`)}let g=null;t.connectToDatabase=async d=>{try{return g&&g.isConnected()?(console.log("✅ Using existing database connection"),g):(g=new Ie(d),await g.connect(),console.log("✅ Database connected successfully"),E.on("SIGTERM",async()=>{g&&g.isConnected()&&(await g.disconnect(),console.log("Database connection closed"))}),g)}catch(m){throw console.error("❌ Failed to connect to database:",m),m}};const F={},fe={};return t.registerApi=(d,m,h={})=>{try{const{prefix:w=i}=h,k=ye.posix.join(w,d).replace(/\\/g,"/");t.use(k,m),F[k]={router:m,options:h},console.log(`🔌 API registered: ${k}`)}catch(w){console.error(`❌ Failed to register API at ${d}:`,w)}return t},t.registerSSR=(d,m,h={})=>o?(fe[d]={component:m,options:h},t.get(d,async(w,k,he)=>{try{if(w.query.nossr==="true")return he();const pe={req:w,res:k,params:w.params,query:w.query,user:w.user,...h.props},at=await N(m(pe));k.send(`
1
+ (function(a,v){typeof exports=="object"&&typeof module<"u"?v(exports,require("express"),require("path"),require("compression"),require("helmet"),require("morgan"),require("mongoose"),require("fs"),require("jsonwebtoken"),require("bcrypt"),require("crypto")):typeof define=="function"&&define.amd?define(["exports","express","path","compression","helmet","morgan","mongoose","fs","jsonwebtoken","bcrypt","crypto"],v):(a=typeof globalThis<"u"?globalThis:a||self,v(a["frontend-hamroun"]={},a.express,a.path,a.compression,a.helmet,a.morgan,a.mongoose,a.fs,a.jwt,a.bcrypt,a.crypto))})(this,function(a,v,we,Je,ze,Qe,$,Ye,K,Xe,Ze){"use strict";function Ke(r){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const e in r)if(e!=="default"){const n=Object.getOwnPropertyDescriptor(r,e);Object.defineProperty(t,e,n.get?n:{enumerable:!0,get:()=>r[e]})}}return t.default=r,Object.freeze(t)}const Ee=Ke(Xe),be=globalThis||void 0||self;function et(r){return r&&r.__esModule&&Object.prototype.hasOwnProperty.call(r,"default")?r.default:r}var Te={exports:{}},y=Te.exports={},k,A;function ee(){throw new Error("setTimeout has not been defined")}function te(){throw new Error("clearTimeout has not been defined")}(function(){try{typeof setTimeout=="function"?k=setTimeout:k=ee}catch{k=ee}try{typeof clearTimeout=="function"?A=clearTimeout:A=te}catch{A=te}})();function ve(r){if(k===setTimeout)return setTimeout(r,0);if((k===ee||!k)&&setTimeout)return k=setTimeout,setTimeout(r,0);try{return k(r,0)}catch{try{return k.call(null,r,0)}catch{return k.call(this,r,0)}}}function tt(r){if(A===clearTimeout)return clearTimeout(r);if((A===te||!A)&&clearTimeout)return A=clearTimeout,clearTimeout(r);try{return A(r)}catch{try{return A.call(null,r)}catch{return A.call(this,r)}}}var C=[],M=!1,R,q=-1;function rt(){!M||!R||(M=!1,R.length?C=R.concat(C):q=-1,C.length&&Se())}function Se(){if(!M){var r=ve(rt);M=!0;for(var t=C.length;t;){for(R=C,C=[];++q<t;)R&&R[q].run();q=-1,t=C.length}R=null,M=!1,tt(r)}}y.nextTick=function(r){var t=new Array(arguments.length-1);if(arguments.length>1)for(var e=1;e<arguments.length;e++)t[e-1]=arguments[e];C.push(new ke(r,t)),C.length===1&&!M&&ve(Se)};function ke(r,t){this.fun=r,this.array=t}ke.prototype.run=function(){this.fun.apply(null,this.array)},y.title="browser",y.browser=!0,y.env={},y.argv=[],y.version="",y.versions={};function j(){}y.on=j,y.addListener=j,y.once=j,y.off=j,y.removeListener=j,y.removeAllListeners=j,y.emit=j,y.prependListener=j,y.prependOnceListener=j,y.listeners=function(r){return[]},y.binding=function(r){throw new Error("process.binding is not supported")},y.cwd=function(){return"/"},y.chdir=function(r){throw new Error("process.chdir is not supported")},y.umask=function(){return 0};var nt=Te.exports;const E=et(nt),O=typeof window<"u"?window:typeof be<"u"?be:{};function W(r,t,e){return{type:r,props:t||{},key:e}}function re(r,t,e){return W(r,t,e)}function U(r){if(typeof r=="string"||typeof r=="number")return document.createTextNode(String(r));if(typeof r.type=="function"){const e=r.type(r.props);return U(e)}const t=document.createElement(r.type);return Object.entries(r.props||{}).forEach(([e,n])=>{if(e==="children")(Array.isArray(n)?n:[n]).forEach(i=>{if(i!=null){const o=U(i);E.env.NODE_ENV==="test"&&typeof window<"u"&&(O.__renderStats||(O.__renderStats={elementsCreated:0,textNodesCreated:0,eventsAttached:0,renderTime:0},typeof afterAll=="function"&&afterAll(()=>{try{const c=require("fs"),f=require("path").resolve(E.cwd(),"jsx-runtime-stats.json");c.writeFileSync(f,JSON.stringify(O.__renderStats,null,2)),console.log(`JSX runtime stats written to ${f}`)}catch(c){console.error("Failed to write stats file:",c)}})),o instanceof Text?O.__renderStats.textNodesCreated++:O.__renderStats.elementsCreated++),t.appendChild(o)}});else if(e.startsWith("on")){const s=e.toLowerCase().substring(2);t.addEventListener(s,n),E.env.NODE_ENV==="test"&&typeof window<"u"&&O.__renderStats&&O.__renderStats.eventsAttached++}else e==="className"?t.setAttribute("class",n):e==="style"&&typeof n=="object"?Object.entries(n).forEach(([s,i])=>{t.style[s]=String(i)}):t.setAttribute(e,n)}),t}const ne=Symbol("Fragment");typeof window<"u"&&(window.jsx=W,window.jsxs=re,window.Fragment=ne);const st=typeof window<"u"&&typeof document<"u";async function I(r){var t;if(console.log("Creating element from:",r),!st){if(r==null)return{nodeType:3,textContent:""};if(typeof r=="boolean")return{nodeType:3,textContent:""};if(typeof r=="number"||typeof r=="string")return{nodeType:3,textContent:String(r)};if(Array.isArray(r)){const e={nodeType:11,childNodes:[]};for(const n of r){const s=await I(n);e.childNodes.push(s)}return e}if("type"in r&&r.props!==void 0){const{type:e,props:n}=r;if(typeof e=="function")try{const o=await e(n||{});return await I(o)}catch(o){return console.error("Error rendering component:",o),{nodeType:3,textContent:""}}const s={nodeType:1,tagName:e,attributes:{},style:{},childNodes:[],setAttribute:function(o,c){this.attributes[o]=c},appendChild:function(o){this.childNodes.push(o)}};for(const[o,c]of Object.entries(n||{}))if(o!=="children")if(o.startsWith("on")&&typeof c=="function"){const u=o.toLowerCase().slice(2);s.__events||(s.__events={}),s.__events[u]=c}else o==="style"&&typeof c=="object"?Object.assign(s.style,c):o==="className"?s.setAttribute("class",String(c)):o!=="key"&&o!=="ref"&&s.setAttribute(o,String(c));const i=n==null?void 0:n.children;if(i!=null){const o=Array.isArray(i)?i.flat():[i];for(const c of o){const u=await I(c);s.appendChild(u)}}return s}return{nodeType:3,textContent:String(r)}}if(r==null||typeof r=="boolean")return document.createTextNode("");if(typeof r=="number"||typeof r=="string")return document.createTextNode(String(r));if(Array.isArray(r)){const e=document.createDocumentFragment();for(const n of r){const s=await I(n);e.appendChild(s)}return e}if("type"in r&&r.props!==void 0){const{type:e,props:n}=r;if(typeof e=="function")try{const o=await e(n||{}),c=await I(o);return c instanceof Element&&c.setAttribute("data-component-id",e.name||e.toString()),c}catch(o){return console.error("Error rendering component:",o),document.createTextNode("")}const s=document.createElement(e);for(const[o,c]of Object.entries(n||{}))if(o!=="children")if(o.startsWith("on")&&typeof c=="function"){const u=o.toLowerCase().slice(2),f=(t=s.__events)==null?void 0:t[u];f&&s.removeEventListener(u,f),s.addEventListener(u,c),s.__events||(s.__events={}),s.__events[u]=c}else o==="style"&&typeof c=="object"?Object.assign(s.style,c):o==="className"?s.setAttribute("class",String(c)):o!=="key"&&o!=="ref"&&s.setAttribute(o,String(c));const i=n==null?void 0:n.children;if(i!=null){const o=Array.isArray(i)?i.flat():[i];for(const c of o){const u=await I(c);s.appendChild(u)}}return s}return document.createTextNode(String(r))}class Ae{constructor(t={}){this.state={},this.element=null,this._mounted=!1,this.props=t}componentDidMount(){}async setState(t){const e={...this.state};this.state={...e,...t},console.log(`${this.constructor.name} state updated:`,{prev:e,next:this.state}),await Promise.resolve(),this._mounted?await this.update():await this.update()}_replayEvents(t,e){const n=t.__events||{};Object.entries(n).forEach(([s,i])=>{e.addEventListener(s,i)}),e.__events=n}_deepCloneWithEvents(t){const e=t.cloneNode(!1),n=t.__events||{};return e.__events=n,Object.entries(n).forEach(([s,i])=>{e.addEventListener(s,i)}),Array.from(t.childNodes).forEach(s=>{s instanceof HTMLElement?e.appendChild(this._deepCloneWithEvents(s)):e.appendChild(s.cloneNode(!0))}),e}async update(){const t=this.render();if(!t)return document.createTextNode("");const e=await I(t);if(e instanceof HTMLElement)return this._updateElement(e);const n=document.createElement("div");return n.appendChild(e),this._updateElement(n)}async _updateElement(t){const e=this._deepCloneWithEvents(t);return e.__instance=this,this.element?this.element.parentNode&&(this.element.parentNode.replaceChild(e,this.element),this.element=e):(this.element=e,this._mounted||(this._mounted=!0,queueMicrotask(()=>this.componentDidMount()))),this.element}render(){throw new Error("Component must implement render() method")}}let G=!1;const se=[];function J(r){if(G){se.push(r);return}G=!0;try{for(r();se.length>0;){const t=se.shift();t==null||t()}}finally{G=!1}}let l=0;const oe=new Map,T=new Map,L=new Map,ie=new Map,ce=new Map;let ae=null,ue=null,le=null;const Ce=typeof window>"u",z=new Map;function je(r,t,e){ae=r,ue=e,le=t}function B(){return l++,T.set(l,0),l}function V(){Ce&&z.delete(l),l=0}function de(r){if(!l)throw new Error("useState must be called within a render");if(Ce){z.has(l)||z.set(l,new Map);const i=z.get(l),o=T.get(l)||0;i.has(o)||i.set(o,r);const c=i.get(o),u=f=>{};return T.set(l,o+1),[c,u]}oe.has(l)||oe.set(l,[]);const t=oe.get(l),e=T.get(l);e>=t.length&&t.push(r);const n=t[e],s=i=>{const o=typeof i=="function"?i(t[e]):i;t[e]!==o&&(t[e]=o,G?J(()=>Re(l)):Re(l))};return T.set(l,e+1),[n,s]}function _e(r,t){if(!l)throw new Error("useEffect must be called within a render");const e=T.get(l);L.has(l)||L.set(l,[]);const n=L.get(l),s=n[e];(!s||!t||!s.deps||t.some((i,o)=>i!==s.deps[o]))&&(s!=null&&s.cleanup&&s.cleanup(),queueMicrotask(()=>{const i=r()||void 0;n[e]={cleanup:i,deps:t}})),T.set(l,e+1)}function $e(r,t){if(!l)throw new Error("useMemo must be called within a render");const e=T.get(l);ie.has(l)||ie.set(l,[]);const n=ie.get(l),s=n[e];if(!s||t&&t.some((i,o)=>!Object.is(i,s.deps[o]))){const i=r();return n[e]={value:i,deps:t},T.set(l,e+1),i}return T.set(l,e+1),s.value}function Ie(r){if(!l)throw new Error("useRef must be called within a render");const t=T.get(l);ce.has(l)||ce.set(l,[]);const e=ce.get(l);if(t>=e.length){const s={current:r};return e.push(s),T.set(l,t+1),s}const n=e[t];return T.set(l,t+1),n}async function Re(r){try{const t=L.get(r);t&&(t.forEach(e=>{e.cleanup&&e.cleanup()}),L.set(r,[])),ae&&ue&&le&&await ae(le,ue)}catch(t){console.error("Error during rerender:",t)}}function Oe(){const[r,t]=de(null);return[r,()=>t(null)]}let Q=!1;async function xe(r,t){Q=!0;try{await Y(r,t)}finally{Q=!1}}async function Y(r,t){console.log("Rendering to:",t.id||"unnamed-container"),J(async()=>{const e=B();try{je(Y,r,t);const n=await I(r);Q||(t.innerHTML=""),Q&&t.firstChild?console.log("Hydrating existing DOM"):t.appendChild(n)}finally{V()}})}async function x(r){B(),je(()=>{},r,null);try{if(r==null||typeof r=="boolean")return"";if(typeof r=="number"||typeof r=="string")return X(String(r));if(Array.isArray(r))return(await Promise.all(r.map(x))).join("");if("type"in r&&r.props!==void 0){const{type:t,props:e}=r;if(typeof t=="function")try{B();const i=await t(e||{}),o=await x(i);return V(),o}catch(i){return console.error("Error rendering component:",i),""}if(t===Symbol.for("react.fragment")||t.name==="Fragment"){if(e.children){const i=Array.isArray(e.children)?e.children:[e.children];return(await Promise.all(i.map(x))).join("")}return""}let n=`<${t}`;for(const[i,o]of Object.entries(e||{}))i==="children"||i==="key"||(i==="className"?n+=` class="${X(String(o))}"`:i==="style"&&typeof o=="object"?n+=` style="${ot(o||{})}"`:i.startsWith("on")||(n+=` ${i}="${X(String(o))}"`));if(new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]).has(t))return n+"/>";if(n+=">",e!=null&&e.children){const i=Array.isArray(e.children)?e.children:[e.children];for(const o of i)n+=await x(o)}return n+`</${t}>`}return X(String(r))}finally{V()}}function X(r){return r.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function ot(r){return Object.entries(r).map(([t,e])=>`${it(t)}:${e}`).join(";")}function it(r){return r.replace(/[A-Z]/g,t=>"-"+t.toLowerCase())}function Ne(r){const t={_currentValue:r,Provider:function({value:n,children:s}){return t._currentValue=n,s},Consumer:function({children:n}){return n(t._currentValue)}};return t}function Pe(r){return r._currentValue}class fe{constructor(t){this.connection=null,this._connected=!1,this.options={retryAttempts:3,retryDelay:1e3,connectionTimeout:1e4,autoIndex:!0,...t}}async connect(){try{if(this._connected&&this.connection)return this.connection;$.set("strictQuery",!0);let t=0;for(;t<(this.options.retryAttempts||3);)try{await $.connect(this.options.uri,{dbName:this.options.name,connectTimeoutMS:this.options.connectionTimeout,autoIndex:this.options.autoIndex,...this.options.options});break}catch(e){if(t++,t>=(this.options.retryAttempts||3))throw e;console.log(`Connection attempt ${t} failed. Retrying in ${this.options.retryDelay}ms...`),await new Promise(n=>setTimeout(n,this.options.retryDelay))}return this.connection=$.connection,this._connected=!0,console.log(`Connected to MongoDB at ${this.options.uri}/${this.options.name}`),this.connection.on("error",e=>{console.error("MongoDB connection error:",e),this._connected=!1}),this.connection.on("disconnected",()=>{console.log("MongoDB disconnected"),this._connected=!1}),this.connection}catch(t){throw console.error("Failed to connect to MongoDB:",t),t}}async disconnect(){this.connection&&(await $.disconnect(),this._connected=!1,this.connection=null,console.log("Disconnected from MongoDB"))}isConnected(){return this._connected}getConnection(){return this.connection}}function De(r={}){const t=v(),{port:e=3e3,staticDir:n="public",enableCors:s=!0,apiPrefix:i="/api",ssrEnabled:o=!0,middlewares:c=[],enableCompression:u=!0,enableHelmet:f=!0,logFormat:p="dev",trustProxy:b=!1,showErrorDetails:_=E.env.NODE_ENV!=="production"}=r;if(b&&t.set("trust proxy",b),t.use(v.json()),t.use(v.urlencoded({extended:!0})),u&&t.use(Je()),f&&t.use(ze({contentSecurityPolicy:r.disableCSP?!1:void 0})),p&&t.use(Qe(p)),s&&t.use((d,m,h)=>{if(m.header("Access-Control-Allow-Origin","*"),m.header("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, PATCH, OPTIONS"),m.header("Access-Control-Allow-Headers","Origin, X-Requested-With, Content-Type, Accept, Authorization"),d.method==="OPTIONS")return m.sendStatus(200);h()}),c.forEach(d=>t.use(d)),n){const d=we.resolve(E.cwd(),n);Ye.existsSync(d)?(t.use(v.static(d,{maxAge:r.staticCacheAge||"1d",etag:!0})),console.log(`📂 Serving static files from: ${d}`)):console.warn(`⚠️ Static directory not found: ${d}`)}let g=null;t.connectToDatabase=async d=>{try{return g&&g.isConnected()?(console.log("✅ Using existing database connection"),g):(g=new fe(d),await g.connect(),console.log("✅ Database connected successfully"),E.on("SIGTERM",async()=>{g&&g.isConnected()&&(await g.disconnect(),console.log("Database connection closed"))}),g)}catch(m){throw console.error("❌ Failed to connect to database:",m),m}};const F={},ye={};return t.registerApi=(d,m,h={})=>{try{const{prefix:w=i}=h,S=we.posix.join(w,d).replace(/\\/g,"/");t.use(S,m),F[S]={router:m,options:h},console.log(`🔌 API registered: ${S}`)}catch(w){console.error(`❌ Failed to register API at ${d}:`,w)}return t},t.registerSSR=(d,m,h={})=>o?(ye[d]={component:m,options:h},t.get(d,async(w,S,me)=>{try{if(w.query.nossr==="true")return me();const ge={req:w,res:S,params:w.params,query:w.query,user:w.user,...h.props},ut=await x(m(ge));S.send(`
2
2
  <!DOCTYPE html>
3
3
  <html lang="${h.lang||"en"}">
4
4
  <head>
5
5
  <meta charset="UTF-8">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
7
  <title>${h.title||"Frontend Hamroun App"}</title>
8
- ${h.meta?h.meta.map(q=>`<meta ${Object.entries(q).map(([ct,ut])=>`${ct}="${ut}"`).join(" ")}>`).join(`
8
+ ${h.meta?h.meta.map(H=>`<meta ${Object.entries(H).map(([lt,dt])=>`${lt}="${dt}"`).join(" ")}>`).join(`
9
9
  `):""}
10
10
  ${h.head||""}
11
11
  ${h.styles?`<style>${h.styles}</style>`:""}
12
- ${h.styleSheets?h.styleSheets.map(q=>`<link rel="stylesheet" href="${q}">`).join(`
12
+ ${h.styleSheets?h.styleSheets.map(H=>`<link rel="stylesheet" href="${H}">`).join(`
13
13
  `):""}
14
14
  </head>
15
15
  <body ${h.bodyAttributes||""}>
16
- <div id="${h.rootId||"root"}">${at}</div>
16
+ <div id="${h.rootId||"root"}">${ut}</div>
17
17
  <script>
18
18
  window.__INITIAL_DATA__ = ${JSON.stringify(h.initialData||{})};
19
19
  <\/script>
20
- ${h.scripts?h.scripts.map(q=>`<script src="${q}"><\/script>`).join(`
20
+ ${h.scripts?h.scripts.map(H=>`<script src="${H}"><\/script>`).join(`
21
21
  `):""}
22
22
  </body>
23
23
  </html>
24
- `)}catch(pe){if(console.error("SSR Error:",pe),h.fallback)return he();k.status(500).send("Server rendering error")}}),console.log(`🖥️ SSR registered: ${d}`),t):(console.log(`⚠️ SSR disabled: skipping registration of ${d}`),t),t.use((d,m,h,w)=>{console.error("Server error:",d);const k=d.statusCode||d.status||500;m.path.startsWith(i)?h.status(k).json({success:!1,error:$?d.message:"Internal Server Error",stack:$?d.stack:void 0}):h.status(k).send(`
24
+ `)}catch(ge){if(console.error("SSR Error:",ge),h.fallback)return me();S.status(500).send("Server rendering error")}}),console.log(`🖥️ SSR registered: ${d}`),t):(console.log(`⚠️ SSR disabled: skipping registration of ${d}`),t),t.use((d,m,h,w)=>{console.error("Server error:",d);const S=d.statusCode||d.status||500;m.path.startsWith(i)?h.status(S).json({success:!1,error:_?d.message:"Internal Server Error",stack:_?d.stack:void 0}):h.status(S).send(`
25
25
  <!DOCTYPE html>
26
26
  <html>
27
27
  <head>
28
- <title>Error - ${k}</title>
28
+ <title>Error - ${S}</title>
29
29
  <style>
30
30
  body { font-family: system-ui, sans-serif; padding: 2rem; max-width: 800px; margin: 0 auto; }
31
31
  .error { background: #f8d7da; border: 1px solid #f5c6cb; padding: 1rem; border-radius: 4px; }
@@ -33,9 +33,9 @@
33
33
  </style>
34
34
  </head>
35
35
  <body>
36
- <h1>Error ${k}</h1>
37
- <div class="error">${$?d.message:"Internal Server Error"}</div>
38
- ${$&&d.stack?`<pre class="stack">${d.stack}</pre>`:""}
36
+ <h1>Error ${S}</h1>
37
+ <div class="error">${_?d.message:"Internal Server Error"}</div>
38
+ ${_&&d.stack?`<pre class="stack">${d.stack}</pre>`:""}
39
39
  </body>
40
40
  </html>
41
41
  `)}),t.use((d,m)=>{d.path.startsWith(i)?m.status(404).json({success:!1,error:"Not Found"}):m.status(404).send(`
@@ -59,8 +59,8 @@ ${Object.keys(F).length>0?`
59
59
  📡 Registered API Routes:
60
60
  ${Object.keys(F).map(w=>` ${w}`).join(`
61
61
  `)}`:""}
62
- ${Object.keys(fe).length>0?`
62
+ ${Object.keys(ye).length>0?`
63
63
  🖥️ Registered SSR Routes:
64
- ${Object.keys(fe).map(w=>` ${w}`).join(`
64
+ ${Object.keys(ye).map(w=>` ${w}`).join(`
65
65
  `)}`:""}
66
- `),d&&d()}),h=async w=>{console.log(`${w} signal received: closing HTTP server and cleaning up`),m.close(async()=>{console.log("HTTP server closed"),g&&g.isConnected()&&(await g.disconnect(),console.log("Database connection closed")),E.exit(0)}),setTimeout(()=>{console.error("Could not close connections in time, forcefully shutting down"),E.exit(1)},1e4)};return E.on("SIGTERM",()=>h("SIGTERM")),E.on("SIGINT",()=>h("SIGINT")),m},t}const Ne=(r,{res:t})=>{console.error("API Error:",r);const e=r.status||r.statusCode||500,n=r.message||"Internal server error";t.status(e).json({success:!1,error:n,stack:E.env.NODE_ENV!=="production"?r.stack:void 0})};function Ze(r,t={}){const e=b.Router(),{middleware:n=[],errorHandler:s=Ne}=t;n.forEach(o=>e.use(o));const i=o=>async(a,u,f)=>{try{const p={req:a,res:u,next:f,params:a.params,query:a.query,body:a.body};return await o(p)}catch(p){const T={req:a,res:u,next:f,params:a.params,query:a.query,body:a.body};return s(p,T)}};return e.get("/",i(async({req:o,res:a})=>{const u=o.pagination||{page:1,limit:10},f=await r.getAll(u);a.json({success:!0,...f})})),e.get("/:id",i(async({params:o,res:a})=>{const u=await r.getById(o.id);if(!u){a.status(404).json({success:!1,error:"Item not found"});return}a.json({success:!0,data:u})})),e.post("/",i(async({body:o,res:a})=>{const u=await r.create(o);a.status(201).json({success:!0,data:u,message:"Item created successfully"})})),e.put("/:id",i(async({params:o,body:a,res:u})=>{const f=await r.update(o.id,a);if(!f){u.status(404).json({success:!1,error:"Item not found"});return}u.json({success:!0,data:f,message:"Item updated successfully"})})),e.delete("/:id",i(async({params:o,res:a})=>{if(!await r.delete(o.id)){a.status(404).json({success:!1,error:"Item not found"});return}a.json({success:!0,message:"Item deleted successfully"})})),e}function Ke(r,t={}){const e=b.Router(),{middleware:n=[],errorHandler:s=Ne}=t;n.forEach(o=>e.use(o));const i=o=>async(a,u,f)=>{try{const p={req:a,res:u,next:f,params:a.params,query:a.query,body:a.body};return u.headersSent?void 0:await o(p)}catch(p){if(u.headersSent){console.error("Error occurred after response was sent:",p);return}const T={req:a,res:u,next:f,params:a.params,query:a.query,body:a.body};return s(p,T)}};return Object.entries(r).forEach(([o,a])=>{const{method:u,handler:f}=a;e[u](o,i(f))}),e}function de(r,t,e,n,s){const i={success:r};return t!==void 0&&(i.data=t),e&&(i.message=e),n&&(i.error=n),s&&(i.meta=s),i}function x(r,t,e,n=200,s){r.status(n).json(de(!0,t,e,void 0,s))}function D(r,t,e=400,n){const s=t instanceof Error?t.message:t;r.status(e).json(de(!1,void 0,void 0,s,n))}function Pe(r){const t=parseInt(r.query.page)||1,e=parseInt(r.query.limit)||10,n=r.query.sort||"createdAt",s=r.query.order==="asc"?"asc":"desc";return{page:t,limit:e,sort:n,order:s}}function xe(r,t,e){r.pagination=Pe(r),e()}function et(r){return(t,e,n)=>{try{const{error:s,value:i}=r.validate(t.body);if(s){D(e,`Validation error: ${s.message}`,400);return}t.body=i,n()}catch{D(e,"Validation error",400)}}}function De(r={},t){const e=b.Router();return r.requireAuth&&t&&(e.use(t.authenticate),r.requiredRole&&e.use(t.hasRole(r.requiredRole))),r.rateLimit&&console.warn("Rate limiting is disabled: express-rate-limit dependency is not installed"),e}function M(r){return(t,e,n)=>{r(t,e,n).catch(n)}}function tt(r){const t=b.Router();return t.get("/",xe,M(async(e,n)=>{const s=await r.getAll(e.pagination);x(n,s)})),t.get("/:id",M(async(e,n)=>{const s=await r.getById(e.params.id);if(!s)return D(n,"Item not found",404);x(n,s)})),t.post("/",M(async(e,n)=>{const s=await r.create(e.body);x(n,s,"Item created successfully",201)})),t.put("/:id",M(async(e,n)=>{const s=await r.update(e.params.id,e.body);if(!s)return D(n,"Item not found",404);x(n,s,"Item updated successfully")})),t.delete("/:id",M(async(e,n)=>{if(!await r.delete(e.params.id))return D(n,"Item not found",404);x(n,null,"Item deleted successfully")})),t}const Me=me.default||me;class rt{constructor(t){if(this.loginAttempts=new Map,this.login=async(e,n)=>{try{const{username:s,password:i}=e.body,o=e.ip||e.connection.remoteAddress||"";if(!this.checkRateLimit(o)){n.status(429).json({success:!1,message:"Too many login attempts. Please try again later."});return}if(!s||!i){n.status(400).json({success:!1,message:"Username and password are required"});return}if(!this.options.findUser){n.status(500).json({success:!1,message:"User finder function not configured"});return}const a=await this.options.findUser(s);if(!a){n.status(401).json({success:!1,message:"Invalid credentials"});return}if(!await this.options.verifyPassword(i,a.password)){n.status(401).json({success:!1,message:"Invalid credentials"});return}const f={...a};delete f.password;const p=this.generateTokenPair({id:a.id||a._id,username:a.username,role:a.role||"user"});if(this.options.saveRefreshToken){const T=new Date;T.setSeconds(T.getSeconds()+this.getExpirationSeconds(this.options.refreshExpiration||"7d")),await this.options.saveRefreshToken(a.id||a._id,p.refreshToken,T)}e.body.useCookies&&this.setAuthCookies(n,p),n.json({success:!0,message:"Authentication successful",tokens:p,user:f})}catch(s){console.error("Authentication error:",s),n.status(500).json({success:!1,message:"Authentication failed",error:E.env.NODE_ENV!=="production"?s.message:void 0})}},this.refreshToken=async(e,n)=>{var s,i;try{const o=((s=e.cookies)==null?void 0:s.refreshToken)||e.body.refreshToken;if(!o){n.status(401).json({success:!1,message:"Refresh token required"});return}const a=this.verifyToken(o,"refresh");if(this.options.verifyRefreshToken&&!await this.options.verifyRefreshToken(a.id,o)){this.clearAuthCookies(n),n.status(401).json({success:!1,message:"Invalid refresh token"});return}const u=this.generateTokenPair({id:a.id,...this.options.findUser?await this.options.findUser(a.id):{}});if(this.options.saveRefreshToken){const p=new Date;p.setSeconds(p.getSeconds()+this.getExpirationSeconds(this.options.refreshExpiration||"7d")),await this.options.saveRefreshToken(a.id,u.refreshToken,p)}(((i=e.cookies)==null?void 0:i.accessToken)||e.body.useCookies)&&this.setAuthCookies(n,u),n.json({success:!0,message:"Token refreshed successfully",tokens:u})}catch(o){this.clearAuthCookies(n),n.status(401).json({success:!1,message:"Invalid or expired refresh token",error:E.env.NODE_ENV!=="production"?o.message:void 0})}},this.logout=async(e,n)=>{var s;try{this.clearAuthCookies(n);const i=((s=e.cookies)==null?void 0:s.refreshToken)||e.body.refreshToken;if(i&&this.options.saveRefreshToken)try{const o=this.verifyToken(i,"refresh");typeof this.options.saveRefreshToken=="function"&&await this.options.saveRefreshToken(o.id,"",new Date)}catch{}n.json({success:!0,message:"Logged out successfully"})}catch(i){console.error("Logout error:",i),n.status(500).json({success:!1,message:"Logout failed",error:i.message})}},this.authenticate=(e,n,s)=>{var i;try{let o=(i=e.cookies)==null?void 0:i.accessToken;if(!o){const u=e.headers.authorization;u&&u.startsWith("Bearer ")&&(o=u.split(" ")[1])}if(!o){n.status(401).json({success:!1,message:"Authentication required"});return}const a=this.verifyToken(o,"access");e.user=a,s()}catch(o){n.status(401).json({success:!1,message:"Invalid or expired token",error:E.env.NODE_ENV!=="production"?o.message:void 0})}},this.hasRole=e=>(n,s,i)=>{const o=n.user;if(!o){s.status(401).json({success:!1,message:"Authentication required"});return}(Array.isArray(e)?e:[e]).includes(o.role)?i():s.status(403).json({success:!1,message:"Insufficient permissions"})},this.options={tokenExpiration:"15m",refreshExpiration:"7d",saltRounds:10,secureCookies:E.env.NODE_ENV==="production",httpOnlyCookies:!0,rateLimit:!0,...t,refreshSecret:t.refreshSecret||t.jwtSecret},!t.jwtSecret)throw new Error("JWT secret is required for authentication");this.options.verifyPassword||(this.options.verifyPassword=this.verifyPasswordWithBcrypt)}async hashPassword(t){return await Me.hash(t,this.options.saltRounds||10)}async verifyPasswordWithBcrypt(t,e){return await Me.compare(t,e)}generateSecureToken(t=32){return Ve.randomBytes(t).toString("hex")}generateTokenPair(t){const e=this.getExpirationSeconds(this.options.tokenExpiration||"15m"),n=Z.sign({...t,type:"access"},this.options.jwtSecret,{expiresIn:this.options.tokenExpiration}),s=Z.sign({id:t.id,type:"refresh"},this.options.refreshSecret,{expiresIn:this.options.refreshExpiration});return{accessToken:n,refreshToken:s,expiresIn:e}}getExpirationSeconds(t){const e=t.charAt(t.length-1),n=parseInt(t.slice(0,-1));switch(e){case"s":return n;case"m":return n*60;case"h":return n*60*60;case"d":return n*60*60*24;default:return 3600}}verifyToken(t,e="access"){try{const n=e==="access"?this.options.jwtSecret:this.options.refreshSecret,s=Z.verify(t,n);if(typeof s=="object"&&s.type!==e)throw new Error("Invalid token type");return s}catch{throw new Error("Invalid or expired token")}}setAuthCookies(t,e){t.cookie("accessToken",e.accessToken,{httpOnly:this.options.httpOnlyCookies,secure:this.options.secureCookies,domain:this.options.cookieDomain,sameSite:"strict",maxAge:e.expiresIn*1e3});const n=this.getExpirationSeconds(this.options.refreshExpiration||"7d");t.cookie("refreshToken",e.refreshToken,{httpOnly:!0,secure:this.options.secureCookies,domain:this.options.cookieDomain,sameSite:"strict",maxAge:n*1e3,path:"/api/auth/refresh"})}clearAuthCookies(t){t.clearCookie("accessToken"),t.clearCookie("refreshToken",{path:"/api/auth/refresh"})}checkRateLimit(t){if(!this.options.rateLimit)return!0;const e=Date.now(),n=this.loginAttempts.get(t);return n?e>n.resetTime?(this.loginAttempts.set(t,{count:1,resetTime:e+36e5}),!0):n.count>=5?!1:(n.count++,this.loginAttempts.set(t,n),!0):(this.loginAttempts.set(t,{count:1,resetTime:e+36e5}),!0)}}function nt(r){return new rt(r)}function st(r,t){const e=_.model(r,t);return{getAll:async n=>{try{const{page:s=1,limit:i=10,sort:o="_id",order:a="desc"}=n||{},u=(s-1)*i,f=a==="asc"?1:-1,p={[o]:f},[T,$]=await Promise.all([e.find().sort(p).skip(u).limit(i).exec(),e.countDocuments().exec()]),g=Math.ceil($/i);return{data:T,pagination:{total:$,totalPages:g,currentPage:s,limit:i,hasNextPage:s<g,hasPrevPage:s>1}}}catch(s){throw console.error(`Error in ${r}.getAll:`,s),new Error(`Failed to retrieve ${r} records: ${s.message}`)}},getById:async n=>{try{return _.isValidObjectId(n)?await e.findById(n).exec():null}catch(s){throw console.error(`Error in ${r}.getById:`,s),new Error(`Failed to retrieve ${r} by ID: ${s.message}`)}},create:async n=>{try{return await new e(n).save()}catch(s){throw console.error(`Error in ${r}.create:`,s),new Error(`Failed to create ${r}: ${s.message}`)}},createMany:async n=>{try{return await e.insertMany(n)}catch(s){throw console.error(`Error in ${r}.createMany:`,s),new Error(`Failed to create multiple ${r} records: ${s.message}`)}},update:async(n,s)=>{try{return _.isValidObjectId(n)?await e.findByIdAndUpdate(n,{$set:s},{new:!0,runValidators:!0}).exec():null}catch(i){throw console.error(`Error in ${r}.update:`,i),new Error(`Failed to update ${r}: ${i.message}`)}},delete:async n=>{try{return _.isValidObjectId(n)?await e.findByIdAndDelete(n).exec()!==null:!1}catch(s){throw console.error(`Error in ${r}.delete:`,s),new Error(`Failed to delete ${r}: ${s.message}`)}},find:async(n,s)=>{try{const{page:i=1,limit:o=10,sort:a="_id",order:u="desc"}=s||{},f=(i-1)*o,p=u==="asc"?1:-1,T={[a]:p},[$,g]=await Promise.all([e.find(n).sort(T).skip(f).limit(o).exec(),e.countDocuments(n).exec()]),F=Math.ceil(g/o);return{data:$,pagination:{total:g,totalPages:F,currentPage:i,limit:o,hasNextPage:i<F,hasPrevPage:i>1}}}catch(i){throw console.error(`Error in ${r}.find:`,i),new Error(`Failed to find ${r} records: ${i.message}`)}},count:async n=>{try{return await e.countDocuments(n||{}).exec()}catch(s){throw console.error(`Error in ${r}.count:`,s),new Error(`Failed to count ${r} records: ${s.message}`)}},findOne:async n=>{try{return await e.findOne(n).exec()}catch(s){throw console.error(`Error in ${r}.findOne:`,s),new Error(`Failed to find ${r} record: ${s.message}`)}}}}const ot={String:{type:String},Number:{type:Number},Boolean:{type:Boolean},Date:{type:Date},ObjectId:{type:String},Required:r=>({...r,required:!0}),Unique:r=>({...r,unique:!0}),Ref:r=>({type:String,ref:r}),Enum:r=>({type:String,enum:r}),Default:(r,t)=>({...r,default:t}),Array:r=>({type:[r]})},it={jsx:W,jsxs:te,createElement:U,Fragment:re,Component:Se,useState:le,useEffect:Ae,useRef:Ce,useMemo:je,useErrorBoundary:_e,render:Y,hydrate:Re,renderToString:N,prepareRender:B,finishRender:H,batchUpdates:J,createServer:Oe,Router:b.Router,createApiRouter:De};Object.defineProperty(c,"Router",{enumerable:!0,get:()=>b.Router}),c.Component=Se,c.DatabaseConnector=Ie,c.FieldTypes=ot,c.Fragment=re,c.apiResponse=de,c.asyncHandler=M,c.batchUpdates=J,c.createApiRouter=De,c.createAuth=nt,c.createCustomRouter=Ke,c.createElement=U,c.createModel=st,c.createModelRouter=Ze,c.createRestEndpoints=tt,c.createServer=Oe,c.default=it,c.finishRender=H,c.getPaginationParams=Pe,c.hydrate=Re,c.jsx=W,c.jsxs=te,c.paginationMiddleware=xe,c.prepareRender=B,c.render=Y,c.renderToString=N,c.sendError=D,c.sendSuccess=x,c.useEffect=Ae,c.useErrorBoundary=_e,c.useMemo=je,c.useRef=Ce,c.useState=le,c.validateRequest=et,Object.defineProperties(c,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
66
+ `),d&&d()}),h=async w=>{console.log(`${w} signal received: closing HTTP server and cleaning up`),m.close(async()=>{console.log("HTTP server closed"),g&&g.isConnected()&&(await g.disconnect(),console.log("Database connection closed")),E.exit(0)}),setTimeout(()=>{console.error("Could not close connections in time, forcefully shutting down"),E.exit(1)},1e4)};return E.on("SIGTERM",()=>h("SIGTERM")),E.on("SIGINT",()=>h("SIGINT")),m},t}const Me=Ee.default||Ee;class ct{constructor(t){if(this.loginAttempts=new Map,this.login=async(e,n)=>{try{const{username:s,password:i}=e.body,o=e.ip||e.connection.remoteAddress||"";if(!this.checkRateLimit(o)){n.status(429).json({success:!1,message:"Too many login attempts. Please try again later."});return}if(!s||!i){n.status(400).json({success:!1,message:"Username and password are required"});return}if(!this.options.findUser){n.status(500).json({success:!1,message:"User finder function not configured"});return}const c=await this.options.findUser(s);if(!c){n.status(401).json({success:!1,message:"Invalid credentials"});return}if(!await this.options.verifyPassword(i,c.password)){n.status(401).json({success:!1,message:"Invalid credentials"});return}const f={...c};delete f.password;const p=this.generateTokenPair({id:c.id||c._id,username:c.username,role:c.role||"user"});if(this.options.saveRefreshToken){const b=new Date;b.setSeconds(b.getSeconds()+this.getExpirationSeconds(this.options.refreshExpiration||"7d")),await this.options.saveRefreshToken(c.id||c._id,p.refreshToken,b)}e.body.useCookies&&this.setAuthCookies(n,p),n.json({success:!0,message:"Authentication successful",tokens:p,user:f})}catch(s){console.error("Authentication error:",s),n.status(500).json({success:!1,message:"Authentication failed",error:E.env.NODE_ENV!=="production"?s.message:void 0})}},this.refreshToken=async(e,n)=>{var s,i;try{const o=((s=e.cookies)==null?void 0:s.refreshToken)||e.body.refreshToken;if(!o){n.status(401).json({success:!1,message:"Refresh token required"});return}const c=this.verifyToken(o,"refresh");if(this.options.verifyRefreshToken&&!await this.options.verifyRefreshToken(c.id,o)){this.clearAuthCookies(n),n.status(401).json({success:!1,message:"Invalid refresh token"});return}const u=this.generateTokenPair({id:c.id,...this.options.findUser?await this.options.findUser(c.id):{}});if(this.options.saveRefreshToken){const p=new Date;p.setSeconds(p.getSeconds()+this.getExpirationSeconds(this.options.refreshExpiration||"7d")),await this.options.saveRefreshToken(c.id,u.refreshToken,p)}(((i=e.cookies)==null?void 0:i.accessToken)||e.body.useCookies)&&this.setAuthCookies(n,u),n.json({success:!0,message:"Token refreshed successfully",tokens:u})}catch(o){this.clearAuthCookies(n),n.status(401).json({success:!1,message:"Invalid or expired refresh token",error:E.env.NODE_ENV!=="production"?o.message:void 0})}},this.logout=async(e,n)=>{var s;try{this.clearAuthCookies(n);const i=((s=e.cookies)==null?void 0:s.refreshToken)||e.body.refreshToken;if(i&&this.options.saveRefreshToken)try{const o=this.verifyToken(i,"refresh");typeof this.options.saveRefreshToken=="function"&&await this.options.saveRefreshToken(o.id,"",new Date)}catch{}n.json({success:!0,message:"Logged out successfully"})}catch(i){console.error("Logout error:",i),n.status(500).json({success:!1,message:"Logout failed",error:i.message})}},this.authenticate=(e,n,s)=>{var i;try{let o=(i=e.cookies)==null?void 0:i.accessToken;if(!o){const u=e.headers.authorization;u&&u.startsWith("Bearer ")&&(o=u.split(" ")[1])}if(!o){n.status(401).json({success:!1,message:"Authentication required"});return}const c=this.verifyToken(o,"access");e.user=c,s()}catch(o){n.status(401).json({success:!1,message:"Invalid or expired token",error:E.env.NODE_ENV!=="production"?o.message:void 0})}},this.hasRole=e=>(n,s,i)=>{const o=n.user;if(!o){s.status(401).json({success:!1,message:"Authentication required"});return}(Array.isArray(e)?e:[e]).includes(o.role)?i():s.status(403).json({success:!1,message:"Insufficient permissions"})},this.options={tokenExpiration:"15m",refreshExpiration:"7d",saltRounds:10,secureCookies:E.env.NODE_ENV==="production",httpOnlyCookies:!0,rateLimit:!0,...t,refreshSecret:t.refreshSecret||t.jwtSecret},!t.jwtSecret)throw new Error("JWT secret is required for authentication");this.options.verifyPassword||(this.options.verifyPassword=this.verifyPasswordWithBcrypt)}async hashPassword(t){return await Me.hash(t,this.options.saltRounds||10)}async verifyPasswordWithBcrypt(t,e){return await Me.compare(t,e)}generateSecureToken(t=32){return Ze.randomBytes(t).toString("hex")}generateTokenPair(t){const e=this.getExpirationSeconds(this.options.tokenExpiration||"15m"),n=K.sign({...t,type:"access"},this.options.jwtSecret,{expiresIn:this.options.tokenExpiration}),s=K.sign({id:t.id,type:"refresh"},this.options.refreshSecret,{expiresIn:this.options.refreshExpiration});return{accessToken:n,refreshToken:s,expiresIn:e}}getExpirationSeconds(t){const e=t.charAt(t.length-1),n=parseInt(t.slice(0,-1));switch(e){case"s":return n;case"m":return n*60;case"h":return n*60*60;case"d":return n*60*60*24;default:return 3600}}verifyToken(t,e="access"){try{const n=e==="access"?this.options.jwtSecret:this.options.refreshSecret,s=K.verify(t,n);if(typeof s=="object"&&s.type!==e)throw new Error("Invalid token type");return s}catch{throw new Error("Invalid or expired token")}}setAuthCookies(t,e){t.cookie("accessToken",e.accessToken,{httpOnly:this.options.httpOnlyCookies,secure:this.options.secureCookies,domain:this.options.cookieDomain,sameSite:"strict",maxAge:e.expiresIn*1e3});const n=this.getExpirationSeconds(this.options.refreshExpiration||"7d");t.cookie("refreshToken",e.refreshToken,{httpOnly:!0,secure:this.options.secureCookies,domain:this.options.cookieDomain,sameSite:"strict",maxAge:n*1e3,path:"/api/auth/refresh"})}clearAuthCookies(t){t.clearCookie("accessToken"),t.clearCookie("refreshToken",{path:"/api/auth/refresh"})}checkRateLimit(t){if(!this.options.rateLimit)return!0;const e=Date.now(),n=this.loginAttempts.get(t);return n?e>n.resetTime?(this.loginAttempts.set(t,{count:1,resetTime:e+36e5}),!0):n.count>=5?!1:(n.count++,this.loginAttempts.set(t,n),!0):(this.loginAttempts.set(t,{count:1,resetTime:e+36e5}),!0)}}function Fe(r){return new ct(r)}function Le(r,t){const e=$.model(r,t);return{getAll:async n=>{try{const{page:s=1,limit:i=10,sort:o="_id",order:c="desc"}=n||{},u=(s-1)*i,f=c==="asc"?1:-1,p={[o]:f},[b,_]=await Promise.all([e.find().sort(p).skip(u).limit(i).exec(),e.countDocuments().exec()]),g=Math.ceil(_/i);return{data:b,pagination:{total:_,totalPages:g,currentPage:s,limit:i,hasNextPage:s<g,hasPrevPage:s>1}}}catch(s){throw console.error(`Error in ${r}.getAll:`,s),new Error(`Failed to retrieve ${r} records: ${s.message}`)}},getById:async n=>{try{return $.isValidObjectId(n)?await e.findById(n).exec():null}catch(s){throw console.error(`Error in ${r}.getById:`,s),new Error(`Failed to retrieve ${r} by ID: ${s.message}`)}},create:async n=>{try{return await new e(n).save()}catch(s){throw console.error(`Error in ${r}.create:`,s),new Error(`Failed to create ${r}: ${s.message}`)}},createMany:async n=>{try{return await e.insertMany(n)}catch(s){throw console.error(`Error in ${r}.createMany:`,s),new Error(`Failed to create multiple ${r} records: ${s.message}`)}},update:async(n,s)=>{try{return $.isValidObjectId(n)?await e.findByIdAndUpdate(n,{$set:s},{new:!0,runValidators:!0}).exec():null}catch(i){throw console.error(`Error in ${r}.update:`,i),new Error(`Failed to update ${r}: ${i.message}`)}},delete:async n=>{try{return $.isValidObjectId(n)?await e.findByIdAndDelete(n).exec()!==null:!1}catch(s){throw console.error(`Error in ${r}.delete:`,s),new Error(`Failed to delete ${r}: ${s.message}`)}},find:async(n,s)=>{try{const{page:i=1,limit:o=10,sort:c="_id",order:u="desc"}=s||{},f=(i-1)*o,p=u==="asc"?1:-1,b={[c]:p},[_,g]=await Promise.all([e.find(n).sort(b).skip(f).limit(o).exec(),e.countDocuments(n).exec()]),F=Math.ceil(g/o);return{data:_,pagination:{total:g,totalPages:F,currentPage:i,limit:o,hasNextPage:i<F,hasPrevPage:i>1}}}catch(i){throw console.error(`Error in ${r}.find:`,i),new Error(`Failed to find ${r} records: ${i.message}`)}},count:async n=>{try{return await e.countDocuments(n||{}).exec()}catch(s){throw console.error(`Error in ${r}.count:`,s),new Error(`Failed to count ${r} records: ${s.message}`)}},findOne:async n=>{try{return await e.findOne(n).exec()}catch(s){throw console.error(`Error in ${r}.findOne:`,s),new Error(`Failed to find ${r} record: ${s.message}`)}}}}const Be={String:{type:String},Number:{type:Number},Boolean:{type:Boolean},Date:{type:Date},ObjectId:{type:String},Required:r=>({...r,required:!0}),Unique:r=>({...r,unique:!0}),Ref:r=>({type:String,ref:r}),Enum:r=>({type:String,enum:r}),Default:(r,t)=>({...r,default:t}),Array:r=>({type:[r]})},Ve=(r,{res:t})=>{console.error("API Error:",r);const e=r.status||r.statusCode||500,n=r.message||"Internal server error";t.status(e).json({success:!1,error:n,stack:E.env.NODE_ENV!=="production"?r.stack:void 0})};function He(r,t={}){const e=v.Router(),{middleware:n=[],errorHandler:s=Ve}=t;n.forEach(o=>e.use(o));const i=o=>async(c,u,f)=>{try{const p={req:c,res:u,next:f,params:c.params,query:c.query,body:c.body};return await o(p)}catch(p){const b={req:c,res:u,next:f,params:c.params,query:c.query,body:c.body};return s(p,b)}};return e.get("/",i(async({req:o,res:c})=>{const u=o.pagination||{page:1,limit:10},f=await r.getAll(u);c.json({success:!0,...f})})),e.get("/:id",i(async({params:o,res:c})=>{const u=await r.getById(o.id);if(!u){c.status(404).json({success:!1,error:"Item not found"});return}c.json({success:!0,data:u})})),e.post("/",i(async({body:o,res:c})=>{const u=await r.create(o);c.status(201).json({success:!0,data:u,message:"Item created successfully"})})),e.put("/:id",i(async({params:o,body:c,res:u})=>{const f=await r.update(o.id,c);if(!f){u.status(404).json({success:!1,error:"Item not found"});return}u.json({success:!0,data:f,message:"Item updated successfully"})})),e.delete("/:id",i(async({params:o,res:c})=>{if(!await r.delete(o.id)){c.status(404).json({success:!1,error:"Item not found"});return}c.json({success:!0,message:"Item deleted successfully"})})),e}function qe(r,t={}){const e=v.Router(),{middleware:n=[],errorHandler:s=Ve}=t;n.forEach(o=>e.use(o));const i=o=>async(c,u,f)=>{try{const p={req:c,res:u,next:f,params:c.params,query:c.query,body:c.body};return u.headersSent?void 0:await o(p)}catch(p){if(u.headersSent){console.error("Error occurred after response was sent:",p);return}const b={req:c,res:u,next:f,params:c.params,query:c.query,body:c.body};return s(p,b)}};return Object.entries(r).forEach(([o,c])=>{const{method:u,handler:f}=c;e[u](o,i(f))}),e}function Z(r,t,e,n,s){const i={success:r};return t!==void 0&&(i.data=t),e&&(i.message=e),n&&(i.error=n),s&&(i.meta=s),i}function N(r,t,e,n=200,s){r.status(n).json(Z(!0,t,e,void 0,s))}function P(r,t,e=400,n){const s=t instanceof Error?t.message:t;r.status(e).json(Z(!1,void 0,void 0,s,n))}function he(r){const t=parseInt(r.query.page)||1,e=parseInt(r.query.limit)||10,n=r.query.sort||"createdAt",s=r.query.order==="asc"?"asc":"desc";return{page:t,limit:e,sort:n,order:s}}function pe(r,t,e){r.pagination=he(r),e()}function We(r){return(t,e,n)=>{try{const{error:s,value:i}=r.validate(t.body);if(s){P(e,`Validation error: ${s.message}`,400);return}t.body=i,n()}catch{P(e,"Validation error",400)}}}function Ue(r={},t){const e=v.Router();return r.requireAuth&&t&&(e.use(t.authenticate),r.requiredRole&&e.use(t.hasRole(r.requiredRole))),r.rateLimit&&console.warn("Rate limiting is disabled: express-rate-limit dependency is not installed"),e}function D(r){return(t,e,n)=>{r(t,e,n).catch(n)}}function Ge(r){const t=v.Router();return t.get("/",pe,D(async(e,n)=>{const s=await r.getAll(e.pagination);N(n,s)})),t.get("/:id",D(async(e,n)=>{const s=await r.getById(e.params.id);if(!s)return P(n,"Item not found",404);N(n,s)})),t.post("/",D(async(e,n)=>{const s=await r.create(e.body);N(n,s,"Item created successfully",201)})),t.put("/:id",D(async(e,n)=>{const s=await r.update(e.params.id,e.body);if(!s)return P(n,"Item not found",404);N(n,s,"Item updated successfully")})),t.delete("/:id",D(async(e,n)=>{if(!await r.delete(e.params.id))return P(n,"Item not found",404);N(n,null,"Item deleted successfully")})),t}const at={jsx:W,jsxs:re,createElement:U,Fragment:ne,Component:Ae,useState:de,useEffect:_e,useRef:Ie,useMemo:$e,useErrorBoundary:Oe,render:Y,hydrate:xe,renderToString:x,prepareRender:B,finishRender:V,batchUpdates:J,createContext:Ne,useContext:Pe,createServer:De,createAuth:Fe,createModel:Le,FieldTypes:Be,createModelRouter:He,createCustomRouter:qe,createApiRouter:Ue,sendSuccess:N,sendError:P,apiResponse:Z,getPaginationParams:he,paginationMiddleware:pe,validateRequest:We,asyncHandler:D,createRestEndpoints:Ge,DatabaseConnector:fe};a.Component=Ae,a.DatabaseConnector=fe,a.FieldTypes=Be,a.Fragment=ne,a.apiResponse=Z,a.asyncHandler=D,a.batchUpdates=J,a.createApiRouter=Ue,a.createAuth=Fe,a.createContext=Ne,a.createCustomRouter=qe,a.createElement=U,a.createModel=Le,a.createModelRouter=He,a.createRestEndpoints=Ge,a.createServer=De,a.default=at,a.finishRender=V,a.getPaginationParams=he,a.hydrate=xe,a.jsx=W,a.jsxs=re,a.paginationMiddleware=pe,a.prepareRender=B,a.render=Y,a.renderToString=x,a.sendError=P,a.sendSuccess=N,a.useContext=Pe,a.useEffect=_e,a.useErrorBoundary=Oe,a.useMemo=$e,a.useRef=Ie,a.useState=de,a.validateRequest=We,Object.defineProperties(a,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
package/dist/index.d.ts CHANGED
@@ -5,14 +5,22 @@ import { render, hydrate } from './renderer';
5
5
  import { renderToString } from './server-renderer';
6
6
  import { prepareRender, finishRender } from './hooks';
7
7
  import { batchUpdates } from './batch';
8
+ import { createContext, useContext } from './context';
8
9
  import { createServer } from './backend/server';
9
- import { Router } from './backend/router';
10
- import { createApiRouter } from './backend/api-utils';
10
+ import { createAuth } from './backend/auth';
11
+ import { createModel, FieldTypes } from './backend/model';
12
+ import { createModelRouter, createApiRouter as createCustomRouter } from './backend/router';
13
+ import { sendSuccess, sendError, apiResponse, getPaginationParams, paginationMiddleware, validateRequest, asyncHandler, createRestEndpoints, createApiRouter } from './backend/api-utils';
14
+ import { DatabaseConnector } from './backend/database';
11
15
  export { jsx, jsxs, createElement, Fragment };
12
- export { useState, useEffect, useRef, useMemo, useErrorBoundary, prepareRender, finishRender, batchUpdates };
16
+ export { useState, useEffect, useRef, useMemo, useErrorBoundary, prepareRender, finishRender, batchUpdates, createContext, useContext };
13
17
  export { Component };
14
18
  export { render, hydrate, renderToString };
15
- export { createServer, Router, createApiRouter };
19
+ export { createServer, createAuth, createModel, FieldTypes, createModelRouter, createCustomRouter, createApiRouter, sendSuccess, sendError, apiResponse, getPaginationParams, paginationMiddleware, validateRequest, asyncHandler, createRestEndpoints, DatabaseConnector };
20
+ export type { Context } from './context';
21
+ export type { VNode } from './types';
22
+ export type { HamrounServerOptions, RouterOptions, RouteContext, PaginationOptions, PaginatedResult, DatabaseOptions, Model, ApiResponse } from './backend/types';
23
+ export type { AuthOptions, TokenPair } from './backend/auth';
16
24
  declare const _default: {
17
25
  jsx: typeof jsx;
18
26
  jsxs: typeof jsxs;
@@ -30,17 +38,53 @@ declare const _default: {
30
38
  prepareRender: typeof prepareRender;
31
39
  finishRender: typeof finishRender;
32
40
  batchUpdates: typeof batchUpdates;
41
+ createContext: typeof createContext;
42
+ useContext: typeof useContext;
33
43
  createServer: typeof createServer;
34
- Router: typeof Router;
44
+ createAuth: typeof createAuth;
45
+ createModel: typeof createModel;
46
+ FieldTypes: {
47
+ String: {
48
+ type: StringConstructor;
49
+ };
50
+ Number: {
51
+ type: NumberConstructor;
52
+ };
53
+ Boolean: {
54
+ type: BooleanConstructor;
55
+ };
56
+ Date: {
57
+ type: DateConstructor;
58
+ };
59
+ ObjectId: {
60
+ type: StringConstructor;
61
+ };
62
+ Required: (fieldType: any) => any;
63
+ Unique: (fieldType: any) => any;
64
+ Ref: (model: string) => {
65
+ type: StringConstructor;
66
+ ref: string;
67
+ };
68
+ Enum: (values: any[]) => {
69
+ type: StringConstructor;
70
+ enum: any[];
71
+ };
72
+ Default: (fieldType: any, defaultValue: any) => any;
73
+ Array: (fieldType: any) => {
74
+ type: any[];
75
+ };
76
+ };
77
+ createModelRouter: typeof createModelRouter;
78
+ createCustomRouter: typeof createCustomRouter;
35
79
  createApiRouter: typeof createApiRouter;
80
+ sendSuccess: typeof sendSuccess;
81
+ sendError: typeof sendError;
82
+ apiResponse: typeof apiResponse;
83
+ getPaginationParams: typeof getPaginationParams;
84
+ paginationMiddleware: typeof paginationMiddleware;
85
+ validateRequest: typeof validateRequest;
86
+ asyncHandler: typeof asyncHandler;
87
+ createRestEndpoints: typeof createRestEndpoints;
88
+ DatabaseConnector: typeof DatabaseConnector;
36
89
  };
37
90
  export default _default;
38
- export type { Context } from './context';
39
- export type { VNode } from './types';
40
- export { createAuth } from './backend/auth';
41
- export { createModel, FieldTypes } from './backend/model';
42
- export { createModelRouter, createApiRouter as createCustomRouter } from './backend/router';
43
- export { sendSuccess, sendError, apiResponse, getPaginationParams, paginationMiddleware, validateRequest, asyncHandler, createRestEndpoints } from './backend/api-utils';
44
- export { DatabaseConnector } from './backend/database';
45
- export type { HamrounServerOptions, RouterOptions, RouteContext, PaginationOptions, PaginatedResult, DatabaseOptions, Model, ApiResponse } from './backend/types';
46
- export type { AuthOptions, TokenPair } from './backend/auth';
package/dist/index.js CHANGED
@@ -6,20 +6,24 @@ import { render, hydrate } from './renderer';
6
6
  import { renderToString } from './server-renderer';
7
7
  import { prepareRender, finishRender } from './hooks';
8
8
  import { batchUpdates } from './batch';
9
- // Backend functionality
9
+ import { createContext, useContext } from './context';
10
+ // Import backend functionality
10
11
  import { createServer } from './backend/server';
11
- import { Router } from './backend/router';
12
- import { createApiRouter } from './backend/api-utils';
12
+ import { createAuth } from './backend/auth';
13
+ import { createModel, FieldTypes } from './backend/model';
14
+ import { createModelRouter, createApiRouter as createCustomRouter } from './backend/router';
15
+ import { sendSuccess, sendError, apiResponse, getPaginationParams, paginationMiddleware, validateRequest, asyncHandler, createRestEndpoints, createApiRouter } from './backend/api-utils';
16
+ import { DatabaseConnector } from './backend/database';
13
17
  // Export JSX runtime
14
18
  export { jsx, jsxs, createElement, Fragment };
15
19
  // Export hooks
16
- export { useState, useEffect, useRef, useMemo, useErrorBoundary, prepareRender, finishRender, batchUpdates };
20
+ export { useState, useEffect, useRef, useMemo, useErrorBoundary, prepareRender, finishRender, batchUpdates, createContext, useContext };
17
21
  // Export component base class
18
22
  export { Component };
19
23
  // Export renderers
20
24
  export { render, hydrate, renderToString };
21
25
  // Export backend functionality
22
- export { createServer, Router, createApiRouter };
26
+ export { createServer, createAuth, createModel, FieldTypes, createModelRouter, createCustomRouter, createApiRouter, sendSuccess, sendError, apiResponse, getPaginationParams, paginationMiddleware, validateRequest, asyncHandler, createRestEndpoints, DatabaseConnector };
23
27
  // Default export with all functionality
24
28
  export default {
25
29
  // Frontend
@@ -39,14 +43,23 @@ export default {
39
43
  prepareRender,
40
44
  finishRender,
41
45
  batchUpdates,
46
+ createContext,
47
+ useContext,
42
48
  // Backend
43
49
  createServer,
44
- Router,
45
- createApiRouter
50
+ createAuth,
51
+ createModel,
52
+ FieldTypes,
53
+ createModelRouter,
54
+ createCustomRouter,
55
+ createApiRouter,
56
+ sendSuccess,
57
+ sendError,
58
+ apiResponse,
59
+ getPaginationParams,
60
+ paginationMiddleware,
61
+ validateRequest,
62
+ asyncHandler,
63
+ createRestEndpoints,
64
+ DatabaseConnector
46
65
  };
47
- // Backend exports
48
- export { createAuth } from './backend/auth';
49
- export { createModel, FieldTypes } from './backend/model';
50
- export { createModelRouter, createApiRouter as createCustomRouter } from './backend/router';
51
- export { sendSuccess, sendError, apiResponse, getPaginationParams, paginationMiddleware, validateRequest, asyncHandler, createRestEndpoints } from './backend/api-utils';
52
- export { DatabaseConnector } from './backend/database';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frontend-hamroun",
3
- "version": "1.2.5",
3
+ "version": "1.2.7",
4
4
  "description": "A lightweight frontend and backend framework for building modern web applications",
5
5
  "type": "module",
6
6
  "main": "dist/frontend-hamroun.umd.js",
package/src/context.ts CHANGED
@@ -1,32 +1,29 @@
1
-
1
+ import { useState, useEffect } from './hooks';
2
2
 
3
3
  const contexts = new Map<symbol, any>();
4
4
  let currentRender: Function | null = null;
5
5
 
6
6
  export interface Context<T> {
7
- Provider: (props: { value: T; children?: any }) => any;
7
+ Provider: (props: { value: T; children: any }) => any;
8
8
  Consumer: (props: { children: (value: T) => any }) => any;
9
- _id: symbol;
10
- useSelector: <S>(selector: (state: T) => S) => S;
9
+ _currentValue: T;
11
10
  }
12
11
 
13
12
  export function createContext<T>(defaultValue: T): Context<T> {
14
- const context = {
15
- Provider: ({ value, children }: { value: T, children?: any }) => {
13
+ const context: Context<T> = {
14
+ _currentValue: defaultValue,
15
+ Provider: function Provider({ value, children }) {
16
+ context._currentValue = value;
16
17
  return children;
17
18
  },
18
- Consumer: ({ children }: { children: (value: T) => any }) => {
19
- return children(defaultValue);
20
- },
21
- _id: Symbol(),
22
- useSelector: <S>(selector: (state: T) => S) => {
23
- return selector(defaultValue);
19
+ Consumer: function Consumer({ children }) {
20
+ return children(context._currentValue);
24
21
  }
25
22
  };
26
23
 
27
24
  return context;
28
25
  }
29
26
 
30
- export function useContext<T>(context: any): T {
31
- return context;
27
+ export function useContext<T>(context: Context<T>): T {
28
+ return context._currentValue;
32
29
  }
package/src/index.ts CHANGED
@@ -6,11 +6,25 @@ import { render, hydrate } from './renderer';
6
6
  import { renderToString } from './server-renderer';
7
7
  import { prepareRender, finishRender } from './hooks';
8
8
  import { batchUpdates } from './batch';
9
+ import { createContext, useContext } from './context';
9
10
 
10
- // Backend functionality
11
+ // Import backend functionality
11
12
  import { createServer } from './backend/server';
12
- import { Router } from './backend/router';
13
- import { createApiRouter } from './backend/api-utils';
13
+ import { createAuth } from './backend/auth';
14
+ import { createModel, FieldTypes } from './backend/model';
15
+ import { createModelRouter, createApiRouter as createCustomRouter } from './backend/router';
16
+ import {
17
+ sendSuccess,
18
+ sendError,
19
+ apiResponse,
20
+ getPaginationParams,
21
+ paginationMiddleware,
22
+ validateRequest,
23
+ asyncHandler,
24
+ createRestEndpoints,
25
+ createApiRouter
26
+ } from './backend/api-utils';
27
+ import { DatabaseConnector } from './backend/database';
14
28
 
15
29
  // Export JSX runtime
16
30
  export {
@@ -29,7 +43,9 @@ export {
29
43
  useErrorBoundary,
30
44
  prepareRender,
31
45
  finishRender,
32
- batchUpdates
46
+ batchUpdates,
47
+ createContext,
48
+ useContext
33
49
  };
34
50
 
35
51
  // Export component base class
@@ -41,13 +57,48 @@ export {
41
57
  hydrate,
42
58
  renderToString
43
59
  };
60
+
44
61
  // Export backend functionality
45
62
  export {
46
63
  createServer,
47
- Router,
48
- createApiRouter
64
+ createAuth,
65
+ createModel,
66
+ FieldTypes,
67
+ createModelRouter,
68
+ createCustomRouter,
69
+ createApiRouter,
70
+ sendSuccess,
71
+ sendError,
72
+ apiResponse,
73
+ getPaginationParams,
74
+ paginationMiddleware,
75
+ validateRequest,
76
+ asyncHandler,
77
+ createRestEndpoints,
78
+ DatabaseConnector
49
79
  };
50
80
 
81
+ // Re-export types
82
+ export type { Context } from './context';
83
+ export type { VNode } from './types';
84
+
85
+ // Backend types
86
+ export type {
87
+ HamrounServerOptions,
88
+ RouterOptions,
89
+ RouteContext,
90
+ PaginationOptions,
91
+ PaginatedResult,
92
+ DatabaseOptions,
93
+ Model,
94
+ ApiResponse
95
+ } from './backend/types';
96
+
97
+ export type {
98
+ AuthOptions,
99
+ TokenPair
100
+ } from './backend/auth';
101
+
51
102
  // Default export with all functionality
52
103
  export default {
53
104
  // Frontend
@@ -67,47 +118,25 @@ export default {
67
118
  prepareRender,
68
119
  finishRender,
69
120
  batchUpdates,
121
+ createContext,
122
+ useContext,
70
123
 
71
124
  // Backend
72
125
  createServer,
73
- Router,
74
- createApiRouter
75
- };
76
-
77
- // Re-export types
78
- export type { Context } from './context';
79
- export type { VNode } from './types';
80
-
81
- // Backend exports
82
- export { createAuth } from './backend/auth';
83
- export { createModel, FieldTypes } from './backend/model';
84
- export { createModelRouter, createApiRouter as createCustomRouter } from './backend/router';
85
- export {
86
- sendSuccess,
87
- sendError,
88
- apiResponse,
89
- getPaginationParams,
126
+ createAuth,
127
+ createModel,
128
+ FieldTypes,
129
+ createModelRouter,
130
+ createCustomRouter,
131
+ createApiRouter,
132
+ sendSuccess,
133
+ sendError,
134
+ apiResponse,
135
+ getPaginationParams,
90
136
  paginationMiddleware,
91
137
  validateRequest,
92
138
  asyncHandler,
93
- createRestEndpoints
94
- } from './backend/api-utils';
95
- export { DatabaseConnector } from './backend/database';
96
-
97
- // Backend types
98
- export type {
99
- HamrounServerOptions,
100
- RouterOptions,
101
- RouteContext,
102
- PaginationOptions,
103
- PaginatedResult,
104
- DatabaseOptions,
105
- Model,
106
- ApiResponse
107
- } from './backend/types';
108
-
109
- export type {
110
- AuthOptions,
111
- TokenPair
112
- } from './backend/auth';
139
+ createRestEndpoints,
140
+ DatabaseConnector
141
+ };
113
142
 
@@ -1,13 +1,23 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "target": "ES2020",
4
+ "useDefineForClassFields": true,
4
5
  "module": "ESNext",
5
6
  "lib": ["ES2020", "DOM", "DOM.Iterable"],
6
- "jsx": "preserve",
7
+ "skipLibCheck": true,
7
8
  "moduleResolution": "bundler",
8
- "esModuleInterop": true,
9
+ "allowImportingTsExtensions": true,
10
+ "resolveJsonModule": true,
11
+ "isolatedModules": true,
12
+ "noEmit": true,
13
+ "jsx": "react-jsx",
14
+ "jsxFactory": "jsx",
15
+ "jsxFragmentFactory": "Fragment",
9
16
  "strict": true,
10
- "skipLibCheck": true
17
+ "noUnusedLocals": true,
18
+ "noUnusedParameters": true,
19
+ "noFallthroughCasesInSwitch": true
11
20
  },
12
- "include": ["src"]
21
+ "include": ["src"],
22
+ "references": [{ "path": "./tsconfig.node.json" }]
13
23
  }