@dataramen/cli 0.0.63-beta.2 → 0.0.63-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/app.js +3 -3
- package/dist/code/server.js +4 -4
- package/dist/code/web/assets/{index-BCWDH7FB.js → index-Cpak9Bnj.js} +38 -38
- package/dist/code/web/assets/index-Dgyy9gky.css +1 -0
- package/dist/code/web/index.html +2 -2
- package/dist/package.json +1 -1
- package/package.json +1 -1
- package/dist/code/web/assets/index-CeZHq8hf.css +0 -1
package/bin/app.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
3
|
-
`);for(let r of a){let s=r.trim();if(!s||s.startsWith("#"))continue;let u=s.indexOf("=");if(u===-1)continue;let w=s.slice(0,u).trim(),l=s.slice(u+1).trim();(l.startsWith('"')&&l.endsWith('"')||l.startsWith("'")&&l.endsWith("'"))&&(l=l.slice(1,-1)),t[w]=l}}return t}function
|
|
2
|
+
var te=Object.create;var P=Object.defineProperty;var re=Object.getOwnPropertyDescriptor;var ne=Object.getOwnPropertyNames;var oe=Object.getPrototypeOf,se=Object.prototype.hasOwnProperty;var ie=(e,t,o,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of ne(t))!se.call(e,r)&&r!==o&&P(e,r,{get:()=>t[r],enumerable:!(a=re(t,r))||a.enumerable});return e};var c=(e,t,o)=>(o=e!=null?te(oe(e)):{},ie(t||!e||!e.__esModule?P(o,"default",{value:e,enumerable:!0}):o,e));var ee=require("commander");var b=c(require("fs-extra")),T=require("node:path");var _=require("node:os"),C=require("node:path"),ae=(0,_.homedir)(),m="@dataramen/server",i=(0,C.join)(ae,".dataramen",".runtime","server");function V(e){let t;function o(){try{return t||(t=b.readJsonSync(e)),t}catch{return}}return o}var N=V((0,T.join)(__dirname,"..","package.json")),A=V((0,T.join)(i,"package.json"));var p=c(require("fs-extra")),f=require("node:path"),k=require("node:child_process"),M=require("node:util"),g=c(require("yocto-spinner")),d=(0,M.promisify)(k.exec);function O(){try{let e=A();if(!e)return!0;let t=p.readJsonSync((0,f.join)(__dirname,"..","dist","package.json"));return e.version!==t.version}catch{return!0}}async function W(){let e=(0,g.default)({text:"Checking if PM2 is installed"}).start();try{return await d("pm2 -v"),e.success("PM2 already installed"),!0}catch{return e.warning("PM2 not installed"),!1}}async function j(){let e=(0,g.default)({text:"Installing PM2"}).start();try{await d("npm i -g pm2"),e.success("Installed PM2")}catch{e.error("Failed to install PM2"),process.exit(1)}}async function E(){let e=(0,g.default)({text:"Stop running instances of "+m}).start();try{await d(`pm2 stop "${m}"`),e.warning("Stopped "+m)}catch{e.success("No running instances of "+m+" found")}}async function I(){let e=(0,g.default)({text:"Create local server"}).start();p.removeSync((0,f.join)(i,"code")),p.copySync((0,f.join)(__dirname,"..","dist","code"),(0,f.join)(i,"code")),p.copySync((0,f.join)(__dirname,"..","dist","package.json"),(0,f.join)(i,"package.json")),e.text="Install local server dependencies",await d("npm i",{cwd:i}),e.success("Local server installed")}var S=c(require("node:crypto"));var v=require("fs-extra"),R=require("node:path");function me(e){try{return(0,v.readFileSync)((0,R.join)(i,e),"utf-8")}catch{return}}function ce(e){let t={},o=me(e);if(o){let a=o.split(`
|
|
3
|
+
`);for(let r of a){let s=r.trim();if(!s||s.startsWith("#"))continue;let u=s.indexOf("=");if(u===-1)continue;let w=s.slice(0,u).trim(),l=s.slice(u+1).trim();(l.startsWith('"')&&l.endsWith('"')||l.startsWith("'")&&l.endsWith("'"))&&(l=l.slice(1,-1)),t[w]=l}}return t}function le(){let e={customValues:{},fileName:".env"};function t(){e.customValues=ce(e.fileName)}function o(){let s=Object.entries(e.customValues).map(([u,w])=>`${u}=${w}`).join(`
|
|
4
4
|
`)+`
|
|
5
|
-
`;(0,
|
|
5
|
+
`;(0,v.writeFileSync)((0,R.join)(i,e.fileName),s,{encoding:"utf8"})}function a(r){if(e.customValues[r])return e.customValues[r]}return t(),{getNumber:r=>fe(a(r)),getString:r=>pe(a(r)),getBoolean:r=>ue(a(r)),flush:o,set:(r,s)=>{e.customValues[r]=s.toString()},unset:r=>{delete e.customValues[r]},values:()=>({...e.customValues})}}function fe(e){if(!e)return;let t=Number(e);if(!isNaN(t)&&e.trim()!=="")return t;throw new Error("Wrong env value type")}function pe(e){if(e){if(typeof e=="string")return e;throw new Error("Wrong env value type")}}function ue(e){if(!e)return;let t=e.toLowerCase();if(t==="true"||t==="1")return!0;if(t==="false"||t==="0")return!1;throw new Error("Wrong env value type")}var n=le();function J(){let e=!1;if(!n.getString("SYMM_ENCRYPTION_KEY")){let t=S.randomBytes(32).toString("hex");n.set("SYMM_ENCRYPTION_KEY",t),console.log("Generated random SYMM_ENCRYPTION_KEY"),e=!0}if(!n.getString("JWT_SECRET")){let t=S.randomBytes(32).toString("hex");n.set("JWT_SECRET",t),console.log("Generated random JWT_SECRET"),e=!0}if(!n.getString("JWT_REFRESH_SECRET")){let t=S.randomBytes(32).toString("hex");n.set("JWT_REFRESH_SECRET",t),console.log("Generated random JWT_REFRESH_SECRET"),e=!0}e&&n.flush()}var $=require("node:net");async function H(e){return new Promise(t=>{let o=(0,$.createServer)().once("error",()=>{t(!1)}).once("listening",()=>{o.close()}).once("close",()=>t(!0)).listen(e,"127.0.0.1")})}var x=c(require("yocto-spinner"));var L=c(require("fs-extra")),Y=require("node:path");var de=async e=>{try{return(await fetch(e,{method:"GET",signal:AbortSignal.timeout(5e3)})).status===200}catch{return!1}},F=async(e,t,o)=>{let a=Date.now();for(;Date.now()-a<t;){if(await de(e))return!0;await new Promise(s=>setTimeout(s,o))}return!1};var K=c(require("open")),ve={command:"start",description:"Start local server, restarts if already running",handler:async()=>{await W()||await j(),await E();try{O()&&await I(),J();let t=n.getNumber("PORT")||4466;if(!t)throw new Error("PORT env variable not found");if(!await H(t))throw new Error(`Port ${t} is occupied by another process`);let a=(0,x.default)({text:"Starting new instance of "+m}).start(),r=L.readJsonSync((0,Y.join)(i,"package.json"));await d(`pm2 start "${r.main}" --name "${m}" --no-autorestart -- "${i}/.env"`,{cwd:i}),a.success("Local server will be available in a couple of seconds");let s=(0,x.default)({text:"Waiting for the server to become available"}).start();await F(`http://localhost:${t}/api/status`,3e4,1e3)?(await(0,K.default)(`http://localhost:${t}`),s.success(`App is running at http://localhost:${t}`)):s.error("Server failed to become available in time")}catch(t){console.error("Failed to start local server",t)}}},h=ve;var D=require("node:child_process");var Se={command:"logs",description:"Listen for logs",handler:async()=>{(0,D.execSync)(`pm2 logs ${m}`,{stdio:"inherit"})}},B=Se;var he={command:"stop",description:"Stop the server",handler:E},G=he;var U=c(require("open")),ye={command:"open",description:"Open webapp",handler:async()=>{let e=n.getNumber("PORT");await(0,U.default)(`http://localhost:${e}`)}},Q=ye;var we={command:"env set <prop> <value>",description:"Set env value",handler:async(e,t)=>{n.set(e,t),n.flush(),console.log(`Environment property set: ${e}`)}},q=we;var Te={command:"env unset <prop>",description:"Remove env value",handler:async e=>{n.unset(e),n.flush(),console.log(`Environment property unset: ${e}`)}},z=Te;var Re={command:"env list",description:"List env values",handler:async()=>{console.table(n.values())}},X=Re;var Z=[h,B,G,Q,q,z,X];var y=new ee.Command;y.name("dataramen").description("A cozy web GUI for MySQL and PostgreSQL - built for developers who like to move fast and stay focused.").version(N().version,"-v, --version","Show version");y.command("default",{hidden:!0,isDefault:!0}).action(h.handler);Z.forEach(e=>{y.command(e.command).description(e.description).action(e.handler)});y.parse();
|
package/dist/code/server.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
"use strict";var Xt=Object.create;var Ue=Object.defineProperty;var Zt=Object.getOwnPropertyDescriptor;var er=Object.getOwnPropertyNames;var tr=Object.getPrototypeOf,rr=Object.prototype.hasOwnProperty;var or=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of er(t))!rr.call(e,a)&&a!==r&&Ue(e,a,{get:()=>t[a],enumerable:!(o=Zt(t,a))||o.enumerable});return e};var D=(e,t,r)=>(r=e!=null?Xt(tr(e)):{},or(t||!e||!e.__esModule?Ue(r,"default",{value:e,enumerable:!0}):r,e));var ee=require("dotenv"),te=require("node:path"),ve=require("node:fs"),ar=(()=>{try{let e=(0,ve.readFileSync)((0,te.join)(__dirname,"..","package.json"),"utf8");return JSON.parse(e)}catch{return{version:"0.0.0"}}})(),xe=[];process.argv[2]&&xe.push((0,te.resolve)(process.argv[2]));(0,ee.config)({path:xe});(0,ee.populate)(process.env,{SERVER_VERSION:ar.version,APP_DB_TYPE:"sqlite",APP_DB_DATABASE:"<home>/.dataramen/.runtime/db.sqlite3",PROD:"true"},{override:!1});var nr=["SYMM_ENCRYPTION_KEY","JWT_SECRET","JWT_REFRESH_SECRET"],Me=()=>{let e=[];for(let t of nr)process.env[t]||e.push(t);if(e.length>0)throw new Error("Following env variables are required but not provided: "+e.join(", "))};function sr(e,t=void 0){return process.env[e]||t}function ir(e,t=void 0){let r=process.env[e];if(!r)return t;let o=Number(r);return!isNaN(o)&&r.trim()!==""?o:t}function ur(e){return process.env[e]==="true"||process.env[e]==="TRUE"||process.env[e]==="1"}var T={str:sr,num:ir,bool:ur};var Vs=require("reflect-metadata"),Ft=D(require("fastify")),$t=D(require("@fastify/cors")),Wt=D(require("@fastify/static")),Ht=D(require("qs"));var s=class extends Error{constructor(r,o){super(o);this.status=r;this.message=o}};var Ye=require("typeorm");var Le=require("typeorm");var y=T.str("APP_DB_TYPE")==="sqlite"?"datetime":"timestamp";var me=new Le.EntitySchema({name:"DatabaseInspection",tableName:"db_inspection",columns:{id:{type:String,unique:!0,primary:!0,generated:"uuid"},tableName:{nullable:!0,type:String},columns:{type:"json",nullable:!0},createdAt:{type:y,default:()=>"CURRENT_TIMESTAMP"},updatedAt:{type:y,default:()=>"CURRENT_TIMESTAMP"}},relations:{datasource:{target:()=>"DataSource",type:"many-to-one",joinTable:!1,cascade:!0}}});var ke=require("typeorm");var pe=new ke.EntitySchema({name:"Team",tableName:"teams",columns:{id:{type:"uuid",primary:!0,generated:"uuid"},name:{type:String},createdAt:{type:y,default:()=>"CURRENT_TIMESTAMP"},updatedAt:{type:y,default:()=>"CURRENT_TIMESTAMP"}},relations:{users:{type:"one-to-many",target:()=>"UsersToTeams",inverseSide:"team"},queries:{type:"one-to-many",target:()=>"Query",inverseSide:"team"},datasources:{type:"one-to-many",target:()=>"DataSource",inverseSide:"team"}}});var qe=require("typeorm");var fe=new qe.EntitySchema({name:"User",tableName:"users",columns:{id:{type:"uuid",primary:!0,generated:"uuid"},createdAt:{type:y,default:()=>"CURRENT_TIMESTAMP"},updatedAt:{type:y,default:()=>"CURRENT_TIMESTAMP"},username:{type:String,unique:!0},password:{type:String}},relations:{teams:{type:"one-to-many",target:()=>"UsersToTeams",inverseSide:"user"},settings:{type:"one-to-one",target:()=>"UserSettings",inverseSide:"user"},currentTeam:{type:"one-to-one",target:()=>"UsersToTeams",inverseSide:"user",joinColumn:!0},queries:{type:"one-to-many",target:()=>"Query",inverseSide:"user"}}});var Qe=require("typeorm");var ye=new Qe.EntitySchema({name:"UserSettings",tableName:"user_settings",columns:{id:{type:"uuid",primary:!0,generated:"uuid"},createdAt:{type:y,default:()=>"CURRENT_TIMESTAMP"},updatedAt:{type:y,default:()=>"CURRENT_TIMESTAMP"}},relations:{user:{type:"one-to-one",target:()=>"User",inverseSide:"settings",joinColumn:!0}}});var Be=require("typeorm");var Te=new Be.EntitySchema({name:"DataSource",tableName:"data_sources",columns:{id:{type:"uuid",primary:!0,generated:"uuid"},dbUrl:{type:String},dbPort:{type:Number,nullable:!0},dbUser:{type:String},dbPassword:{type:String,nullable:!0,select:!1},dbPasswordIv:{type:String,nullable:!0,select:!1},dbPasswordTag:{type:String,nullable:!0,select:!1},dbType:{type:String},createdAt:{type:y,default:()=>"CURRENT_TIMESTAMP"},updatedAt:{type:y,default:()=>"CURRENT_TIMESTAMP"},name:{type:String},description:{type:String,nullable:!0},dbDatabase:{type:String},dbSchema:{type:String,nullable:!0},allowInsert:{type:Boolean,default:!1},allowUpdate:{type:Boolean,default:!1},lastInspected:{type:y,nullable:!0,default:null},status:{type:String,nullable:!0}},relations:{team:{type:"many-to-one",target:()=>"Team",inverseSide:"datasources",joinColumn:!0},inspections:{type:"one-to-many",target:()=>"DatabaseInspection",inverseSide:"datasource"},queries:{type:"one-to-many",target:()=>"Query",inverseSide:"dataSource"},owner:{type:"many-to-one",target:()=>"User",joinColumn:!0}}});var je=D(require("node:os")),Ge=require("node:path");var Fe=require("typeorm");var he=new Fe.EntitySchema({name:"Query",tableName:"query",columns:{id:{type:"uuid",primary:!0,generated:"uuid"},name:{type:String},opts:{type:"json",default:"{}"},createdAt:{type:y,default:()=>"CURRENT_TIMESTAMP"},updatedAt:{type:y,default:()=>"CURRENT_TIMESTAMP",onUpdate:"CURRENT_TIMESTAMP"}},relations:{team:{type:"many-to-one",target:()=>"Team",inverseSide:"queries",joinColumn:!0},dataSource:{type:"many-to-one",target:()=>"DataSource",inverseSide:"datasources",joinColumn:!0},user:{type:"many-to-one",target:()=>"User",inverseSide:"queries",joinColumn:!0,nullable:!0}}});var $e=require("typeorm"),ge=new $e.EntitySchema({name:"UsersToTeams",tableName:"users_to_teams",columns:{id:{type:"uuid",primary:!0,generated:"uuid"},role:{type:"varchar",default:"admin",nullable:!1}},relations:{team:{type:"many-to-one",target:()=>"Team",inverseSide:"users"},user:{type:"many-to-one",target:()=>"User",inverseSide:"teams"}}});var We=require("typeorm");var we=new We.EntitySchema({name:"SavedQuery",tableName:"saved_queries",columns:{id:{type:"uuid",primary:!0,generated:"uuid"},isPersonal:{type:Boolean},createdAt:{type:y,default:()=>"CURRENT_TIMESTAMP"},updatedAt:{type:y,default:()=>"CURRENT_TIMESTAMP",onUpdate:"CURRENT_TIMESTAMP"},searchString:{type:String,default:()=>null}},relations:{team:{type:"many-to-one",target:()=>"Team",inverseSide:"queries",joinColumn:!0},user:{type:"many-to-one",target:()=>"User",inverseSide:"queries",joinColumn:!0,nullable:!0},query:{type:"one-to-one",target:()=>"Query",joinColumn:!0,nullable:!1}}});var He=require("typeorm");var Ee=new He.EntitySchema({name:"WorkbenchTab",tableName:"workbench_tabs",columns:{id:{type:"uuid",primary:!0,generated:"uuid"},name:{type:String},createdAt:{type:y,default:()=>"CURRENT_TIMESTAMP"},updatedAt:{type:y,default:()=>"CURRENT_TIMESTAMP",onUpdate:"CURRENT_TIMESTAMP"},opts:{type:"json",default:"{}"},archived:{type:Boolean,default:!1},searchString:{type:String,default:()=>null}},relations:{team:{type:"many-to-one",target:()=>"Team",joinColumn:!0},user:{type:"many-to-one",target:()=>"User",joinColumn:!0},dataSource:{type:"many-to-one",target:()=>"DataSource",joinColumn:!0}}});function cr(){let e=T.str("APP_DB_DATABASE");if(!e)throw new Error("Bad value for TYPEORM_DATABASE. Please check your config!");return e.startsWith("<home>")&&(e=e.replace("<home>",je.default.homedir())),e}var h=new Ye.DataSource({type:T.str("APP_DB_TYPE"),database:cr(),host:T.str("APP_DB_HOST"),username:T.str("APP_DB_USERNAME"),password:T.str("APP_DB_PASSWORD"),port:T.num("APP_DB_PORT"),schema:T.str("APP_DB_SCHEMA"),logging:T.bool("APP_DB_LOGGING"),migrationsRun:!0,migrations:[Ge.posix.join(__dirname,"migrations","*.js")],entities:[me,Te,pe,fe,ge,ye,he,we,Ee]}),Ke=async()=>{if(!h.isInitialized)return h.initialize();throw new Error("Already initialized")},v=h.getRepository(me),S=h.getRepository(Te),M=h.getRepository(pe),R=h.getRepository(fe),N=h.getRepository(ge),$=h.getRepository(ye),I=h.getRepository(he),x=h.getRepository(we),A=h.getRepository(Ee);var g=e=>(t,r,o)=>{e(t),o()};var j=require("jose");var Ve=new TextEncoder,ze=Ve.encode(T.str("JWT_SECRET")),Je=Ve.encode(T.str("JWT_REFRESH_SECRET")),Se=async({userId:e})=>new j.SignJWT({sub:e}).setProtectedHeader({alg:"HS256"}).setExpirationTime("1h").sign(ze),be=async({userId:e})=>new j.SignJWT({sub:e}).setProtectedHeader({alg:"HS256"}).setExpirationTime("10d").sign(Je),Xe=async(e,t)=>{try{let{payload:r}=await(0,j.jwtVerify)(e,t);if(!r.sub)throw new s(401,"Failed to verify access token");return{userId:r.sub}}catch(r){throw r instanceof s?r:r instanceof Error?new s(401,r.message):new s(401,"Failed to verify refresh token")}},Ze=async e=>Xe(e,ze),et=async e=>Xe(e,Je);var m=(e,t)=>{let r=e.body;return t&&t(r),r},L=(e,t)=>{let r=e.query;return t&&t(r),r},p=(e,t)=>{let r=e.params;return t&&t(r),r};var rt=D(require("bcryptjs"));var tt=e=>{if(!e?.username)throw new s(400,"Username is required");if(!e?.password)throw new s(400,"Password is required")};var re="DATARAMEN_refresh_token",Re={httpOnly:!0,secure:T.bool("PROD"),sameSite:T.bool("PROD"),path:"/",maxAge:10*24*60*60},ot=g(e=>{e.route({method:"post",url:"/login",config:{isPublic:!0},handler:async(t,r)=>{let{username:o,password:a}=m(t,tt),n=await R.findOne({where:{username:o}});if(!n||!rt.default.compareSync(a,n.password))throw new s(401,"Invalid credentials");let[i,u]=await Promise.all([Se({userId:n?.id}),be({userId:n?.id})]);return r.setCookie(re,u,Re),{data:{accessToken:i}}}}),e.route({method:"post",url:"/refresh",config:{isPublic:!0},handler:async(t,r)=>{let o=t.cookies[re];if(!o)return r.code(401).send({message:"Missing refresh token"});let{userId:a}=await et(o),[n,i]=await Promise.all([Se({userId:a}),be({userId:a})]);return r.setCookie(re,i,Re),{data:{accessToken:n}}}}),e.route({method:"post",url:"/logout",config:{isPublic:!0},handler:async(t,r)=>(r.clearCookie(re,Re),{data:!0})})});var at=e=>{if(!e.dbUrl)throw new s(400,"url is required");if(!e.dbUser)throw new s(400,"user is required");if(!e.dbType)throw new s(400,"type is required");if(!e.name)throw new s(400,"name is required");if(!e.dbDatabase)throw new s(400,"database is required")};var st=D(require("mysql2/promise"));function G(e){if(e!==void 0)return e.toLowerCase()}var dr=({database:e,password:t,user:r,url:o})=>st.default.createConnection({host:o,user:r,database:e,password:t}),lr=async e=>{let t=`
|
|
1
|
+
"use strict";var Xt=Object.create;var Ue=Object.defineProperty;var Zt=Object.getOwnPropertyDescriptor;var er=Object.getOwnPropertyNames;var tr=Object.getPrototypeOf,rr=Object.prototype.hasOwnProperty;var or=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of er(t))!rr.call(e,a)&&a!==r&&Ue(e,a,{get:()=>t[a],enumerable:!(o=Zt(t,a))||o.enumerable});return e};var D=(e,t,r)=>(r=e!=null?Xt(tr(e)):{},or(t||!e||!e.__esModule?Ue(r,"default",{value:e,enumerable:!0}):r,e));var ee=require("dotenv"),te=require("node:path"),ve=require("node:fs"),ar=(()=>{try{let e=(0,ve.readFileSync)((0,te.join)(__dirname,"..","package.json"),"utf8");return JSON.parse(e)}catch{return{version:"0.0.0"}}})(),xe=[];process.argv[2]&&xe.push((0,te.resolve)(process.argv[2]));(0,ee.config)({path:xe});(0,ee.populate)(process.env,{SERVER_VERSION:ar.version,APP_DB_TYPE:"sqlite",APP_DB_DATABASE:"<home>/.dataramen/.runtime/db.sqlite3",PROD:"true"},{override:!1});var nr=["SYMM_ENCRYPTION_KEY","JWT_SECRET","JWT_REFRESH_SECRET"],Me=()=>{let e=[];for(let t of nr)process.env[t]||e.push(t);if(e.length>0)throw new Error("Following env variables are required but not provided: "+e.join(", "))};function sr(e,t=void 0){return process.env[e]||t}function ir(e,t=void 0){let r=process.env[e];if(!r)return t;let o=Number(r);return!isNaN(o)&&r.trim()!==""?o:t}function ur(e){return process.env[e]==="true"||process.env[e]==="TRUE"||process.env[e]==="1"}var T={str:sr,num:ir,bool:ur};var Gs=require("reflect-metadata"),$t=D(require("fastify")),Wt=D(require("@fastify/cors")),Ht=D(require("@fastify/static")),Yt=D(require("qs"));var s=class extends Error{constructor(r,o){super(o);this.status=r;this.message=o}};var Ye=require("typeorm");var Le=require("typeorm");var y=T.str("APP_DB_TYPE")==="sqlite"?"datetime":"timestamp";var le=new Le.EntitySchema({name:"DatabaseInspection",tableName:"db_inspection",columns:{id:{type:String,unique:!0,primary:!0,generated:"uuid"},tableName:{nullable:!0,type:String},columns:{type:"json",nullable:!0},createdAt:{type:y,default:()=>"CURRENT_TIMESTAMP"},updatedAt:{type:y,default:()=>"CURRENT_TIMESTAMP"}},relations:{datasource:{target:()=>"DataSource",type:"many-to-one",joinTable:!1,cascade:!0}}});var ke=require("typeorm");var pe=new ke.EntitySchema({name:"Team",tableName:"teams",columns:{id:{type:"uuid",primary:!0,generated:"uuid"},name:{type:String},createdAt:{type:y,default:()=>"CURRENT_TIMESTAMP"},updatedAt:{type:y,default:()=>"CURRENT_TIMESTAMP"}},relations:{users:{type:"one-to-many",target:()=>"UsersToTeams",inverseSide:"team"},queries:{type:"one-to-many",target:()=>"Query",inverseSide:"team"},datasources:{type:"one-to-many",target:()=>"DataSource",inverseSide:"team"}}});var qe=require("typeorm");var fe=new qe.EntitySchema({name:"User",tableName:"users",columns:{id:{type:"uuid",primary:!0,generated:"uuid"},createdAt:{type:y,default:()=>"CURRENT_TIMESTAMP"},updatedAt:{type:y,default:()=>"CURRENT_TIMESTAMP"},username:{type:String,unique:!0},password:{type:String}},relations:{teams:{type:"one-to-many",target:()=>"UsersToTeams",inverseSide:"user"},settings:{type:"one-to-one",target:()=>"UserSettings",inverseSide:"user"},currentTeam:{type:"one-to-one",target:()=>"UsersToTeams",inverseSide:"user",joinColumn:!0},queries:{type:"one-to-many",target:()=>"Query",inverseSide:"user"}}});var Qe=require("typeorm");var ye=new Qe.EntitySchema({name:"UserSettings",tableName:"user_settings",columns:{id:{type:"uuid",primary:!0,generated:"uuid"},createdAt:{type:y,default:()=>"CURRENT_TIMESTAMP"},updatedAt:{type:y,default:()=>"CURRENT_TIMESTAMP"}},relations:{user:{type:"one-to-one",target:()=>"User",inverseSide:"settings",joinColumn:!0}}});var Be=require("typeorm");var Te=new Be.EntitySchema({name:"DataSource",tableName:"data_sources",columns:{id:{type:"uuid",primary:!0,generated:"uuid"},dbUrl:{type:String},dbPort:{type:Number,nullable:!0},dbUser:{type:String},dbPassword:{type:String,nullable:!0,select:!1},dbPasswordIv:{type:String,nullable:!0,select:!1},dbPasswordTag:{type:String,nullable:!0,select:!1},dbType:{type:String},createdAt:{type:y,default:()=>"CURRENT_TIMESTAMP"},updatedAt:{type:y,default:()=>"CURRENT_TIMESTAMP"},name:{type:String},description:{type:String,nullable:!0},dbDatabase:{type:String},dbSchema:{type:String,nullable:!0},allowInsert:{type:Boolean,default:!1},allowUpdate:{type:Boolean,default:!1},lastInspected:{type:y,nullable:!0,default:null},status:{type:String,nullable:!0}},relations:{team:{type:"many-to-one",target:()=>"Team",inverseSide:"datasources",joinColumn:!0},inspections:{type:"one-to-many",target:()=>"DatabaseInspection",inverseSide:"datasource"},queries:{type:"one-to-many",target:()=>"Query",inverseSide:"dataSource"},owner:{type:"many-to-one",target:()=>"User",joinColumn:!0}}});var je=D(require("node:os")),Ge=require("node:path");var Fe=require("typeorm");var he=new Fe.EntitySchema({name:"Query",tableName:"query",columns:{id:{type:"uuid",primary:!0,generated:"uuid"},name:{type:String},opts:{type:"json",default:"{}"},createdAt:{type:y,default:()=>"CURRENT_TIMESTAMP"},updatedAt:{type:y,default:()=>"CURRENT_TIMESTAMP",onUpdate:"CURRENT_TIMESTAMP"}},relations:{team:{type:"many-to-one",target:()=>"Team",inverseSide:"queries",joinColumn:!0},dataSource:{type:"many-to-one",target:()=>"DataSource",inverseSide:"datasources",joinColumn:!0},user:{type:"many-to-one",target:()=>"User",inverseSide:"queries",joinColumn:!0,nullable:!0}}});var $e=require("typeorm"),ge=new $e.EntitySchema({name:"UsersToTeams",tableName:"users_to_teams",columns:{id:{type:"uuid",primary:!0,generated:"uuid"},role:{type:"varchar",default:"admin",nullable:!1}},relations:{team:{type:"many-to-one",target:()=>"Team",inverseSide:"users"},user:{type:"many-to-one",target:()=>"User",inverseSide:"teams"}}});var We=require("typeorm");var we=new We.EntitySchema({name:"SavedQuery",tableName:"saved_queries",columns:{id:{type:"uuid",primary:!0,generated:"uuid"},isPersonal:{type:Boolean},createdAt:{type:y,default:()=>"CURRENT_TIMESTAMP"},updatedAt:{type:y,default:()=>"CURRENT_TIMESTAMP",onUpdate:"CURRENT_TIMESTAMP"},searchString:{type:String,default:()=>null}},relations:{team:{type:"many-to-one",target:()=>"Team",inverseSide:"queries",joinColumn:!0},user:{type:"many-to-one",target:()=>"User",inverseSide:"queries",joinColumn:!0,nullable:!0},query:{type:"one-to-one",target:()=>"Query",joinColumn:!0,nullable:!1}}});var He=require("typeorm");var Ee=new He.EntitySchema({name:"WorkbenchTab",tableName:"workbench_tabs",columns:{id:{type:"uuid",primary:!0,generated:"uuid"},name:{type:String},createdAt:{type:y,default:()=>"CURRENT_TIMESTAMP"},updatedAt:{type:y,default:()=>"CURRENT_TIMESTAMP",onUpdate:"CURRENT_TIMESTAMP"},opts:{type:"json",default:"{}"},archived:{type:Boolean,default:!1},searchString:{type:String,default:()=>null}},relations:{team:{type:"many-to-one",target:()=>"Team",joinColumn:!0},user:{type:"many-to-one",target:()=>"User",joinColumn:!0},dataSource:{type:"many-to-one",target:()=>"DataSource",joinColumn:!0}}});function cr(){let e=T.str("APP_DB_DATABASE");if(!e)throw new Error("Bad value for TYPEORM_DATABASE. Please check your config!");return e.startsWith("<home>")&&(e=e.replace("<home>",je.default.homedir())),e}var h=new Ye.DataSource({type:T.str("APP_DB_TYPE"),database:cr(),host:T.str("APP_DB_HOST"),username:T.str("APP_DB_USERNAME"),password:T.str("APP_DB_PASSWORD"),port:T.num("APP_DB_PORT"),schema:T.str("APP_DB_SCHEMA"),logging:T.bool("APP_DB_LOGGING"),migrationsRun:!0,migrations:[Ge.posix.join(__dirname,"migrations","*.js")],entities:[le,Te,pe,fe,ge,ye,he,we,Ee]}),Ke=async()=>{if(!h.isInitialized)return h.initialize();throw new Error("Already initialized")},v=h.getRepository(le),S=h.getRepository(Te),M=h.getRepository(pe),R=h.getRepository(fe),N=h.getRepository(ge),$=h.getRepository(ye),I=h.getRepository(he),x=h.getRepository(we),A=h.getRepository(Ee);var g=e=>(t,r,o)=>{e(t),o()};var j=require("jose");var Ve=new TextEncoder,ze=Ve.encode(T.str("JWT_SECRET")),Je=Ve.encode(T.str("JWT_REFRESH_SECRET")),Se=async({userId:e})=>new j.SignJWT({sub:e}).setProtectedHeader({alg:"HS256"}).setExpirationTime("1h").sign(ze),be=async({userId:e})=>new j.SignJWT({sub:e}).setProtectedHeader({alg:"HS256"}).setExpirationTime("10d").sign(Je),Xe=async(e,t)=>{try{let{payload:r}=await(0,j.jwtVerify)(e,t);if(!r.sub)throw new s(401,"Failed to verify access token");return{userId:r.sub}}catch(r){throw r instanceof s?r:r instanceof Error?new s(401,r.message):new s(401,"Failed to verify refresh token")}},Ze=async e=>Xe(e,ze),et=async e=>Xe(e,Je);var l=(e,t)=>{let r=e.body;return t&&t(r),r},L=(e,t)=>{let r=e.query;return t&&t(r),r},p=(e,t)=>{let r=e.params;return t&&t(r),r};var rt=D(require("bcryptjs"));var tt=e=>{if(!e?.username)throw new s(400,"Username is required");if(!e?.password)throw new s(400,"Password is required")};var re="DATARAMEN_refresh_token",Re={httpOnly:!0,secure:T.bool("PROD"),sameSite:T.bool("PROD"),path:"/",maxAge:10*24*60*60},ot=g(e=>{e.route({method:"post",url:"/login",config:{isPublic:!0},handler:async(t,r)=>{let{username:o,password:a}=l(t,tt),n=await R.findOne({where:{username:o}});if(!n||!rt.default.compareSync(a,n.password))throw new s(401,"Invalid credentials");let[i,u]=await Promise.all([Se({userId:n?.id}),be({userId:n?.id})]);return r.setCookie(re,u,Re),{data:{accessToken:i}}}}),e.route({method:"post",url:"/refresh",config:{isPublic:!0},handler:async(t,r)=>{let o=t.cookies[re];if(!o)return r.code(401).send({message:"Missing refresh token"});let{userId:a}=await et(o),[n,i]=await Promise.all([Se({userId:a}),be({userId:a})]);return r.setCookie(re,i,Re),{data:{accessToken:n}}}}),e.route({method:"post",url:"/logout",config:{isPublic:!0},handler:async(t,r)=>(r.clearCookie(re,Re),{data:!0})})});var at=e=>{if(!e.dbUrl)throw new s(400,"url is required");if(!e.dbUser)throw new s(400,"user is required");if(!e.dbType)throw new s(400,"type is required");if(!e.name)throw new s(400,"name is required");if(!e.dbDatabase)throw new s(400,"database is required")};var st=D(require("mysql2/promise"));function G(e){if(e!==void 0)return e.toLowerCase()}var dr=({database:e,password:t,user:r,url:o})=>st.default.createConnection({host:o,user:r,database:e,password:t}),mr=async e=>{let t=`
|
|
2
2
|
SELECT LOWER(TABLE_NAME) as TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION
|
|
3
3
|
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
|
|
4
4
|
WHERE CONSTRAINT_NAME = 'PRIMARY'
|
|
5
5
|
ORDER BY TABLE_NAME, ORDINAL_POSITION;
|
|
6
|
-
`,[r]=await e.execute(t),o={};return r.forEach(a=>{let n=G(a.TABLE_NAME),i=a.COLUMN_NAME;o[n]||(o[n]=[]),o[n].push(i)}),o},
|
|
6
|
+
`,[r]=await e.execute(t),o={};return r.forEach(a=>{let n=G(a.TABLE_NAME),i=a.COLUMN_NAME;o[n]||(o[n]=[]),o[n].push(i)}),o},lr=async e=>{let t=`
|
|
7
7
|
SELECT
|
|
8
8
|
LOWER(TABLE_NAME) AS table_name,
|
|
9
9
|
COLUMN_NAME AS field,
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
WHERE
|
|
15
15
|
REFERENCED_TABLE_NAME IS NOT NULL
|
|
16
16
|
AND CONSTRAINT_SCHEMA = DATABASE();
|
|
17
|
-
`,[r]=await e.execute(t),o={};return Array.isArray(r)&&r.forEach(a=>{o[a.table_name]||(o[a.table_name]={}),o[a.table_name][a.field]={refTable:a.referenced_table,refField:a.referenced_field}}),o},pr=async(e,t)=>{let o=(await t.query("SHOW TABLES"))[0],a=await
|
|
17
|
+
`,[r]=await e.execute(t),o={};return Array.isArray(r)&&r.forEach(a=>{o[a.table_name]||(o[a.table_name]={}),o[a.table_name][a.field]={refTable:a.referenced_table,refField:a.referenced_field}}),o},pr=async(e,t)=>{let o=(await t.query("SHOW TABLES"))[0],a=await lr(t),n=await mr(t),i=o.map(async u=>{let f=G(Object.values(u)[0]),c=`select COLUMN_NAME, DATA_TYPE from information_schema.columns where table_schema = '${e.database}' and LOWER(table_name) = '${f}'`,[E]=await t.query(c),C=a[f];return{columns:E.map(d=>({name:d.COLUMN_NAME,type:d.DATA_TYPE,isPrimary:n[f]?.includes(d.COLUMN_NAME),ref:C?.[d.COLUMN_NAME]?{table:C[d.COLUMN_NAME].refTable,field:C[d.COLUMN_NAME].refField}:void 0})).sort((d,w)=>d.isPrimary&&w.isPrimary?d.name.localeCompare(w.name):d.isPrimary?-1:1),createdAt:new Date,tableName:f,updatedAt:new Date}});return Promise.all(i)},nt=async(e,t,r)=>{try{console.log(`[MYSQL CONN] Query: ${e}`);let[o,a]=await t.query({sql:e,rowsAsArray:!0}),n=o?.constructor?.name;if(n==="ResultSetHeader"){let i=o;if(i.affectedRows>1&&r.allowBulkUpdate!==!0)throw new Error("[MYSQL CONN] Bulk update performed without permission.");return{columns:[{column:"affectedRows",alias:"Affected rows",full:"affectedRows"}],rows:[[i.affectedRows]],query:e}}else if(n==="Array"){let i=o;return{columns:a?.map(u=>({column:u.orgName||u.name,table:G(u.orgTable),alias:u.name,full:u.orgTable?G(u.orgTable)+"."+u.orgName:u.name}))||[],rows:i,query:e}}throw new Error(`[MYSQL CONN] Unknown result type: ${n}`)}catch(o){throw console.error(o),o instanceof s?o:new s(400,o.message)}},fr=async(e,t)=>{await e.beginTransaction();try{let r=await t();return await e.commit(),console.log("[MYSQL CONN] Commit"),r}catch(r){throw await e.rollback(),console.warn(r.message),console.log("[MYSQL CONN] Rollback"),r}},yr=async(e,t)=>{await e.query("START TRANSACTION READ ONLY");try{let r=await t();return console.log("[MYSQL CONN] Read only rollback"),await e.query("ROLLBACK"),r}catch(r){throw console.warn(r.message),await e.query("ROLLBACK"),r}},it=async e=>{let t=await dr(e),r=!1;return{dbType:"mysql",dataSource:e,inspectSchema:()=>pr(e,t),executeQuery:(o,a)=>a.type==="SELECT"?yr(t,()=>nt(o,t,a)):fr(t,()=>nt(o,t,a)),checkConnection:async()=>t.ping(),isClosed:()=>r,close:async()=>{if(!r)return r=!0,t.destroy()}}};var ct=D(require("pg"));var Tr=async({database:e,password:t,user:r,url:o,port:a})=>{let n=new ct.default.Client({host:o,user:r,database:e,password:t,port:a,query_timeout:1e4});return await n.connect(),n},hr=async e=>{let r=await e.query(`
|
|
18
18
|
SELECT
|
|
19
19
|
LOWER(kcu.table_name) as table_name,
|
|
20
20
|
kcu.column_name,
|
|
@@ -54,4 +54,4 @@
|
|
|
54
54
|
left join pg_class on pg_attribute.attrelid = pg_class.oid
|
|
55
55
|
where
|
|
56
56
|
concat(pg_class.oid, '-', attnum) IN (${e.join(", ")})
|
|
57
|
-
limit 75;`;return(await t.query(r)).rows.reduce((a,n)=>(a[n.row_key]={table:n.relname,column:n.attname},a),{})},ut=async(e,t,r)=>{try{console.log(`[PG CONN] Query: ${e}`);let{rows:o,fields:a,command:n,rowCount:i}=await t.query({text:e,rowMode:"array"});if(n==="UPDATE"||n==="INSERT"||n==="DELETE"){if(i!=null&&i>1&&r.allowBulkUpdate!==!0)throw new Error("[PG CONN] Bulk update performed without permission.");return{columns:[{column:"affectedRows",alias:"Affected rows",full:"affectedRows"}],rows:[[i]],query:e}}if(n==="SELECT"){let u=a.map(c=>`'${c.tableID}-${c.columnID}'`),f=await Er(u,t);return{columns:a.map(c=>{let E=f[`${c.tableID}-${c.columnID}`];return{column:E?.column||c.name,alias:c.name,table:E?.table||"",full:E?E.table+"."+E.column:c.name}}),rows:o,query:e}}throw new Error(`[PG CONN] Unsupported command: ${n}`)}catch(o){throw o instanceof s?o:new s(400,o.message)}},Sr=async(e,t)=>{await e.query("BEGIN");try{let r=await t();return await e.query("COMMIT"),console.log("[PG CONN] Commit"),r}catch(r){throw await e.query("ROLLBACK"),console.log("[PG CONN] Rollback"),r}},br=async(e,t)=>{await e.query("BEGIN READ ONLY");try{let r=await t();return console.log("[PG CONN] Read only rollback"),await e.query("ROLLBACK"),r}catch(r){throw console.log("[PG CONN] Rollback"),await e.query("ROLLBACK"),r}},dt=async e=>{let t=await Tr(e),r=!1,o=!1,a=async n=>(o||await t.query(`SET search_path TO ${e.schema}`),n());return{dbType:"postgres",dataSource:e,inspectSchema:()=>wr(e,t),executeQuery:(n,i)=>a(()=>i.type==="SELECT"?br(t,()=>ut(n,t,i)):Sr(t,()=>ut(n,t,i))),checkConnection:async()=>{},isClosed:()=>r,close:async()=>{if(!r)return r=!0,t.end()}}};var k=async(e,t,r)=>{try{let o;if(t==="mysql")o=await it(e);else if(t==="postgres")o=await dt(e);else throw new s(500,`Connection manager for ${t} not found`);return r.__connections?r.__connections.push(o):r.__connections=[o],o}catch(o){throw console.error(o),o instanceof s?o:o?.code==="ECONNREFUSED"?new s(500,"Failed to connect to the database"):new s(500,o.message)}};var oe=D(require("node:crypto"));var lt="aes-256-gcm",Rr=12,mt=()=>{let e=T.str("SYMM_ENCRYPTION_KEY");if(!e)throw new Error("Missing ENCRYPTION_KEY in environment variables.");let t=Buffer.from(e,"hex");if(t.length!==32)throw new Error("ENCRYPTION_KEY must be a 64-character hex string (256 bits).");return t},Ir=e=>{let t=oe.default.randomBytes(Rr),r=mt(),o=oe.default.createCipheriv(lt,r,t),a=o.update(e,"utf8","hex");a+=o.final("hex");let n=o.getAuthTag();return{encrypted:a,iv:t.toString("hex"),tag:n.toString("hex")}},Cr=({encrypted:e,iv:t,tag:r})=>{let o=mt(),a=oe.default.createDecipheriv(lt,o,Buffer.from(t,"hex"));a.setAuthTag(Buffer.from(r,"hex"));let n=a.update(e,"hex","utf8");return n+=a.final("utf8"),n},ae={encrypt:Ir,decrypt:Cr};var q=(e,t=!1)=>{if(t){let r=ae.decrypt({encrypted:e.dbPassword,tag:e.dbPasswordTag,iv:e.dbPasswordIv});return{url:e.dbUrl,user:e.dbUser,database:e.dbDatabase,password:r,port:e.dbPort,schema:e.dbSchema}}return{url:e.dbUrl,user:e.dbUser,database:e.dbDatabase,password:e.dbPassword,port:e.dbPort,schema:e.dbSchema}};var pt=[{value:"=",label:"equals"},{value:"<>",label:"not equal"},{value:">",label:"greater than"},{value:">=",label:"greater than or equal"},{value:"<",label:"less than"},{value:"<=",label:"less than or equal"},{value:"LIKE",label:"contains"},{value:"NOT LIKE",label:"not contains"},{value:"IN",label:"in list"},{value:"NOT IN",label:"not in list"},{value:"IS NULL",label:"is null"},{value:"IS NOT NULL",label:"is not null"}],Nr=pt.reduce((e,t)=>(e[t.value]=t.label,e),{}),la=pt.reduce((e,t)=>(e[t.label]=t.value,e),{}),W=e=>e.map(t=>({label:Nr[t],value:t})),ma=W(["=","<>",">",">=","<","<=","IN","NOT IN","IS NULL","IS NOT NULL"]),pa=W(["=","<>","LIKE","NOT LIKE","IN","NOT IN","IS NULL","IS NOT NULL"]),fa=W(["=","<>","IS NULL","IS NOT NULL"]),ya=W(["=","<>",">",">=","<","<=","IS NULL","IS NOT NULL"]),Ta=W(["IS NULL","IS NOT NULL"]),ha=W(["IN","NOT IN"]);var Ie=["char","varchar","binary","varbinary","blob","text","enum","set","character","character varying","text","citext","uuid","xml","json","jsonb"],ga=new Set(Ie);var wa=["date","datetime","timestamp","timestamptz"].reduce((e,t)=>(e[t]=!0,e),{});var Ce=e=>e.fn?e.distinct===!0?`${e.fn} distinct ${e.value}`:`${e.fn} ${e.value}`:e.value;var Ne={read_only:10,editor:20,admin:30,owner:40};var b=e=>{let t=Ne[e];return r=>Ne[r.currentTeamRole]>=t},ft=async e=>{let t=e.routeOptions.config.requireRole;if(t&&!t(e.user))throw new s(403,"You are not authorized to perform this action")};var yt=g(e=>{e.route({method:"get",url:"/:id",handler:async t=>{let{id:r}=p(t),o=await S.findOne({where:{id:r}});if(!o)throw new s(404,"Data source not found");return{data:o}}}),e.route({method:"get",url:"/",handler:async t=>{let{teamId:r}=L(t);return{data:await S.find({where:{team:{id:r}},order:{createdAt:"DESC"}})}}}),e.route({url:"/",method:"post",config:{requireRole:b("admin")},handler:async t=>{let{teamId:r,ownerId:o,...a}=m(t,at),n=S.create({...a,allowUpdate:!!a.allowUpdate,allowInsert:!!a.allowInsert,team:{id:r},owner:{id:o}}),i=await k(q(n),n.dbType,t);try{await i.checkConnection()}catch{throw new s(400,"Cannot connect to the database, please check datasource configuration")}let{tag:u,iv:f,encrypted:c}=ae.encrypt(n.dbPassword);return n.dbPassword=c,n.dbPasswordIv=f,n.dbPasswordTag=u,{data:await S.save(n)}}}),e.route({method:"put",url:"/:id",config:{requireRole:b("admin")},handler:async t=>{let{id:r}=p(t),o=m(t),a=await S.findOneBy({id:r});if(!a)throw new s(404,"Data source not found");let n=S.merge(a,o);return await S.save(n),{data:n}}}),e.route({method:"delete",url:"/:id",config:{requireRole:b("admin")},handler:async(t,r)=>h.transaction(async()=>{let{id:o}=p(t);await Promise.all([v.delete({datasource:{id:o}}),I.delete({dataSource:{id:o}})]),await S.delete({id:o})})}),e.route({method:"post",url:"/:id/inspect",handler:async(t,r)=>{let{id:o}=p(t),a=await S.findOne({where:{id:o},select:["id","dbType","dbDatabase","dbPassword","dbPasswordTag","dbPasswordIv","dbPort","dbUrl","dbSchema","dbUser"]});if(!a)throw new Error("Data source not found");a.status="INSPECTING",await S.save(a);let i=await(await k(q(a,!0),a.dbType,t)).inspectSchema();await v.delete({datasource:{id:o}}),await v.insert(i.sort().map(u=>v.create({tableName:u.tableName,columns:u.columns,datasource:{id:o}}))),a.status="READY",a.lastInspected=new Date,await S.save(a)}}),e.route({method:"get",url:"/:id/inspections",handler:async t=>{let{id:r}=p(t);return{data:await v.find({where:{datasource:{id:r}}})}}})});var B=require("typeorm"),Tt=g(e=>{e.route({method:"get",url:"/team/:teamId/datasources",handler:async t=>{let{teamId:r}=p(t);return{data:await S.find({where:{team:{id:r}},order:{name:"ASC"},select:{id:!0,name:!0,updatedAt:!0,dbType:!0,description:!0,allowInsert:!0,allowUpdate:!0}})}}}),e.route({method:"get",url:"/team/:teamId/queries",handler:async t=>{let o=p(t).teamId||t.user.currentTeamId;return{data:(await x.find({where:[{isPersonal:!1,team:{id:o}},{isPersonal:!0,team:{id:o},user:{id:t.user.id}}],relations:{query:!0},select:{id:!0,query:{id:!0,name:!0,updatedAt:!0}}})).map(i=>({name:i.query.name,id:i.query.id,updatedAt:i.query.updatedAt,savedQueryId:i.id}))}}}),e.route({method:"get",url:"/team/:teamId/query",handler:async t=>{let{teamId:r}=p(t),{search:o,size:a,selectedDataSources:n}=L(t),i=o.length>3?parseInt(a)||20:8,u={};n?.length&&(u.id=(0,B.In)(n));let[f,c,E]=await Promise.all([v.find({where:{tableName:(0,B.Raw)(d=>`LOWER(${d}) LIKE :search`,{search:`%${o.toLowerCase()}%`}),datasource:u},relations:{datasource:!0},select:{id:!0,tableName:!0,datasource:{name:!0,id:!0}},order:{tableName:"ASC"},take:i}),A.find({where:{searchString:(0,B.Like)(`%${o.toLowerCase()}%`),team:{id:r},user:{id:t.user.id},dataSource:u},relations:{dataSource:!0},select:{id:!0,name:!0,updatedAt:!0,dataSource:{id:!0,name:!0}},order:{updatedAt:"ASC"},take:i}),x.find({where:{searchString:(0,B.Like)(`%${o.toLowerCase()}%`),team:{id:r},query:{dataSource:u}},relations:{query:{dataSource:!0}},select:{id:!0,updatedAt:!0,query:{id:!0,name:!0,dataSource:{name:!0}}},order:{updatedAt:"ASC"},take:i})]),C=[];return f.forEach(d=>{C.push({name:d.tableName,id:d.id,dataSourceName:d.datasource?.name||"--",dataSourceId:d.datasource?.id||"--",type:"table"})}),c.forEach(d=>{C.push({name:d.name,id:d.id,dataSourceName:d.dataSource?.name||"--",dataSourceId:d.dataSource?.id||"--",type:"tab"})}),E.forEach(d=>{C.push({name:d.query.name,id:d.query.id,dataSourceName:d.query.dataSource?.name||"--",dataSourceId:d.query.dataSource?.id||"--",type:"query"})}),{data:C}}}),e.route({method:"get",url:"/team/:teamId/tabs-history",handler:async t=>{let{teamId:r}=p(t),o=L(t),a=Number(o.page),n=Number(o.size),i=t.user.id,u=await A.find({where:{team:{id:r},user:{id:i}},relations:{dataSource:!0},order:{updatedAt:"DESC"},take:n+1,skip:a*n}),f=!1;return u.length>n&&(u.pop(),f=!0),{data:u.map(c=>({name:c.name,id:c.id,updatedAt:c.updatedAt,archived:c.archived,createdAt:c.createdAt,dataSourceId:c.dataSource?.id,dataSourceName:c.dataSource?.name,dataSourceType:c.dataSource?.dbType})),hasMore:f}}})});var ht=g(e=>{e.route({method:"get",url:"/:id",handler:async t=>{let{id:r}=p(t),o=await I.findOne({where:{id:r},select:{dataSource:{id:!0}},relations:{dataSource:!0}});return o?{data:o}:{status:404,data:"Query not found"}}}),e.route({method:"post",url:"/",config:{requireRole:b("editor")},handler:async t=>{let r=m(t),o=await S.findOne({where:{id:r.dataSourceId},relations:{team:!0}});return{data:await I.save(I.create({name:r.name,opts:r.opts,team:{id:o?.team.id},dataSource:{id:r.dataSourceId},user:{id:t.user.id}}))}}}),e.route({method:"patch",url:"/:id",config:{requireRole:b("editor")},handler:async t=>{let{id:r}=p(t),o=m(t);if(!(await I.update(r,o)).affected)throw new s(404,"Query not found");return{data:await I.findOneBy({id:r})}}}),e.route({method:"delete",url:"/:id",config:{requireRole:b("editor")},handler:async t=>h.transaction(async()=>{let{id:r}=p(t);if(!(await I.delete({id:r})).affected)return{status:404,data:"Query not found"}})})});var ne=e=>{let t=e.distinct===!0?"distinct ":"";return`${e.fn}(${t}${e.value})`},K={YEAR:e=>`EXTRACT(YEAR FROM ${e.value})`,MONTH:e=>`EXTRACT(MONTH FROM ${e.value})`,DAY:e=>`EXTRACT(DAY FROM ${e.value})`,SUM:e=>`COALESCE(SUM(${e.distinct===!0?"distinct ":""}${e.value}), 0)`,AVG:ne,MAX:ne,MIN:ne,COUNT:ne};var se=e=>{let t=e.distinct===!0?"distinct ":"";return`${e.fn}(${t}${e.value})`},V={YEAR:e=>`YEAR(${e.value})`,MONTH:e=>`MONTH(${e.value})`,DAY:e=>`DAY(${e.value})`,SUM:e=>{let t=e.distinct===!0?"distinct ":"";return`coalesce(${e.fn}(${t}${e.value}), 0)`},AVG:se,MAX:se,MIN:se,COUNT:se};var gt=["SUM","COUNT","AVG","MAX","MIN"],Ar=["YEAR","MONTH","DAY",...gt],Or=Ar.reduce((e,t)=>(e[t]=!0,e),{}),Pr=gt.reduce((e,t)=>(e[t]=!0,e),{}),ie=e=>Or[e],wt=e=>Pr[e],Et=(e,t)=>e.fn&&ie(e.fn)?(t==="postgres"?K:V)[e.fn](e):e.value;var ue=e=>typeof e=="string",St=e=>{let t="SELECT ";if(e.columns&&e.columns.length>0?t+=e.columns.join(", "):t+="*",e.table&&(t+=` FROM ${e.table}`),e.joins&&e.joins.length>0&&e.joins.forEach(r=>{t+=` ${r.type} JOIN ${r.table} ON ${r.on}`}),e.where&&(t+=` WHERE ${e.where}`),e.groupBy&&e.groupBy.length>0&&(t+=` GROUP BY ${e.groupBy.join(", ")}`),e.having&&(t+=` HAVING ${e.having}`),e.orderBy&&e.orderBy.length>0){let r=e.orderBy.reduce((a,n)=>(a[n.column]=n.direction,a),{}),o=Object.entries(r).map(([a,n])=>`${a} ${n}`);t+=` ORDER BY ${o.join(", ")}`}return e.limit!==void 0&&(t+=` LIMIT ${e.limit}`),e.offset!==void 0&&(t+=` OFFSET ${e.offset}`),t},z=(e,t)=>{let{column:r,operator:o,value:a,fn:n}=e,i=Et({value:r,fn:n},t);switch(o){case"IS NULL":case"IS NOT NULL":return`${i} ${o}`;case"IN":case"NOT IN":let u=a?.map(d=>ue(d.value)?`'${d.value}'`:d.value).join(", ");return`${i} ${o} (${u})`;case"LIKE":return`${i} ${t==="postgres"?"ILIKE":"LIKE"} '%${a?.[0].value}%'`;case"NOT LIKE":return`${i} ${t==="postgres"?"NOT ILIKE":"NOT LIKE"} '%${a?.[0].value}%'`;default:let E=a?.[0],C;return ue(E?.value)&&E?.isColumn!==!0?C=`'${E?.value}'`:C=E?.value,`${i} ${o} ${C}`}};var ce=class{constructor(t="mysql"){this.dialect=t,this.skeleton={type:"SELECT"}}addWhere(t){let r=z(t,this.dialect);if(t.isEnabled!==!1)if(this.skeleton.where){let o=t.connector||"AND";this.skeleton.where+=` ${o} ${r}`}else this.skeleton.where=r;return this}addWhereRaw(t,r="AND"){return this.skeleton.where?this.skeleton.where+=` ${r} ${t}`:this.skeleton.where=t,this}clearWhere(){return this.skeleton.where=void 0,this}addHaving(t){let r=z(t,this.dialect);if(t.isEnabled!==!1)if(this.skeleton.having){let o=t.connector||"AND";this.skeleton.having+=` ${o} ${r}`}else this.skeleton.having=r;return this}clearHaving(){return this.skeleton.having=void 0,this}addOrderBy(...t){return this.skeleton.orderBy||(this.skeleton.orderBy=[]),this.skeleton.orderBy.push(...t),this}clearOrderBy(){return this.skeleton.orderBy=void 0,this}setLimit(t){return this.skeleton.limit=t,this}setOffset(t){return this.skeleton.offset=t,this}addGroupBy(t){this.skeleton.groupBy||(this.skeleton.groupBy=[]);let r=this.skeleton.groupBy.findIndex(o=>o===t);return r>-1?this.skeleton.groupBy[r]=t:this.skeleton.groupBy.push(t),this}setTable(t){return this.skeleton.table=t,this}addJoin(...t){return this.skeleton.joins||(this.skeleton.joins=[]),this.skeleton.joins.push(...t),this}selectColumns(t){if(this.skeleton.type!=="SELECT")throw new Error("Column selection is only supported for SELECT queries");return this.skeleton.columns=t,this}toSQL(){return St(this.skeleton)}};var Rt=require("typeorm");var de=async(e,t)=>{let{datasourceId:r,size:o=20,page:a,name:n}=t,{table:i,filters:u,joins:f,groupBy:c,searchAll:E,orderBy:C}=t.opts,d=xr(t.opts.columns,t.opts.groupBy,t.opts.aggregations),w=await S.findOne({where:{id:r},select:["id","dbType","dbDatabase","dbPassword","dbPasswordTag","dbPasswordIv","dbPort","dbUrl","dbSchema","dbUser"]}),F=[i],Y=[];if(!w)throw new s(404,"Data source not found");let Vt=await I.save(I.create({user:{id:e.user.id},team:{id:e.user.currentTeamId},dataSource:{id:r},name:n,opts:t.opts})),P=new ce(w.dbType);P.setTable(i),P.setLimit(o+1),P.setOffset(o*a),u?.forEach(l=>{l.fn&&wt(l.fn)?P.addHaving(l):P.addWhere(l)}),f&&(P.addJoin(...f),f.forEach(l=>{F.push(l.table)}));let _e=vr(d,C,w.dbType);_e.length>0&&P.addOrderBy(..._e),c&&c.length>0&&c.forEach(l=>P.addGroupBy(Ur(l,w.dbType)));let zt=await v.find({where:{tableName:(0,Rt.In)(F),datasource:{id:r}}});for(let l of zt)if(l.columns)for(let _ of l.columns)Y.push({column:_.name,table:l.tableName||"",full:`${l.tableName}.${_.name}`,type:_.type});let Jt=Y.reduce((l,_)=>(l[_.full]=_.type,l),{}),X;if(d&&d.length>0?X=d.map(l=>Dr(l,w.dbType)):X=Y.map(l=>`${l.full} as "${l.full}"`),P.selectColumns(X),E){let l=Y.filter(_=>Ie.includes(_.type)&&X.some(le=>le.startsWith(_.full)));if(l.length>0){let _=l.map(le=>`LOWER(${le.full}) LIKE '%${E.toLowerCase()}%'`);P.addWhereRaw(`(${_.join(" OR ")})`,"AND")}}let Z=await(await k(q(w,!0),w.dbType,e)).executeQuery(P.toSQL(),{type:"SELECT",allowBulkUpdate:!1}),De=Z.rows.length>o;return De&&Z.rows.pop(),{...Z,queryHistoryId:Vt.id,tables:F,allColumns:Y,columns:Z.columns.map(l=>({...l,type:Jt[l.full]})),hasMore:De}},It=async(e,t)=>{let r=await S.findOne({where:{id:t.datasourceId},select:["id","dbType","dbDatabase","dbPassword","dbPasswordTag","dbPasswordIv","dbPort","dbUrl","dbSchema","dbUser","allowUpdate"]});if(!r)throw new s(404,"Data source not found");if(!r.allowUpdate)throw new s(403,"This datasource does not allow update operations");let o=t.values.map(({value:u,column:f})=>typeof u=="string"?u&&u.startsWith("=")?`${f}=${u.substring(1)}`:`${f}='${u}'`:`${f}='${u}'`).join(", "),a=t.filters.map(u=>z(u,r.dbType)).join(" AND "),n=`UPDATE ${t.table} SET ${o} WHERE ${a}`;return(await k(q(r,!0),r.dbType,e)).executeQuery(n,{type:"UPDATE",allowBulkUpdate:!1})},Ct=async(e,t)=>{let r=await S.findOne({where:{id:t.datasourceId},select:["id","dbType","dbDatabase","dbPassword","dbPasswordTag","dbPasswordIv","dbPort","dbUrl","dbSchema","dbUser","allowInsert"]});if(!r)throw new s(404,"Data source not found");if(!r.allowInsert)throw new s(403,"This datasource does not allow insert operations");let{keys:o,values:a}=_r(t.values),n=`INSERT INTO ${t.table} (${o}) VALUES (${a})`;return(await k(q(r,!0),r.dbType,e)).executeQuery(n,{type:"INSERT",allowBulkUpdate:!1})},_r=e=>{let t=e.map(({column:o})=>o).join(", "),r=e.map(({value:o})=>typeof o=="string"?o&&o.startsWith("=")?o.substring(1):`'${o}'`:o).join(", ");return{keys:t,values:r}},Dr=(e,t)=>{if(e.fn){if(ie(e.fn))return`${(t==="postgres"?K:V)[e.fn](e)} as "${Ce(e)}"`;throw new Error("Function not allowed: "+e.fn)}return`${e.value} as "${e.value}"`},Ur=(e,t)=>{if(e.fn){if(ie(e.fn))return(t==="postgres"?K:V)[e.fn]({...e,value:bt(e.value,t)});throw new Error("Function not allowed: "+e.fn)}return bt(e.value,t)},Ae=(e,t)=>t==="postgres"?`"${e}"`:t==="mysql"?`\`${e}\``:e,bt=(e,t)=>{let[r,o]=e.split(".");return Ae(r,t)+"."+Ae(o,t)},vr=(e,t,r)=>{if(e&&e.length>0){let o=e.reduce((a,n)=>(a.set(Ce(n),{isFn:!!(n.fn||n.distinct)}),a),new Map);t=t.filter(a=>o.has(a.column)).map(a=>o.get(a.column)?.isFn?{...a,column:Ae(a.column,r)}:a)}return t},xr=(e,t,r)=>{let o=[];return t.length>0||r.length>0?o.push(...t,...r):e.length>0&&o.push(...e),o};var Nt=e=>{},Mr=["--",";","DROP","drop"],At=e=>{if(ue(e.value)&&e.value.startsWith("=")){let t=e.value;Mr.forEach(r=>{if(t.includes(r))throw new s(400,"Invalid input value for "+e.column)})}},Ot=e=>{if(!e.table)throw new s(400,"Table is required");e.values.forEach(At)},Pt=e=>{if(!e.table)throw new s(400,"Table is required");e.values.forEach(At)};var _t=g(e=>{e.route({method:"post",url:"/select",handler:async t=>{let r=m(t,Nt);return{data:await de(t,r)}}}),e.route({method:"post",url:"/insert",config:{requireRole:b("editor")},handler:async t=>{let r=m(t,Ot);return{data:await Ct(t,r)}}}),e.route({method:"post",url:"/update",config:{requireRole:b("editor")},handler:async t=>{let r=m(t,Pt);return{data:await It(t,r)}}})});var Dt=g(e=>{e.get("/",{config:{isPublic:!0}},async()=>({data:{active:!0,version:T.str("SERVER_VERSION")}}))});var Ut=g(e=>{e.route({method:"get",url:"/:id/users",handler:async t=>{let{id:r}=p(t),o=await M.findOne({where:{id:r},relations:{users:{user:!0}}});if(!o)throw new s(404,"Team not found");return{data:o.users.map(a=>({role:a.role,id:a.user.id,name:a.user.username}))}}}),e.route({method:"post",url:"/",config:{requireRole:b("editor")},handler:async t=>h.transaction(async()=>{let r=t.user.id,o=m(t),a=R.create();a.id=r;let n=M.create(o);await M.save(n);let i=N.create({user:a,team:n});return await N.save(i),{data:n}})}),e.route({method:"patch",url:"/:id/user-role",config:{requireRole:b("admin")},handler:async t=>{let{id:r}=p(t),{role:o,userId:a}=m(t,({role:i})=>{if(i==="owner")throw new s(400,"Only one owner is allowed")});if((await N.findOneBy({user:{id:a},team:{id:r}}))?.role==="owner")throw new s(400,"Cannot change owner role");await N.update({user:{id:a},team:{id:r}},{role:o})}}),e.route({method:"delete",url:"/:id",config:{requireRole:b("admin")},handler:async t=>h.transaction(async()=>{let{id:r}=p(t),{userId:o}=L(t);if((await N.findOneBy({user:{id:o},team:{id:r}}))?.role==="owner")throw new s(400,"Cannot delete team owner");await R.update(o,{currentTeam:null}),await N.delete({user:{id:o},team:{id:r}}),await R.delete({id:o})})})});var Oe=D(require("bcryptjs")),J=async e=>{let t=await Oe.default.genSalt(10);return Oe.default.hash(e,t)};var vt=g(e=>{e.route({method:"get",url:"/",handler:async t=>{let r=await R.findOne({where:{id:t.user.id},relations:{currentTeam:{team:!0}}});if(!r)throw new s(404,"User not found");return{data:{id:r.id,teamId:r.currentTeam?.team.id,teamName:r.currentTeam?.team.name,teamRole:r.currentTeam?.role,username:r.username}}}}),e.route({method:"patch",url:"/",handler:async t=>{let r=t.user.id,o=m(t);if(o.password&&(o.password=await J(o.password)),!(await R.update(r,o)).affected)throw new s(404,"User not found");let n=await R.findOne({where:{id:r},relations:{currentTeam:{team:!0}}});return{data:{id:n?.id,teamId:n?.currentTeam?.team.id,teamName:n?.currentTeam?.team.name,teamRole:n?.currentTeam?.role,username:n?.username}}}}),e.route({method:"post",url:"/",config:{requireRole:b("admin")},handler:async t=>h.transaction(async()=>{let r=m(t),o=await J(r.password),a=await R.save(R.create({username:r.username,password:o})),n=await N.save(N.create({role:"read_only",team:{id:r.teamId},user:{id:a.id}}));await R.update(a.id,{currentTeam:{id:n.id}})})})});var xt=g(e=>{e.route({method:"get",url:"/",handler:async t=>{let r=t.user.id,o=await $.findOneBy({user:{id:r}});return o||(o=await $.save($.create({user:{id:r}}))),{data:o}}}),e.route({method:"patch",url:"/",handler:async t=>{let{settings:r}=m(t);if(!r.id)throw new s(400,"Settings id is required!");if(!(await $.update(r.id,r)).affected)throw new s(404,"You do not own these settings!");return{data:await $.findOneBy({id:r.id})}}})});function H(e,...t){let r=[...t];if(e.searchAll&&r.push(e.searchAll),e.filters){for(let o of e.filters)if(o.value)for(let a of o.value)a.value&&r.push(a.value.toString())}return r.map(o=>o.toLowerCase()).join(",")}var Mt=g(e=>{e.route({method:"post",url:"/",config:{requireRole:b("editor")},handler:async t=>{let r=m(t),o=await I.findOne({where:{id:r.queryId}});if(!o)throw new s(400,"Query not found");let a=await x.save(x.create({isPersonal:!1,team:{id:t.user.currentTeamId},user:{id:t.user.id},query:{id:r.queryId},searchString:H(o.opts,r.name)}));return await I.update(r.queryId,{name:r.name}),{data:a}}}),e.route({method:"delete",url:"/:id",config:{requireRole:b("editor")},handler:async t=>{let{id:r}=p(t);if(!(await x.delete({id:r})).affected)return{status:404,data:"Query not found"}}}),e.route({method:"patch",url:"/:id",handler:async t=>await h.transaction(async()=>{let{id:r}=p(t),o=m(t,i=>{if(!i.name)throw new s(400,"Name is required")}),a=await x.findOne({where:{id:r},relations:{query:!0}});if(!a)throw new s(400,"Query not found");let n=H(a.query.opts,o.name);return await Promise.all([x.update({id:r},{searchString:n}),I.update({id:a.query.id},{name:o.name})]),{data:!0}})})});var Lt=e=>{if(!e.queryId&&!(e.opts&&e.name))throw new s(400,"Either queryId or name and opts are required")};var kt=g(e=>{e.route({method:"get",url:"/",handler:async t=>{let{currentTeamId:r,id:o}=t.user;return{data:(await A.find({where:{team:{id:r},user:{id:o},archived:!1},select:["id","name"]})).map(n=>({name:n.name,id:n.id}))}}}),e.route({method:"get",url:"/:id",handler:async t=>{let{id:r}=p(t),{currentTeamId:o,id:a}=t.user,n=await A.findOne({where:{id:r,team:{id:o},user:{id:a}}});if(!n)throw new s(404,"Not Found");return{data:n}}}),e.route({method:"post",url:"/",handler:async t=>{let{opts:r,name:o,queryId:a}=m(t,Lt),n,i,u=o;if(r)i=r.dataSourceId,n=r;else{let c=await I.findOne({where:{id:a},relations:{dataSource:!0}});if(!c)throw new s(404,"Query not Found");i=c.dataSource.id,n={table:c.opts.table,filters:c.opts.filters,joins:c.opts.joins,orderBy:c.opts.orderBy,columns:c.opts.columns,groupBy:c.opts.groupBy,searchAll:c.opts.searchAll,aggregations:c.opts.aggregations,dataSourceId:c.dataSource.id,page:0,size:50},o||(u=c.name)}return{data:await A.save(A.create({name:u||new Date().toISOString(),opts:n,dataSource:{id:i},user:{id:t.user.id},team:{id:t.user.currentTeamId}}))}}}),e.route({method:"post",url:"/:id/run",handler:async t=>{let{id:r}=p(t),o=m(t),a=await A.findOne({where:{id:r},relations:{user:!0}});if(!a)throw new s(404,"Not found");if(a.user?.id!==t.user.id)throw new s(404,"Not found");return o&&A.update(r,{opts:o,searchString:H(o,a.name),updatedAt:new Date}),{data:{result:await de(t,{datasourceId:o.dataSourceId,size:o.size,name:a.name,page:o.page,opts:{table:o.table,filters:o.filters,joins:o.joins,orderBy:o.orderBy,columns:o.columns,groupBy:o.groupBy,searchAll:o.searchAll,aggregations:o.aggregations}})}}}}),e.route({method:"patch",url:"/:id",handler:async t=>{let{id:r}=p(t),o=m(t),a=await A.findOne({where:{id:r,user:{id:t.user.id}}});if(!a)throw new s(404,"Not Found");let n=a.searchString;return o.name&&(n=H(a.opts,o.name)),await A.update(r,{...o,searchString:n}),{data:{id:r}}}}),e.route({method:"delete",url:"/:id",handler:async t=>{let{id:r}=p(t),o=t.user.id;return await A.delete({id:r,user:{id:o}}),{data:!0}}})});var Yt=require("node:path");var Lr=e=>e.routeOptions.config.isPublic?!0:!e.url.startsWith("/api/"),qt=async e=>{if(Lr(e))return;let t=e.headers.authorization;if(!t)throw new s(401,"Missing auth token");let[r,o]=t.split(" ");try{let{userId:a}=await Ze(o),n=await R.findOne({where:{id:a},select:{id:!0,currentTeam:{role:!0,team:{id:!0}}},relations:{currentTeam:{team:!0}}});if(!n)throw new s(401,"User is not part of a team");e.user={id:a,currentTeamId:n.currentTeam.team.id,currentTeamRole:n.currentTeam.role}}catch{throw new s(401,"Unauthorized")}};var Qt=(e,t)=>{e.__connections&&e.__connections.forEach(r=>{r.close()})};var jt=D(require("@fastify/cookie"));var Pe={teamName:"Default Team",username:"admin",password:"admin"},kr=async()=>{let e=await M.findOneBy({});return e||M.save(M.create({name:Pe.teamName}))},Bt=async()=>{let e=await N.findOne({where:{role:"owner"},relations:{user:!0}});if(e)return e.user;let t=await kr(),r=await J(Pe.password),o=await R.save(R.create({username:Pe.username,password:r})),a=await N.save(N.create({user:o,team:t,role:"owner"}));return await R.update(o.id,{currentTeam:a}),o};var O=(0,Ft.default)({querystringParser:e=>Ht.default.parse(e)}),Gt=T.num("PORT",4466),Kt=T.str("ALLOWED_ORIGINS","").split(",").map(e=>e.trim()),qr="0.0.0.0",Qr=[`http://localhost:${Gt}`,...Kt],Br=Kt.includes("*");function Fr(e){return Br||Qr.includes(e)}function U(e,t){O.register(e,{prefix:t}),console.log("Registered "+t)}(async function(){Me(),await O.register(jt.default,{}),await O.register($t.default,{origin:(t,r)=>{t&&Fr(t)?r(null,!0):r(new Error("Not allowed by CORS"),!1)},methods:["GET","POST","PUT","PATCH","DELETE","OPTIONS"],credentials:!0}),await O.register(Wt.default,{root:(0,Yt.join)(__dirname,"web")}),O.get("/",(t,r)=>{r.sendFile("index.html")}),O.addHook("onRequest",qt),O.addHook("onRequest",ft),O.addHook("onResponse",Qt),U(ot,"/api/auth"),U(yt,"/api/data-sources"),U(Tt,"/api/project"),U(ht,"/api/queries"),U(_t,"/api/runner"),U(Dt,"/api/status"),U(Ut,"/api/teams"),U(vt,"/api/users"),U(xt,"/api/user-settings"),U(Mt,"/api/saved-queries"),U(kt,"/api/workbench-tabs"),O.setNotFoundHandler((t,r)=>{if(t.raw.url?.startsWith("/api/")){r.code(404).send({error:"API route not found"});return}r.sendFile("index.html")}),O.setErrorHandler((t,r,o)=>{if(console.error(t),t instanceof s){o.status(t.status).send({error:t.message});return}else o.status(500).send({error:"Internal Server Error"})}),await O.after(),await Ke(),await Bt(),O.listen({port:Gt,host:qr},(t,r)=>{t&&(console.error(t),process.exit(1)),console.log(`Server listening at ${r}`)})})();
|
|
57
|
+
limit 75;`;return(await t.query(r)).rows.reduce((a,n)=>(a[n.row_key]={table:n.relname,column:n.attname},a),{})},ut=async(e,t,r)=>{try{console.log(`[PG CONN] Query: ${e}`);let{rows:o,fields:a,command:n,rowCount:i}=await t.query({text:e,rowMode:"array"});if(n==="UPDATE"||n==="INSERT"||n==="DELETE"){if(i!=null&&i>1&&r.allowBulkUpdate!==!0)throw new Error("[PG CONN] Bulk update performed without permission.");return{columns:[{column:"affectedRows",alias:"Affected rows",full:"affectedRows"}],rows:[[i]],query:e}}if(n==="SELECT"){let u=a.map(c=>`'${c.tableID}-${c.columnID}'`),f=await Er(u,t);return{columns:a.map(c=>{let E=f[`${c.tableID}-${c.columnID}`];return{column:E?.column||c.name,alias:c.name,table:E?.table||"",full:E?E.table+"."+E.column:c.name}}),rows:o,query:e}}throw new Error(`[PG CONN] Unsupported command: ${n}`)}catch(o){throw o instanceof s?o:new s(400,o.message)}},Sr=async(e,t)=>{await e.query("BEGIN");try{let r=await t();return await e.query("COMMIT"),console.log("[PG CONN] Commit"),r}catch(r){throw await e.query("ROLLBACK"),console.log("[PG CONN] Rollback"),r}},br=async(e,t)=>{await e.query("BEGIN READ ONLY");try{let r=await t();return console.log("[PG CONN] Read only rollback"),await e.query("ROLLBACK"),r}catch(r){throw console.log("[PG CONN] Rollback"),await e.query("ROLLBACK"),r}},dt=async e=>{let t=await Tr(e),r=!1,o=!1,a=async n=>(o||await t.query(`SET search_path TO ${e.schema}`),n());return{dbType:"postgres",dataSource:e,inspectSchema:()=>wr(e,t),executeQuery:(n,i)=>a(()=>i.type==="SELECT"?br(t,()=>ut(n,t,i)):Sr(t,()=>ut(n,t,i))),checkConnection:async()=>{},isClosed:()=>r,close:async()=>{if(!r)return r=!0,t.end()}}};var k=async(e,t,r)=>{try{let o;if(t==="mysql")o=await it(e);else if(t==="postgres")o=await dt(e);else throw new s(500,`Connection manager for ${t} not found`);return r.__connections?r.__connections.push(o):r.__connections=[o],o}catch(o){throw console.error(o),o instanceof s?o:o?.code==="ECONNREFUSED"?new s(500,"Failed to connect to the database"):new s(500,o.message)}};var oe=D(require("node:crypto"));var mt="aes-256-gcm",Rr=12,lt=()=>{let e=T.str("SYMM_ENCRYPTION_KEY");if(!e)throw new Error("Missing ENCRYPTION_KEY in environment variables.");let t=Buffer.from(e,"hex");if(t.length!==32)throw new Error("ENCRYPTION_KEY must be a 64-character hex string (256 bits).");return t},Ir=e=>{let t=oe.default.randomBytes(Rr),r=lt(),o=oe.default.createCipheriv(mt,r,t),a=o.update(e,"utf8","hex");a+=o.final("hex");let n=o.getAuthTag();return{encrypted:a,iv:t.toString("hex"),tag:n.toString("hex")}},Cr=({encrypted:e,iv:t,tag:r})=>{let o=lt(),a=oe.default.createDecipheriv(mt,o,Buffer.from(t,"hex"));a.setAuthTag(Buffer.from(r,"hex"));let n=a.update(e,"hex","utf8");return n+=a.final("utf8"),n},ae={encrypt:Ir,decrypt:Cr};var q=(e,t=!1)=>{if(t){let r=ae.decrypt({encrypted:e.dbPassword,tag:e.dbPasswordTag,iv:e.dbPasswordIv});return{url:e.dbUrl,user:e.dbUser,database:e.dbDatabase,password:r,port:e.dbPort,schema:e.dbSchema}}return{url:e.dbUrl,user:e.dbUser,database:e.dbDatabase,password:e.dbPassword,port:e.dbPort,schema:e.dbSchema}};var pt=[{value:"=",label:"equals"},{value:"<>",label:"not equal"},{value:">",label:"greater than"},{value:">=",label:"greater than or equal"},{value:"<",label:"less than"},{value:"<=",label:"less than or equal"},{value:"LIKE",label:"contains"},{value:"NOT LIKE",label:"not contains"},{value:"IN",label:"in list"},{value:"NOT IN",label:"not in list"},{value:"IS NULL",label:"is null"},{value:"IS NOT NULL",label:"is not null"}],Nr=pt.reduce((e,t)=>(e[t.value]=t.label,e),{}),ca=pt.reduce((e,t)=>(e[t.label]=t.value,e),{}),W=e=>e.map(t=>({label:Nr[t],value:t})),da=W(["=","<>",">",">=","<","<=","IN","NOT IN","IS NULL","IS NOT NULL"]),ma=W(["=","<>","LIKE","NOT LIKE","IN","NOT IN","IS NULL","IS NOT NULL"]),la=W(["=","<>","IS NULL","IS NOT NULL"]),pa=W(["=","<>",">",">=","<","<=","IS NULL","IS NOT NULL"]),fa=W(["IS NULL","IS NOT NULL"]),ya=W(["IN","NOT IN"]);var Ie=["char","varchar","binary","varbinary","blob","text","enum","set","character","character varying","text","citext","uuid","xml","json","jsonb"],Ta=new Set(Ie);var ha=["date","datetime","timestamp","timestamptz"].reduce((e,t)=>(e[t]=!0,e),{});var Ce=e=>e.fn?e.distinct===!0?`${e.fn} distinct ${e.value}`:`${e.fn} ${e.value}`:e.value;var Ne={read_only:10,editor:20,admin:30,owner:40};var b=e=>{let t=Ne[e];return r=>Ne[r.currentTeamRole]>=t},ft=async e=>{let t=e.routeOptions.config.requireRole;if(t&&!t(e.user))throw new s(403,"You are not authorized to perform this action")};var yt=g(e=>{e.route({method:"get",url:"/:id",handler:async t=>{let{id:r}=p(t),o=await S.findOne({where:{id:r}});if(!o)throw new s(404,"Data source not found");return{data:o}}}),e.route({method:"get",url:"/",handler:async t=>{let{teamId:r}=L(t);return{data:await S.find({where:{team:{id:r}},order:{createdAt:"DESC"}})}}}),e.route({url:"/",method:"post",config:{requireRole:b("admin")},handler:async t=>{let{teamId:r,ownerId:o,...a}=l(t,at),n=S.create({...a,allowUpdate:!!a.allowUpdate,allowInsert:!!a.allowInsert,team:{id:r},owner:{id:o}}),i=await k(q(n),n.dbType,t);try{await i.checkConnection()}catch{throw new s(400,"Cannot connect to the database, please check datasource configuration")}let{tag:u,iv:f,encrypted:c}=ae.encrypt(n.dbPassword);return n.dbPassword=c,n.dbPasswordIv=f,n.dbPasswordTag=u,{data:await S.save(n)}}}),e.route({method:"put",url:"/:id",config:{requireRole:b("admin")},handler:async t=>{let{id:r}=p(t),o=l(t),a=await S.findOneBy({id:r});if(!a)throw new s(404,"Data source not found");let n=S.merge(a,o);return await S.save(n),{data:n}}}),e.route({method:"delete",url:"/:id",config:{requireRole:b("admin")},handler:async(t,r)=>h.transaction(async()=>{let{id:o}=p(t);await Promise.all([v.delete({datasource:{id:o}}),I.delete({dataSource:{id:o}})]),await S.delete({id:o})})}),e.route({method:"post",url:"/:id/inspect",handler:async(t,r)=>{let{id:o}=p(t),a=await S.findOne({where:{id:o},select:["id","dbType","dbDatabase","dbPassword","dbPasswordTag","dbPasswordIv","dbPort","dbUrl","dbSchema","dbUser"]});if(!a)throw new Error("Data source not found");a.status="INSPECTING",await S.save(a);let i=await(await k(q(a,!0),a.dbType,t)).inspectSchema();await v.delete({datasource:{id:o}}),await v.insert(i.sort().map(u=>v.create({tableName:u.tableName,columns:u.columns,datasource:{id:o}}))),a.status="READY",a.lastInspected=new Date,await S.save(a)}}),e.route({method:"get",url:"/:id/inspections",handler:async t=>{let{id:r}=p(t);return{data:await v.find({where:{datasource:{id:r}}})}}})});var B=require("typeorm"),Tt=g(e=>{e.route({method:"get",url:"/team/:teamId/datasources",handler:async t=>{let{teamId:r}=p(t);return{data:await S.find({where:{team:{id:r}},order:{name:"ASC"},select:{id:!0,name:!0,updatedAt:!0,dbType:!0,description:!0,allowInsert:!0,allowUpdate:!0}})}}}),e.route({method:"get",url:"/team/:teamId/queries",handler:async t=>{let o=p(t).teamId||t.user.currentTeamId;return{data:(await x.find({where:[{isPersonal:!1,team:{id:o}},{isPersonal:!0,team:{id:o},user:{id:t.user.id}}],relations:{query:!0},select:{id:!0,query:{id:!0,name:!0,updatedAt:!0}}})).map(i=>({name:i.query.name,id:i.query.id,updatedAt:i.query.updatedAt,savedQueryId:i.id}))}}}),e.route({method:"get",url:"/team/:teamId/query",handler:async t=>{let{teamId:r}=p(t),{search:o,size:a,selectedDataSources:n}=L(t),i=o.length>3?parseInt(a)||20:8,u={};n?.length&&(u.id=(0,B.In)(n));let[f,c,E]=await Promise.all([v.find({where:{tableName:(0,B.Raw)(d=>`LOWER(${d}) LIKE :search`,{search:`%${o.toLowerCase()}%`}),datasource:u},relations:{datasource:!0},select:{id:!0,tableName:!0,datasource:{name:!0,id:!0}},order:{tableName:"ASC"},take:i}),A.find({where:{searchString:(0,B.Like)(`%${o.toLowerCase()}%`),team:{id:r},user:{id:t.user.id},dataSource:u},relations:{dataSource:!0},select:{id:!0,name:!0,updatedAt:!0,dataSource:{id:!0,name:!0}},order:{updatedAt:"ASC"},take:i}),x.find({where:{searchString:(0,B.Like)(`%${o.toLowerCase()}%`),team:{id:r},query:{dataSource:u}},relations:{query:{dataSource:!0}},select:{id:!0,updatedAt:!0,query:{id:!0,name:!0,dataSource:{name:!0}}},order:{updatedAt:"ASC"},take:i})]),C=[];return f.forEach(d=>{C.push({name:d.tableName,id:d.id,dataSourceName:d.datasource?.name||"--",dataSourceId:d.datasource?.id||"--",type:"table"})}),c.forEach(d=>{C.push({name:d.name,id:d.id,dataSourceName:d.dataSource?.name||"--",dataSourceId:d.dataSource?.id||"--",type:"tab"})}),E.forEach(d=>{C.push({name:d.query.name,id:d.query.id,dataSourceName:d.query.dataSource?.name||"--",dataSourceId:d.query.dataSource?.id||"--",type:"query"})}),{data:C}}}),e.route({method:"get",url:"/team/:teamId/tabs-history",handler:async t=>{let{teamId:r}=p(t),o=L(t),a=Number(o.page),n=Number(o.size),i=t.user.id,u=await A.find({where:{team:{id:r},user:{id:i}},relations:{dataSource:!0},order:{updatedAt:"DESC"},take:n+1,skip:a*n}),f=!1;return u.length>n&&(u.pop(),f=!0),{data:u.map(c=>({name:c.name,id:c.id,updatedAt:c.updatedAt,archived:c.archived,createdAt:c.createdAt,dataSourceId:c.dataSource?.id,dataSourceName:c.dataSource?.name,dataSourceType:c.dataSource?.dbType})),hasMore:f}}})});var ht=g(e=>{e.route({method:"get",url:"/:id",handler:async t=>{let{id:r}=p(t),o=await I.findOne({where:{id:r},select:{dataSource:{id:!0}},relations:{dataSource:!0}});return o?{data:o}:{status:404,data:"Query not found"}}}),e.route({method:"post",url:"/",config:{requireRole:b("editor")},handler:async t=>{let r=l(t),o=await S.findOne({where:{id:r.dataSourceId},relations:{team:!0}});return{data:await I.save(I.create({name:r.name,opts:r.opts,team:{id:o?.team.id},dataSource:{id:r.dataSourceId},user:{id:t.user.id}}))}}}),e.route({method:"patch",url:"/:id",config:{requireRole:b("editor")},handler:async t=>{let{id:r}=p(t),o=l(t);if(!(await I.update(r,o)).affected)throw new s(404,"Query not found");return{data:await I.findOneBy({id:r})}}}),e.route({method:"delete",url:"/:id",config:{requireRole:b("editor")},handler:async t=>h.transaction(async()=>{let{id:r}=p(t);if(!(await I.delete({id:r})).affected)return{status:404,data:"Query not found"}})})});var ne=e=>{let t=e.distinct===!0?"distinct ":"";return`${e.fn}(${t}${e.value})`},K={YEAR:e=>`EXTRACT(YEAR FROM ${e.value})`,MONTH:e=>`EXTRACT(MONTH FROM ${e.value})`,DAY:e=>`EXTRACT(DAY FROM ${e.value})`,SUM:e=>`COALESCE(SUM(${e.distinct===!0?"distinct ":""}${e.value}), 0)`,AVG:ne,MAX:ne,MIN:ne,COUNT:ne};var se=e=>{let t=e.distinct===!0?"distinct ":"";return`${e.fn}(${t}${e.value})`},V={YEAR:e=>`YEAR(${e.value})`,MONTH:e=>`MONTH(${e.value})`,DAY:e=>`DAY(${e.value})`,SUM:e=>{let t=e.distinct===!0?"distinct ":"";return`coalesce(${e.fn}(${t}${e.value}), 0)`},AVG:se,MAX:se,MIN:se,COUNT:se};var gt=["SUM","COUNT","AVG","MAX","MIN"],Ar=["YEAR","MONTH","DAY",...gt],Or=Ar.reduce((e,t)=>(e[t]=!0,e),{}),Pr=gt.reduce((e,t)=>(e[t]=!0,e),{}),ie=e=>Or[e],wt=e=>Pr[e],Et=(e,t)=>e.fn&&ie(e.fn)?(t==="postgres"?K:V)[e.fn](e):e.value;var ue=e=>typeof e=="string",St=e=>{let t="SELECT ";if(e.columns&&e.columns.length>0?t+=e.columns.join(", "):t+="*",e.table&&(t+=` FROM ${e.table}`),e.joins&&e.joins.length>0&&e.joins.forEach(r=>{t+=` ${r.type} JOIN ${r.table} ON ${r.on}`}),e.where&&(t+=` WHERE ${e.where}`),e.groupBy&&e.groupBy.length>0&&(t+=` GROUP BY ${e.groupBy.join(", ")}`),e.having&&(t+=` HAVING ${e.having}`),e.orderBy&&e.orderBy.length>0){let r=e.orderBy.reduce((a,n)=>(a[n.column]=n.direction,a),{}),o=Object.entries(r).map(([a,n])=>`${a} ${n}`);t+=` ORDER BY ${o.join(", ")}`}return e.limit!==void 0&&(t+=` LIMIT ${e.limit}`),e.offset!==void 0&&(t+=` OFFSET ${e.offset}`),t},z=(e,t)=>{let{column:r,operator:o,value:a,fn:n}=e,i=Et({value:r,fn:n},t);switch(o){case"IS NULL":case"IS NOT NULL":return`${i} ${o}`;case"IN":case"NOT IN":let u=a?.map(d=>ue(d.value)?`'${d.value}'`:d.value).join(", ");return`${i} ${o} (${u})`;case"LIKE":return`${i} ${t==="postgres"?"ILIKE":"LIKE"} '%${a?.[0].value}%'`;case"NOT LIKE":return`${i} ${t==="postgres"?"NOT ILIKE":"NOT LIKE"} '%${a?.[0].value}%'`;default:let E=a?.[0],C;return ue(E?.value)&&E?.isColumn!==!0?C=`'${E?.value}'`:C=E?.value,`${i} ${o} ${C}`}};var ce=class{constructor(t="mysql"){this.dialect=t,this.skeleton={type:"SELECT"}}addWhere(t){let r=z(t,this.dialect);if(t.isEnabled!==!1)if(this.skeleton.where){let o=t.connector||"AND";this.skeleton.where+=` ${o} ${r}`}else this.skeleton.where=r;return this}addWhereRaw(t,r="AND"){return this.skeleton.where?this.skeleton.where+=` ${r} ${t}`:this.skeleton.where=t,this}clearWhere(){return this.skeleton.where=void 0,this}addHaving(t){let r=z(t,this.dialect);if(t.isEnabled!==!1)if(this.skeleton.having){let o=t.connector||"AND";this.skeleton.having+=` ${o} ${r}`}else this.skeleton.having=r;return this}clearHaving(){return this.skeleton.having=void 0,this}addOrderBy(...t){return this.skeleton.orderBy||(this.skeleton.orderBy=[]),this.skeleton.orderBy.push(...t),this}clearOrderBy(){return this.skeleton.orderBy=void 0,this}setLimit(t){return this.skeleton.limit=t,this}setOffset(t){return this.skeleton.offset=t,this}addGroupBy(t){this.skeleton.groupBy||(this.skeleton.groupBy=[]);let r=this.skeleton.groupBy.findIndex(o=>o===t);return r>-1?this.skeleton.groupBy[r]=t:this.skeleton.groupBy.push(t),this}setTable(t){return this.skeleton.table=t,this}addJoin(...t){return this.skeleton.joins||(this.skeleton.joins=[]),this.skeleton.joins.push(...t),this}selectColumns(t){if(this.skeleton.type!=="SELECT")throw new Error("Column selection is only supported for SELECT queries");return this.skeleton.columns=t,this}toSQL(){return St(this.skeleton)}};var Rt=require("typeorm");var de=async(e,t)=>{let{datasourceId:r,size:o=20,page:a,name:n}=t,{table:i,filters:u,joins:f,groupBy:c,searchAll:E,orderBy:C}=t.opts,d=xr(t.opts.columns,t.opts.groupBy,t.opts.aggregations),w=await S.findOne({where:{id:r},select:["id","dbType","dbDatabase","dbPassword","dbPasswordTag","dbPasswordIv","dbPort","dbUrl","dbSchema","dbUser"]}),F=[i],Y=[];if(!w)throw new s(404,"Data source not found");let Vt=await I.save(I.create({user:{id:e.user.id},team:{id:e.user.currentTeamId},dataSource:{id:r},name:n,opts:t.opts})),P=new ce(w.dbType);P.setTable(i),P.setLimit(o+1),P.setOffset(o*a),u?.forEach(m=>{m.fn&&wt(m.fn)?P.addHaving(m):P.addWhere(m)}),f&&(P.addJoin(...f),f.forEach(m=>{F.push(m.table)}));let _e=vr(d,C,w.dbType);_e.length>0&&P.addOrderBy(..._e),c&&c.length>0&&c.forEach(m=>P.addGroupBy(Ur(m,w.dbType)));let zt=await v.find({where:{tableName:(0,Rt.In)(F),datasource:{id:r}}});for(let m of zt)if(m.columns)for(let _ of m.columns)Y.push({column:_.name,table:m.tableName||"",full:`${m.tableName}.${_.name}`,type:_.type});let Jt=Y.reduce((m,_)=>(m[_.full]=_.type,m),{}),X;if(d&&d.length>0?X=d.map(m=>Dr(m,w.dbType)):X=Y.map(m=>`${m.full} as "${m.full}"`),P.selectColumns(X),E){let m=Y.filter(_=>Ie.includes(_.type)&&X.some(me=>me.startsWith(_.full)));if(m.length>0){let _=m.map(me=>`LOWER(${me.full}) LIKE '%${E.toLowerCase()}%'`);P.addWhereRaw(`(${_.join(" OR ")})`,"AND")}}let Z=await(await k(q(w,!0),w.dbType,e)).executeQuery(P.toSQL(),{type:"SELECT",allowBulkUpdate:!1}),De=Z.rows.length>o;return De&&Z.rows.pop(),{...Z,queryHistoryId:Vt.id,tables:F,allColumns:Y,columns:Z.columns.map(m=>({...m,type:Jt[m.full]})),hasMore:De}},It=async(e,t)=>{let r=await S.findOne({where:{id:t.datasourceId},select:["id","dbType","dbDatabase","dbPassword","dbPasswordTag","dbPasswordIv","dbPort","dbUrl","dbSchema","dbUser","allowUpdate"]});if(!r)throw new s(404,"Data source not found");if(!r.allowUpdate)throw new s(403,"This datasource does not allow update operations");let o=t.values.map(({value:u,column:f})=>typeof u=="string"?u&&u.startsWith("=")?`${f}=${u.substring(1)}`:`${f}='${u}'`:`${f}='${u}'`).join(", "),a=t.filters.map(u=>z(u,r.dbType)).join(" AND "),n=`UPDATE ${t.table} SET ${o} WHERE ${a}`;return(await k(q(r,!0),r.dbType,e)).executeQuery(n,{type:"UPDATE",allowBulkUpdate:!1})},Ct=async(e,t)=>{let r=await S.findOne({where:{id:t.datasourceId},select:["id","dbType","dbDatabase","dbPassword","dbPasswordTag","dbPasswordIv","dbPort","dbUrl","dbSchema","dbUser","allowInsert"]});if(!r)throw new s(404,"Data source not found");if(!r.allowInsert)throw new s(403,"This datasource does not allow insert operations");let{keys:o,values:a}=_r(t.values),n=`INSERT INTO ${t.table} (${o}) VALUES (${a})`;return(await k(q(r,!0),r.dbType,e)).executeQuery(n,{type:"INSERT",allowBulkUpdate:!1})},_r=e=>{let t=e.map(({column:o})=>o).join(", "),r=e.map(({value:o})=>typeof o=="string"?o&&o.startsWith("=")?o.substring(1):`'${o}'`:o).join(", ");return{keys:t,values:r}},Dr=(e,t)=>{if(e.fn){if(ie(e.fn))return`${(t==="postgres"?K:V)[e.fn](e)} as "${Ce(e)}"`;throw new Error("Function not allowed: "+e.fn)}return`${e.value} as "${e.value}"`},Ur=(e,t)=>{if(e.fn){if(ie(e.fn))return(t==="postgres"?K:V)[e.fn]({...e,value:bt(e.value,t)});throw new Error("Function not allowed: "+e.fn)}return bt(e.value,t)},Ae=(e,t)=>t==="postgres"?`"${e}"`:t==="mysql"?`\`${e}\``:e,bt=(e,t)=>{let[r,o]=e.split(".");return Ae(r,t)+"."+Ae(o,t)},vr=(e,t,r)=>{if(e&&e.length>0){let o=e.reduce((a,n)=>(a.set(Ce(n),{isFn:!!(n.fn||n.distinct)}),a),new Map);t=t.filter(a=>o.has(a.column)).map(a=>o.get(a.column)?.isFn?{...a,column:Ae(a.column,r)}:a)}return t},xr=(e,t,r)=>{let o=[];return t.length>0||r.length>0?o.push(...t,...r):e.length>0&&o.push(...e),o};var Nt=e=>{},Mr=["--",";","DROP","drop"],At=e=>{if(ue(e.value)&&e.value.startsWith("=")){let t=e.value;Mr.forEach(r=>{if(t.includes(r))throw new s(400,"Invalid input value for "+e.column)})}},Ot=e=>{if(!e.table)throw new s(400,"Table is required");e.values.forEach(At)},Pt=e=>{if(!e.table)throw new s(400,"Table is required");e.values.forEach(At)};var _t=g(e=>{e.route({method:"post",url:"/select",handler:async t=>{let r=l(t,Nt);return{data:await de(t,r)}}}),e.route({method:"post",url:"/insert",config:{requireRole:b("editor")},handler:async t=>{let r=l(t,Ot);return{data:await Ct(t,r)}}}),e.route({method:"post",url:"/update",config:{requireRole:b("editor")},handler:async t=>{let r=l(t,Pt);return{data:await It(t,r)}}})});var Dt=g(e=>{e.get("/",{config:{isPublic:!0}},async()=>({data:{active:!0,version:T.str("SERVER_VERSION")}}))});var Ut=g(e=>{e.route({method:"get",url:"/:id/users",handler:async t=>{let{id:r}=p(t),o=await M.findOne({where:{id:r},relations:{users:{user:!0}}});if(!o)throw new s(404,"Team not found");return{data:o.users.map(a=>({role:a.role,id:a.user.id,name:a.user.username}))}}}),e.route({method:"post",url:"/",config:{requireRole:b("editor")},handler:async t=>h.transaction(async()=>{let r=t.user.id,o=l(t),a=R.create();a.id=r;let n=M.create(o);await M.save(n);let i=N.create({user:a,team:n});return await N.save(i),{data:n}})}),e.route({method:"patch",url:"/:id/user-role",config:{requireRole:b("admin")},handler:async t=>{let{id:r}=p(t),{role:o,userId:a}=l(t,({role:i})=>{if(i==="owner")throw new s(400,"Only one owner is allowed")});if((await N.findOneBy({user:{id:a},team:{id:r}}))?.role==="owner")throw new s(400,"Cannot change owner role");await N.update({user:{id:a},team:{id:r}},{role:o})}}),e.route({method:"delete",url:"/:id",config:{requireRole:b("admin")},handler:async t=>h.transaction(async()=>{let{id:r}=p(t),{userId:o}=L(t);if((await N.findOneBy({user:{id:o},team:{id:r}}))?.role==="owner")throw new s(400,"Cannot delete team owner");await R.update(o,{currentTeam:null}),await N.delete({user:{id:o},team:{id:r}}),await R.delete({id:o})})})});var Oe=D(require("bcryptjs")),J=async e=>{let t=await Oe.default.genSalt(10);return Oe.default.hash(e,t)};var vt=g(e=>{e.route({method:"get",url:"/",handler:async t=>{let r=await R.findOne({where:{id:t.user.id},relations:{currentTeam:{team:!0}}});if(!r)throw new s(404,"User not found");return{data:{id:r.id,teamId:r.currentTeam?.team.id,teamName:r.currentTeam?.team.name,teamRole:r.currentTeam?.role,username:r.username}}}}),e.route({method:"patch",url:"/",handler:async t=>{let r=t.user.id,o=l(t);if(o.password&&(o.password=await J(o.password)),!(await R.update(r,o)).affected)throw new s(404,"User not found");let n=await R.findOne({where:{id:r},relations:{currentTeam:{team:!0}}});return{data:{id:n?.id,teamId:n?.currentTeam?.team.id,teamName:n?.currentTeam?.team.name,teamRole:n?.currentTeam?.role,username:n?.username}}}}),e.route({method:"post",url:"/",config:{requireRole:b("admin")},handler:async t=>h.transaction(async()=>{let r=l(t),o=await J(r.password),a=await R.save(R.create({username:r.username,password:o})),n=await N.save(N.create({role:"read_only",team:{id:r.teamId},user:{id:a.id}}));await R.update(a.id,{currentTeam:{id:n.id}})})})});var xt=g(e=>{e.route({method:"get",url:"/",handler:async t=>{let r=t.user.id,o=await $.findOneBy({user:{id:r}});return o||(o=await $.save($.create({user:{id:r}}))),{data:o}}}),e.route({method:"patch",url:"/",handler:async t=>{let{settings:r}=l(t);if(!r.id)throw new s(400,"Settings id is required!");if(!(await $.update(r.id,r)).affected)throw new s(404,"You do not own these settings!");return{data:await $.findOneBy({id:r.id})}}})});function H(e,...t){let r=[...t];if(e.searchAll&&r.push(e.searchAll),e.filters){for(let o of e.filters)if(o.value)for(let a of o.value)a.value&&r.push(a.value.toString())}return r.map(o=>o.toLowerCase()).join(",")}var Mt=g(e=>{e.route({method:"post",url:"/",config:{requireRole:b("editor")},handler:async t=>{let r=l(t),o=await I.findOne({where:{id:r.queryId}});if(!o)throw new s(400,"Query not found");let a=await x.save(x.create({isPersonal:!1,team:{id:t.user.currentTeamId},user:{id:t.user.id},query:{id:r.queryId},searchString:H(o.opts,r.name)}));return await I.update(r.queryId,{name:r.name}),{data:a}}}),e.route({method:"delete",url:"/:id",config:{requireRole:b("editor")},handler:async t=>{let{id:r}=p(t);if(!(await x.delete({id:r})).affected)return{status:404,data:"Query not found"}}}),e.route({method:"patch",url:"/:id",handler:async t=>await h.transaction(async()=>{let{id:r}=p(t),o=l(t,i=>{if(!i.name)throw new s(400,"Name is required")}),a=await x.findOne({where:{id:r},relations:{query:!0}});if(!a)throw new s(400,"Query not found");let n=H(a.query.opts,o.name);return await Promise.all([x.update({id:r},{searchString:n}),I.update({id:a.query.id},{name:o.name})]),{data:!0}})})});var Lt=e=>{if(!e.queryId&&!(e.opts&&e.name))throw new s(400,"Either queryId or name and opts are required")};var kt=g(e=>{e.route({method:"get",url:"/",handler:async t=>{let{currentTeamId:r,id:o}=t.user;return{data:(await A.find({where:{team:{id:r},user:{id:o},archived:!1},select:["id","name"]})).map(n=>({name:n.name,id:n.id}))}}}),e.route({method:"get",url:"/:id",handler:async t=>{let{id:r}=p(t),{currentTeamId:o,id:a}=t.user,n=await A.findOne({where:{id:r,team:{id:o},user:{id:a}}});if(!n)throw new s(404,"Not Found");return{data:n}}}),e.route({method:"post",url:"/",handler:async t=>{let{opts:r,name:o,queryId:a}=l(t,Lt),n,i,u=o;if(r)i=r.dataSourceId,n=r;else{let c=await I.findOne({where:{id:a},relations:{dataSource:!0}});if(!c)throw new s(404,"Query not Found");i=c.dataSource.id,n={table:c.opts.table,filters:c.opts.filters,joins:c.opts.joins,orderBy:c.opts.orderBy,columns:c.opts.columns,groupBy:c.opts.groupBy,searchAll:c.opts.searchAll,aggregations:c.opts.aggregations,dataSourceId:c.dataSource.id,page:0,size:50},o||(u=c.name)}return{data:await A.save(A.create({name:u||new Date().toISOString(),opts:n,dataSource:{id:i},user:{id:t.user.id},team:{id:t.user.currentTeamId}}))}}}),e.route({method:"post",url:"/:id/run",handler:async t=>{let{id:r}=p(t),o=l(t),a=await A.findOne({where:{id:r},relations:{user:!0}});if(!a)throw new s(404,"Not found");if(a.user?.id!==t.user.id)throw new s(404,"Not found");return o&&A.update(r,{opts:o,searchString:H(o,a.name),updatedAt:new Date}),{data:{result:await de(t,{datasourceId:o.dataSourceId,size:o.size,name:a.name,page:o.page,opts:{table:o.table,filters:o.filters,joins:o.joins,orderBy:o.orderBy,columns:o.columns,groupBy:o.groupBy,searchAll:o.searchAll,aggregations:o.aggregations}})}}}}),e.route({method:"patch",url:"/:id",handler:async t=>{let{id:r}=p(t),o=l(t),a=await A.findOne({where:{id:r,user:{id:t.user.id}}});if(!a)throw new s(404,"Not Found");let n=a.searchString;return o.name&&(n=H(a.opts,o.name)),await A.update(r,{...o,searchString:n}),{data:{id:r}}}}),e.route({method:"delete",url:"/:id",handler:async t=>{let{id:r}=p(t),o=t.user.id;return await A.delete({id:r,user:{id:o}}),{data:!0}}})});var jt=require("node:path");var Lr=e=>e.routeOptions.config.isPublic?!0:!e.url.startsWith("/api/"),qt=async e=>{if(Lr(e))return;let t=e.headers.authorization;if(!t)throw new s(401,"Missing auth token");let[r,o]=t.split(" ");try{let{userId:a}=await Ze(o),n=await R.findOne({where:{id:a},select:{id:!0,currentTeam:{role:!0,team:{id:!0}}},relations:{currentTeam:{team:!0}}});if(!n)throw new s(401,"User is not part of a team");e.user={id:a,currentTeamId:n.currentTeam.team.id,currentTeamRole:n.currentTeam.role}}catch{throw new s(401,"Unauthorized")}};var Qt=(e,t)=>{e.__connections&&e.__connections.forEach(r=>{r.close()})};var Gt=D(require("@fastify/cookie"));var Pe={teamName:"Default Team",username:"admin",password:"admin"},kr=async()=>{let e=await M.findOneBy({});return e||M.save(M.create({name:Pe.teamName}))},Bt=async()=>{let e=await N.findOne({where:{role:"owner"},relations:{user:!0}});if(e)return e.user;let t=await kr(),r=await J(Pe.password),o=await R.save(R.create({username:Pe.username,password:r})),a=await N.save(N.create({user:o,team:t,role:"owner"}));return await R.update(o.id,{currentTeam:a}),o};var O=(0,$t.default)({querystringParser:e=>Yt.default.parse(e)}),Kt=T.num("PORT",4466),Ft=T.str("ALLOWED_ORIGINS","").split(",").map(e=>e.trim()),qr="0.0.0.0",Qr=Ft.includes("*")?"*":[`http://localhost:${Kt}`,...Ft];function U(e,t){O.register(e,{prefix:t}),console.log("Registered "+t)}(async function(){Me(),await O.register(Gt.default,{}),await O.register(Wt.default,{origin:Qr,methods:["GET","POST","PUT","PATCH","DELETE","OPTIONS"],credentials:!0}),await O.register(Ht.default,{root:(0,jt.join)(__dirname,"web")}),O.get("/",(t,r)=>{r.sendFile("index.html")}),O.addHook("onRequest",qt),O.addHook("onRequest",ft),O.addHook("onResponse",Qt),U(ot,"/api/auth"),U(yt,"/api/data-sources"),U(Tt,"/api/project"),U(ht,"/api/queries"),U(_t,"/api/runner"),U(Dt,"/api/status"),U(Ut,"/api/teams"),U(vt,"/api/users"),U(xt,"/api/user-settings"),U(Mt,"/api/saved-queries"),U(kt,"/api/workbench-tabs"),O.setNotFoundHandler((t,r)=>{if(t.raw.url?.startsWith("/api/")){r.code(404).send({error:"API route not found"});return}r.sendFile("index.html")}),O.setErrorHandler((t,r,o)=>{if(console.error(t),t instanceof s){o.status(t.status).send({error:t.message});return}else o.status(500).send({error:"Internal Server Error"})}),await O.after(),await Ke(),await Bt(),O.listen({port:Kt,host:qr},(t,r)=>{t&&(console.error(t),process.exit(1)),console.log(`Server listening at ${r}`)})})();
|