frontend-hamroun 1.2.4 ā 1.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backend/auth.js +2 -1
- package/dist/backend/model.js +2 -0
- package/dist/context.d.ts +3 -4
- package/dist/context.js +6 -8
- package/dist/frontend-hamroun.es.js +989 -1276
- package/dist/frontend-hamroun.umd.js +66 -2
- package/dist/index.d.ts +58 -14
- package/dist/index.js +26 -13
- package/package.json +1 -1
- package/src/backend/auth.ts +2 -1
- package/src/backend/model.ts +2 -0
- package/src/context.ts +11 -14
- package/src/index.ts +72 -43
- package/src/shims.d.ts +20 -0
- package/templates/basic-app/src/App.tsx +53 -1
- package/templates/basic-app/src/main.tsx +18 -1
- package/templates/basic-app/vite.config.ts +9 -36
- package/dist/frontend-hamroun.es.js.map +0 -1
- package/dist/frontend-hamroun.umd.js.map +0 -1
@@ -1,2 +1,66 @@
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("express"),require("path"),require("compression"),require("helmet"),require("morgan"),require("mongoose"),require("fs"),require("jsonwebtoken"),require("bcrypt")):"function"==typeof define&&define.amd?define(["exports","express","path","compression","helmet","morgan","mongoose","fs","jsonwebtoken","bcrypt"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self)["frontend-hamroun"]={},e.express,e.path,e.compression,e.helmet,e.morgan,e.mongoose,e.fs,e.jwt,e.bcrypt)}(this,(function(e,t,n,s,r,o,i,a,c,d){"use strict";const u="undefined"!=typeof window?window:"undefined"!=typeof global?global:{};function l(e,t,n){return{type:e,props:t||{},key:n}}function p(e,t,n){return l(e,t,n)}function h(e){if("string"==typeof e||"number"==typeof e)return document.createTextNode(String(e));if("function"==typeof e.type){return h(e.type(e.props))}const t=document.createElement(e.type);return Object.entries(e.props||{}).forEach((([e,n])=>{if("children"===e){(Array.isArray(n)?n:[n]).forEach((e=>{if(null!=e){const n=h(e);"test"===process.env.NODE_ENV&&"undefined"!=typeof window&&(u.__renderStats||(u.__renderStats={elementsCreated:0,textNodesCreated:0,eventsAttached:0,renderTime:0},"function"==typeof afterAll&&afterAll((()=>{try{const e=require("fs"),t=require("path").resolve(process.cwd(),"jsx-runtime-stats.json");e.writeFileSync(t,JSON.stringify(u.__renderStats,null,2)),console.log(`JSX runtime stats written to ${t}`)}catch(e){console.error("Failed to write stats file:",e)}}))),n instanceof Text?u.__renderStats.textNodesCreated++:u.__renderStats.elementsCreated++),t.appendChild(n)}}))}else if(e.startsWith("on")){const s=e.toLowerCase().substring(2);t.addEventListener(s,n),"test"===process.env.NODE_ENV&&"undefined"!=typeof window&&u.__renderStats&&u.__renderStats.eventsAttached++}else"className"===e?t.setAttribute("class",n):"style"===e&&"object"==typeof n?Object.entries(n).forEach((([e,n])=>{t.style[e]=String(n)})):t.setAttribute(e,n)})),t}const f=Symbol("Fragment");"undefined"!=typeof window&&(window.jsx=l,window.jsxs=p,window.Fragment=f);const y="undefined"!=typeof window&&"undefined"!=typeof document;async function m(e){var t;if(console.log("Creating element from:",e),!y){if(null==e)return{nodeType:3,textContent:""};if("boolean"==typeof e)return{nodeType:3,textContent:""};if("number"==typeof e||"string"==typeof e)return{nodeType:3,textContent:String(e)};if(Array.isArray(e)){const t={nodeType:11,childNodes:[]};for(const n of e){const e=await m(n);t.childNodes.push(e)}return t}if("type"in e&&void 0!==e.props){const{type:t,props:s}=e;if("function"==typeof t)try{const e=await t(s||{});return await m(e)}catch(n){return console.error("Error rendering component:",n),{nodeType:3,textContent:""}}const r={nodeType:1,tagName:t,attributes:{},style:{},childNodes:[],setAttribute:function(e,t){this.attributes[e]=t},appendChild:function(e){this.childNodes.push(e)}};for(const[e,n]of Object.entries(s||{}))if("children"!==e)if(e.startsWith("on")&&"function"==typeof n){const t=e.toLowerCase().slice(2);r.__events||(r.__events={}),r.__events[t]=n}else"style"===e&&"object"==typeof n?Object.assign(r.style,n):"className"===e?r.setAttribute("class",String(n)):"key"!==e&&"ref"!==e&&r.setAttribute(e,String(n));const o=null==s?void 0:s.children;if(null!=o){const e=Array.isArray(o)?o.flat():[o];for(const t of e){const e=await m(t);r.appendChild(e)}}return r}return{nodeType:3,textContent:String(e)}}if(null==e)return document.createTextNode("");if("boolean"==typeof e)return document.createTextNode("");if("number"==typeof e||"string"==typeof e)return document.createTextNode(String(e));if(Array.isArray(e)){const t=document.createDocumentFragment();for(const n of e){const e=await m(n);t.appendChild(e)}return t}if("type"in e&&void 0!==e.props){const{type:s,props:r}=e;if("function"==typeof s)try{const e=await s(r||{}),t=await m(e);return t instanceof Element&&t.setAttribute("data-component-id",s.name||s.toString()),t}catch(n){return console.error("Error rendering component:",n),document.createTextNode("")}const o=document.createElement(s);for(const[e,n]of Object.entries(r||{}))if("children"!==e)if(e.startsWith("on")&&"function"==typeof n){const s=e.toLowerCase().slice(2),r=null==(t=o.__events)?void 0:t[s];r&&o.removeEventListener(s,r),o.addEventListener(s,n),o.__events||(o.__events={}),o.__events[s]=n}else"style"===e&&"object"==typeof n?Object.assign(o.style,n):"className"===e?o.setAttribute("class",String(n)):"key"!==e&&"ref"!==e&&o.setAttribute(e,String(n));const i=null==r?void 0:r.children;if(null!=i){const e=Array.isArray(i)?i.flat():[i];for(const t of e){const e=await m(t);o.appendChild(e)}}return o}return document.createTextNode(String(e))}class g{constructor(e={}){this.state={},this.element=null,this._mounted=!1,this.props=e}componentDidMount(){}async setState(e){const t={...this.state};this.state={...t,...e},console.log(`${this.constructor.name} state updated:`,{prev:t,next:this.state}),await Promise.resolve(),this._mounted,await this.update()}_replayEvents(e,t){const n=e.__events||{};Object.entries(n).forEach((([e,n])=>{t.addEventListener(e,n)})),t.__events=n}_deepCloneWithEvents(e){const t=e.cloneNode(!1),n=e.__events||{};return t.__events=n,Object.entries(n).forEach((([e,n])=>{t.addEventListener(e,n)})),Array.from(e.childNodes).forEach((e=>{e instanceof HTMLElement?t.appendChild(this._deepCloneWithEvents(e)):t.appendChild(e.cloneNode(!0))})),t}async update(){const e=this.render();if(!e)return document.createTextNode("");const t=await m(e);if(t instanceof HTMLElement)return this._updateElement(t);const n=document.createElement("div");return n.appendChild(t),this._updateElement(n)}async _updateElement(e){const t=this._deepCloneWithEvents(e);return t.__instance=this,this.element?this.element.parentNode&&(this.element.parentNode.replaceChild(t,this.element),this.element=t):(this.element=t,this._mounted||(this._mounted=!0,queueMicrotask((()=>this.componentDidMount())))),this.element}render(){throw new Error("Component must implement render() method")}}let w=!1;const v=[];function b(e){if(w)v.push(e);else{w=!0;try{for(e();v.length>0;){const e=v.shift();null==e||e()}}finally{w=!1}}}let E=0;const k=new Map,S=new Map,T=new Map,x=new Map,A=new Map;let j=null,$=null,_=null;const C="undefined"==typeof window,I=new Map;function R(e,t,n){j=e,$=n,_=t}function N(){return E++,S.set(E,0),E}function O(){C&&I.delete(E),E=0}function q(e){if(!E)throw new Error("useState must be called within a render");if(C){I.has(E)||I.set(E,new Map);const t=I.get(E),n=S.get(E)||0;t.has(n)||t.set(n,e);const s=t.get(n),r=e=>{};return S.set(E,n+1),[s,r]}k.has(E)||k.set(E,[]);const t=k.get(E),n=S.get(E);n>=t.length&&t.push(e);const s=t[n];return S.set(E,n+1),[s,e=>{const s="function"==typeof e?e(t[n]):e;t[n]!==s&&(t[n]=s,w?b((()=>F(E))):F(E))}]}function D(e,t){if(!E)throw new Error("useEffect must be called within a render");const n=S.get(E);T.has(E)||T.set(E,[]);const s=T.get(E),r=s[n];r&&t&&r.deps&&!t.some(((e,t)=>e!==r.deps[t]))||((null==r?void 0:r.cleanup)&&r.cleanup(),queueMicrotask((()=>{const r=e()||void 0;s[n]={cleanup:r,deps:t}}))),S.set(E,n+1)}function P(e,t){if(!E)throw new Error("useMemo must be called within a render");const n=S.get(E);x.has(E)||x.set(E,[]);const s=x.get(E),r=s[n];if(!r||t&&t.some(((e,t)=>!Object.is(e,r.deps[t])))){const r=e();return s[n]={value:r,deps:t},S.set(E,n+1),r}return S.set(E,n+1),r.value}function M(e){if(!E)throw new Error("useRef must be called within a render");const t=S.get(E);A.has(E)||A.set(E,[]);const n=A.get(E);if(t>=n.length){const s={current:e};return n.push(s),S.set(E,t+1),s}const s=n[t];return S.set(E,t+1),s}async function F(e){try{const t=T.get(e);t&&(t.forEach((e=>{e.cleanup&&e.cleanup()})),T.set(e,[])),j&&$&&_&&await j(_,$)}catch(t){console.error("Error during rerender:",t)}}function L(){const[e,t]=q(null);return[e,()=>t(null)]}let B=!1;async function H(e,t){B=!0;try{await V(e,t)}finally{B=!1}}async function V(e,t){console.log("Rendering to:",t.id||"unnamed-container"),b((async()=>{N();try{R(V,e,t);const n=await m(e);B||(t.innerHTML=""),B&&t.firstChild?console.log("Hydrating existing DOM"):t.appendChild(n)}finally{O()}}))}async function W(e){N(),R((()=>{}),e,null);try{if(null==e)return"";if("boolean"==typeof e)return"";if("number"==typeof e||"string"==typeof e)return U(String(e));if(Array.isArray(e)){return(await Promise.all(e.map(W))).join("")}if("type"in e&&void 0!==e.props){const{type:s,props:r}=e;if("function"==typeof s)try{N();const e=await s(r||{}),t=await W(e);return O(),t}catch(n){return console.error("Error rendering component:",n),""}if(s===Symbol.for("react.fragment")||"Fragment"===s.name){if(r.children){const e=Array.isArray(r.children)?r.children:[r.children];return(await Promise.all(e.map(W))).join("")}return""}let o=`<${s}`;for(const[e,n]of Object.entries(r||{}))"children"!==e&&"key"!==e&&("className"===e?o+=` class="${U(String(n))}"`:"style"===e&&"object"==typeof n?o+=` style="${t=n||{},Object.entries(t).map((([e,t])=>{return`${n=e,n.replace(/[A-Z]/g,(e=>"-"+e.toLowerCase()))}:${t}`;var n})).join(";")}"`:e.startsWith("on")||(o+=` ${e}="${U(String(n))}"`));if(new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]).has(s))return o+"/>";if(o+=">",null==r?void 0:r.children){const e=Array.isArray(r.children)?r.children:[r.children];for(const t of e)o+=await W(t)}return o+`</${s}>`}return U(String(e))}finally{O()}var t}function U(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}class G{constructor(e){this.connection=null,this._connected=!1,this.options={retryAttempts:3,retryDelay:1e3,connectionTimeout:1e4,autoIndex:!0,...e}}async connect(){try{if(this._connected&&this.connection)return this.connection;i.set("strictQuery",!0);let t=0;for(;t<(this.options.retryAttempts||3);)try{await i.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((e=>setTimeout(e,this.options.retryDelay)))}return this.connection=i.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(e){throw console.error("Failed to connect to MongoDB:",e),e}}async disconnect(){this.connection&&(await i.disconnect(),this._connected=!1,this.connection=null,console.log("Disconnected from MongoDB"))}isConnected(){return this._connected}getConnection(){return this.connection}}function J(e={}){const i=t(),{port:c=3e3,staticDir:d="public",enableCors:u=!0,apiPrefix:l="/api",ssrEnabled:p=!0,middlewares:h=[],enableCompression:f=!0,enableHelmet:y=!0,logFormat:m="dev",trustProxy:g=!1,showErrorDetails:w="production"!==process.env.NODE_ENV}=e;if(g&&i.set("trust proxy",g),i.use(t.json()),i.use(t.urlencoded({extended:!0})),f&&i.use(s()),y&&i.use(r({contentSecurityPolicy:!e.disableCSP&&void 0})),m&&i.use(o(m)),u&&i.use(((e,t,n)=>{if(t.header("Access-Control-Allow-Origin","*"),t.header("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, PATCH, OPTIONS"),t.header("Access-Control-Allow-Headers","Origin, X-Requested-With, Content-Type, Accept, Authorization"),"OPTIONS"===e.method)return t.sendStatus(200);n()})),h.forEach((e=>i.use(e))),d){const s=n.resolve(process.cwd(),d);a.existsSync(s)?(i.use(t.static(s,{maxAge:e.staticCacheAge||"1d",etag:!0})),console.log(`š Serving static files from: ${s}`)):console.warn(`ā ļø Static directory not found: ${s}`)}let v=null;i.connectToDatabase=async e=>{try{return v&&v.isConnected()?(console.log("ā
Using existing database connection"),v):(v=new G(e),await v.connect(),console.log("ā
Database connected successfully"),process.on("SIGTERM",(async()=>{v&&v.isConnected()&&(await v.disconnect(),console.log("Database connection closed"))})),v)}catch(t){throw console.error("ā Failed to connect to database:",t),t}};const b={},E={};return i.registerApi=(e,t,s={})=>{try{const{prefix:r=l}=s,o=n.posix.join(r,e).replace(/\\/g,"/");i.use(o,t),b[o]={router:t,options:s},console.log(`š API registered: ${o}`)}catch(r){console.error(`ā Failed to register API at ${e}:`,r)}return i},i.registerSSR=(e,t,n={})=>p?(E[e]={component:t,options:n},i.get(e,(async(e,s,r)=>{try{if("true"===e.query.nossr)return r();const o={req:e,res:s,params:e.params,query:e.query,user:e.user,...n.props},i=await W(t(o));s.send(`\n <!DOCTYPE html>\n <html lang="${n.lang||"en"}">\n <head>\n <meta charset="UTF-8">\n <meta name="viewport" content="width=device-width, initial-scale=1.0">\n <title>${n.title||"Frontend Hamroun App"}</title>\n ${n.meta?n.meta.map((e=>`<meta ${Object.entries(e).map((([e,t])=>`${e}="${t}"`)).join(" ")}>`)).join("\n "):""}\n ${n.head||""}\n ${n.styles?`<style>${n.styles}</style>`:""}\n ${n.styleSheets?n.styleSheets.map((e=>`<link rel="stylesheet" href="${e}">`)).join("\n "):""}\n </head>\n <body ${n.bodyAttributes||""}>\n <div id="${n.rootId||"root"}">${i}</div>\n <script>\n window.__INITIAL_DATA__ = ${JSON.stringify(n.initialData||{})};\n <\/script>\n ${n.scripts?n.scripts.map((e=>`<script src="${e}"><\/script>`)).join("\n "):""}\n </body>\n </html>\n `)}catch(o){if(console.error("SSR Error:",o),n.fallback)return r();s.status(500).send("Server rendering error")}})),console.log(`š„ļø SSR registered: ${e}`),i):(console.log(`ā ļø SSR disabled: skipping registration of ${e}`),i),i.use(((e,t,n,s)=>{console.error("Server error:",e);const r=e.statusCode||e.status||500;t.path.startsWith(l)?n.status(r).json({success:!1,error:w?e.message:"Internal Server Error",stack:w?e.stack:void 0}):n.status(r).send(`\n <!DOCTYPE html>\n <html>\n <head>\n <title>Error - ${r}</title>\n <style>\n body { font-family: system-ui, sans-serif; padding: 2rem; max-width: 800px; margin: 0 auto; }\n .error { background: #f8d7da; border: 1px solid #f5c6cb; padding: 1rem; border-radius: 4px; }\n .stack { background: #f8f9fa; padding: 1rem; border-radius: 4px; overflow: auto; }\n </style>\n </head>\n <body>\n <h1>Error ${r}</h1>\n <div class="error">${w?e.message:"Internal Server Error"}</div>\n ${w&&e.stack?`<pre class="stack">${e.stack}</pre>`:""}\n </body>\n </html>\n `)})),i.use(((e,t)=>{e.path.startsWith(l)?t.status(404).json({success:!1,error:"Not Found"}):t.status(404).send('\n <!DOCTYPE html>\n <html>\n <head>\n <title>404 - Not Found</title>\n <style>\n body { font-family: system-ui, sans-serif; padding: 2rem; max-width: 800px; margin: 0 auto; }\n </style>\n </head>\n <body>\n <h1>404 - Not Found</h1>\n <p>The requested resource was not found on this server.</p>\n <p><a href="/">Return to homepage</a></p>\n </body>\n </html>\n ')})),i.start=e=>{const t=i.listen(c,(()=>{console.log(`\nš Frontend Hamroun server running at http://localhost:${c}\n${Object.keys(b).length>0?`\nš” Registered API Routes:\n${Object.keys(b).map((e=>` ${e}`)).join("\n")}`:""}\n${Object.keys(E).length>0?`\nš„ļø Registered SSR Routes:\n${Object.keys(E).map((e=>` ${e}`)).join("\n")}`:""}\n `),e&&e()})),n=async e=>{console.log(`${e} signal received: closing HTTP server and cleaning up`),t.close((async()=>{console.log("HTTP server closed"),v&&v.isConnected()&&(await v.disconnect(),console.log("Database connection closed")),process.exit(0)})),setTimeout((()=>{console.error("Could not close connections in time, forcefully shutting down"),process.exit(1)}),1e4)};return process.on("SIGTERM",(()=>n("SIGTERM"))),process.on("SIGINT",(()=>n("SIGINT"))),t},i}const Y=(e,{res:t})=>{console.error("API Error:",e);const n=e.status||e.statusCode||500,s=e.message||"Internal server error";t.status(n).json({success:!1,error:s,stack:"production"!==process.env.NODE_ENV?e.stack:void 0})};function z(e,t,n,s,r){const o={success:e};return void 0!==t&&(o.data=t),n&&(o.message=n),s&&(o.error=s),r&&(o.meta=r),o}function X(e,t,n,s=200,r){e.status(s).json(z(!0,t,n,void 0,r))}function Q(e,t,n=400,s){const r=t instanceof Error?t.message:t;e.status(n).json(z(!1,void 0,void 0,r,s))}function Z(e){return{page:parseInt(e.query.page)||1,limit:parseInt(e.query.limit)||10,sort:e.query.sort||"createdAt",order:"asc"===e.query.order?"asc":"desc"}}function K(e,t,n){e.pagination=Z(e),n()}function ee(e={},n){const s=t.Router();return e.requireAuth&&n&&(s.use(n.authenticate),e.requiredRole&&s.use(n.hasRole(e.requiredRole))),e.rateLimit&&console.warn("Rate limiting is disabled: express-rate-limit dependency is not installed"),s}function te(e){return(t,n,s)=>{e(t,n,s).catch(s)}}const ne={};class se{constructor(e){if(this.loginAttempts=new Map,this.login=async(e,t)=>{try{const{username:n,password:s}=e.body,r=e.ip||e.connection.remoteAddress||"";if(!this.checkRateLimit(r))return void t.status(429).json({success:!1,message:"Too many login attempts. Please try again later."});if(!n||!s)return void t.status(400).json({success:!1,message:"Username and password are required"});if(!this.options.findUser)return void t.status(500).json({success:!1,message:"User finder function not configured"});const o=await this.options.findUser(n);if(!o)return void t.status(401).json({success:!1,message:"Invalid credentials"});if(!(await this.options.verifyPassword(s,o.password)))return void t.status(401).json({success:!1,message:"Invalid credentials"});const i={...o};delete i.password;const a=this.generateTokenPair({id:o.id||o._id,username:o.username,role:o.role||"user"});if(this.options.saveRefreshToken){const e=new Date;e.setSeconds(e.getSeconds()+this.getExpirationSeconds(this.options.refreshExpiration||"7d")),await this.options.saveRefreshToken(o.id||o._id,a.refreshToken,e)}e.body.useCookies&&this.setAuthCookies(t,a),t.json({success:!0,message:"Authentication successful",tokens:a,user:i})}catch(n){console.error("Authentication error:",n),t.status(500).json({success:!1,message:"Authentication failed",error:"production"!==process.env.NODE_ENV?n.message:void 0})}},this.refreshToken=async(e,t)=>{var n,s;try{const r=(null==(n=e.cookies)?void 0:n.refreshToken)||e.body.refreshToken;if(!r)return void t.status(401).json({success:!1,message:"Refresh token required"});const o=this.verifyToken(r,"refresh");if(this.options.verifyRefreshToken){if(!(await this.options.verifyRefreshToken(o.id,r)))return this.clearAuthCookies(t),void t.status(401).json({success:!1,message:"Invalid refresh token"})}const i=this.generateTokenPair({id:o.id,...this.options.findUser?await this.options.findUser(o.id):{}});if(this.options.saveRefreshToken){const e=new Date;e.setSeconds(e.getSeconds()+this.getExpirationSeconds(this.options.refreshExpiration||"7d")),await this.options.saveRefreshToken(o.id,i.refreshToken,e)}((null==(s=e.cookies)?void 0:s.accessToken)||e.body.useCookies)&&this.setAuthCookies(t,i),t.json({success:!0,message:"Token refreshed successfully",tokens:i})}catch(r){this.clearAuthCookies(t),t.status(401).json({success:!1,message:"Invalid or expired refresh token",error:"production"!==process.env.NODE_ENV?r.message:void 0})}},this.logout=async(e,t)=>{var n;try{this.clearAuthCookies(t);const r=(null==(n=e.cookies)?void 0:n.refreshToken)||e.body.refreshToken;if(r&&this.options.saveRefreshToken)try{const e=this.verifyToken(r,"refresh");"function"==typeof this.options.saveRefreshToken&&await this.options.saveRefreshToken(e.id,"",new Date)}catch(s){}t.json({success:!0,message:"Logged out successfully"})}catch(r){console.error("Logout error:",r),t.status(500).json({success:!1,message:"Logout failed",error:r.message})}},this.authenticate=(e,t,n)=>{var s;try{let r=null==(s=e.cookies)?void 0:s.accessToken;if(!r){const t=e.headers.authorization;t&&t.startsWith("Bearer ")&&(r=t.split(" ")[1])}if(!r)return void t.status(401).json({success:!1,message:"Authentication required"});const o=this.verifyToken(r,"access");e.user=o,n()}catch(r){t.status(401).json({success:!1,message:"Invalid or expired token",error:"production"!==process.env.NODE_ENV?r.message:void 0})}},this.hasRole=e=>(t,n,s)=>{const r=t.user;if(!r)return void n.status(401).json({success:!1,message:"Authentication required"});(Array.isArray(e)?e:[e]).includes(r.role)?s():n.status(403).json({success:!1,message:"Insufficient permissions"})},this.options={tokenExpiration:"15m",refreshExpiration:"7d",saltRounds:10,secureCookies:"production"===process.env.NODE_ENV,httpOnlyCookies:!0,rateLimit:!0,...e,refreshSecret:e.refreshSecret||e.jwtSecret},!e.jwtSecret)throw new Error("JWT secret is required for authentication");this.options.verifyPassword||(this.options.verifyPassword=this.verifyPasswordWithBcrypt)}async hashPassword(e){return await d.hash(e,this.options.saltRounds||10)}async verifyPasswordWithBcrypt(e,t){return await d.compare(e,t)}generateSecureToken(e=32){return ne.randomBytes(e).toString("hex")}generateTokenPair(e){const t=this.getExpirationSeconds(this.options.tokenExpiration||"15m");return{accessToken:c.sign({...e,type:"access"},this.options.jwtSecret,{expiresIn:this.options.tokenExpiration}),refreshToken:c.sign({id:e.id,type:"refresh"},this.options.refreshSecret,{expiresIn:this.options.refreshExpiration}),expiresIn:t}}getExpirationSeconds(e){const t=e.charAt(e.length-1),n=parseInt(e.slice(0,-1));switch(t){case"s":return n;case"m":return 60*n;case"h":return 60*n*60;case"d":return 60*n*60*24;default:return 3600}}verifyToken(e,t="access"){try{const n="access"===t?this.options.jwtSecret:this.options.refreshSecret,s=c.verify(e,n);if("object"==typeof s&&s.type!==t)throw new Error("Invalid token type");return s}catch(n){throw new Error("Invalid or expired token")}}setAuthCookies(e,t){e.cookie("accessToken",t.accessToken,{httpOnly:this.options.httpOnlyCookies,secure:this.options.secureCookies,domain:this.options.cookieDomain,sameSite:"strict",maxAge:1e3*t.expiresIn});const n=this.getExpirationSeconds(this.options.refreshExpiration||"7d");e.cookie("refreshToken",t.refreshToken,{httpOnly:!0,secure:this.options.secureCookies,domain:this.options.cookieDomain,sameSite:"strict",maxAge:1e3*n,path:"/api/auth/refresh"})}clearAuthCookies(e){e.clearCookie("accessToken"),e.clearCookie("refreshToken",{path:"/api/auth/refresh"})}checkRateLimit(e){if(!this.options.rateLimit)return!0;const t=Date.now(),n=this.loginAttempts.get(e);return n?t>n.resetTime?(this.loginAttempts.set(e,{count:1,resetTime:t+36e5}),!0):!(n.count>=5)&&(n.count++,this.loginAttempts.set(e,n),!0):(this.loginAttempts.set(e,{count:1,resetTime:t+36e5}),!0)}}const re={String:{type:String},Number:{type:Number},Boolean:{type:Boolean},Date:{type:Date},ObjectId:{type:String},Required:e=>({...e,required:!0}),Unique:e=>({...e,unique:!0}),Ref:e=>({type:String,ref:e}),Enum:e=>({type:String,enum:e}),Default:(e,t)=>({...e,default:t}),Array:e=>({type:[e]})},oe={jsx:l,jsxs:p,createElement:h,Fragment:f,Component:g,useState:q,useEffect:D,useRef:M,useMemo:P,useErrorBoundary:L,render:V,hydrate:H,renderToString:W,prepareRender:N,finishRender:O,batchUpdates:b,createServer:J,Router:t.Router,createApiRouter:ee};Object.defineProperty(e,"Router",{enumerable:!0,get:()=>t.Router}),e.Component=g,e.DatabaseConnector=G,e.FieldTypes=re,e.Fragment=f,e.apiResponse=z,e.asyncHandler=te,e.batchUpdates=b,e.createApiRouter=ee,e.createAuth=function(e){return new se(e)},e.createCustomRouter=function(e,n={}){const s=t.Router(),{middleware:r=[],errorHandler:o=Y}=n;return r.forEach((e=>s.use(e))),Object.entries(e).forEach((([e,t])=>{const{method:n,handler:r}=t;s[n](e,(e=>async(t,n,s)=>{try{const r={req:t,res:n,next:s,params:t.params,query:t.query,body:t.body};if(n.headersSent)return;return await e(r)}catch(r){if(n.headersSent)return void console.error("Error occurred after response was sent:",r);const e={req:t,res:n,next:s,params:t.params,query:t.query,body:t.body};return o(r,e)}})(r))})),s},e.createElement=h,e.createModel=function(e,t){const n=i.model(e,t);return{getAll:async t=>{try{const{page:e=1,limit:s=10,sort:r="_id",order:o="desc"}=t||{},i=(e-1)*s,a="asc"===o?1:-1,c={[r]:a},[d,u]=await Promise.all([n.find().sort(c).skip(i).limit(s).exec(),n.countDocuments().exec()]),l=Math.ceil(u/s);return{data:d,pagination:{total:u,totalPages:l,currentPage:e,limit:s,hasNextPage:e<l,hasPrevPage:e>1}}}catch(s){throw console.error(`Error in ${e}.getAll:`,s),new Error(`Failed to retrieve ${e} records: ${s.message}`)}},getById:async t=>{try{return i.isValidObjectId(t)?await n.findById(t).exec():null}catch(s){throw console.error(`Error in ${e}.getById:`,s),new Error(`Failed to retrieve ${e} by ID: ${s.message}`)}},create:async t=>{try{const e=new n(t);return await e.save()}catch(s){throw console.error(`Error in ${e}.create:`,s),new Error(`Failed to create ${e}: ${s.message}`)}},createMany:async t=>{try{return await n.insertMany(t)}catch(s){throw console.error(`Error in ${e}.createMany:`,s),new Error(`Failed to create multiple ${e} records: ${s.message}`)}},update:async(t,s)=>{try{return i.isValidObjectId(t)?await n.findByIdAndUpdate(t,{$set:s},{new:!0,runValidators:!0}).exec():null}catch(r){throw console.error(`Error in ${e}.update:`,r),new Error(`Failed to update ${e}: ${r.message}`)}},delete:async t=>{try{if(!i.isValidObjectId(t))return!1;return null!==await n.findByIdAndDelete(t).exec()}catch(s){throw console.error(`Error in ${e}.delete:`,s),new Error(`Failed to delete ${e}: ${s.message}`)}},find:async(t,s)=>{try{const{page:e=1,limit:r=10,sort:o="_id",order:i="desc"}=s||{},a=(e-1)*r,c="asc"===i?1:-1,d={[o]:c},[u,l]=await Promise.all([n.find(t).sort(d).skip(a).limit(r).exec(),n.countDocuments(t).exec()]),p=Math.ceil(l/r);return{data:u,pagination:{total:l,totalPages:p,currentPage:e,limit:r,hasNextPage:e<p,hasPrevPage:e>1}}}catch(r){throw console.error(`Error in ${e}.find:`,r),new Error(`Failed to find ${e} records: ${r.message}`)}},count:async t=>{try{return await n.countDocuments(t||{}).exec()}catch(s){throw console.error(`Error in ${e}.count:`,s),new Error(`Failed to count ${e} records: ${s.message}`)}},findOne:async t=>{try{return await n.findOne(t).exec()}catch(s){throw console.error(`Error in ${e}.findOne:`,s),new Error(`Failed to find ${e} record: ${s.message}`)}}}},e.createModelRouter=function(e,n={}){const s=t.Router(),{middleware:r=[],errorHandler:o=Y}=n;r.forEach((e=>s.use(e)));const i=e=>async(t,n,s)=>{try{const r={req:t,res:n,next:s,params:t.params,query:t.query,body:t.body};return await e(r)}catch(r){const e={req:t,res:n,next:s,params:t.params,query:t.query,body:t.body};return o(r,e)}};return s.get("/",i((async({req:t,res:n})=>{const s=t.pagination||{page:1,limit:10},r=await e.getAll(s);n.json({success:!0,...r})}))),s.get("/:id",i((async({params:t,res:n})=>{const s=await e.getById(t.id);s?n.json({success:!0,data:s}):n.status(404).json({success:!1,error:"Item not found"})}))),s.post("/",i((async({body:t,res:n})=>{const s=await e.create(t);n.status(201).json({success:!0,data:s,message:"Item created successfully"})}))),s.put("/:id",i((async({params:t,body:n,res:s})=>{const r=await e.update(t.id,n);r?s.json({success:!0,data:r,message:"Item updated successfully"}):s.status(404).json({success:!1,error:"Item not found"})}))),s.delete("/:id",i((async({params:t,res:n})=>{await e.delete(t.id)?n.json({success:!0,message:"Item deleted successfully"}):n.status(404).json({success:!1,error:"Item not found"})}))),s},e.createRestEndpoints=function(e){const n=t.Router();return n.get("/",K,te((async(t,n)=>{X(n,await e.getAll(t.pagination))}))),n.get("/:id",te((async(t,n)=>{const s=await e.getById(t.params.id);if(!s)return Q(n,"Item not found",404);X(n,s)}))),n.post("/",te((async(t,n)=>{X(n,await e.create(t.body),"Item created successfully",201)}))),n.put("/:id",te((async(t,n)=>{const s=await e.update(t.params.id,t.body);if(!s)return Q(n,"Item not found",404);X(n,s,"Item updated successfully")}))),n.delete("/:id",te((async(t,n)=>{if(!(await e.delete(t.params.id)))return Q(n,"Item not found",404);X(n,null,"Item deleted successfully")}))),n},e.createServer=J,e.default=oe,e.finishRender=O,e.getPaginationParams=Z,e.hydrate=H,e.jsx=l,e.jsxs=p,e.paginationMiddleware=K,e.prepareRender=N,e.render=V,e.renderToString=W,e.sendError=Q,e.sendSuccess=X,e.useEffect=D,e.useErrorBoundary=L,e.useMemo=P,e.useRef=M,e.useState=q,e.validateRequest=function(e){return(t,n,s)=>{try{const{error:r,value:o}=e.validate(t.body);if(r)return void Q(n,`Validation error: ${r.message}`,400);t.body=o,s()}catch(r){Q(n,"Validation error",400)}}},Object.defineProperties(e,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|
2
|
-
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}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
|
+
<!DOCTYPE html>
|
3
|
+
<html lang="${h.lang||"en"}">
|
4
|
+
<head>
|
5
|
+
<meta charset="UTF-8">
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
7
|
+
<title>${h.title||"Frontend Hamroun App"}</title>
|
8
|
+
${h.meta?h.meta.map(H=>`<meta ${Object.entries(H).map(([lt,dt])=>`${lt}="${dt}"`).join(" ")}>`).join(`
|
9
|
+
`):""}
|
10
|
+
${h.head||""}
|
11
|
+
${h.styles?`<style>${h.styles}</style>`:""}
|
12
|
+
${h.styleSheets?h.styleSheets.map(H=>`<link rel="stylesheet" href="${H}">`).join(`
|
13
|
+
`):""}
|
14
|
+
</head>
|
15
|
+
<body ${h.bodyAttributes||""}>
|
16
|
+
<div id="${h.rootId||"root"}">${ut}</div>
|
17
|
+
<script>
|
18
|
+
window.__INITIAL_DATA__ = ${JSON.stringify(h.initialData||{})};
|
19
|
+
<\/script>
|
20
|
+
${h.scripts?h.scripts.map(H=>`<script src="${H}"><\/script>`).join(`
|
21
|
+
`):""}
|
22
|
+
</body>
|
23
|
+
</html>
|
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
|
+
<!DOCTYPE html>
|
26
|
+
<html>
|
27
|
+
<head>
|
28
|
+
<title>Error - ${S}</title>
|
29
|
+
<style>
|
30
|
+
body { font-family: system-ui, sans-serif; padding: 2rem; max-width: 800px; margin: 0 auto; }
|
31
|
+
.error { background: #f8d7da; border: 1px solid #f5c6cb; padding: 1rem; border-radius: 4px; }
|
32
|
+
.stack { background: #f8f9fa; padding: 1rem; border-radius: 4px; overflow: auto; }
|
33
|
+
</style>
|
34
|
+
</head>
|
35
|
+
<body>
|
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
|
+
</body>
|
40
|
+
</html>
|
41
|
+
`)}),t.use((d,m)=>{d.path.startsWith(i)?m.status(404).json({success:!1,error:"Not Found"}):m.status(404).send(`
|
42
|
+
<!DOCTYPE html>
|
43
|
+
<html>
|
44
|
+
<head>
|
45
|
+
<title>404 - Not Found</title>
|
46
|
+
<style>
|
47
|
+
body { font-family: system-ui, sans-serif; padding: 2rem; max-width: 800px; margin: 0 auto; }
|
48
|
+
</style>
|
49
|
+
</head>
|
50
|
+
<body>
|
51
|
+
<h1>404 - Not Found</h1>
|
52
|
+
<p>The requested resource was not found on this server.</p>
|
53
|
+
<p><a href="/">Return to homepage</a></p>
|
54
|
+
</body>
|
55
|
+
</html>
|
56
|
+
`)}),t.start=d=>{const m=t.listen(e,()=>{console.log(`
|
57
|
+
š Frontend Hamroun server running at http://localhost:${e}
|
58
|
+
${Object.keys(F).length>0?`
|
59
|
+
š” Registered API Routes:
|
60
|
+
${Object.keys(F).map(w=>` ${w}`).join(`
|
61
|
+
`)}`:""}
|
62
|
+
${Object.keys(ye).length>0?`
|
63
|
+
š„ļø Registered SSR Routes:
|
64
|
+
${Object.keys(ye).map(w=>` ${w}`).join(`
|
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 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 {
|
10
|
-
import {
|
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,
|
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
|
-
|
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
|
-
|
9
|
+
import { createContext, useContext } from './context';
|
10
|
+
// Import backend functionality
|
10
11
|
import { createServer } from './backend/server';
|
11
|
-
import {
|
12
|
-
import {
|
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,
|
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
|
-
|
45
|
-
|
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
package/src/backend/auth.ts
CHANGED
package/src/backend/model.ts
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
import mongoose, { Schema, Document, SortOrder } from 'mongoose';
|
2
2
|
import { Model, PaginationOptions, PaginatedResult } from './types';
|
3
|
+
import * as bcryptModule from 'bcrypt';
|
4
|
+
const bcrypt = bcryptModule.default || bcryptModule;
|
3
5
|
|
4
6
|
/**
|
5
7
|
* Creates a data model from a Mongoose schema
|
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
|
7
|
+
Provider: (props: { value: T; children: any }) => any;
|
8
8
|
Consumer: (props: { children: (value: T) => any }) => any;
|
9
|
-
|
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
|
-
|
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 }
|
19
|
-
return children(
|
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:
|
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
|
-
//
|
11
|
+
// Import backend functionality
|
11
12
|
import { createServer } from './backend/server';
|
12
|
-
import {
|
13
|
-
import {
|
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
|
-
|
48
|
-
|
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
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
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
|
-
|
95
|
-
|
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
|
|
package/src/shims.d.ts
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
/**
|
2
|
+
* Module declaration shims for third-party libraries
|
3
|
+
*/
|
4
|
+
|
5
|
+
// Handle bcrypt CommonJS module in ESM context
|
6
|
+
declare module 'bcrypt' {
|
7
|
+
export function genSalt(rounds?: number): Promise<string>;
|
8
|
+
export function hash(data: string, saltOrRounds: string | number): Promise<string>;
|
9
|
+
export function compare(data: string, encrypted: string): Promise<boolean>;
|
10
|
+
|
11
|
+
// Allow either default or named imports to work
|
12
|
+
const bcrypt: {
|
13
|
+
genSalt: typeof genSalt;
|
14
|
+
hash: typeof hash;
|
15
|
+
compare: typeof compare;
|
16
|
+
};
|
17
|
+
export default bcrypt;
|
18
|
+
}
|
19
|
+
|
20
|
+
// Add similar declarations for other problematic Node.js modules if needed
|