feat: initialize core server architecture, API key socket handler, and postgres patch utilities
All checks were successful
Deploy Beta (NATIVE) / deploy (push) Successful in 13s

This commit is contained in:
vickytechkey 2026-10-19 22:47:33 +05:30
parent 766c3deae0
commit 873c295e35
9 changed files with 131 additions and 15 deletions

View file

@ -259,16 +259,16 @@ export async function getDisableAuthSession(): ReturnType<typeof getSession> {
createdAt: obj.createdAt as Date,
updatedAt: obj.updatedAt as Date,
email: obj.email as string,
emailVerified: obj.emailVerified === 1,
emailVerified: Boolean(obj.emailVerified),
name: obj.name as string,
image: obj.image as string | null,
username: obj.username as string | null,
displayUsername: obj.displayUsername as string | null,
banned: obj.banned === 1,
banned: Boolean(obj.banned),
role: obj.role as string | null,
banReason: obj.banReason as string | null,
banExpires: obj.banExpires as Date | null,
twoFactorEnabled: obj.twoFactorEnabled === 1,
twoFactorEnabled: Boolean(obj.twoFactorEnabled),
};
return {

View file

@ -23,8 +23,8 @@ async function sendNotificationList(socket) {
for (let bean of list) {
let notificationObject = bean.export();
notificationObject.isDefault = notificationObject.isDefault === 1;
notificationObject.active = notificationObject.active === 1;
notificationObject.isDefault = Boolean(notificationObject.isDefault);
notificationObject.active = Boolean(notificationObject.active);
result.push(notificationObject);
}

View file

@ -503,6 +503,7 @@ class Database {
CREATE OR REPLACE FUNCTION int_eq_bool(integer, boolean) RETURNS boolean STRICT IMMUTABLE LANGUAGE SQL AS $$ SELECT ($1 != 0) = $2; $$;
CREATE OR REPLACE FUNCTION bool_ne_int(boolean, integer) RETURNS boolean STRICT IMMUTABLE LANGUAGE SQL AS $$ SELECT $1 != ($2 != 0); $$;
CREATE OR REPLACE FUNCTION int_ne_bool(integer, boolean) RETURNS boolean STRICT IMMUTABLE LANGUAGE SQL AS $$ SELECT ($1 != 0) != $2; $$;
CREATE OR REPLACE FUNCTION int_to_bool(integer) RETURNS boolean STRICT IMMUTABLE LANGUAGE SQL AS $$ SELECT ($1 != 0); $$;
DO $$ BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_operator WHERE oprname = '=' AND oprleft = 'boolean'::regtype AND oprright = 'integer'::regtype) THEN
CREATE OPERATOR = (LEFTARG = boolean, RIGHTARG = integer, PROCEDURE = bool_eq_int, COMMUTATOR = =);
@ -516,6 +517,13 @@ class Database {
IF NOT EXISTS (SELECT 1 FROM pg_operator WHERE oprname = '<>' AND oprleft = 'integer'::regtype AND oprright = 'boolean'::regtype) THEN
CREATE OPERATOR <> (LEFTARG = integer, RIGHTARG = boolean, PROCEDURE = int_ne_bool, COMMUTATOR = <>);
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_cast WHERE castsource = 'integer'::regtype AND casttarget = 'boolean'::regtype) THEN
BEGIN
CREATE CAST (integer AS boolean) WITH FUNCTION int_to_bool(integer) AS IMPLICIT;
EXCEPTION WHEN OTHERS THEN
NULL;
END;
END IF;
END $$;
`);
} catch (e) {

View file

@ -1307,7 +1307,7 @@ class Monitor extends BeanModel {
static async isActive(monitorID, active) {
const parentActive = await Monitor.isParentActive(monitorID);
return active === 1 && parentActive;
return Boolean(active) && parentActive;
}
/**
@ -2038,7 +2038,7 @@ class Monitor extends BeanModel {
}
const parentActive = await Monitor.isParentActive(parent.id);
return parent.active === 1 && parentActive;
return Boolean(parent.active) && parentActive;
}
/**

View file

@ -39,7 +39,7 @@ class Proxy {
// When proxy is default update deactivate old default proxy
if (proxy.default) {
await R.exec("UPDATE proxy SET `default` = 0 WHERE `default` = 1");
await R.exec("UPDATE proxy SET `default` = FALSE WHERE `default` = TRUE");
}
bean.user_id = userID;

View file

@ -1290,7 +1290,7 @@ app.use(function (req, res, next) {
log.info("manage", `Clear Events Monitor: ${monitorID} User ID: ${socket.userID}`);
await R.exec("UPDATE heartbeat SET msg = ?, important = ? WHERE monitor_id = ? ", ["", "0", monitorID]);
await R.exec("UPDATE heartbeat SET msg = ?, important = ? WHERE monitor_id = ? ", ["", false, monitorID]);
callback({
ok: true,
@ -1496,7 +1496,7 @@ async function initDatabase(testMode = false) {
async function startMonitor(userID, monitorID) {
log.info("manage", `Resume Monitor: ${monitorID} User ID: ${userID}`);
await R.exec("UPDATE monitor SET active = 1 WHERE id = ? ", [monitorID]);
await R.exec("UPDATE monitor SET active = TRUE WHERE id = ? ", [monitorID]);
let monitor = await R.findOne("monitor", " id = ? ", [monitorID]);
@ -1527,7 +1527,7 @@ async function restartMonitor(userID, monitorID) {
async function pauseMonitor(userID, monitorID) {
log.info("manage", `Pause Monitor: ${monitorID} User ID: ${userID}`);
await R.exec("UPDATE monitor SET active = 0 WHERE id = ? ", [monitorID]);
await R.exec("UPDATE monitor SET active = FALSE WHERE id = ? ", [monitorID]);
if (monitorID in server.monitorList) {
await server.monitorList[monitorID].stop();

View file

@ -98,7 +98,7 @@ module.exports.apiKeySocketHandler = (socket) => {
log.debug("apikeys", `Disabled Key: ${keyID} User ID: ${socket.userID}`);
await R.exec("UPDATE api_key SET active = 0 WHERE id = ? ", [keyID]);
await R.exec("UPDATE api_key SET active = FALSE WHERE id = ? ", [keyID]);
apicache.clear();
@ -123,7 +123,7 @@ module.exports.apiKeySocketHandler = (socket) => {
log.debug("apikeys", `Enabled Key: ${keyID} User ID: ${socket.userID}`);
await R.exec("UPDATE api_key SET active = 1 WHERE id = ? ", [keyID]);
await R.exec("UPDATE api_key SET active = TRUE WHERE id = ? ", [keyID]);
apicache.clear();

View file

@ -87,7 +87,7 @@ module.exports.statusPageSocketHandler = (socket) => {
let statusPageID = await StatusPage.slugToID(slug);
await R.exec("UPDATE incident SET pin = 0 WHERE pin = 1 AND status_page_id = ? ", [statusPageID]);
await R.exec("UPDATE incident SET pin = FALSE WHERE pin = TRUE AND status_page_id = ? ", [statusPageID]);
callback({
ok: true,

View file

@ -1,5 +1,38 @@
const { R } = require("redbean-node");
const PG_BOOLEAN_COLUMNS = [
"active",
"pin",
"default",
"important",
"public",
"ignore_tls",
"upside_down",
"expiry_notification",
"domain_expiry_notification",
"save_response",
"save_error_response",
"published",
"twofa_status",
"is_default",
"invert_keyword",
"kafka_producer_ssl",
"kafka_producer_allow_auto_topic_creation",
"show_certificate_expiry",
"gamedig_given_port_only",
"ws_ignore_sec_websocket_accept_header",
"ping_numeric",
"show_only_last_heartbeat",
"retry_only_on_status_code_failure",
"cache_bust",
"email_verified",
"banned",
"two_factor_enabled",
"verified",
"enabled",
"rate_limit_enabled",
];
function patchRedBeanPostgres() {
const RedBeanNode = R.constructor;
if (RedBeanNode.prototype._pgPatched) {
@ -9,11 +42,46 @@ function patchRedBeanPostgres() {
function cleanPgSql(sql) {
if (typeof sql === "string") {
return sql.replace(/`([^`]+)`/g, '"$1"');
// Replace MySQL backticks with standard quotes
sql = sql.replace(/`([^`]+)`/g, '"$1"');
// Replace bracket identifier escaping [col] with "col"
sql = sql.replace(/\[([^\]]+)\]/g, '"$1"');
// PostgreSQL is strictly typed for booleans: convert integer assignments and comparisons
const boolPattern = PG_BOOLEAN_COLUMNS.join("|");
sql = sql.replace(new RegExp(`(["\`]?\\b(?:${boolPattern})\\b["\`]?)\\s*=\\s*1\\b`, "gi"), "$1 = true");
sql = sql.replace(new RegExp(`(["\`]?\\b(?:${boolPattern})\\b["\`]?)\\s*=\\s*0\\b`, "gi"), "$1 = false");
sql = sql.replace(new RegExp(`(["\`]?\\b(?:${boolPattern})\\b["\`]?)\\s*(?:!=|<>)\\s*1\\b`, "gi"), "$1 != true");
sql = sql.replace(new RegExp(`(["\`]?\\b(?:${boolPattern})\\b["\`]?)\\s*(?:!=|<>)\\s*0\\b`, "gi"), "$1 != false");
sql = sql.replace(new RegExp(`\\b1\\s*=\\s*(["\`]?\\b(?:${boolPattern})\\b["\`]?)`, "gi"), "true = $1");
sql = sql.replace(new RegExp(`\\b0\\s*=\\s*(["\`]?\\b(?:${boolPattern})\\b["\`]?)`, "gi"), "false = $1");
}
return sql;
}
function sanitizePgBeanBooleans(bean) {
if (!bean) {
return;
}
for (const col of PG_BOOLEAN_COLUMNS) {
if (bean[col] === 0 || bean[col] === "0") {
bean[col] = false;
} else if (bean[col] === 1 || bean[col] === "1") {
bean[col] = true;
}
}
}
const origExec = RedBeanNode.prototype.exec;
if (origExec) {
RedBeanNode.prototype.exec = function (sql, data) {
if (this.dbType === "pg") {
sql = cleanPgSql(sql);
}
return origExec.call(this, sql, data);
};
}
const origNormalizeRawCore = RedBeanNode.prototype.normalizeRawCore;
RedBeanNode.prototype.normalizeRawCore = function (sql, data) {
if (this.dbType === "pg") {
@ -59,6 +127,36 @@ function patchRedBeanPostgres() {
}
};
const origGetAll = RedBeanNode.prototype.getAll;
if (origGetAll) {
RedBeanNode.prototype.getAll = function (sql, data) {
if (this.dbType === "pg") {
sql = cleanPgSql(sql);
}
return origGetAll.call(this, sql, data);
};
}
const origGetCell = RedBeanNode.prototype.getCell;
if (origGetCell) {
RedBeanNode.prototype.getCell = function (sql, data) {
if (this.dbType === "pg") {
sql = cleanPgSql(sql);
}
return origGetCell.call(this, sql, data);
};
}
const origGetCol = RedBeanNode.prototype.getCol;
if (origGetCol) {
RedBeanNode.prototype.getCol = function (sql, data) {
if (this.dbType === "pg") {
sql = cleanPgSql(sql);
}
return origGetCol.call(this, sql, data);
};
}
const origFindCore = RedBeanNode.prototype.findCore;
RedBeanNode.prototype.findCore = function (type, clause, data = []) {
if (this.dbType === "pg") {
@ -95,6 +193,9 @@ function patchRedBeanPostgres() {
const origStoreCore = RedBeanNode.prototype.storeCore;
RedBeanNode.prototype.storeCore = async function (bean, changedFieldsOnly = true) {
if (this.dbType === "pg") {
sanitizePgBeanBooleans(bean);
}
if (this.dbType === "pg" && !bean.id) {
this.devLog("Store PG insert", bean.beanMeta.type);
await bean.storeTypeBeanList();
@ -103,6 +204,13 @@ function patchRedBeanPostgres() {
}
let obj = bean.export(false);
delete obj.id;
for (const col of PG_BOOLEAN_COLUMNS) {
if (obj[col] === 0 || obj[col] === "0") {
obj[col] = false;
} else if (obj[col] === 1 || obj[col] === "1") {
obj[col] = true;
}
}
let queryPromise = this.knex(bean.getType()).insert(obj).returning("id");
this.queryLog(queryPromise);
let result = await queryPromise;