@andrewcaires/api 2.0.1 → 2.0.2

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/index.cjs.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @andrewcaires/api v2.0.1
2
+ * @andrewcaires/api v2.0.2
3
3
  * Simple api for small applications using express, jsonwebtoken, sequelize and websocket
4
4
  * (c) 2022 Andrew Caires
5
5
  * @license: MIT
6
6
  */
7
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@andrewcaires/utils.js"),t=require("cors"),r=require("express"),s=require("fs"),i=require("http"),o=require("https"),n=require("net"),a=require("ws"),u=require("dotenv"),d=require("sequelize"),l=require("jsonwebtoken"),c=require("mime-types"),p=require("multer"),h=require("path"),m=require("crypto-js");function v(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function g(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var s=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,s.get?s:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var f=v(t),y=v(r),_=g(i),I=g(o),T=v(a),A=v(c),w=v(p);function S(e,t,r,s){return new(r||(r=Promise))((function(i,o){function n(e){try{u(s.next(e))}catch(e){o(e)}}function a(e){try{u(s.throw(e))}catch(e){o(e)}}function u(e){var t;e.done?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(n,a)}u((s=s.apply(e,t||[])).next())}))}u.config();const b=parseInt(process.env.API_AUTH_SLEEP||"1000"),P=process.env.API_DB_DATABASE||"",x=process.env.API_DB_HOST||"127.0.0.1",O=process.env.API_DB_PASSWORD||"",E=parseInt(process.env.API_DB_PORT||"3306"),q=process.env.API_DB_TYPE||"",D=process.env.API_DB_USERNAME||"root",R=e.toBool(process.env.API_DB_LOG||"false"),N=process.env.API_HTTP_CRT||"",k=process.env.API_HTTP_KEY||"",B=parseInt(process.env.API_HTTP_PORT||"3000"),C=process.env.API_HTTP_PUBLIC||"",j=e.toBool(process.env.API_HTTP_CROSS||"false"),z=e.toBool(process.env.API_HTTP_HYBRID||"false"),G=process.env.API_TOKEN_CRT||"",V=process.env.API_TOKEN_KEY||"",M=process.env.API_TOKEN_HEADER||"authorization",U=parseInt(process.env.API_TOKEN_LIFETIME||"15"),H=parseInt(process.env.API_UPLOAD_COUNT||"1"),L=process.env.API_UPLOAD_FIELD||"upload",K=parseInt(process.env.API_UPLOAD_SIZE||"2"),F=process.env.API_UPLOAD_TEMP||"./temp",Y=e.toBool(process.env.API_WEBSOCKET_START||"false");class W{static connect(){const e={database:P,username:D,password:O,hostname:x,hostport:E};switch(q){case"mariadb":return W.mariadb(e);case"memory":default:return W.memory();case"mysql":return W.mysql(e);case"postgres":return W.postgres(e);case"sqlite":return W.sqlite(P)}}static mariadb(e){return new d.Sequelize(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"mariadb",logging:R,define:{timestamps:!1}})}static memory(){return new d.Sequelize("sqlite::memory:",{logging:R,define:{timestamps:!1}})}static mysql(e){return new d.Sequelize(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"mysql",logging:R,define:{timestamps:!1}})}static postgres(e){return new d.Sequelize(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"postgres",logging:R,define:{timestamps:!1}})}static sqlite(e){return new d.Sequelize({dialect:"sqlite",storage:e,logging:R,define:{timestamps:!1}})}}const X=W.connect();class J extends d.Model{}J.init({login:d.DataTypes.BIGINT,logout:d.DataTypes.BIGINT,secret:d.DataTypes.STRING,timestamp:d.DataTypes.BIGINT,useragent:d.DataTypes.STRING},{sequelize:X,modelName:"auth"});class Z extends d.Model{}Z.init({name:d.DataTypes.STRING,description:d.DataTypes.TEXT,state:d.DataTypes.BOOLEAN},{sequelize:X,modelName:"group"});class $ extends d.Model{}$.init({name:d.DataTypes.STRING,description:d.DataTypes.TEXT,state:d.DataTypes.BOOLEAN},{sequelize:X,modelName:"route"});class Q extends d.Model{}Q.init({},{sequelize:X,modelName:"groups_routes"}),Q.removeAttribute("id");class ee extends d.Model{}ee.init({name:d.DataTypes.STRING,email:d.DataTypes.STRING,username:d.DataTypes.STRING,password:d.DataTypes.STRING,description:d.DataTypes.TEXT,state:d.DataTypes.BOOLEAN},{sequelize:X,modelName:"user"});class te extends d.Model{}te.init({},{sequelize:X,modelName:"users_groups"}),te.removeAttribute("id");class re extends d.Model{}re.init({key:d.DataTypes.STRING,value:d.DataTypes.STRING},{sequelize:X,modelName:"configs",timestamps:!0,createdAt:"created",updatedAt:"updated"}),re.removeAttribute("id");class se extends d.Model{}var ie;se.init({type:d.DataTypes.STRING,source:d.DataTypes.STRING,message:d.DataTypes.TEXT},{sequelize:X,modelName:"logs",timestamps:!0,createdAt:"created",updatedAt:!1}),ee.hasMany(J),J.belongsTo(ee),Z.hasMany(Q),Q.belongsTo(Z),$.hasMany(Q),Q.belongsTo($),ee.hasMany(te),te.belongsTo(ee),Z.hasMany(te),te.belongsTo(Z),function(e){e.ERROR="",e.INFO="",e.NONE="",e.SUCCESS="",e.WARNING=""}(ie||(ie={}));class oe{static write(e,t,r){return S(this,void 0,void 0,(function*(){yield oe.writeRaw(ie.NONE,"",e,t,r)}))}static error(e,t,r){return S(this,void 0,void 0,(function*(){yield oe.writeRaw(ie.ERROR,"error",e,t,r)}))}static info(e,t,r){return S(this,void 0,void 0,(function*(){yield oe.writeRaw(ie.INFO,"info",e,t,r)}))}static success(e,t,r){return S(this,void 0,void 0,(function*(){yield oe.writeRaw(ie.ERROR,"success",e,t,r)}))}static warning(e,t,r){return S(this,void 0,void 0,(function*(){yield oe.writeRaw(ie.WARNING,"warning",e,t,r)}))}static writeConsole(t,r,s){const i=e.dateFormat(new Date,"%H:%M:%S");console.log(">",t,r+" ".repeat(10-r.length),"","|",i,"|",s)}static writeRaw(e,t,r,s,i){return S(this,void 0,void 0,(function*(){i&&oe.writeConsole(e,t,r),X&&(yield se.create({type:t,source:s,message:r}).catch((()=>null)))}))}}class ne{static success(e,t){return e.status(200).json({message:t})}static data(e,t){return e.status(200).json(Object.assign({},t))}static error(e,t){return e.status(500).json({message:t})}static list(e,t){return e.status(200).json([...t])}static notfound(e,t){return e.status(404).json({message:t})}static validation(e,t){return e.status(400).json({message:t})}static unauthorized(e,t){return e.status(401).json({message:t})}}const ae=e=>s.existsSync(e)?s.readFileSync(e):void 0,ue={http:ae(N),token:ae(G)},de={http:ae(k),token:ae(V)};class le{static sign(e){return de.token?{token:l.sign(e,de.token,{algorithm:"RS256"})}:{error:"Invalid Secret"}}static user(e){return S(this,void 0,void 0,(function*(){const{error:t,decode:r}=le.verify(e);if(t)return{error:t};if(r){const{id:e,secret:t}=r;if(e&&r){const r=yield ee.findOne({where:{id:e,state:!0}}).catch((e=>{oe.error(e.message,"api.token",!0)}));if(r){const e=yield J.findOne({where:{secret:t,userId:r.id}}).catch((e=>{oe.error(e.message,"api.token",!0)}));if(e){const t=Date.now();if(t>e.timestamp)return{error:"Expired token"};if(e.timestamp=t+6e4*U,yield e.save(),!e.logout)return{auth:e,user:r}}}return{error:"Access denied"}}}return{error:"Invalid token"}}))}static verify(e){if(!ue.token)return{error:"Invalid Secret"};if(!e||e.split(".").length<3)return{error:"Invalid Token"};try{return{decode:l.verify(e,ue.token)}}catch(e){return{error:"Invalid Token"}}}}class ce extends e.EventEmitter{constructor(e){super(),this.app=y.default(),this.router=r.Router(),this.middlewares(),this.controllers(e)}controllers(e){e.forEach((e=>{e.intialize(),this.router.use(e.path(),e.router)}))}listen(){return S(this,void 0,void 0,(function*(){if(yield X.sync(),ue.http&&de.http||(this._server=_.createServer(this.app),this._server.listen(B,(()=>oe.info("Server started on port "+B,"api.server",!0)))),!this._server){const e=_.createServer(((e,t)=>{const r=80==B?":80":"";t.writeHead(301,{Location:"https://"+e.headers.host+r+e.url}),t.end()})),t=I.createServer({key:de.http,cert:ue.http},this.app);if(z){new n.Server((r=>{r.once("data",(s=>{r.pause(),r.unshift(s),(22===s[0]?t:e).emit("connection",r),process.nextTick((()=>r.resume()))}))})).listen(B,(()=>oe.info("Server started on port "+B,"api.server",!0))),this._server=t}this._server||(443==B&&e.listen(80,(()=>oe.info("Server started on port 80","api.server",!0))),t.listen(B,(()=>oe.info("Server started on port "+B,"api.server",!0))),this._server=t)}Y&&this._server&&(this._webSocket=new T.default.Server({server:this._server,verifyClient:(e,t)=>t(Y)}),this._webSocket.on("connection",((t,r)=>S(this,void 0,void 0,(function*(){r.url||(r.url="");const s=r.url.length<=1?"":r.url.replace(/\//g,".");let i;t.on("message",(e=>S(this,void 0,void 0,(function*(){if(i)try{const o=JSON.parse(e);this.emit("ws.message"+s,{data:o,message:e,req:r,user:i,ws:t})}catch(o){this.emit("ws.message"+s,{message:e,req:r,user:i,ws:t})}else{const{user:o}=yield le.user(e.toString());o&&(i=o,this.emit("ws.connection"+s,{req:r,user:i,ws:t}))}i||t.close()})))),t.on("close",(()=>{i&&this.emit("ws.close"+s,{user:i,ws:t})})),yield e.sleep(2e3),i||t.close()})))))}))}middlewares(){this.app.use(r.json()),this.app.use(((e,t,r,s)=>e?(oe.error(e.message,"api.express",!0),ne.error(r,"Internal Server Error")):s())),this.app.use(r.urlencoded({extended:!0})),this.app.disable("x-powered-by"),j&&this.app.use(f.default()),this.app.use("/api",this.router),this.app.all("/api/*",((e,t)=>ne.notfound(t,"Invalid API"))),C&&(s.existsSync(C)&&this.app.use(y.default.static(C)),this.app.get("*",((e,t)=>{if(!s.existsSync(C))return ne.notfound(t,'File "index.html" not found');t.sendFile(C+"/index.html")})))}server(){return this._server}websocket(){return this._webSocket}}class pe{static all(e,t){return S(this,void 0,void 0,(function*(){return yield $.findAll({where:Object.assign(Object.assign({},t),{state:!0}),include:[{model:Q,required:!0,include:[{model:Z,required:!0,where:{state:!0},include:[{model:te,required:!0,where:{userId:e.id}}]}]}]}).catch((e=>{oe.error(e.message,"api.permission",!0)}))}))}static get(e){return S(this,void 0,void 0,(function*(){const t=yield pe.all(e);return t?t.map((e=>e.name)):[]}))}static is(e,t){return S(this,void 0,void 0,(function*(){const r=yield pe.all(e,{name:t});return r&&!!r.length}))}}const he=(t,r)=>{const i=e.uuidv4()+"."+r;return s.existsSync(h.join(t,i))?he(t,r):i};class me{constructor(e){this.router=r.Router(),this._path=e}auth(e,t,r){return S(this,void 0,void 0,(function*(){const s=e.get(M)||"",{auth:i,error:o,user:n}=yield le.user(s);if(o)return ne.error(t,o);if(i&&n){const t=e.get("User-Agent");return t&&(i.useragent=t),yield i.save(),e.auth=i,e.user=n,r()}return ne.error(t,"Internal Server Error")}))}intialize(){}name(){return"api"}path(){return this._path}permission(e){return(t,r,s)=>S(this,void 0,void 0,(function*(){const i=t.user;return i?(yield pe.is(i,e))?s():ne.error(r,"Unauthorized access"):ne.unauthorized(r,"Access denied")}))}read(e=""){return this.permission((e||this.name())+".read")}upload(e){const t=(null==e?void 0:e.path)||F,r=w.default.diskStorage({destination:(e,r,s)=>s(null,t),filename:(e,r,s)=>S(this,void 0,void 0,(function*(){return s(null,he(t,A.default.extension(r.mimetype)||"bin"))}))}),s=1e6*((null==e?void 0:e.size)||K),i=w.default({storage:r,fileFilter(t,r,s){var i;return S(this,void 0,void 0,(function*(){const t=null===(i=null==e?void 0:e.types)||void 0===i?void 0:i.indexOf(r.mimetype);return void 0!==t&&t<0?s(new Error("File type not allowed")):s(null,!0)}))},limits:{fileSize:s}}),o=(null==e?void 0:e.count)||H,n=(null==e?void 0:e.field)||L,a=i.array(n,o);return(e,t,r)=>{a(e,t,(function(e){return e?ne.error(t,e.message):r()}))}}validation(t){return(r,s,i)=>S(this,void 0,void 0,(function*(){const{error:o,value:n}=yield e.Validation.object(t).validateAsync(r.body);return o?ne.validation(s,o):(r.body=n,i())}))}write(e=""){return this.permission((e||this.name())+".write")}}class ve extends me{add(){return(e,t)=>S(this,void 0,void 0,(function*(){if(!this._model)return ne.error(t,"Internal Server Error");const r=yield this._model.create(e.body).catch((e=>{oe.error(e.message,"api.controller."+this.name(),!0)}));return r?ne.data(t,{id:r.id}):ne.error(t,"Internal Server Error")}))}all(t,r){return(s,i)=>S(this,void 0,void 0,(function*(){var o,n,a,u,l;if(!this._model)return ne.error(i,"Internal Server Error");const c=Object.assign({},t||{});c.where=Object.assign({},c.where||{});const p=null===(o=s.query.limit)||void 0===o?void 0:o.toString();p&&(c.limit=parseInt(p));const h=null===(n=s.query.offset)||void 0===n?void 0:n.toString();h&&(c.offset=parseInt(h));const m=Object.keys(this._model.getAttributes()),v=[],g=null===(a=s.query.asc)||void 0===a?void 0:a.toString();g&&g.length&&g.split(",").forEach((e=>{m.indexOf(e)>=0&&v.push([e,"ASC"])}));const f=null===(u=s.query.desc)||void 0===u?void 0:u.toString();f&&f.length&&f.split(",").forEach((e=>{m.indexOf(e)>=0&&v.push([e,"DESC"])})),v.length&&(c.order=v);const y=[],_=e.isArray(c.attributes)?c.attributes:m,I=null===(l=s.query.search)||void 0===l?void 0:l.toString();_.forEach((t=>{var r;if(e.isString(t)&&(I&&I.length&&y.push({[t]:{[d.Op.like]:`%${I}%`}}),"search_"+t in s.query)){const e=null===(r=s.query["search_"+t])||void 0===r?void 0:r.toString();e&&e.length&&y.push({[t]:{[d.Op.like]:`%${e}%`}})}})),y.length&&(c.where=Object.assign(Object.assign({},c.where),{[d.Op.or]:[...y]}));const T=yield this._model.findAll(c).catch((e=>{oe.error(e.message,"api.controller."+this.name(),!0)})),A=yield this._model.count(c).catch(e.noop);return T?ne.data(i,{count:A,records:r?r(T):T}):ne.error(i,"Internal Server Error")}))}del(){return(e,t)=>S(this,void 0,void 0,(function*(){if(!this._model)return ne.error(t,"Internal Server Error");const{id:r}=e.params;return(yield this._model.destroy({where:{id:r}}).catch((e=>{oe.error(e.message,"api.controller."+this.name(),!0)})))?ne.success(t,"OK"):ne.notfound(t,"Record not found")}))}get(e,t){return(r,s)=>S(this,void 0,void 0,(function*(){if(!this._model)return ne.error(s,"Internal Server Error");e||(e={});const i=Object.assign({},e);i.where=i.where?Object.assign({},i.where):{};const{id:o}=r.params,n=yield this._model.findByPk(o,i).catch((e=>{oe.error(e.message,"api.controller."+this.name(),!0)}));return n?ne.data(s,t?t(n):n.toJSON()):null===n?ne.notfound(s,"Record not found"):ne.error(s,"Internal Server Error")}))}name(){var e;return this._model?null===(e=this._model)||void 0===e?void 0:e.tableName:super.name()}set(){return(e,t)=>S(this,void 0,void 0,(function*(){if(!this._model)return ne.error(t,"Internal Server Error");const{id:r}=e.params,[s]=(yield this._model.update(e.body,{where:{id:r}}).catch((e=>{oe.error(e.message,"api.controller."+this.name(),!0)})))||[];return s?ne.success(t,"OK"):ne.success(t,"Record not changed")}))}getModel(){return this._model}setModel(e){this._model=e}}class ge extends ve{intialize(){const e=this.model();e&&this.setModel(e),this.router.use(this.auth),this.router.get("/",this.read(),this.all().bind(this)),this.router.post("/",this.write(),this.validation(this.create()),this.add().bind(this)),this.router.route("/:id").get(this.read(),this.get().bind(this)).put(this.write(),this.validation(this.update()),this.set().bind(this)).delete(this.write(),this.del().bind(this))}}exports.API_AUTH_SLEEP=b,exports.API_DB_DATABASE=P,exports.API_DB_HOST=x,exports.API_DB_LOG=R,exports.API_DB_PASSWORD=O,exports.API_DB_PORT=E,exports.API_DB_TYPE=q,exports.API_DB_USERNAME=D,exports.API_HTTP_CROSS=j,exports.API_HTTP_CRT=N,exports.API_HTTP_HYBRID=z,exports.API_HTTP_KEY=k,exports.API_HTTP_PORT=B,exports.API_HTTP_PUBLIC=C,exports.API_TOKEN_CRT=G,exports.API_TOKEN_HEADER=M,exports.API_TOKEN_KEY=V,exports.API_TOKEN_LIFETIME=U,exports.API_UPLOAD_COUNT=H,exports.API_UPLOAD_FIELD=L,exports.API_UPLOAD_SIZE=K,exports.API_UPLOAD_TEMP=F,exports.API_WEBSOCKET_START=Y,exports.App=ce,exports.Auth=J,exports.AuthController=class extends me{constructor(){super(...arguments),this.attributes=["id","name","email","username"],this.query={username:e.Validation.string().min(4).required(),password:e.Validation.string().min(5).required()}}intialize(){this.router.get("/",this.auth,this.user.bind(this)),this.router.post("/login",this.validation(this.query),this.login.bind(this)),this.router.get("/logout",this.auth,this.logout.bind(this))}login(t,r){return S(this,void 0,void 0,(function*(){yield e.sleep(b);const{username:s,password:i}=t.body,o=yield ee.findOne({where:{username:s}}).catch((e=>{oe.error(e.message,"api.controller."+this.name(),!0)}));if(!o)return ne.notfound(r,"Username not found");if(!o.state)return ne.error(r,"Username is disabled");const n=m.SHA256(i).toString();if(o.password!=n)return ne.error(r,"Invalid password");const a=o.id,u=e.uniqueID(),{error:d,token:l}=le.sign({id:a,secret:u});if(d)return ne.error(r,d);if(l){const e=Date.now(),s=e+6e4*U,i=t.get("User-Agent"),o=yield J.create({login:e,secret:u,timestamp:s,useragent:i,userId:a}).catch((e=>{oe.error(e.message,"api.controller."+this.name(),!0)}));if(o)return ne.data(r,{token:l})}return ne.error(r,"Internal Server Error")}))}logout(e,t){return S(this,void 0,void 0,(function*(){const r=e.auth;return r?(r.logout=Date.now(),r.timestamp=r.logout,yield r.save(),ne.success(t,"Disconcerted")):ne.unauthorized(t,"Access denied")}))}user(t,r){return S(this,void 0,void 0,(function*(){const s=t.user;if(!s)return ne.unauthorized(r,"Access denied");const i=yield pe.all(s);if(i){const t=e.allowedObject(this.attributes,s.toJSON()),o=i.map((e=>e.name));return ne.data(r,Object.assign(Object.assign({},t),{permissions:o}))}return ne.error(r,"Internal Server Error")}))}},exports.Config=class{static all(){return S(this,void 0,void 0,(function*(){const e=yield re.findAll().catch((e=>{oe.error(e.message,"api.config",!0)})),t={};return e&&e.forEach((e=>{t[e.key]=e.value})),t}))}static del(e){return S(this,void 0,void 0,(function*(){return((yield re.destroy({where:{key:e}}).catch((e=>{oe.error(e.message,"api.config",!0)})))||0)>0}))}static get(e){return S(this,void 0,void 0,(function*(){const t=yield re.findOne({where:{key:e}}).catch((e=>{oe.error(e.message,"api.config",!0)}));return t&&t.value||""}))}static set(e,t){return S(this,void 0,void 0,(function*(){const[r]=(yield re.findOrCreate({where:{key:e}}).catch((e=>{oe.error(e.message,"api.config",!0)})))||[];r&&(r.value=t,yield r.save().catch((e=>{oe.error(e.message,"api.config",!0)})))}))}},exports.Configs=re,exports.Controller=me,exports.CrudController=ge,exports.Database=W,exports.Group=Z,exports.GroupController=class extends ge{create(){return{name:e.Validation.string().required(),description:e.Validation.string().empty(""),state:e.Validation.boolean().required()}}model(){return Z}update(){return{name:e.Validation.string().empty(),description:e.Validation.string().empty(),state:e.Validation.boolean().empty()}}},exports.GroupRoute=Q,exports.GroupRouteController=class extends ve{constructor(){super(...arguments),this.groups={groups:e.Validation.array().items(e.Validation.number())}}intialize(){this.setModel(Q),this.router.use(this.auth),this.router.route("/:id/groups").get(this.read("users"),this.groupRouteAll.bind(this)).put(this.write("users"),this.validation(this.groups),this.groupRouteSet.bind(this))}groupRouteAll(e,t){return S(this,void 0,void 0,(function*(){const{id:r}=e.params;return this.all({where:{groupId:r},include:[{model:$,required:!0}]},(e=>e.map((e=>e.route))))(e,t)}))}groupRouteSet(e,t){return S(this,void 0,void 0,(function*(){const{id:r}=e.params,{routes:s}=e.body,i=yield Z.findByPk(r,{attributes:["id"]}).catch((e=>{oe.error(e.message,"api.controller."+this.name(),!0)}));if(i){const e=i.id;if(yield Q.destroy({where:{groupId:e}}),s){let t=0;for(let r=0;r<s.length;r++)t=yield $.count({where:{id:s[r]}}),t&&(yield Q.create({groupId:e,routeId:s[r]}))}return ne.success(t,"OK")}return null===i?ne.notfound(t,"Record not found"):ne.error(t,"Internal Server Error")}))}},exports.Log=oe,exports.Logs=se,exports.LogsController=class extends ve{intialize(){this.setModel(se),this.router.use(this.auth),this.router.get("/",this.read("logs"),this.logsAll.bind(this))}logsAll(e,t){return S(this,void 0,void 0,(function*(){const{source:r,type:s}=e.query,i=r&&s?{source:r,type:s}:r?{source:r}:s?{type:s}:{};return this.all({where:i,order:[["created","DESC"]]})(e,t)}))}},exports.ModelController=ve,exports.Permission=pe,exports.Responses=ne,exports.Route=$,exports.RouteController=class extends ge{create(){return{name:e.Validation.string().required(),description:e.Validation.string().empty(""),state:e.Validation.boolean().required()}}model(){return $}update(){return{name:e.Validation.string().empty(),description:e.Validation.string().empty(),state:e.Validation.boolean().empty()}}},exports.Token=le,exports.User=ee,exports.UserController=class extends ve{constructor(){super(...arguments),this.attributes=["id","name","email","username","description","state"],this.create={name:e.Validation.string().required(),email:e.Validation.string().email().required(),username:e.Validation.string().min(4).required(),password:e.Validation.string().min(5).required(),description:e.Validation.string().required(),state:e.Validation.boolean().required()},this.update={name:e.Validation.string().empty(),email:e.Validation.string().email().empty(),username:e.Validation.string().min(4).empty(),password:e.Validation.string().min(5).empty(),description:e.Validation.string().empty(),state:e.Validation.boolean().empty()}}intialize(){this.setModel(ee),this.router.use(this.auth),this.router.get("/",this.read(),this.userAll.bind(this)),this.router.post("/",this.write(),this.validation(this.create),this.userAdd.bind(this)),this.router.route("/:id").get(this.read(),this.userGet.bind(this)).put(this.write(),this.validation(this.update),this.userSet.bind(this)).delete(this.write(),this.userDel.bind(this))}userAdd(e,t){return S(this,void 0,void 0,(function*(){return e.body.password=m.SHA256(e.body.password).toString(),yield this.add()(e,t)}))}userAll(e,t){return S(this,void 0,void 0,(function*(){return this.all({attributes:this.attributes})(e,t)}))}userDel(e,t){return S(this,void 0,void 0,(function*(){const r=e.user;if(r){const{id:s}=e.params;if(r.id.toString()!=s)return this.del()(e,t)}return ne.error(t,"Internal Server Error")}))}userGet(e,t){return S(this,void 0,void 0,(function*(){return this.get({attributes:this.attributes})(e,t)}))}userSet(e,t){return S(this,void 0,void 0,(function*(){return e.body.password&&(e.body.password=m.SHA256(e.body.password).toString()),this.set()(e,t)}))}},exports.UserGroup=te,exports.UserGroupController=class extends ve{constructor(){super(...arguments),this.groups={groups:e.Validation.array(e.Validation.number())}}intialize(){this.setModel(te),this.router.use(this.auth),this.router.route("/:id/groups").get(this.read("groups"),this.userGroupsAll.bind(this)).put(this.write("groups"),this.validation(this.groups),this.userGroupsSet.bind(this))}userGroupsAll(e,t){return S(this,void 0,void 0,(function*(){const{id:r}=e.params;return this.all({where:{userId:r},include:[{model:Z,required:!0}]},(e=>e.map((e=>e.group))))(e,t)}))}userGroupsSet(e,t){return S(this,void 0,void 0,(function*(){const{id:r}=e.params,{groups:s}=e.body,i=yield ee.findByPk(r,{attributes:["id"]}).catch((e=>{oe.error(e.message,"api.controller."+this.name(),!0)}));if(i){if(yield te.destroy({where:{userId:i.id}}),s){let e=0;for(let t=0;t<s.length;t++)e=yield Z.count({where:{id:s[t]}}),e&&(yield te.create({userId:i.id,groupId:s[t]}))}return ne.success(t,"OK")}return ne.notfound(t,"Record not found")}))}},exports.crt=ue,exports.key=de,exports.sequelize=X;
7
+ "use strict";var e=require("@andrewcaires/utils.js"),t=require("cors"),r=require("express"),s=require("fs"),i=require("http"),o=require("https"),n=require("net"),a=require("ws"),d=require("dotenv"),u=require("sequelize"),l=require("jsonwebtoken"),c=require("mime-types"),h=require("multer"),p=require("path"),m=require("crypto-js");function v(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var s=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,s.get?s:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var g=v(i),f=v(o);function y(e,t,r,s){return new(r||(r=Promise))((function(i,o){function n(e){try{d(s.next(e))}catch(e){o(e)}}function a(e){try{d(s.throw(e))}catch(e){o(e)}}function d(e){var t;e.done?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(n,a)}d((s=s.apply(e,t||[])).next())}))}d.config();const _=parseInt(process.env.API_AUTH_SLEEP||"1000"),I=process.env.API_DB_DATABASE||"",T=process.env.API_DB_HOST||"127.0.0.1",A=process.env.API_DB_PASSWORD||"",w=parseInt(process.env.API_DB_PORT||"3306"),S=process.env.API_DB_TYPE||"",b=process.env.API_DB_USERNAME||"root",P=e.toBool(process.env.API_DB_LOG||"false"),x=process.env.API_HTTP_CRT||"",E=process.env.API_HTTP_KEY||"",O=parseInt(process.env.API_HTTP_PORT||"3000"),q=process.env.API_HTTP_PUBLIC||"",D=e.toBool(process.env.API_HTTP_CROSS||"false"),R=e.toBool(process.env.API_HTTP_HYBRID||"false"),N=process.env.API_TOKEN_CRT||"",k=process.env.API_TOKEN_KEY||"",B=process.env.API_TOKEN_HEADER||"authorization",C=parseInt(process.env.API_TOKEN_LIFETIME||"15"),z=parseInt(process.env.API_UPLOAD_COUNT||"1"),j=process.env.API_UPLOAD_FIELD||"upload",G=parseInt(process.env.API_UPLOAD_SIZE||"2"),V=process.env.API_UPLOAD_TEMP||"./temp",M=e.toBool(process.env.API_WEBSOCKET_START||"false");class L{static connect(e){const t=S.toLowerCase();if("connect_"+t in L)return L["connect_"+t](e);throw new Error("No database is connected to this API")}static connect_mariadb(e){return new u.Sequelize(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"mariadb",logging:P,define:{timestamps:!1}})}static connect_memory(){return new u.Sequelize("sqlite::memory:",{logging:P,define:{timestamps:!1}})}static connect_mysql(e){return new u.Sequelize(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"mysql",logging:P,define:{timestamps:!1}})}static connect_postgres(e){return new u.Sequelize(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"postgres",logging:P,define:{timestamps:!1}})}static connect_sqlite(e){return new u.Sequelize({dialect:"sqlite",storage:e.database,logging:P,define:{timestamps:!1}})}}const U=L.connect({database:I,username:b,password:A,hostname:T,hostport:w});class H extends u.Model{}H.init({login:u.DataTypes.BIGINT,logout:u.DataTypes.BIGINT,secret:u.DataTypes.STRING,timestamp:u.DataTypes.BIGINT,useragent:u.DataTypes.STRING},{sequelize:U,modelName:"auth"});class K extends u.Model{}K.init({name:u.DataTypes.STRING,description:u.DataTypes.TEXT,state:u.DataTypes.BOOLEAN},{sequelize:U,modelName:"group"});class F extends u.Model{}F.init({name:u.DataTypes.STRING,description:u.DataTypes.TEXT,state:u.DataTypes.BOOLEAN},{sequelize:U,modelName:"route"});class Y extends u.Model{}Y.init({},{sequelize:U,modelName:"groups_routes"}),Y.removeAttribute("id");class W extends u.Model{}W.init({name:u.DataTypes.STRING,email:u.DataTypes.STRING,username:u.DataTypes.STRING,password:u.DataTypes.STRING,description:u.DataTypes.TEXT,state:u.DataTypes.BOOLEAN},{sequelize:U,modelName:"user"});class X extends u.Model{}X.init({},{sequelize:U,modelName:"users_groups"}),X.removeAttribute("id");class J extends u.Model{}J.init({key:u.DataTypes.STRING,value:u.DataTypes.STRING},{sequelize:U,modelName:"configs",timestamps:!0,createdAt:"created",updatedAt:"updated"}),J.removeAttribute("id");class Z extends u.Model{}var $;Z.init({type:u.DataTypes.STRING,source:u.DataTypes.STRING,message:u.DataTypes.TEXT},{sequelize:U,modelName:"logs",timestamps:!0,createdAt:"created",updatedAt:!1}),W.hasMany(H),H.belongsTo(W),K.hasMany(Y),Y.belongsTo(K),F.hasMany(Y),Y.belongsTo(F),W.hasMany(X),X.belongsTo(W),K.hasMany(X),X.belongsTo(K),function(e){e.ERROR="",e.INFO="",e.NONE="",e.SUCCESS="",e.WARNING=""}($||($={}));class Q{static write(e,t,r){return y(this,void 0,void 0,(function*(){yield Q.writeRaw($.NONE,"",e,t,r)}))}static error(e,t,r){return y(this,void 0,void 0,(function*(){yield Q.writeRaw($.ERROR,"error",e,t,r)}))}static info(e,t,r){return y(this,void 0,void 0,(function*(){yield Q.writeRaw($.INFO,"info",e,t,r)}))}static success(e,t,r){return y(this,void 0,void 0,(function*(){yield Q.writeRaw($.ERROR,"success",e,t,r)}))}static warning(e,t,r){return y(this,void 0,void 0,(function*(){yield Q.writeRaw($.WARNING,"warning",e,t,r)}))}static writeConsole(t,r,s){const i=e.dateFormat(new Date,"%H:%M:%S");console.log(">",t,r+" ".repeat(10-r.length),"","|",i,"|",s)}static writeRaw(e,t,r,s,i){return y(this,void 0,void 0,(function*(){i&&Q.writeConsole(e,t,r),U&&(yield Z.create({type:t,source:s,message:r}).catch((()=>null)))}))}}class ee{static success(e,t){return e.status(200).json({message:t})}static data(e,t){return e.status(200).json(Object.assign({},t))}static error(e,t){return e.status(500).json({message:t})}static list(e,t){return e.status(200).json([...t])}static notfound(e,t){return e.status(404).json({message:t})}static validation(e,t){return e.status(400).json({message:t})}static unauthorized(e,t){return e.status(401).json({message:t})}}const te=e=>s.existsSync(e)?s.readFileSync(e):void 0,re={http:te(x),token:te(N)},se={http:te(E),token:te(k)};class ie{static sign(e){return se.token?{token:l.sign(e,se.token,{algorithm:"RS256"})}:{error:"Invalid Secret"}}static user(e){return y(this,void 0,void 0,(function*(){const{error:t,decode:r}=ie.verify(e);if(t)return{error:t};if(r){const{id:e,secret:t}=r;if(e&&r){const r=yield W.findOne({where:{id:e,state:!0}}).catch((e=>{Q.error(e.message,"api.token",!0)}));if(r){const e=yield H.findOne({where:{secret:t,userId:r.id}}).catch((e=>{Q.error(e.message,"api.token",!0)}));if(e){const t=Date.now();if(t>e.timestamp)return{error:"Expired token"};if(e.timestamp=t+6e4*C,yield e.save(),!e.logout)return{auth:e,user:r}}}return{error:"Access denied"}}}return{error:"Invalid token"}}))}static verify(e){if(!re.token)return{error:"Invalid Secret"};if(!e||e.split(".").length<3)return{error:"Invalid Token"};try{return{decode:l.verify(e,re.token)}}catch(e){return{error:"Invalid Token"}}}}class oe extends e.EventEmitter{constructor(e){super(),this.app=r(),this.router=r.Router(),this.middlewares(),this.controllers(e)}controllers(e){e.forEach((e=>{e.intialize(),this.router.use(e.path(),e.router)}))}listen(){return y(this,void 0,void 0,(function*(){if(yield U.sync(),re.http&&se.http||(this._server=g.createServer(this.app),this._server.listen(O,(()=>Q.info("Server started on port "+O,"api.server",!0)))),!this._server){const e=g.createServer(((e,t)=>{const r=80==O?":80":"";t.writeHead(301,{Location:"https://"+e.headers.host+r+e.url}),t.end()})),t=f.createServer({key:se.http,cert:re.http},this.app);if(R){new n.Server((r=>{r.once("data",(s=>{r.pause(),r.unshift(s),(22===s[0]?t:e).emit("connection",r),process.nextTick((()=>r.resume()))}))})).listen(O,(()=>Q.info("Server started on port "+O,"api.server",!0))),this._server=t}this._server||(443==O&&e.listen(80,(()=>Q.info("Server started on port 80","api.server",!0))),t.listen(O,(()=>Q.info("Server started on port "+O,"api.server",!0))),this._server=t)}M&&this._server&&(this._webSocket=new a.Server({server:this._server,verifyClient:(e,t)=>t(M)}),this._webSocket.on("connection",((t,r)=>y(this,void 0,void 0,(function*(){r.url||(r.url="");const s=r.url.length<=1?"":r.url.replace(/\//g,".");let i;t.on("message",(e=>y(this,void 0,void 0,(function*(){if(i)try{const o=JSON.parse(e);this.emit("ws.message"+s,{data:o,message:e,req:r,user:i,ws:t})}catch(o){this.emit("ws.message"+s,{message:e,req:r,user:i,ws:t})}else{const{user:o}=yield ie.user(e.toString());o&&(i=o,this.emit("ws.connection"+s,{req:r,user:i,ws:t}))}i||t.close()})))),t.on("close",(()=>{i&&this.emit("ws.close"+s,{user:i,ws:t})})),yield e.sleep(2e3),i||t.close()})))))}))}middlewares(){this.app.use(r.json()),this.app.use(((e,t,r,s)=>e?(Q.error(e.message,"api.express",!0),ee.error(r,"Internal Server Error")):s())),this.app.use(r.urlencoded({extended:!0})),this.app.disable("x-powered-by"),D&&this.app.use(t()),this.app.use("/api",this.router),this.app.all("/api/*",((e,t)=>ee.notfound(t,"Invalid API"))),q&&(s.existsSync(q)&&this.app.use(r.static(q)),this.app.get("*",((e,t)=>{if(!s.existsSync(q))return ee.notfound(t,'File "index.html" not found');t.sendFile(q+"/index.html")})))}server(){return this._server}websocket(){return this._webSocket}}class ne{static all(e,t){return y(this,void 0,void 0,(function*(){return yield F.findAll({where:Object.assign(Object.assign({},t),{state:!0}),include:[{model:Y,required:!0,include:[{model:K,required:!0,where:{state:!0},include:[{model:X,required:!0,where:{userId:e.id}}]}]}]}).catch((e=>{Q.error(e.message,"api.permission",!0)}))}))}static get(e){return y(this,void 0,void 0,(function*(){const t=yield ne.all(e);return t?t.map((e=>e.name)):[]}))}static is(e,t){return y(this,void 0,void 0,(function*(){const r=yield ne.all(e,{name:t});return r&&!!r.length}))}}const ae=(t,r)=>{const i=e.uuidv4()+"."+r;return s.existsSync(p.join(t,i))?ae(t,r):i};class de{constructor(e){this.router=r.Router(),this._path=e}auth(e,t,r){return y(this,void 0,void 0,(function*(){const s=e.get(B)||"",{auth:i,error:o,user:n}=yield ie.user(s);if(o)return ee.error(t,o);if(i&&n){const t=e.get("User-Agent");return t&&(i.useragent=t),yield i.save(),e.auth=i,e.user=n,r()}return ee.error(t,"Internal Server Error")}))}intialize(){}name(){return"api"}path(){return this._path}permission(e){return(t,r,s)=>y(this,void 0,void 0,(function*(){const i=t.user;return i?(yield ne.is(i,e))?s():ee.error(r,"Unauthorized access"):ee.unauthorized(r,"Access denied")}))}read(e=""){return this.permission((e||this.name())+".read")}upload(e){const t=(null==e?void 0:e.path)||V,r=h.diskStorage({destination:(e,r,s)=>s(null,t),filename:(e,r,s)=>y(this,void 0,void 0,(function*(){return s(null,ae(t,c.extension(r.mimetype)||"bin"))}))}),s=1e6*((null==e?void 0:e.size)||G),i=h({storage:r,fileFilter(t,r,s){var i;return y(this,void 0,void 0,(function*(){const t=null===(i=null==e?void 0:e.types)||void 0===i?void 0:i.indexOf(r.mimetype);return void 0!==t&&t<0?s(new Error("File type not allowed")):s(null,!0)}))},limits:{fileSize:s}}),o=(null==e?void 0:e.count)||z,n=(null==e?void 0:e.field)||j,a=i.array(n,o);return(e,t,r)=>{a(e,t,(function(e){return e?ee.error(t,e.message):r()}))}}validation(t){return(r,s,i)=>y(this,void 0,void 0,(function*(){const{error:o,value:n}=yield e.Validation.object(t).validateAsync(r.body);return o?ee.validation(s,o):(r.body=n,i())}))}write(e=""){return this.permission((e||this.name())+".write")}}class ue extends de{add(){return(e,t)=>y(this,void 0,void 0,(function*(){if(!this._model)return ee.error(t,"Internal Server Error");const r=yield this._model.create(e.body).catch((e=>{Q.error(e.message,"api.controller."+this.name(),!0)}));return r?ee.data(t,{id:r.id}):ee.error(t,"Internal Server Error")}))}all(t,r){return(s,i)=>y(this,void 0,void 0,(function*(){var o,n,a,d,l;if(!this._model)return ee.error(i,"Internal Server Error");const c=Object.assign({},t||{});c.where=Object.assign({},c.where||{});const h=null===(o=s.query.limit)||void 0===o?void 0:o.toString();h&&(c.limit=parseInt(h));const p=null===(n=s.query.offset)||void 0===n?void 0:n.toString();p&&(c.offset=parseInt(p));const m=Object.keys(this._model.getAttributes()),v=[],g=null===(a=s.query.asc)||void 0===a?void 0:a.toString();g&&g.length&&g.split(",").forEach((e=>{m.indexOf(e)>=0&&v.push([e,"ASC"])}));const f=null===(d=s.query.desc)||void 0===d?void 0:d.toString();f&&f.length&&f.split(",").forEach((e=>{m.indexOf(e)>=0&&v.push([e,"DESC"])})),v.length&&(c.order=v);const y=[],_=e.isArray(c.attributes)?c.attributes:m,I=null===(l=s.query.search)||void 0===l?void 0:l.toString();_.forEach((t=>{var r;if(e.isString(t)&&(I&&I.length&&y.push({[t]:{[u.Op.like]:`%${I}%`}}),"search_"+t in s.query)){const e=null===(r=s.query["search_"+t])||void 0===r?void 0:r.toString();e&&e.length&&y.push({[t]:{[u.Op.like]:`%${e}%`}})}})),y.length&&(c.where=Object.assign(Object.assign({},c.where),{[u.Op.or]:[...y]}));const T=yield this._model.findAll(c).catch((e=>{Q.error(e.message,"api.controller."+this.name(),!0)})),A=yield this._model.count(c).catch(e.noop);return T?ee.data(i,{count:A,records:r?r(T):T}):ee.error(i,"Internal Server Error")}))}del(){return(e,t)=>y(this,void 0,void 0,(function*(){if(!this._model)return ee.error(t,"Internal Server Error");const{id:r}=e.params;return(yield this._model.destroy({where:{id:r}}).catch((e=>{Q.error(e.message,"api.controller."+this.name(),!0)})))?ee.success(t,"OK"):ee.notfound(t,"Record not found")}))}get(e,t){return(r,s)=>y(this,void 0,void 0,(function*(){if(!this._model)return ee.error(s,"Internal Server Error");e||(e={});const i=Object.assign({},e);i.where=i.where?Object.assign({},i.where):{};const{id:o}=r.params,n=yield this._model.findByPk(o,i).catch((e=>{Q.error(e.message,"api.controller."+this.name(),!0)}));return n?ee.data(s,t?t(n):n.toJSON()):null===n?ee.notfound(s,"Record not found"):ee.error(s,"Internal Server Error")}))}name(){var e;return this._model?null===(e=this._model)||void 0===e?void 0:e.tableName:super.name()}set(){return(e,t)=>y(this,void 0,void 0,(function*(){if(!this._model)return ee.error(t,"Internal Server Error");const{id:r}=e.params,[s]=(yield this._model.update(e.body,{where:{id:r}}).catch((e=>{Q.error(e.message,"api.controller."+this.name(),!0)})))||[];return s?ee.success(t,"OK"):ee.success(t,"Record not changed")}))}getModel(){return this._model}setModel(e){this._model=e}}class le extends ue{intialize(){const e=this.model();e&&this.setModel(e),this.router.use(this.auth),this.router.get("/",this.read(),this.all().bind(this)),this.router.post("/",this.write(),this.validation(this.create()),this.add().bind(this)),this.router.route("/:id").get(this.read(),this.get().bind(this)).put(this.write(),this.validation(this.update()),this.set().bind(this)).delete(this.write(),this.del().bind(this))}}exports.API_AUTH_SLEEP=_,exports.API_DB_DATABASE=I,exports.API_DB_HOST=T,exports.API_DB_LOG=P,exports.API_DB_PASSWORD=A,exports.API_DB_PORT=w,exports.API_DB_TYPE=S,exports.API_DB_USERNAME=b,exports.API_HTTP_CROSS=D,exports.API_HTTP_CRT=x,exports.API_HTTP_HYBRID=R,exports.API_HTTP_KEY=E,exports.API_HTTP_PORT=O,exports.API_HTTP_PUBLIC=q,exports.API_TOKEN_CRT=N,exports.API_TOKEN_HEADER=B,exports.API_TOKEN_KEY=k,exports.API_TOKEN_LIFETIME=C,exports.API_UPLOAD_COUNT=z,exports.API_UPLOAD_FIELD=j,exports.API_UPLOAD_SIZE=G,exports.API_UPLOAD_TEMP=V,exports.API_WEBSOCKET_START=M,exports.App=oe,exports.Auth=H,exports.AuthController=class extends de{constructor(){super(...arguments),this.attributes=["id","name","email","username"],this.query={username:e.Validation.string().min(4).required(),password:e.Validation.string().min(5).required()}}intialize(){this.router.get("/",this.auth,this.user.bind(this)),this.router.post("/login",this.validation(this.query),this.login.bind(this)),this.router.get("/logout",this.auth,this.logout.bind(this))}login(t,r){return y(this,void 0,void 0,(function*(){yield e.sleep(_);const{username:s,password:i}=t.body,o=yield W.findOne({where:{username:s}}).catch((e=>{Q.error(e.message,"api.controller."+this.name(),!0)}));if(!o)return ee.notfound(r,"Username not found");if(!o.state)return ee.error(r,"Username is disabled");const n=m.SHA256(i).toString();if(o.password!=n)return ee.error(r,"Invalid password");const a=o.id,d=e.uniqueID(),{error:u,token:l}=ie.sign({id:a,secret:d});if(u)return ee.error(r,u);if(l){const e=Date.now(),s=e+6e4*C,i=t.get("User-Agent"),o=yield H.create({login:e,secret:d,timestamp:s,useragent:i,userId:a}).catch((e=>{Q.error(e.message,"api.controller."+this.name(),!0)}));if(o)return ee.data(r,{token:l})}return ee.error(r,"Internal Server Error")}))}logout(e,t){return y(this,void 0,void 0,(function*(){const r=e.auth;return r?(r.logout=Date.now(),r.timestamp=r.logout,yield r.save(),ee.success(t,"Disconcerted")):ee.unauthorized(t,"Access denied")}))}user(t,r){return y(this,void 0,void 0,(function*(){const s=t.user;if(!s)return ee.unauthorized(r,"Access denied");const i=yield ne.all(s);if(i){const t=e.allowedObject(this.attributes,s.toJSON()),o=i.map((e=>e.name));return ee.data(r,Object.assign(Object.assign({},t),{permissions:o}))}return ee.error(r,"Internal Server Error")}))}},exports.Config=class{static all(){return y(this,void 0,void 0,(function*(){const e=yield J.findAll().catch((e=>{Q.error(e.message,"api.config",!0)})),t={};return e&&e.forEach((e=>{t[e.key]=e.value})),t}))}static del(e){return y(this,void 0,void 0,(function*(){return((yield J.destroy({where:{key:e}}).catch((e=>{Q.error(e.message,"api.config",!0)})))||0)>0}))}static get(e){return y(this,void 0,void 0,(function*(){const t=yield J.findOne({where:{key:e}}).catch((e=>{Q.error(e.message,"api.config",!0)}));return t&&t.value||""}))}static set(e,t){return y(this,void 0,void 0,(function*(){const[r]=(yield J.findOrCreate({where:{key:e}}).catch((e=>{Q.error(e.message,"api.config",!0)})))||[];r&&(r.value=t,yield r.save().catch((e=>{Q.error(e.message,"api.config",!0)})))}))}},exports.Configs=J,exports.Controller=de,exports.CrudController=le,exports.Database=L,exports.Group=K,exports.GroupController=class extends le{create(){return{name:e.Validation.string().required(),description:e.Validation.string().empty(""),state:e.Validation.boolean().required()}}model(){return K}update(){return{name:e.Validation.string().empty(),description:e.Validation.string().empty(),state:e.Validation.boolean().empty()}}},exports.GroupRoute=Y,exports.GroupRouteController=class extends ue{constructor(){super(...arguments),this.groups={groups:e.Validation.array().items(e.Validation.number())}}intialize(){this.setModel(Y),this.router.use(this.auth),this.router.route("/:id/groups").get(this.read("users"),this.groupRouteAll.bind(this)).put(this.write("users"),this.validation(this.groups),this.groupRouteSet.bind(this))}groupRouteAll(e,t){return y(this,void 0,void 0,(function*(){const{id:r}=e.params;return this.all({where:{groupId:r},include:[{model:F,required:!0}]},(e=>e.map((e=>e.route))))(e,t)}))}groupRouteSet(e,t){return y(this,void 0,void 0,(function*(){const{id:r}=e.params,{routes:s}=e.body,i=yield K.findByPk(r,{attributes:["id"]}).catch((e=>{Q.error(e.message,"api.controller."+this.name(),!0)}));if(i){const e=i.id;if(yield Y.destroy({where:{groupId:e}}),s){let t=0;for(let r=0;r<s.length;r++)t=yield F.count({where:{id:s[r]}}),t&&(yield Y.create({groupId:e,routeId:s[r]}))}return ee.success(t,"OK")}return null===i?ee.notfound(t,"Record not found"):ee.error(t,"Internal Server Error")}))}},exports.Log=Q,exports.Logs=Z,exports.LogsController=class extends ue{intialize(){this.setModel(Z),this.router.use(this.auth),this.router.get("/",this.read("logs"),this.logsAll.bind(this))}logsAll(e,t){return y(this,void 0,void 0,(function*(){const{source:r,type:s}=e.query,i=r&&s?{source:r,type:s}:r?{source:r}:s?{type:s}:{};return this.all({where:i,order:[["created","DESC"]]})(e,t)}))}},exports.ModelController=ue,exports.Permission=ne,exports.Responses=ee,exports.Route=F,exports.RouteController=class extends le{create(){return{name:e.Validation.string().required(),description:e.Validation.string().empty(""),state:e.Validation.boolean().required()}}model(){return F}update(){return{name:e.Validation.string().empty(),description:e.Validation.string().empty(),state:e.Validation.boolean().empty()}}},exports.Token=ie,exports.User=W,exports.UserController=class extends ue{constructor(){super(...arguments),this.attributes=["id","name","email","username","description","state"],this.create={name:e.Validation.string().required(),email:e.Validation.string().email().required(),username:e.Validation.string().min(4).required(),password:e.Validation.string().min(5).required(),description:e.Validation.string().required(),state:e.Validation.boolean().required()},this.update={name:e.Validation.string().empty(),email:e.Validation.string().email().empty(),username:e.Validation.string().min(4).empty(),password:e.Validation.string().min(5).empty(),description:e.Validation.string().empty(),state:e.Validation.boolean().empty()}}intialize(){this.setModel(W),this.router.use(this.auth),this.router.get("/",this.read(),this.userAll.bind(this)),this.router.post("/",this.write(),this.validation(this.create),this.userAdd.bind(this)),this.router.route("/:id").get(this.read(),this.userGet.bind(this)).put(this.write(),this.validation(this.update),this.userSet.bind(this)).delete(this.write(),this.userDel.bind(this))}userAdd(e,t){return y(this,void 0,void 0,(function*(){return e.body.password=m.SHA256(e.body.password).toString(),yield this.add()(e,t)}))}userAll(e,t){return y(this,void 0,void 0,(function*(){return this.all({attributes:this.attributes})(e,t)}))}userDel(e,t){return y(this,void 0,void 0,(function*(){const r=e.user;if(r){const{id:s}=e.params;if(r.id.toString()!=s)return this.del()(e,t)}return ee.error(t,"Internal Server Error")}))}userGet(e,t){return y(this,void 0,void 0,(function*(){return this.get({attributes:this.attributes})(e,t)}))}userSet(e,t){return y(this,void 0,void 0,(function*(){return e.body.password&&(e.body.password=m.SHA256(e.body.password).toString()),this.set()(e,t)}))}},exports.UserGroup=X,exports.UserGroupController=class extends ue{constructor(){super(...arguments),this.groups={groups:e.Validation.array(e.Validation.number())}}intialize(){this.setModel(X),this.router.use(this.auth),this.router.route("/:id/groups").get(this.read("groups"),this.userGroupsAll.bind(this)).put(this.write("groups"),this.validation(this.groups),this.userGroupsSet.bind(this))}userGroupsAll(e,t){return y(this,void 0,void 0,(function*(){const{id:r}=e.params;return this.all({where:{userId:r},include:[{model:K,required:!0}]},(e=>e.map((e=>e.group))))(e,t)}))}userGroupsSet(e,t){return y(this,void 0,void 0,(function*(){const{id:r}=e.params,{groups:s}=e.body,i=yield W.findByPk(r,{attributes:["id"]}).catch((e=>{Q.error(e.message,"api.controller."+this.name(),!0)}));if(i){if(yield X.destroy({where:{userId:i.id}}),s){let e=0;for(let t=0;t<s.length;t++)e=yield K.count({where:{id:s[t]}}),e&&(yield X.create({userId:i.id,groupId:s[t]}))}return ee.success(t,"OK")}return ee.notfound(t,"Record not found")}))}},exports.crt=re,exports.key=se,exports.sequelize=U;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * @andrewcaires/api v2.0.1
2
+ * @andrewcaires/api v2.0.2
3
3
  * Simple api for small applications using express, jsonwebtoken, sequelize and websocket
4
4
  * (c) 2022 Andrew Caires
5
5
  * @license: MIT
@@ -232,12 +232,12 @@ interface DatabaseOptions {
232
232
  hostport: number;
233
233
  }
234
234
  declare class Database {
235
- static connect(): Sequelize;
236
- static mariadb(options: DatabaseOptions): Sequelize;
237
- static memory(): Sequelize;
238
- static mysql(options: DatabaseOptions): Sequelize;
239
- static postgres(options: DatabaseOptions): Sequelize;
240
- static sqlite(database: string): Sequelize;
235
+ static connect(options: DatabaseOptions): Sequelize;
236
+ static connect_mariadb(options: DatabaseOptions): Sequelize;
237
+ static connect_memory(): Sequelize;
238
+ static connect_mysql(options: DatabaseOptions): Sequelize;
239
+ static connect_postgres(options: DatabaseOptions): Sequelize;
240
+ static connect_sqlite(options: DatabaseOptions): Sequelize;
241
241
  }
242
242
  declare const sequelize: Sequelize;
243
243
 
package/dist/index.esm.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * @andrewcaires/api v2.0.1
2
+ * @andrewcaires/api v2.0.2
3
3
  * Simple api for small applications using express, jsonwebtoken, sequelize and websocket
4
4
  * (c) 2022 Andrew Caires
5
5
  * @license: MIT
6
6
  */
7
- import{toBool as e,dateFormat as t,EventEmitter as r,sleep as s,Validation as i,uuidv4 as n,uniqueID as o,allowedObject as a,isArray as d,isString as u,noop as c}from"@andrewcaires/utils.js";import l from"cors";import h,{Router as p,json as m,urlencoded as v}from"express";import{existsSync as g,readFileSync as f}from"fs";import*as y from"http";import*as w from"https";import{Server as I}from"net";import b from"ws";import{config as S}from"dotenv";import{Sequelize as _,DataTypes as A,Model as T,Op as E}from"sequelize";import{sign as O,verify as R}from"jsonwebtoken";import q from"mime-types";import N from"multer";import{join as P}from"path";import{SHA256 as k}from"crypto-js";function x(e,t,r,s){return new(r||(r=Promise))((function(i,n){function o(e){try{d(s.next(e))}catch(e){n(e)}}function a(e){try{d(s.throw(e))}catch(e){n(e)}}function d(e){var t;e.done?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(o,a)}d((s=s.apply(e,t||[])).next())}))}S();const z=parseInt(process.env.API_AUTH_SLEEP||"1000"),D=process.env.API_DB_DATABASE||"",G=process.env.API_DB_HOST||"127.0.0.1",j=process.env.API_DB_PASSWORD||"",B=parseInt(process.env.API_DB_PORT||"3306"),M=process.env.API_DB_TYPE||"",C=process.env.API_DB_USERNAME||"root",U=e(process.env.API_DB_LOG||"false"),L=process.env.API_HTTP_CRT||"",H=process.env.API_HTTP_KEY||"",K=parseInt(process.env.API_HTTP_PORT||"3000"),F=process.env.API_HTTP_PUBLIC||"",W=e(process.env.API_HTTP_CROSS||"false"),X=e(process.env.API_HTTP_HYBRID||"false"),Y=process.env.API_TOKEN_CRT||"",J=process.env.API_TOKEN_KEY||"",$=process.env.API_TOKEN_HEADER||"authorization",Z=parseInt(process.env.API_TOKEN_LIFETIME||"15"),Q=parseInt(process.env.API_UPLOAD_COUNT||"1"),V=process.env.API_UPLOAD_FIELD||"upload",ee=parseInt(process.env.API_UPLOAD_SIZE||"2"),te=process.env.API_UPLOAD_TEMP||"./temp",re=e(process.env.API_WEBSOCKET_START||"false");class se{static connect(){const e={database:D,username:C,password:j,hostname:G,hostport:B};switch(M){case"mariadb":return se.mariadb(e);case"memory":default:return se.memory();case"mysql":return se.mysql(e);case"postgres":return se.postgres(e);case"sqlite":return se.sqlite(D)}}static mariadb(e){return new _(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"mariadb",logging:U,define:{timestamps:!1}})}static memory(){return new _("sqlite::memory:",{logging:U,define:{timestamps:!1}})}static mysql(e){return new _(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"mysql",logging:U,define:{timestamps:!1}})}static postgres(e){return new _(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"postgres",logging:U,define:{timestamps:!1}})}static sqlite(e){return new _({dialect:"sqlite",storage:e,logging:U,define:{timestamps:!1}})}}const ie=se.connect();class ne extends T{}ne.init({login:A.BIGINT,logout:A.BIGINT,secret:A.STRING,timestamp:A.BIGINT,useragent:A.STRING},{sequelize:ie,modelName:"auth"});class oe extends T{}oe.init({name:A.STRING,description:A.TEXT,state:A.BOOLEAN},{sequelize:ie,modelName:"group"});class ae extends T{}ae.init({name:A.STRING,description:A.TEXT,state:A.BOOLEAN},{sequelize:ie,modelName:"route"});class de extends T{}de.init({},{sequelize:ie,modelName:"groups_routes"}),de.removeAttribute("id");class ue extends T{}ue.init({name:A.STRING,email:A.STRING,username:A.STRING,password:A.STRING,description:A.TEXT,state:A.BOOLEAN},{sequelize:ie,modelName:"user"});class ce extends T{}ce.init({},{sequelize:ie,modelName:"users_groups"}),ce.removeAttribute("id");class le extends T{}le.init({key:A.STRING,value:A.STRING},{sequelize:ie,modelName:"configs",timestamps:!0,createdAt:"created",updatedAt:"updated"}),le.removeAttribute("id");class he extends T{}var pe;he.init({type:A.STRING,source:A.STRING,message:A.TEXT},{sequelize:ie,modelName:"logs",timestamps:!0,createdAt:"created",updatedAt:!1}),ue.hasMany(ne),ne.belongsTo(ue),oe.hasMany(de),de.belongsTo(oe),ae.hasMany(de),de.belongsTo(ae),ue.hasMany(ce),ce.belongsTo(ue),oe.hasMany(ce),ce.belongsTo(oe),function(e){e.ERROR="",e.INFO="",e.NONE="",e.SUCCESS="",e.WARNING=""}(pe||(pe={}));class me{static write(e,t,r){return x(this,void 0,void 0,(function*(){yield me.writeRaw(pe.NONE,"",e,t,r)}))}static error(e,t,r){return x(this,void 0,void 0,(function*(){yield me.writeRaw(pe.ERROR,"error",e,t,r)}))}static info(e,t,r){return x(this,void 0,void 0,(function*(){yield me.writeRaw(pe.INFO,"info",e,t,r)}))}static success(e,t,r){return x(this,void 0,void 0,(function*(){yield me.writeRaw(pe.ERROR,"success",e,t,r)}))}static warning(e,t,r){return x(this,void 0,void 0,(function*(){yield me.writeRaw(pe.WARNING,"warning",e,t,r)}))}static writeConsole(e,r,s){const i=t(new Date,"%H:%M:%S");console.log(">",e,r+" ".repeat(10-r.length),"","|",i,"|",s)}static writeRaw(e,t,r,s,i){return x(this,void 0,void 0,(function*(){i&&me.writeConsole(e,t,r),ie&&(yield he.create({type:t,source:s,message:r}).catch((()=>null)))}))}}class ve{static success(e,t){return e.status(200).json({message:t})}static data(e,t){return e.status(200).json(Object.assign({},t))}static error(e,t){return e.status(500).json({message:t})}static list(e,t){return e.status(200).json([...t])}static notfound(e,t){return e.status(404).json({message:t})}static validation(e,t){return e.status(400).json({message:t})}static unauthorized(e,t){return e.status(401).json({message:t})}}const ge=e=>g(e)?f(e):void 0,fe={http:ge(L),token:ge(Y)},ye={http:ge(H),token:ge(J)};class we{static sign(e){return ye.token?{token:O(e,ye.token,{algorithm:"RS256"})}:{error:"Invalid Secret"}}static user(e){return x(this,void 0,void 0,(function*(){const{error:t,decode:r}=we.verify(e);if(t)return{error:t};if(r){const{id:e,secret:t}=r;if(e&&r){const r=yield ue.findOne({where:{id:e,state:!0}}).catch((e=>{me.error(e.message,"api.token",!0)}));if(r){const e=yield ne.findOne({where:{secret:t,userId:r.id}}).catch((e=>{me.error(e.message,"api.token",!0)}));if(e){const t=Date.now();if(t>e.timestamp)return{error:"Expired token"};if(e.timestamp=t+6e4*Z,yield e.save(),!e.logout)return{auth:e,user:r}}}return{error:"Access denied"}}}return{error:"Invalid token"}}))}static verify(e){if(!fe.token)return{error:"Invalid Secret"};if(!e||e.split(".").length<3)return{error:"Invalid Token"};try{return{decode:R(e,fe.token)}}catch(e){return{error:"Invalid Token"}}}}class Ie extends r{constructor(e){super(),this.app=h(),this.router=p(),this.middlewares(),this.controllers(e)}controllers(e){e.forEach((e=>{e.intialize(),this.router.use(e.path(),e.router)}))}listen(){return x(this,void 0,void 0,(function*(){if(yield ie.sync(),fe.http&&ye.http||(this._server=y.createServer(this.app),this._server.listen(K,(()=>me.info("Server started on port "+K,"api.server",!0)))),!this._server){const e=y.createServer(((e,t)=>{const r=80==K?":80":"";t.writeHead(301,{Location:"https://"+e.headers.host+r+e.url}),t.end()})),t=w.createServer({key:ye.http,cert:fe.http},this.app);if(X){new I((r=>{r.once("data",(s=>{r.pause(),r.unshift(s),(22===s[0]?t:e).emit("connection",r),process.nextTick((()=>r.resume()))}))})).listen(K,(()=>me.info("Server started on port "+K,"api.server",!0))),this._server=t}this._server||(443==K&&e.listen(80,(()=>me.info("Server started on port 80","api.server",!0))),t.listen(K,(()=>me.info("Server started on port "+K,"api.server",!0))),this._server=t)}re&&this._server&&(this._webSocket=new b.Server({server:this._server,verifyClient:(e,t)=>t(re)}),this._webSocket.on("connection",((e,t)=>x(this,void 0,void 0,(function*(){t.url||(t.url="");const r=t.url.length<=1?"":t.url.replace(/\//g,".");let i;e.on("message",(s=>x(this,void 0,void 0,(function*(){if(i)try{const n=JSON.parse(s);this.emit("ws.message"+r,{data:n,message:s,req:t,user:i,ws:e})}catch(n){this.emit("ws.message"+r,{message:s,req:t,user:i,ws:e})}else{const{user:n}=yield we.user(s.toString());n&&(i=n,this.emit("ws.connection"+r,{req:t,user:i,ws:e}))}i||e.close()})))),e.on("close",(()=>{i&&this.emit("ws.close"+r,{user:i,ws:e})})),yield s(2e3),i||e.close()})))))}))}middlewares(){this.app.use(m()),this.app.use(((e,t,r,s)=>e?(me.error(e.message,"api.express",!0),ve.error(r,"Internal Server Error")):s())),this.app.use(v({extended:!0})),this.app.disable("x-powered-by"),W&&this.app.use(l()),this.app.use("/api",this.router),this.app.all("/api/*",((e,t)=>ve.notfound(t,"Invalid API"))),F&&(g(F)&&this.app.use(h.static(F)),this.app.get("*",((e,t)=>{if(!g(F))return ve.notfound(t,'File "index.html" not found');t.sendFile(F+"/index.html")})))}server(){return this._server}websocket(){return this._webSocket}}class be{static all(){return x(this,void 0,void 0,(function*(){const e=yield le.findAll().catch((e=>{me.error(e.message,"api.config",!0)})),t={};return e&&e.forEach((e=>{t[e.key]=e.value})),t}))}static del(e){return x(this,void 0,void 0,(function*(){return((yield le.destroy({where:{key:e}}).catch((e=>{me.error(e.message,"api.config",!0)})))||0)>0}))}static get(e){return x(this,void 0,void 0,(function*(){const t=yield le.findOne({where:{key:e}}).catch((e=>{me.error(e.message,"api.config",!0)}));return t&&t.value||""}))}static set(e,t){return x(this,void 0,void 0,(function*(){const[r]=(yield le.findOrCreate({where:{key:e}}).catch((e=>{me.error(e.message,"api.config",!0)})))||[];r&&(r.value=t,yield r.save().catch((e=>{me.error(e.message,"api.config",!0)})))}))}}class Se{static all(e,t){return x(this,void 0,void 0,(function*(){return yield ae.findAll({where:Object.assign(Object.assign({},t),{state:!0}),include:[{model:de,required:!0,include:[{model:oe,required:!0,where:{state:!0},include:[{model:ce,required:!0,where:{userId:e.id}}]}]}]}).catch((e=>{me.error(e.message,"api.permission",!0)}))}))}static get(e){return x(this,void 0,void 0,(function*(){const t=yield Se.all(e);return t?t.map((e=>e.name)):[]}))}static is(e,t){return x(this,void 0,void 0,(function*(){const r=yield Se.all(e,{name:t});return r&&!!r.length}))}}const _e=(e,t)=>{const r=n()+"."+t;return g(P(e,r))?_e(e,t):r};class Ae{constructor(e){this.router=p(),this._path=e}auth(e,t,r){return x(this,void 0,void 0,(function*(){const s=e.get($)||"",{auth:i,error:n,user:o}=yield we.user(s);if(n)return ve.error(t,n);if(i&&o){const t=e.get("User-Agent");return t&&(i.useragent=t),yield i.save(),e.auth=i,e.user=o,r()}return ve.error(t,"Internal Server Error")}))}intialize(){}name(){return"api"}path(){return this._path}permission(e){return(t,r,s)=>x(this,void 0,void 0,(function*(){const i=t.user;return i?(yield Se.is(i,e))?s():ve.error(r,"Unauthorized access"):ve.unauthorized(r,"Access denied")}))}read(e=""){return this.permission((e||this.name())+".read")}upload(e){const t=(null==e?void 0:e.path)||te,r=N.diskStorage({destination:(e,r,s)=>s(null,t),filename:(e,r,s)=>x(this,void 0,void 0,(function*(){return s(null,_e(t,q.extension(r.mimetype)||"bin"))}))}),s=1e6*((null==e?void 0:e.size)||ee),i=N({storage:r,fileFilter(t,r,s){var i;return x(this,void 0,void 0,(function*(){const t=null===(i=null==e?void 0:e.types)||void 0===i?void 0:i.indexOf(r.mimetype);return void 0!==t&&t<0?s(new Error("File type not allowed")):s(null,!0)}))},limits:{fileSize:s}}),n=(null==e?void 0:e.count)||Q,o=(null==e?void 0:e.field)||V,a=i.array(o,n);return(e,t,r)=>{a(e,t,(function(e){return e?ve.error(t,e.message):r()}))}}validation(e){return(t,r,s)=>x(this,void 0,void 0,(function*(){const{error:n,value:o}=yield i.object(e).validateAsync(t.body);return n?ve.validation(r,n):(t.body=o,s())}))}write(e=""){return this.permission((e||this.name())+".write")}}class Te extends Ae{constructor(){super(...arguments),this.attributes=["id","name","email","username"],this.query={username:i.string().min(4).required(),password:i.string().min(5).required()}}intialize(){this.router.get("/",this.auth,this.user.bind(this)),this.router.post("/login",this.validation(this.query),this.login.bind(this)),this.router.get("/logout",this.auth,this.logout.bind(this))}login(e,t){return x(this,void 0,void 0,(function*(){yield s(z);const{username:r,password:i}=e.body,n=yield ue.findOne({where:{username:r}}).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)}));if(!n)return ve.notfound(t,"Username not found");if(!n.state)return ve.error(t,"Username is disabled");const a=k(i).toString();if(n.password!=a)return ve.error(t,"Invalid password");const d=n.id,u=o(),{error:c,token:l}=we.sign({id:d,secret:u});if(c)return ve.error(t,c);if(l){const r=Date.now(),s=r+6e4*Z,i=e.get("User-Agent"),n=yield ne.create({login:r,secret:u,timestamp:s,useragent:i,userId:d}).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)}));if(n)return ve.data(t,{token:l})}return ve.error(t,"Internal Server Error")}))}logout(e,t){return x(this,void 0,void 0,(function*(){const r=e.auth;return r?(r.logout=Date.now(),r.timestamp=r.logout,yield r.save(),ve.success(t,"Disconcerted")):ve.unauthorized(t,"Access denied")}))}user(e,t){return x(this,void 0,void 0,(function*(){const r=e.user;if(!r)return ve.unauthorized(t,"Access denied");const s=yield Se.all(r);if(s){const e=a(this.attributes,r.toJSON()),i=s.map((e=>e.name));return ve.data(t,Object.assign(Object.assign({},e),{permissions:i}))}return ve.error(t,"Internal Server Error")}))}}class Ee extends Ae{add(){return(e,t)=>x(this,void 0,void 0,(function*(){if(!this._model)return ve.error(t,"Internal Server Error");const r=yield this._model.create(e.body).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)}));return r?ve.data(t,{id:r.id}):ve.error(t,"Internal Server Error")}))}all(e,t){return(r,s)=>x(this,void 0,void 0,(function*(){var i,n,o,a,l;if(!this._model)return ve.error(s,"Internal Server Error");const h=Object.assign({},e||{});h.where=Object.assign({},h.where||{});const p=null===(i=r.query.limit)||void 0===i?void 0:i.toString();p&&(h.limit=parseInt(p));const m=null===(n=r.query.offset)||void 0===n?void 0:n.toString();m&&(h.offset=parseInt(m));const v=Object.keys(this._model.getAttributes()),g=[],f=null===(o=r.query.asc)||void 0===o?void 0:o.toString();f&&f.length&&f.split(",").forEach((e=>{v.indexOf(e)>=0&&g.push([e,"ASC"])}));const y=null===(a=r.query.desc)||void 0===a?void 0:a.toString();y&&y.length&&y.split(",").forEach((e=>{v.indexOf(e)>=0&&g.push([e,"DESC"])})),g.length&&(h.order=g);const w=[],I=d(h.attributes)?h.attributes:v,b=null===(l=r.query.search)||void 0===l?void 0:l.toString();I.forEach((e=>{var t;if(u(e)&&(b&&b.length&&w.push({[e]:{[E.like]:`%${b}%`}}),"search_"+e in r.query)){const s=null===(t=r.query["search_"+e])||void 0===t?void 0:t.toString();s&&s.length&&w.push({[e]:{[E.like]:`%${s}%`}})}})),w.length&&(h.where=Object.assign(Object.assign({},h.where),{[E.or]:[...w]}));const S=yield this._model.findAll(h).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)})),_=yield this._model.count(h).catch(c);return S?ve.data(s,{count:_,records:t?t(S):S}):ve.error(s,"Internal Server Error")}))}del(){return(e,t)=>x(this,void 0,void 0,(function*(){if(!this._model)return ve.error(t,"Internal Server Error");const{id:r}=e.params;return(yield this._model.destroy({where:{id:r}}).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)})))?ve.success(t,"OK"):ve.notfound(t,"Record not found")}))}get(e,t){return(r,s)=>x(this,void 0,void 0,(function*(){if(!this._model)return ve.error(s,"Internal Server Error");e||(e={});const i=Object.assign({},e);i.where=i.where?Object.assign({},i.where):{};const{id:n}=r.params,o=yield this._model.findByPk(n,i).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)}));return o?ve.data(s,t?t(o):o.toJSON()):null===o?ve.notfound(s,"Record not found"):ve.error(s,"Internal Server Error")}))}name(){var e;return this._model?null===(e=this._model)||void 0===e?void 0:e.tableName:super.name()}set(){return(e,t)=>x(this,void 0,void 0,(function*(){if(!this._model)return ve.error(t,"Internal Server Error");const{id:r}=e.params,[s]=(yield this._model.update(e.body,{where:{id:r}}).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)})))||[];return s?ve.success(t,"OK"):ve.success(t,"Record not changed")}))}getModel(){return this._model}setModel(e){this._model=e}}class Oe extends Ee{intialize(){const e=this.model();e&&this.setModel(e),this.router.use(this.auth),this.router.get("/",this.read(),this.all().bind(this)),this.router.post("/",this.write(),this.validation(this.create()),this.add().bind(this)),this.router.route("/:id").get(this.read(),this.get().bind(this)).put(this.write(),this.validation(this.update()),this.set().bind(this)).delete(this.write(),this.del().bind(this))}}class Re extends Oe{create(){return{name:i.string().required(),description:i.string().empty(""),state:i.boolean().required()}}model(){return oe}update(){return{name:i.string().empty(),description:i.string().empty(),state:i.boolean().empty()}}}class qe extends Ee{constructor(){super(...arguments),this.groups={groups:i.array().items(i.number())}}intialize(){this.setModel(de),this.router.use(this.auth),this.router.route("/:id/groups").get(this.read("users"),this.groupRouteAll.bind(this)).put(this.write("users"),this.validation(this.groups),this.groupRouteSet.bind(this))}groupRouteAll(e,t){return x(this,void 0,void 0,(function*(){const{id:r}=e.params;return this.all({where:{groupId:r},include:[{model:ae,required:!0}]},(e=>e.map((e=>e.route))))(e,t)}))}groupRouteSet(e,t){return x(this,void 0,void 0,(function*(){const{id:r}=e.params,{routes:s}=e.body,i=yield oe.findByPk(r,{attributes:["id"]}).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)}));if(i){const e=i.id;if(yield de.destroy({where:{groupId:e}}),s){let t=0;for(let r=0;r<s.length;r++)t=yield ae.count({where:{id:s[r]}}),t&&(yield de.create({groupId:e,routeId:s[r]}))}return ve.success(t,"OK")}return null===i?ve.notfound(t,"Record not found"):ve.error(t,"Internal Server Error")}))}}class Ne extends Ee{intialize(){this.setModel(he),this.router.use(this.auth),this.router.get("/",this.read("logs"),this.logsAll.bind(this))}logsAll(e,t){return x(this,void 0,void 0,(function*(){const{source:r,type:s}=e.query,i=r&&s?{source:r,type:s}:r?{source:r}:s?{type:s}:{};return this.all({where:i,order:[["created","DESC"]]})(e,t)}))}}class Pe extends Oe{create(){return{name:i.string().required(),description:i.string().empty(""),state:i.boolean().required()}}model(){return ae}update(){return{name:i.string().empty(),description:i.string().empty(),state:i.boolean().empty()}}}class ke extends Ee{constructor(){super(...arguments),this.attributes=["id","name","email","username","description","state"],this.create={name:i.string().required(),email:i.string().email().required(),username:i.string().min(4).required(),password:i.string().min(5).required(),description:i.string().required(),state:i.boolean().required()},this.update={name:i.string().empty(),email:i.string().email().empty(),username:i.string().min(4).empty(),password:i.string().min(5).empty(),description:i.string().empty(),state:i.boolean().empty()}}intialize(){this.setModel(ue),this.router.use(this.auth),this.router.get("/",this.read(),this.userAll.bind(this)),this.router.post("/",this.write(),this.validation(this.create),this.userAdd.bind(this)),this.router.route("/:id").get(this.read(),this.userGet.bind(this)).put(this.write(),this.validation(this.update),this.userSet.bind(this)).delete(this.write(),this.userDel.bind(this))}userAdd(e,t){return x(this,void 0,void 0,(function*(){return e.body.password=k(e.body.password).toString(),yield this.add()(e,t)}))}userAll(e,t){return x(this,void 0,void 0,(function*(){return this.all({attributes:this.attributes})(e,t)}))}userDel(e,t){return x(this,void 0,void 0,(function*(){const r=e.user;if(r){const{id:s}=e.params;if(r.id.toString()!=s)return this.del()(e,t)}return ve.error(t,"Internal Server Error")}))}userGet(e,t){return x(this,void 0,void 0,(function*(){return this.get({attributes:this.attributes})(e,t)}))}userSet(e,t){return x(this,void 0,void 0,(function*(){return e.body.password&&(e.body.password=k(e.body.password).toString()),this.set()(e,t)}))}}class xe extends Ee{constructor(){super(...arguments),this.groups={groups:i.array(i.number())}}intialize(){this.setModel(ce),this.router.use(this.auth),this.router.route("/:id/groups").get(this.read("groups"),this.userGroupsAll.bind(this)).put(this.write("groups"),this.validation(this.groups),this.userGroupsSet.bind(this))}userGroupsAll(e,t){return x(this,void 0,void 0,(function*(){const{id:r}=e.params;return this.all({where:{userId:r},include:[{model:oe,required:!0}]},(e=>e.map((e=>e.group))))(e,t)}))}userGroupsSet(e,t){return x(this,void 0,void 0,(function*(){const{id:r}=e.params,{groups:s}=e.body,i=yield ue.findByPk(r,{attributes:["id"]}).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)}));if(i){if(yield ce.destroy({where:{userId:i.id}}),s){let e=0;for(let t=0;t<s.length;t++)e=yield oe.count({where:{id:s[t]}}),e&&(yield ce.create({userId:i.id,groupId:s[t]}))}return ve.success(t,"OK")}return ve.notfound(t,"Record not found")}))}}export{z as API_AUTH_SLEEP,D as API_DB_DATABASE,G as API_DB_HOST,U as API_DB_LOG,j as API_DB_PASSWORD,B as API_DB_PORT,M as API_DB_TYPE,C as API_DB_USERNAME,W as API_HTTP_CROSS,L as API_HTTP_CRT,X as API_HTTP_HYBRID,H as API_HTTP_KEY,K as API_HTTP_PORT,F as API_HTTP_PUBLIC,Y as API_TOKEN_CRT,$ as API_TOKEN_HEADER,J as API_TOKEN_KEY,Z as API_TOKEN_LIFETIME,Q as API_UPLOAD_COUNT,V as API_UPLOAD_FIELD,ee as API_UPLOAD_SIZE,te as API_UPLOAD_TEMP,re as API_WEBSOCKET_START,Ie as App,ne as Auth,Te as AuthController,be as Config,le as Configs,Ae as Controller,Oe as CrudController,se as Database,oe as Group,Re as GroupController,de as GroupRoute,qe as GroupRouteController,me as Log,he as Logs,Ne as LogsController,Ee as ModelController,Se as Permission,ve as Responses,ae as Route,Pe as RouteController,we as Token,ue as User,ke as UserController,ce as UserGroup,xe as UserGroupController,fe as crt,ye as key,ie as sequelize};
7
+ import{toBool as e,dateFormat as t,EventEmitter as r,sleep as s,Validation as i,uuidv4 as n,uniqueID as o,allowedObject as a,isArray as d,isString as u,noop as c}from"@andrewcaires/utils.js";import l from"cors";import h,{Router as p,json as m,urlencoded as v}from"express";import{existsSync as g,readFileSync as f}from"fs";import*as y from"http";import*as w from"https";import{Server as I}from"net";import b from"ws";import{config as _}from"dotenv";import{Sequelize as S,DataTypes as A,Model as T,Op as E}from"sequelize";import{sign as O,verify as R}from"jsonwebtoken";import N from"mime-types";import P from"multer";import{join as q}from"path";import{SHA256 as k}from"crypto-js";function x(e,t,r,s){return new(r||(r=Promise))((function(i,n){function o(e){try{d(s.next(e))}catch(e){n(e)}}function a(e){try{d(s.throw(e))}catch(e){n(e)}}function d(e){var t;e.done?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(o,a)}d((s=s.apply(e,t||[])).next())}))}_();const z=parseInt(process.env.API_AUTH_SLEEP||"1000"),D=process.env.API_DB_DATABASE||"",G=process.env.API_DB_HOST||"127.0.0.1",j=process.env.API_DB_PASSWORD||"",B=parseInt(process.env.API_DB_PORT||"3306"),C=process.env.API_DB_TYPE||"",M=process.env.API_DB_USERNAME||"root",L=e(process.env.API_DB_LOG||"false"),U=process.env.API_HTTP_CRT||"",H=process.env.API_HTTP_KEY||"",K=parseInt(process.env.API_HTTP_PORT||"3000"),F=process.env.API_HTTP_PUBLIC||"",W=e(process.env.API_HTTP_CROSS||"false"),X=e(process.env.API_HTTP_HYBRID||"false"),Y=process.env.API_TOKEN_CRT||"",J=process.env.API_TOKEN_KEY||"",$=process.env.API_TOKEN_HEADER||"authorization",Z=parseInt(process.env.API_TOKEN_LIFETIME||"15"),Q=parseInt(process.env.API_UPLOAD_COUNT||"1"),V=process.env.API_UPLOAD_FIELD||"upload",ee=parseInt(process.env.API_UPLOAD_SIZE||"2"),te=process.env.API_UPLOAD_TEMP||"./temp",re=e(process.env.API_WEBSOCKET_START||"false");class se{static connect(e){const t=C.toLowerCase();if("connect_"+t in se)return se["connect_"+t](e);throw new Error("No database is connected to this API")}static connect_mariadb(e){return new S(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"mariadb",logging:L,define:{timestamps:!1}})}static connect_memory(){return new S("sqlite::memory:",{logging:L,define:{timestamps:!1}})}static connect_mysql(e){return new S(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"mysql",logging:L,define:{timestamps:!1}})}static connect_postgres(e){return new S(e.database,e.username,e.password,{host:e.hostname,port:e.hostport,dialect:"postgres",logging:L,define:{timestamps:!1}})}static connect_sqlite(e){return new S({dialect:"sqlite",storage:e.database,logging:L,define:{timestamps:!1}})}}const ie=se.connect({database:D,username:M,password:j,hostname:G,hostport:B});class ne extends T{}ne.init({login:A.BIGINT,logout:A.BIGINT,secret:A.STRING,timestamp:A.BIGINT,useragent:A.STRING},{sequelize:ie,modelName:"auth"});class oe extends T{}oe.init({name:A.STRING,description:A.TEXT,state:A.BOOLEAN},{sequelize:ie,modelName:"group"});class ae extends T{}ae.init({name:A.STRING,description:A.TEXT,state:A.BOOLEAN},{sequelize:ie,modelName:"route"});class de extends T{}de.init({},{sequelize:ie,modelName:"groups_routes"}),de.removeAttribute("id");class ue extends T{}ue.init({name:A.STRING,email:A.STRING,username:A.STRING,password:A.STRING,description:A.TEXT,state:A.BOOLEAN},{sequelize:ie,modelName:"user"});class ce extends T{}ce.init({},{sequelize:ie,modelName:"users_groups"}),ce.removeAttribute("id");class le extends T{}le.init({key:A.STRING,value:A.STRING},{sequelize:ie,modelName:"configs",timestamps:!0,createdAt:"created",updatedAt:"updated"}),le.removeAttribute("id");class he extends T{}var pe;he.init({type:A.STRING,source:A.STRING,message:A.TEXT},{sequelize:ie,modelName:"logs",timestamps:!0,createdAt:"created",updatedAt:!1}),ue.hasMany(ne),ne.belongsTo(ue),oe.hasMany(de),de.belongsTo(oe),ae.hasMany(de),de.belongsTo(ae),ue.hasMany(ce),ce.belongsTo(ue),oe.hasMany(ce),ce.belongsTo(oe),function(e){e.ERROR="",e.INFO="",e.NONE="",e.SUCCESS="",e.WARNING=""}(pe||(pe={}));class me{static write(e,t,r){return x(this,void 0,void 0,(function*(){yield me.writeRaw(pe.NONE,"",e,t,r)}))}static error(e,t,r){return x(this,void 0,void 0,(function*(){yield me.writeRaw(pe.ERROR,"error",e,t,r)}))}static info(e,t,r){return x(this,void 0,void 0,(function*(){yield me.writeRaw(pe.INFO,"info",e,t,r)}))}static success(e,t,r){return x(this,void 0,void 0,(function*(){yield me.writeRaw(pe.ERROR,"success",e,t,r)}))}static warning(e,t,r){return x(this,void 0,void 0,(function*(){yield me.writeRaw(pe.WARNING,"warning",e,t,r)}))}static writeConsole(e,r,s){const i=t(new Date,"%H:%M:%S");console.log(">",e,r+" ".repeat(10-r.length),"","|",i,"|",s)}static writeRaw(e,t,r,s,i){return x(this,void 0,void 0,(function*(){i&&me.writeConsole(e,t,r),ie&&(yield he.create({type:t,source:s,message:r}).catch((()=>null)))}))}}class ve{static success(e,t){return e.status(200).json({message:t})}static data(e,t){return e.status(200).json(Object.assign({},t))}static error(e,t){return e.status(500).json({message:t})}static list(e,t){return e.status(200).json([...t])}static notfound(e,t){return e.status(404).json({message:t})}static validation(e,t){return e.status(400).json({message:t})}static unauthorized(e,t){return e.status(401).json({message:t})}}const ge=e=>g(e)?f(e):void 0,fe={http:ge(U),token:ge(Y)},ye={http:ge(H),token:ge(J)};class we{static sign(e){return ye.token?{token:O(e,ye.token,{algorithm:"RS256"})}:{error:"Invalid Secret"}}static user(e){return x(this,void 0,void 0,(function*(){const{error:t,decode:r}=we.verify(e);if(t)return{error:t};if(r){const{id:e,secret:t}=r;if(e&&r){const r=yield ue.findOne({where:{id:e,state:!0}}).catch((e=>{me.error(e.message,"api.token",!0)}));if(r){const e=yield ne.findOne({where:{secret:t,userId:r.id}}).catch((e=>{me.error(e.message,"api.token",!0)}));if(e){const t=Date.now();if(t>e.timestamp)return{error:"Expired token"};if(e.timestamp=t+6e4*Z,yield e.save(),!e.logout)return{auth:e,user:r}}}return{error:"Access denied"}}}return{error:"Invalid token"}}))}static verify(e){if(!fe.token)return{error:"Invalid Secret"};if(!e||e.split(".").length<3)return{error:"Invalid Token"};try{return{decode:R(e,fe.token)}}catch(e){return{error:"Invalid Token"}}}}class Ie extends r{constructor(e){super(),this.app=h(),this.router=p(),this.middlewares(),this.controllers(e)}controllers(e){e.forEach((e=>{e.intialize(),this.router.use(e.path(),e.router)}))}listen(){return x(this,void 0,void 0,(function*(){if(yield ie.sync(),fe.http&&ye.http||(this._server=y.createServer(this.app),this._server.listen(K,(()=>me.info("Server started on port "+K,"api.server",!0)))),!this._server){const e=y.createServer(((e,t)=>{const r=80==K?":80":"";t.writeHead(301,{Location:"https://"+e.headers.host+r+e.url}),t.end()})),t=w.createServer({key:ye.http,cert:fe.http},this.app);if(X){new I((r=>{r.once("data",(s=>{r.pause(),r.unshift(s),(22===s[0]?t:e).emit("connection",r),process.nextTick((()=>r.resume()))}))})).listen(K,(()=>me.info("Server started on port "+K,"api.server",!0))),this._server=t}this._server||(443==K&&e.listen(80,(()=>me.info("Server started on port 80","api.server",!0))),t.listen(K,(()=>me.info("Server started on port "+K,"api.server",!0))),this._server=t)}re&&this._server&&(this._webSocket=new b.Server({server:this._server,verifyClient:(e,t)=>t(re)}),this._webSocket.on("connection",((e,t)=>x(this,void 0,void 0,(function*(){t.url||(t.url="");const r=t.url.length<=1?"":t.url.replace(/\//g,".");let i;e.on("message",(s=>x(this,void 0,void 0,(function*(){if(i)try{const n=JSON.parse(s);this.emit("ws.message"+r,{data:n,message:s,req:t,user:i,ws:e})}catch(n){this.emit("ws.message"+r,{message:s,req:t,user:i,ws:e})}else{const{user:n}=yield we.user(s.toString());n&&(i=n,this.emit("ws.connection"+r,{req:t,user:i,ws:e}))}i||e.close()})))),e.on("close",(()=>{i&&this.emit("ws.close"+r,{user:i,ws:e})})),yield s(2e3),i||e.close()})))))}))}middlewares(){this.app.use(m()),this.app.use(((e,t,r,s)=>e?(me.error(e.message,"api.express",!0),ve.error(r,"Internal Server Error")):s())),this.app.use(v({extended:!0})),this.app.disable("x-powered-by"),W&&this.app.use(l()),this.app.use("/api",this.router),this.app.all("/api/*",((e,t)=>ve.notfound(t,"Invalid API"))),F&&(g(F)&&this.app.use(h.static(F)),this.app.get("*",((e,t)=>{if(!g(F))return ve.notfound(t,'File "index.html" not found');t.sendFile(F+"/index.html")})))}server(){return this._server}websocket(){return this._webSocket}}class be{static all(){return x(this,void 0,void 0,(function*(){const e=yield le.findAll().catch((e=>{me.error(e.message,"api.config",!0)})),t={};return e&&e.forEach((e=>{t[e.key]=e.value})),t}))}static del(e){return x(this,void 0,void 0,(function*(){return((yield le.destroy({where:{key:e}}).catch((e=>{me.error(e.message,"api.config",!0)})))||0)>0}))}static get(e){return x(this,void 0,void 0,(function*(){const t=yield le.findOne({where:{key:e}}).catch((e=>{me.error(e.message,"api.config",!0)}));return t&&t.value||""}))}static set(e,t){return x(this,void 0,void 0,(function*(){const[r]=(yield le.findOrCreate({where:{key:e}}).catch((e=>{me.error(e.message,"api.config",!0)})))||[];r&&(r.value=t,yield r.save().catch((e=>{me.error(e.message,"api.config",!0)})))}))}}class _e{static all(e,t){return x(this,void 0,void 0,(function*(){return yield ae.findAll({where:Object.assign(Object.assign({},t),{state:!0}),include:[{model:de,required:!0,include:[{model:oe,required:!0,where:{state:!0},include:[{model:ce,required:!0,where:{userId:e.id}}]}]}]}).catch((e=>{me.error(e.message,"api.permission",!0)}))}))}static get(e){return x(this,void 0,void 0,(function*(){const t=yield _e.all(e);return t?t.map((e=>e.name)):[]}))}static is(e,t){return x(this,void 0,void 0,(function*(){const r=yield _e.all(e,{name:t});return r&&!!r.length}))}}const Se=(e,t)=>{const r=n()+"."+t;return g(q(e,r))?Se(e,t):r};class Ae{constructor(e){this.router=p(),this._path=e}auth(e,t,r){return x(this,void 0,void 0,(function*(){const s=e.get($)||"",{auth:i,error:n,user:o}=yield we.user(s);if(n)return ve.error(t,n);if(i&&o){const t=e.get("User-Agent");return t&&(i.useragent=t),yield i.save(),e.auth=i,e.user=o,r()}return ve.error(t,"Internal Server Error")}))}intialize(){}name(){return"api"}path(){return this._path}permission(e){return(t,r,s)=>x(this,void 0,void 0,(function*(){const i=t.user;return i?(yield _e.is(i,e))?s():ve.error(r,"Unauthorized access"):ve.unauthorized(r,"Access denied")}))}read(e=""){return this.permission((e||this.name())+".read")}upload(e){const t=(null==e?void 0:e.path)||te,r=P.diskStorage({destination:(e,r,s)=>s(null,t),filename:(e,r,s)=>x(this,void 0,void 0,(function*(){return s(null,Se(t,N.extension(r.mimetype)||"bin"))}))}),s=1e6*((null==e?void 0:e.size)||ee),i=P({storage:r,fileFilter(t,r,s){var i;return x(this,void 0,void 0,(function*(){const t=null===(i=null==e?void 0:e.types)||void 0===i?void 0:i.indexOf(r.mimetype);return void 0!==t&&t<0?s(new Error("File type not allowed")):s(null,!0)}))},limits:{fileSize:s}}),n=(null==e?void 0:e.count)||Q,o=(null==e?void 0:e.field)||V,a=i.array(o,n);return(e,t,r)=>{a(e,t,(function(e){return e?ve.error(t,e.message):r()}))}}validation(e){return(t,r,s)=>x(this,void 0,void 0,(function*(){const{error:n,value:o}=yield i.object(e).validateAsync(t.body);return n?ve.validation(r,n):(t.body=o,s())}))}write(e=""){return this.permission((e||this.name())+".write")}}class Te extends Ae{constructor(){super(...arguments),this.attributes=["id","name","email","username"],this.query={username:i.string().min(4).required(),password:i.string().min(5).required()}}intialize(){this.router.get("/",this.auth,this.user.bind(this)),this.router.post("/login",this.validation(this.query),this.login.bind(this)),this.router.get("/logout",this.auth,this.logout.bind(this))}login(e,t){return x(this,void 0,void 0,(function*(){yield s(z);const{username:r,password:i}=e.body,n=yield ue.findOne({where:{username:r}}).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)}));if(!n)return ve.notfound(t,"Username not found");if(!n.state)return ve.error(t,"Username is disabled");const a=k(i).toString();if(n.password!=a)return ve.error(t,"Invalid password");const d=n.id,u=o(),{error:c,token:l}=we.sign({id:d,secret:u});if(c)return ve.error(t,c);if(l){const r=Date.now(),s=r+6e4*Z,i=e.get("User-Agent"),n=yield ne.create({login:r,secret:u,timestamp:s,useragent:i,userId:d}).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)}));if(n)return ve.data(t,{token:l})}return ve.error(t,"Internal Server Error")}))}logout(e,t){return x(this,void 0,void 0,(function*(){const r=e.auth;return r?(r.logout=Date.now(),r.timestamp=r.logout,yield r.save(),ve.success(t,"Disconcerted")):ve.unauthorized(t,"Access denied")}))}user(e,t){return x(this,void 0,void 0,(function*(){const r=e.user;if(!r)return ve.unauthorized(t,"Access denied");const s=yield _e.all(r);if(s){const e=a(this.attributes,r.toJSON()),i=s.map((e=>e.name));return ve.data(t,Object.assign(Object.assign({},e),{permissions:i}))}return ve.error(t,"Internal Server Error")}))}}class Ee extends Ae{add(){return(e,t)=>x(this,void 0,void 0,(function*(){if(!this._model)return ve.error(t,"Internal Server Error");const r=yield this._model.create(e.body).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)}));return r?ve.data(t,{id:r.id}):ve.error(t,"Internal Server Error")}))}all(e,t){return(r,s)=>x(this,void 0,void 0,(function*(){var i,n,o,a,l;if(!this._model)return ve.error(s,"Internal Server Error");const h=Object.assign({},e||{});h.where=Object.assign({},h.where||{});const p=null===(i=r.query.limit)||void 0===i?void 0:i.toString();p&&(h.limit=parseInt(p));const m=null===(n=r.query.offset)||void 0===n?void 0:n.toString();m&&(h.offset=parseInt(m));const v=Object.keys(this._model.getAttributes()),g=[],f=null===(o=r.query.asc)||void 0===o?void 0:o.toString();f&&f.length&&f.split(",").forEach((e=>{v.indexOf(e)>=0&&g.push([e,"ASC"])}));const y=null===(a=r.query.desc)||void 0===a?void 0:a.toString();y&&y.length&&y.split(",").forEach((e=>{v.indexOf(e)>=0&&g.push([e,"DESC"])})),g.length&&(h.order=g);const w=[],I=d(h.attributes)?h.attributes:v,b=null===(l=r.query.search)||void 0===l?void 0:l.toString();I.forEach((e=>{var t;if(u(e)&&(b&&b.length&&w.push({[e]:{[E.like]:`%${b}%`}}),"search_"+e in r.query)){const s=null===(t=r.query["search_"+e])||void 0===t?void 0:t.toString();s&&s.length&&w.push({[e]:{[E.like]:`%${s}%`}})}})),w.length&&(h.where=Object.assign(Object.assign({},h.where),{[E.or]:[...w]}));const _=yield this._model.findAll(h).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)})),S=yield this._model.count(h).catch(c);return _?ve.data(s,{count:S,records:t?t(_):_}):ve.error(s,"Internal Server Error")}))}del(){return(e,t)=>x(this,void 0,void 0,(function*(){if(!this._model)return ve.error(t,"Internal Server Error");const{id:r}=e.params;return(yield this._model.destroy({where:{id:r}}).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)})))?ve.success(t,"OK"):ve.notfound(t,"Record not found")}))}get(e,t){return(r,s)=>x(this,void 0,void 0,(function*(){if(!this._model)return ve.error(s,"Internal Server Error");e||(e={});const i=Object.assign({},e);i.where=i.where?Object.assign({},i.where):{};const{id:n}=r.params,o=yield this._model.findByPk(n,i).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)}));return o?ve.data(s,t?t(o):o.toJSON()):null===o?ve.notfound(s,"Record not found"):ve.error(s,"Internal Server Error")}))}name(){var e;return this._model?null===(e=this._model)||void 0===e?void 0:e.tableName:super.name()}set(){return(e,t)=>x(this,void 0,void 0,(function*(){if(!this._model)return ve.error(t,"Internal Server Error");const{id:r}=e.params,[s]=(yield this._model.update(e.body,{where:{id:r}}).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)})))||[];return s?ve.success(t,"OK"):ve.success(t,"Record not changed")}))}getModel(){return this._model}setModel(e){this._model=e}}class Oe extends Ee{intialize(){const e=this.model();e&&this.setModel(e),this.router.use(this.auth),this.router.get("/",this.read(),this.all().bind(this)),this.router.post("/",this.write(),this.validation(this.create()),this.add().bind(this)),this.router.route("/:id").get(this.read(),this.get().bind(this)).put(this.write(),this.validation(this.update()),this.set().bind(this)).delete(this.write(),this.del().bind(this))}}class Re extends Oe{create(){return{name:i.string().required(),description:i.string().empty(""),state:i.boolean().required()}}model(){return oe}update(){return{name:i.string().empty(),description:i.string().empty(),state:i.boolean().empty()}}}class Ne extends Ee{constructor(){super(...arguments),this.groups={groups:i.array().items(i.number())}}intialize(){this.setModel(de),this.router.use(this.auth),this.router.route("/:id/groups").get(this.read("users"),this.groupRouteAll.bind(this)).put(this.write("users"),this.validation(this.groups),this.groupRouteSet.bind(this))}groupRouteAll(e,t){return x(this,void 0,void 0,(function*(){const{id:r}=e.params;return this.all({where:{groupId:r},include:[{model:ae,required:!0}]},(e=>e.map((e=>e.route))))(e,t)}))}groupRouteSet(e,t){return x(this,void 0,void 0,(function*(){const{id:r}=e.params,{routes:s}=e.body,i=yield oe.findByPk(r,{attributes:["id"]}).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)}));if(i){const e=i.id;if(yield de.destroy({where:{groupId:e}}),s){let t=0;for(let r=0;r<s.length;r++)t=yield ae.count({where:{id:s[r]}}),t&&(yield de.create({groupId:e,routeId:s[r]}))}return ve.success(t,"OK")}return null===i?ve.notfound(t,"Record not found"):ve.error(t,"Internal Server Error")}))}}class Pe extends Ee{intialize(){this.setModel(he),this.router.use(this.auth),this.router.get("/",this.read("logs"),this.logsAll.bind(this))}logsAll(e,t){return x(this,void 0,void 0,(function*(){const{source:r,type:s}=e.query,i=r&&s?{source:r,type:s}:r?{source:r}:s?{type:s}:{};return this.all({where:i,order:[["created","DESC"]]})(e,t)}))}}class qe extends Oe{create(){return{name:i.string().required(),description:i.string().empty(""),state:i.boolean().required()}}model(){return ae}update(){return{name:i.string().empty(),description:i.string().empty(),state:i.boolean().empty()}}}class ke extends Ee{constructor(){super(...arguments),this.attributes=["id","name","email","username","description","state"],this.create={name:i.string().required(),email:i.string().email().required(),username:i.string().min(4).required(),password:i.string().min(5).required(),description:i.string().required(),state:i.boolean().required()},this.update={name:i.string().empty(),email:i.string().email().empty(),username:i.string().min(4).empty(),password:i.string().min(5).empty(),description:i.string().empty(),state:i.boolean().empty()}}intialize(){this.setModel(ue),this.router.use(this.auth),this.router.get("/",this.read(),this.userAll.bind(this)),this.router.post("/",this.write(),this.validation(this.create),this.userAdd.bind(this)),this.router.route("/:id").get(this.read(),this.userGet.bind(this)).put(this.write(),this.validation(this.update),this.userSet.bind(this)).delete(this.write(),this.userDel.bind(this))}userAdd(e,t){return x(this,void 0,void 0,(function*(){return e.body.password=k(e.body.password).toString(),yield this.add()(e,t)}))}userAll(e,t){return x(this,void 0,void 0,(function*(){return this.all({attributes:this.attributes})(e,t)}))}userDel(e,t){return x(this,void 0,void 0,(function*(){const r=e.user;if(r){const{id:s}=e.params;if(r.id.toString()!=s)return this.del()(e,t)}return ve.error(t,"Internal Server Error")}))}userGet(e,t){return x(this,void 0,void 0,(function*(){return this.get({attributes:this.attributes})(e,t)}))}userSet(e,t){return x(this,void 0,void 0,(function*(){return e.body.password&&(e.body.password=k(e.body.password).toString()),this.set()(e,t)}))}}class xe extends Ee{constructor(){super(...arguments),this.groups={groups:i.array(i.number())}}intialize(){this.setModel(ce),this.router.use(this.auth),this.router.route("/:id/groups").get(this.read("groups"),this.userGroupsAll.bind(this)).put(this.write("groups"),this.validation(this.groups),this.userGroupsSet.bind(this))}userGroupsAll(e,t){return x(this,void 0,void 0,(function*(){const{id:r}=e.params;return this.all({where:{userId:r},include:[{model:oe,required:!0}]},(e=>e.map((e=>e.group))))(e,t)}))}userGroupsSet(e,t){return x(this,void 0,void 0,(function*(){const{id:r}=e.params,{groups:s}=e.body,i=yield ue.findByPk(r,{attributes:["id"]}).catch((e=>{me.error(e.message,"api.controller."+this.name(),!0)}));if(i){if(yield ce.destroy({where:{userId:i.id}}),s){let e=0;for(let t=0;t<s.length;t++)e=yield oe.count({where:{id:s[t]}}),e&&(yield ce.create({userId:i.id,groupId:s[t]}))}return ve.success(t,"OK")}return ve.notfound(t,"Record not found")}))}}export{z as API_AUTH_SLEEP,D as API_DB_DATABASE,G as API_DB_HOST,L as API_DB_LOG,j as API_DB_PASSWORD,B as API_DB_PORT,C as API_DB_TYPE,M as API_DB_USERNAME,W as API_HTTP_CROSS,U as API_HTTP_CRT,X as API_HTTP_HYBRID,H as API_HTTP_KEY,K as API_HTTP_PORT,F as API_HTTP_PUBLIC,Y as API_TOKEN_CRT,$ as API_TOKEN_HEADER,J as API_TOKEN_KEY,Z as API_TOKEN_LIFETIME,Q as API_UPLOAD_COUNT,V as API_UPLOAD_FIELD,ee as API_UPLOAD_SIZE,te as API_UPLOAD_TEMP,re as API_WEBSOCKET_START,Ie as App,ne as Auth,Te as AuthController,be as Config,le as Configs,Ae as Controller,Oe as CrudController,se as Database,oe as Group,Re as GroupController,de as GroupRoute,Ne as GroupRouteController,me as Log,he as Logs,Pe as LogsController,Ee as ModelController,_e as Permission,ve as Responses,ae as Route,qe as RouteController,we as Token,ue as User,ke as UserController,ce as UserGroup,xe as UserGroupController,fe as crt,ye as key,ie as sequelize};
package/package.json CHANGED
@@ -1,21 +1,31 @@
1
1
  {
2
2
  "name": "@andrewcaires/api",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "description": "Simple api for small applications using express, jsonwebtoken, sequelize and websocket",
5
- "main": "dist/index.cjs.js",
6
- "module": "dist/index.esm.js",
7
- "types": "dist/index.d.ts",
5
+ "main": "./dist/index.cjs.js",
6
+ "types": "./dist/index.d.ts",
7
+ "module": "./dist/index.esm.js",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.esm.js",
12
+ "require": "./dist/index.cjs.js",
13
+ "default": "./dist/index.cjs.js"
14
+ },
15
+ "./package.json": "./package.json"
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
8
20
  "scripts": {
9
- "build": "rollup -c build/rollup.config.js",
10
- "dev": "ts-node-dev --respawn --transpile-only ./src/dev.ts",
11
- "lint": "eslint . --ext .ts --fix"
21
+ "build": "rollup --bundleConfigAsCjs -c rollup.config.js",
22
+ "dev": "ts-node-dev --respawn --transpile-only ./src/dev.ts"
12
23
  },
13
24
  "repository": {
14
25
  "type": "git",
15
26
  "url": "git+https://github.com/andrewcaires/npm.git"
16
27
  },
17
28
  "keywords": [
18
- "app",
19
29
  "api",
20
30
  "auth",
21
31
  "express",
@@ -35,41 +45,38 @@
35
45
  },
36
46
  "homepage": "https://github.com/andrewcaires/npm/tree/main/api#readme",
37
47
  "dependencies": {
38
- "@andrewcaires/utils.js": "^0.2.2",
48
+ "@andrewcaires/utils.js": "^0.2.5",
39
49
  "cors": "^2.8.5",
40
50
  "crypto-js": "^4.1.1",
41
51
  "dotenv": "^16.0.3",
42
52
  "express": "^4.18.2",
43
53
  "jsonwebtoken": "^8.5.1",
44
- "mariadb": "^3.0.1",
54
+ "mariadb": "^3.0.2",
45
55
  "mime-types": "^2.1.35",
46
56
  "multer": "^1.4.5-lts.1",
47
57
  "mysql2": "^2.3.3",
48
- "pg": "^8.8.0",
49
- "pg-hstore": "^2.3.4",
50
- "sequelize": "^6.25.0",
51
- "sqlite3": "^5.1.2",
52
- "ws": "^8.9.0"
58
+ "sequelize": "^6.25.3",
59
+ "ws": "^8.10.0"
53
60
  },
54
61
  "devDependencies": {
55
- "@rollup/plugin-commonjs": "^23.0.0",
56
- "@rollup/plugin-typescript": "^9.0.1",
62
+ "@rollup/plugin-commonjs": "^23.0.2",
63
+ "@rollup/plugin-terser": "^0.1.0",
64
+ "@rollup/plugin-typescript": "^9.0.2",
57
65
  "@types/cors": "^2.8.12",
58
66
  "@types/crypto-js": "^4.1.1",
59
67
  "@types/express": "^4.17.14",
60
68
  "@types/jsonwebtoken": "^8.5.9",
61
69
  "@types/mime-types": "^2.1.1",
62
70
  "@types/multer": "^1.4.7",
63
- "@types/node": "^18.8.5",
71
+ "@types/node": "^18.11.9",
64
72
  "@types/ws": "^8.5.3",
65
- "@typescript-eslint/eslint-plugin": "^5.40.0",
66
- "@typescript-eslint/parser": "^5.40.0",
67
- "eslint": "^8.25.0",
68
- "rollup": "^2.79.1",
69
- "rollup-plugin-dts": "^4.2.3",
70
- "rollup-plugin-terser": "^7.0.2",
73
+ "@typescript-eslint/eslint-plugin": "^5.42.0",
74
+ "@typescript-eslint/parser": "^5.42.0",
75
+ "eslint": "^8.26.0",
76
+ "rollup": "^3.2.5",
77
+ "rollup-plugin-dts": "^5.0.0",
71
78
  "ts-node": "^10.9.1",
72
79
  "ts-node-dev": "^2.0.0",
73
- "tslib": "^2.4.0"
80
+ "tslib": "^2.4.1"
74
81
  }
75
82
  }