{"version":3,"sources":["jsdelivr-header.js","/npm/backend-plus@2.6.10/lib/backend-plus.js"],"names":[],"mappings":"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","file":"/npm/backend-plus@2.6.10/lib/backend-plus.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.48.0.\n * Original file: /npm/backend-plus@2.6.10/lib/backend-plus.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","/// <reference path=\"./in-backend-plus.d.ts\" />\r\n\"use strict\";\r\n\r\nvar backendPlus = {};\r\n\r\n/** @type {(()=>void)|null} */\r\nvar logWhy = null; // require('why-is-node-running') // should be your first require\r\n\r\nvar timeStartBackendPlus = new Date();\r\n\r\nvar express = require('express');\r\n//var cookieParser = require('cookie-parser');\r\nvar bodyParser = require('body-parser');\r\nvar multiparty = require('multiparty');\r\nvar Path = require('path');\r\nvar useragent = require('express-useragent');\r\nvar numeral = require('numeral');\r\nvar MiniTools = require('mini-tools');\r\nMiniTools.globalOpts.serveErr.propertiesWhiteList=['message','detail','code','table','constraint','name','severity'];\r\nvar crypto = require('crypto');\r\nvar serveContent = require('serve-content');\r\nvar pg = require('pg-promise-strict');\r\nvar pgTriggers = require('pg-triggers');\r\nvar SessionFileStore = require('session-file-store');\r\nvar memorystore = require('memorystore');\r\nvar jsToHtml=require('js-to-html');\r\nvar html=jsToHtml.html;\r\nvar packagejson = require(process.cwd()+'/package.json');\r\nvar stackTrace = require('stack-trace');\r\nvar locatePath = require('@upgraded/locate-path');\r\nvar jsYaml = require('js-yaml');\r\nvar nodemailer = require('nodemailer');\r\nvar os = require('os');\r\nconst cors = require('cors');\r\n\r\nvar likeAr = require('like-ar');\r\n\r\nvar regexpDistCheck=/(^|[/\\\\])dist[/\\\\]/\r\nvar regexpDistReplacer=/(^|[/\\\\])dist[/\\\\](?:[^/\\\\]+[/\\\\])*([^/\\\\]*inst[^/\\\\]*[/\\\\][^/\\\\]*$)/\r\n\r\npg.easy = true;\r\npg.debug.pool=true; // TODO: quitar. Esto está buscando un code leak\r\npg.setAllTypes();\r\n/*\r\npg.log=function log(m){\r\n    console.log(m);\r\n}\r\n// */\r\n\r\nvar readYaml = require('read-yaml-promise');\r\n\r\nvar fs = require('fs-extra');\r\nvar fsP = require('fs/promises');\r\n\r\nvar bestGlobals = require('best-globals');\r\nvar coalesce = bestGlobals.coalesce;\r\nvar changing = bestGlobals.changing;\r\nvar datetime = bestGlobals.datetime;\r\nvar splitRawRowIntoRow = bestGlobals.splitRawRowIntoRow;\r\nconst escapeRegExp = bestGlobals.escapeRegExp;\r\nvar isLowerIdent = bestGlobals.isLowerIdent;\r\n\r\nvar myOwn = require('../for-client/my-things.js');\r\n\r\nvar typeStore = require('type-store');\r\nvar json4all = require('json4all');\r\nvar XLSX = require('xlsx');\r\n\r\nvar loginPlus = require('login-plus');\r\nvar dashDashDir=Array.prototype.indexOf.call(process.argv,'--dir')\r\n\r\nif(dashDashDir>0){\r\n    console.log('--dir',process.argv[dashDashDir+1]);\r\n    process.chdir(process.argv[dashDashDir+1]);\r\n    console.log('cwd',process.cwd());\r\n}\r\n\r\n/** \r\n  * @param {string} text\r\n  * @return {string}\r\n  */\r\nfunction md5(text){\r\n    return crypto.createHash('md5').update(text).digest('hex');\r\n}\r\n\r\nconst DEFAULT_ITERATIONS = 4096; \r\nconst HASH_ALGORITHM = 'sha256';\r\n\r\n// primera version de scram sha 256. El Verifier completo tenía 64 bytes.\r\nconst LEGACY_KEY_LENGTH = 64; \r\n\r\n// Formato nuevo/PG-Compatible: El Client Key tiene 32 bytes (SHA-256).\r\nconst SCRAM_KEY_LENGTH = 32; \r\n\r\nconst bufferToBase64 = (buffer) => buffer.toString('base64');\r\n\r\n/**\r\n * Función central para PBKDF2 (Acepta KEY_LEN para compatibilidad).\r\n * Devuelve la clave derivada con la longitud especificada.\r\n */\r\nasync function deriveKey(password, saltBuffer, iterations, keyLength) { \r\n    return new Promise((resolve, reject) => {\r\n        crypto.pbkdf2(\r\n            password, \r\n            saltBuffer,\r\n            iterations, \r\n            keyLength,\r\n            HASH_ALGORITHM, \r\n            (err, derivedKey) => {\r\n                if (err) return reject(err);\r\n                resolve(derivedKey); \r\n            }\r\n        );\r\n    });\r\n}\r\n\r\nasync function generateScramVerifier(password) {\r\n    const saltBuffer = crypto.randomBytes(16); \r\n    const saltBase64 = bufferToBase64(saltBuffer);\r\n\r\n    const Hi = await deriveKey(\r\n        password, \r\n        saltBuffer, \r\n        DEFAULT_ITERATIONS,\r\n        SCRAM_KEY_LENGTH \r\n    );\r\n    const clientKey = crypto.createHmac('sha256', Hi).update('Client Key').digest();\r\n    const serverKey = crypto.createHmac('sha256', Hi).update('Server Key').digest();\r\n\r\n    const storedKey = crypto.createHash('sha256').update(clientKey).digest();\r\n\r\n    const storedKeyBase64 = bufferToBase64(storedKey);\r\n    const serverKeyBase64 = bufferToBase64(serverKey);\r\n\r\n    return `SCRAM-SHA-256$${DEFAULT_ITERATIONS}:${saltBase64}$${storedKeyBase64}:${serverKeyBase64}`;\r\n}\r\n\r\n/**\r\n * Verifica una contraseña contra el hash SCRAM PG-Compatible.\r\n * Formato PG: SCRAM-SHA-256$<iteraciones>:<Salt>$<StoredKey>:<ServerKey>\r\n * @param {string} password - Contraseña en texto plano.\r\n * @param {string} storedScramString - Cadena SCRAM de PostgreSQL.\r\n * @returns {Promise<boolean>} True si la contraseña es válida.\r\n */\r\nasync function verifyScramPG(password, storedScramString) {\r\n    if (!storedScramString.startsWith('SCRAM-SHA-256$')) {\r\n        return false;\r\n    }\r\n    \r\n    const parts = storedScramString.split('$');\r\n    if (parts.length !== 3) {\r\n        return false;\r\n    }\r\n        \r\n    const [storedIterations, saltBase64] = parts[1].split(':');\r\n    const [storedKeyBase64, serverKeyBase64] = parts[2].split(':'); // Asume StoredKey y ServerKey\r\n\r\n    if (!saltBase64 || !storedKeyBase64 || !serverKeyBase64 || isNaN(parseInt(storedIterations))) {\r\n        return false;\r\n    }\r\n    \r\n    const iterations = parseInt(storedIterations);\r\n    const saltBuffer = Buffer.from(saltBase64, 'base64');\r\n    const storedKeyBuffer = Buffer.from(storedKeyBase64, 'base64');\r\n    const serverKeyBuffer = Buffer.from(serverKeyBase64, 'base64');\r\n\r\n    const Hi = await deriveKey(\r\n        password, \r\n        saltBuffer, \r\n        iterations,\r\n        SCRAM_KEY_LENGTH\r\n    );\r\n\r\n    const clientKey = crypto.createHmac(HASH_ALGORITHM, Hi)\r\n        .update('Client Key')\r\n        .digest();\r\n\r\n    const serverKeyActual = crypto.createHmac(HASH_ALGORITHM, Hi)\r\n        .update('Server Key')\r\n        .digest();\r\n\r\n    const storedKeyActual = crypto.createHash('sha256').update(clientKey).digest();\r\n\r\n    const storedKeyMatch = crypto.timingSafeEqual(storedKeyActual, storedKeyBuffer);\r\n    const serverKeyMatch = crypto.timingSafeEqual(serverKeyActual, serverKeyBuffer);\r\n    return storedKeyMatch && serverKeyMatch;\r\n}\r\n\r\n/**\r\n * Verifica una contraseña contra el hash SCRAM Legacy (64 bytes).\r\n * Formato Legacy: SCRAM-SHA-256$<iteraciones>:<Salt>$<Verifier(64 bytes)>\r\n * @param {string} password - Contraseña en texto plano.\r\n * @param {string} storedScramString - Cadena SCRAM Legacy.\r\n * @returns {Promise<boolean>} True si la contraseña es válida.\r\n */\r\nasync function verifyScramLegacy(password, storedScramString) {\r\n    if (!storedScramString.startsWith('SCRAM-SHA-256$')) {\r\n        // No es formato SCRAM. Debe ser MD5 u otro algoritmo.\r\n        return false;\r\n    }\r\n\r\n    // Parsea la cadena SCRAM\r\n    // Ejemplo: SCRAM-SHA-256$4096:SALT_BASE64$VERIFIER_BASE64\r\n    const parts = storedScramString.split('$');\r\n    if (parts.length !== 3) {\r\n        throw new Error('Formato SCRAM almacenado inválido.');\r\n    }\r\n        \r\n    // Obtiene iteraciones y salt de la segunda parte (ej: '4096:SALT_BASE64')\r\n    const [storedIterations, storedSalt] = parts[1].split(':');\r\n    const storedVerifier = parts[2];\r\n    \r\n    if (!storedSalt || !storedVerifier || isNaN(parseInt(storedIterations))) {\r\n        throw new Error('Datos de SCRAM incompletos o malformados.');\r\n    }\r\n    \r\n    const iterations = parseInt(storedIterations);\r\n\r\n    // Deriva la clave de la contraseña ingresada\r\n    const generatedVerifierBuffer = await deriveKey(\r\n        password, \r\n        storedSalt, \r\n        iterations,\r\n        LEGACY_KEY_LENGTH\r\n    );\r\n    const generatedVerifier = bufferToBase64(generatedVerifierBuffer);\r\n\r\n    // Compara de manera segura contra el Verificador Almacenado\r\n    const storedVerifierBuffer = Buffer.from(storedVerifier, 'base64');\r\n    const generatedVerifierBufferFromBase64 = Buffer.from(generatedVerifier, 'base64');\r\n\r\n    // Usa crypto.timingSafeEqual para evitar ataques de temporización\r\n    if (generatedVerifierBufferFromBase64.length !== storedVerifierBuffer.length) {\r\n        return false;\r\n    }\r\n\r\n    return crypto.timingSafeEqual(generatedVerifierBufferFromBase64, storedVerifierBuffer);\r\n}\r\n\r\nvar dist=regexpDistCheck.test(packagejson.main)?'dist/':'';\r\n\r\n/**\r\n * @typedef {{name: string; path?:string; fileName?: string; source?: string; tableGenerator?:()=>void; title?:string; mixin?:any[]}} TableItem\r\n */\r\n\r\nclass AppBackend{\r\n    constructor(){\r\n        let be = this;\r\n        /** @type {any} */\r\n        this.config={};\r\n        /** @type {{path:string}[]} */\r\n        this.appStack=[];\r\n        /** @type {{message:string; fun:()=>void}[]} */\r\n        this.shutdownCallbackList=[];\r\n        this.sessionStores={\r\n            file: SessionFileStore,\r\n            memory: memorystore,\r\n            memoryDevel: BindMemoryPerodicallySaved(this),\r\n            \"memory-saved\": BindMemoryPerodicallySaved(this),\r\n        }\r\n        if(!this.rootPath){\r\n            console.log('ATENCIÓN hay que poner be.rootPath antes de llamar a super()');\r\n            this.rootPath=Path.resolve(__dirname,'..');\r\n        }\r\n        console.log('rootPath',this.rootPath);\r\n        var trace = stackTrace.get();\r\n        trace.forEach(function(callSite){\r\n            var path = callSite.getFileName();\r\n            if(path && !path.startsWith('internal/') && !path.startsWith('node:internal/')){\r\n                path = Path.dirname(path);\r\n                if(path!='.' && path != be.appStack[0]?.path){\r\n                    be.appStack.unshift({path});\r\n                }\r\n            }\r\n        });\r\n        this.defaultMethod='post';\r\n        this.app = express();\r\n        this.clearCaches();\r\n        this.tableStructures = {};\r\n        this.configStaticConfig();\r\n        /** @type {null|()=>Promise<void>} */\r\n        this.shutdownBackend = null;\r\n        /** @type {bp.Server} */\r\n        // @ts-ignore\r\n        this.server = null;\r\n    }\r\n    esJavascript(type){\r\n        return ['js','mjs'].includes(type)\r\n    }\r\n    clearCaches(){\r\n        this.caches={\r\n            procedures:{}\r\n        }\r\n    }\r\n}\r\nAppBackend.prototype.configStaticConfig = function configStaticConfig(){\r\n    this.setStaticConfig(`\r\n        login:\r\n          unloggedLandPage: /not-logged-in\r\n          plus:\r\n            successRedirect: /menu\r\n            successReturns: true\r\n            store: {}\r\n            loginForm:\r\n              autoLogin: true\r\n            chPassUrlPath: /chpass\r\n          activeClausule: true\r\n          lockedClausule: false\r\n        keepAlive: 1800\r\n        data:\r\n          transformers:\r\n            text: keepAll\r\n        db:\r\n          motor: postgresql\r\n          min-version: 12\r\n          fkOnUpdate: cascade\r\n          max: 50\r\n        log: \r\n          db:\r\n            until: 2001-01-01 00:00\r\n            last-error: false\r\n            on-demand: false\r\n        server:\r\n          base-url: ''\r\n          bitacoraSchema: his\r\n          bitacoraTableName: bitacora\r\n          skins:\r\n            \"\":\r\n              local-path: for-client\r\n          bin: {}\r\n        client-setup: \r\n          skin: \"\"\r\n          lang: en\r\n          version: 1.0\r\n          inherit-fields-mode: display-fk\r\n        install:\r\n          dump:\r\n            db:\r\n              host: localhost\r\n              extensions: []\r\n            scripts:\r\n              parts-order: []\r\n              post-adapt: []\r\n        devel:\r\n          delay: false\r\n        imports:\r\n          allow-plain-xls: false\r\n    `);\r\n}\r\nAppBackend.exposes={};\r\nAppBackend.prototype.i18n={messages:{}};\r\n\r\nAppBackend.prototype.messages=\r\nAppBackend.prototype.i18n.messages.en={\r\n    unlogged:{\r\n        login:{\r\n            title: \"log in\",\r\n            username: \"username\",\r\n            password: \"password\",\r\n            button: \"Sign In\",\r\n            forget: \"Forgot your password?\",\r\n            userOrPassFail: \"username or password error\",\r\n            lockedFail: \"user account is locked\",\r\n            inactiveFail: \"user account is marked as inactive\",\r\n            internalError: \"internal error\",\r\n            passTooShort: \"pass too short (minimum length $1)\",\r\n            passDoesntMatch: \"pass doesn't match\"\r\n        },\r\n        newPassword:{\r\n            button: \"Reset password\",\r\n            email: \"Email\",\r\n            invalidMail: \"invalid email\",\r\n            mailSubject: \"Password Reset Request\",\r\n            mailHtml: `<p>You told us you forgot your password. If you really did, click here to choose a new one:</p>\r\n            <p><a href=\"\"></a></p>\r\n            <p>If you didn’t mean to reset your password, then you can just ignore this email; your password will not change.</p>`,\r\n            mayBeMailSent: \"Mail sent if found.\",\r\n            return: \"I know my password. Go to login.\",\r\n            title: \"Forgot password form\",\r\n        },\r\n        loading:'loading',\r\n    },\r\n    logged:{\r\n        login:{\r\n                title: \"log in\",\r\n                username: \"username\",\r\n                password: \"password\",\r\n                button: \"Sign In\"\r\n        },\r\n        chpass:{\r\n            title: 'change password',\r\n            username: 'Username',\r\n            oldPassword:'Old password',\r\n            newPassword:'New password',\r\n            repPassword:'Reenter password',\r\n            button:'Change',\r\n            cancel: 'Cancel'\r\n        },\r\n        fileUploaded:'file uploaded',\r\n        unkownExt:'unkown file extension'\r\n    },\r\n    server:{\r\n        backupNotAvailable: 'Backup not available',\r\n        backupReady: 'Backup ready to download',\r\n        backupZipping: 'Zipping backup file',\r\n        badBackupEncryptKey: 'encrypt key not present or less than 10 characters',\r\n        cantDelete_TLDR:'Can\\'t delete. May be rights problems, locked records or internal problems',\r\n        cantInsert_TLDR:'Can\\'t insert. May be rights problems, locked records or internal problems',\r\n        cantUpdate_TLDR:'Can\\'t update. May be rights problems, locked records or internal problems',\r\n        checkingConstraints:'checking constraints',\r\n        cellOfA1DoesNotExists:'cell of A1 does not exists',\r\n        columnDoesNotExistInTable:'column $1 does not exist in table',\r\n        dbMinVersionFail:'database min version $2 fail. Actual version $1',\r\n        deleted:'deleted',\r\n        deleting:'deleting',\r\n        dependences:'dependences',\r\n        ErrorCheckDatabaseStructure:'ERROR checkDatabaseStructure fail in startup',\r\n        fileReaded:'file readed',\r\n        files:'files',\r\n        importColumnDoesNotHasColumnName:'column $1 does not has a string value',\r\n        insertingRows:'inserting rows',\r\n        lackOfBackendPlusInImport:'lack of #backend-plus signal in A1 or imports.allow-plain-xls in local-config',\r\n        line:'line',\r\n        missingPrimaryKeyValues:'missing primary key values',\r\n        noMailerConfig:'not mailer configurated',\r\n        notInputCuidado:'The uploaded file is not a \"#cuidado\" file',\r\n        notLoggedIn:'not logged in',\r\n        oldPassDontMatch:'old password does not matchs or username is not longer valid or token is invalid',\r\n        passChangedSuccesfully: 'password was changed successfully',\r\n        passDontMatch:'passwords does not matchs or password is not long enough',\r\n        prefilledField1IsInConflictWithImportedField:'Prefilled field \"$1\" is in conclict with imported field',\r\n        primarKeyCantBeNull4:'error at line $1. Primary key field \"$2\" can not be #NULL',\r\n        spreadsheetProcessed:'spread sheet processed',\r\n        unkownHashValue4Import:'unknown # code in value import',\r\n        updateWithoutModfiedColumns:'update without modified columns',\r\n        updatingDb:'updating database',\r\n        versions:'versions',\r\n    }\r\n};\r\n\r\nAppBackend.prototype.i18n.messages.es={\r\n    unlogged:{\r\n        login:{\r\n            title: \"entrada\",\r\n            username: \"usuario\",\r\n            password: \"clave\",\r\n            button: \"Entrar\",\r\n            forget: \"me olvidé la clave / es mi primer ingreso\",\r\n            userOrPassFail: \"usuario o clave incorrecta\",\r\n            lockedFail: \"usuario bloqueado\",\r\n            inactiveFail: \"el usuario está marcado como inactivo\",\r\n            internalError: \"error interno en login\",\r\n            passTooShort: \"la clave es demasiado corta (el mínimo es $1)\",\r\n            passDoesntMatch: \"las claves no coinciden\"\r\n        },\r\n        newPassword:{\r\n            button: \"Obtener una nueva contraseña\",\r\n            email: \"e-mail\",\r\n            invalidMail: \"la dirección de mail es incorrecta\",\r\n            mailSubject: \"Solicitud de cambio de contraseña\",\r\n            mailHtml: `<p>Hemos recibido una solicitud para restablecer la contraseña de su cuenta. Si usted realizó esta petición, por favor, haga clic en el siguiente enlace para crear una nueva contraseña:</p>\r\n            <p><a href=\"\"></a></p>\r\n            <p>Si usted no solicitó este cambio, puede ignorar este correo electrónico. Su contraseña actual permanecerá sin modificaciones.</p>`,\r\n            mayBeMailSent: \"Se procede a buscar el usuario correspondiente al email. Si se encuentra se envia al mismo un correo que permite cambiar la contraseña. Si envió más de un formulario solo el último es válido.\",\r\n            return: \"Recuerdo mi contraseña. Ir a la pantalla de ingreso.\",\r\n            title: \"Formulario de recuperación de contraseña\",\r\n        },\r\n        loading:'cargando',\r\n    },\r\n    logged:{\r\n        chpass:{\r\n            title: 'cambio de clave',\r\n            username: 'usuario',\r\n            oldPassword:'clave anterior',\r\n            newPassword:'nueva clave',\r\n            repPassword:'repetir nueva clave',\r\n            button:'Cambiar',\r\n            cancel: 'Cancelar'\r\n        },\r\n        fileUploaded:'archivo subido',\r\n        unkownExt:'extensión de archivo desconocida'\r\n    },\r\n    server:{\r\n        backupNotAvailable: 'Backup no disponible',\r\n        backupReady: 'Archivo listo para bajar',\r\n        backupZipping: 'Compactando el backup',\r\n        badBackupEncryptKey: 'Debe proveer una clave de encriptacion de 10 caracteres o mas para encriptar el archivo de destino',\r\n        cantDelete_TLDR:'no se pudo eliminar el registro. Podrían haber problemas de persmisos, bloqueo de registros o problemas internos en la definición de la PK',\r\n        cantInsert_TLDR:'no se pudo insertar el registro. Podrían haber problemas de persmisos, bloqueo de registros o problemas internos en la definición de la PK',\r\n        cantUpdate_TLDR:'no se pudo modificar el registro. Podrían haber problemas de persmisos, bloqueo de registros o problemas internos en la definición de la PK',\r\n        checkingConstraints:'verificando las restricciones',\r\n        cellOfA1DoesNotExists:'no hay valor en la celda A1',\r\n        columnDoesNotExistInTable:'la columna $1 no existe en la tabla',\r\n        dbMinVersionFail:'La versión actual de la base de datos es $1, pero debe ser como mínimo $2',\r\n        deleted:'borrado',\r\n        deleting:'borrando',\r\n        dependences:'dependencias',\r\n        ErrorCheckDatabaseStructure:'ERROR en checkDatabaseStructure. Falló al controlar la estructura de la base de datos',\r\n        fileReaded:'archivo leído',\r\n        files:'archivos',\r\n        importColumnDoesNotHasStringValue:'la columna $1 no valor de texto',\r\n        insertingRows:'insertando registros',\r\n        lackOfBackendPlusInImport:'falta la señal #backend-plus en la celda A1 o la opción imports.allow-plain-xls en local-config',\r\n        line:'linea',\r\n        missingPrimaryKeyValues:'faltan valores en los campos de la clave principal',\r\n        noMailerConfig:'falta la configuración del mailer',\r\n        notInputCuidado:'El archivo no es un archivo \"#cuidado\"',\r\n        notLoggedIn:'sin inicio de sesión',\r\n        oldPassDontMatch:'la clave anterior no coincide o el usuario es inválido o el token está vencido',\r\n        passChangedSuccesfully: 'password was changed successfully',\r\n        passDontMatch:'las claves no coinciden o son muy cortas',\r\n        prefilledField1IsInConflictWithImportedField:'El valor del campo \"$1\" está en conflicto con el esperado',\r\n        primarKeyCantBeNull4:'error en la línea $1. El campo \"$2\" de la clave principal no puede ser #NULL',\r\n        spreadsheetProcessed:'hoja de datos procesada',\r\n        unkownHashValue4Import:'código # desconocido en la importación de un valor',\r\n        updateWithoutModfiedColumns:'se detectó una orden de modificación sin columnas a modificar',\r\n        updatingDb:'actualizando la base de datos',\r\n        versions:'versiones',\r\n    }\r\n};\r\n\r\nfunction BindMemoryPerodicallySaved(be){\r\n    return (\r\n/**\r\n * @param {Express.Session} session\r\n */\r\nfunction MemoryPerodicallySaved(session){\r\n    var MemoryStoreConstructor = memorystore(session);\r\n    class MemoryDevelConstructor extends MemoryStoreConstructor{\r\n        /**\r\n         * @param {memorystore.MemoryConsOpts} opts\r\n         */\r\n        constructor(opts){\r\n            super(opts);\r\n            var store=this;\r\n            var fileName='sessions/local-sessions.dump';\r\n            Promise.resolve().then(function(){\r\n                return fs.mkdir('sessions').then(function(){\r\n                    console.log('sessions dir created');\r\n                },function(err){\r\n                    if(err.code!='EEXIST'){\r\n                        console.log('ERROR in mkdir sessions');\r\n                        console.log(err.code);\r\n                        console.log(err);\r\n                        process.exit(1);\r\n                    }\r\n                });\r\n            }).then(function(){\r\n                return fs.writeFile('sessions/local-start','running since '+new Date(), {encoding:'utf8'});\r\n            }).then(function(){\r\n                return fs.stat(fileName);\r\n            }).then(function(stats){\r\n                if(new Date().getTime() - stats.mtimeMs > 15*60*1000){\r\n                    console.log('Sessions is 15 minutes old or more');\r\n                }else{\r\n                    return fs.readFile(fileName, {encoding:'utf8'}).then(function(content){\r\n                        var sessionInfo = json4all.parse(content);\r\n                        store.store.load(sessionInfo);\r\n                        console.log('session reabsorved with ',sessionInfo.length, 'sessions')\r\n                    });\r\n                }\r\n            },function(err){\r\n                console.log('No sessions stored for reabsorve');\r\n            }).catch(function(err){\r\n                console.log('ERROR REABSORVING sessions');\r\n                console.log(err);\r\n            }).then(function(){\r\n                var dumpEverySeconds=4;\r\n                console.log('dumping sessions every',dumpEverySeconds,'seconds');\r\n                var errorsToShow=4;\r\n                // TODO: hangs the server in devel mode\r\n                var interval = setInterval(function(){\r\n                    try{\r\n                        fs.writeFile(fileName,json4all.stringify(store.store.dump()));\r\n                    }catch(err){\r\n                        if(errorsToShow-->0){\r\n                            console.log('error saving local-sessions.dump');\r\n                            console.log(err);\r\n                            console.log(err.stack);\r\n                        }\r\n                    }\r\n                },dumpEverySeconds*1000);\r\n                be.shutdownCallbackListAdd({\r\n                    message:'session saver',\r\n                    fun:()=>clearInterval(interval)\r\n                })\r\n            });\r\n        }\r\n    }\r\n    return MemoryDevelConstructor;\r\n})}\r\n\r\n/**\r\n * @param {string} text \r\n */\r\nAppBackend.prototype.jsonPass = function jsonPass(text){\r\n    return JSON.stringify(text,null,'    ').replace(/\\n(.*\".*(pass|clave|secret).*\":\\s*\").*(\",?)\\n/gi,'\\n$1********$3\\n');\r\n};\r\n\r\nAppBackend.prototype.setStaticConfig = function setStaticConfig(defConfigYamlString){\r\n    var be=this;\r\n    this.staticConfig=this.staticConfig||{};\r\n    this.staticConfig=changing(this.staticConfig,jsYaml.load(defConfigYamlString));\r\n    var controlNotSet=['db.password', 'kill-9.master-pass', 'login.plus.secret'];\r\n    controlNotSet.forEach(function(attrs){\r\n        var attrList=attrs.split('.');\r\n        var value=be.staticConfig;\r\n        while(attrList.length && value && typeof value == \"object\"){\r\n            value=value[attrList.shift()];\r\n        }\r\n        if(value != null){\r\n            console.log('configuración insegura del servidor, no debe especificarse en modo estatico:',attrs);\r\n            throw Error('insecure config')\r\n        }\r\n    })\r\n}\r\n\r\nAppBackend.prototype.configList = function configList(){\r\n    var list=[\r\n        {\r\n            package:{\r\n                version: packagejson.version\r\n            }\r\n        },\r\n        this.staticConfig];\r\n    if(!this.staticConfig[\"client-setup\"]?.title && fs.existsSync(this.rootPath+'/def-config.yaml')){\r\n        console.log('DEPRECATED!!!!!!')\r\n        console.error('ERROR el def-config hay que ponerlo dentro de staticConfig');\r\n        console.log('DEPRECATED!!!!!!')\r\n        console.error('DEPRECATED!!!!!!')\r\n        console.log('DEPRECATED!!!!!!')\r\n        console.error('DEPRECATED!!!!!!')\r\n        list.push(this.rootPath+'/def-config.yaml')\r\n    };\r\n    list.push(this.rootPath+'/local-config');\r\n    list.push(process.env.BACKEND_PLUS_LOCAL_CONFIG?.trim()||{});\r\n    return list;\r\n};\r\n\r\n/**\r\n * @param {bp.Request} req\r\n */\r\nAppBackend.prototype.getMachineId = function getMachineId(req){\r\n    var be = this;\r\n    var ip = req.connection.remoteAddress;\r\n    var ipParts = ip.split('.');\r\n    var prefix = (be.config.server[\"ip-replacer\"]||{})[ipParts.slice(0,3).join('.')];\r\n    if(prefix){\r\n        return prefix+ipParts[3];\r\n    }\r\n    var iSame = 0;\r\n    var serverIpParts=req.socket.address().address.split('.');\r\n    while(iSame<ipParts.length && ipParts[iSame] === serverIpParts[iSame]){ iSame++; }\r\n    return ipParts.slice(iSame).join('.')||'local';\r\n};\r\n\r\nAppBackend.prototype.isAdmin = function isAdmin(reqOrContext){\r\n    var be = this;\r\n    return reqOrContext && (reqOrContext.forDump || reqOrContext.user && reqOrContext.user[be.config.login.rolFieldName] == 'admin');\r\n}\r\n\r\nAppBackend.prototype.can = function can(reqOrContext, what){\r\n    var be = this;\r\n    if (be.isAdmin(reqOrContext)) return true;\r\n    return reqOrContext?.user?.['can' + what];\r\n}\r\n\r\nAppBackend.prototype.canChangePass = async function canChangePass(reqOrContext, _userToChangePass){\r\n    var be = this;\r\n    return be.isAdmin(reqOrContext);\r\n}\r\n\r\nAppBackend.prototype.shutdownCallbackListAdd = function(messageFun){\r\n    this.shutdownCallbackList.push(messageFun);\r\n}\r\n\r\n\r\nAppBackend.prototype._Browsers = {\r\n    Edge:      {short:'Ed'  , minVer:14  , polly:117},\r\n    Konqueror: {short:'Kq'  , minVer:null, polly:true},\r\n    Chromium:  {short:'Chmm', minVer:49  , polly:117},\r\n    Chrome:    {short:'Ch'  , minVer:49  , polly:117},\r\n    Safari:    {short:'Sf'  , minVer:9   , polly:17},\r\n    IE:        {short:'IE'  , minVer:11  , polly:true},\r\n    Opera:     {short:'Op'  , minVer:null, polly:true},\r\n    Firefox:   {short:'FF'  , minVer:52  , polly:119},\r\n};\r\n\r\nvar fontExts = [ 'jfproj', 'ttf', 'pfa', 'woff', 'woff2', 'fnt', 'fot', 'otf', 'odttf', 'fon']\r\nvar imgExts =  ['jpg', 'png', 'jpeg', 'ico', 'gif', 'svg']\r\n\r\nAppBackend.prototype.exts = {\r\n    img: imgExts,\r\n    normal: ['', 'js', 'map', 'html', 'css', ...imgExts, 'appcache', 'manifest', 'json', 'webmanifest', 'zip', 'pdf', ...fontExts, 'xlsx', 'csv', 'mjs']\r\n};\r\n\r\n/**\r\n * @param {null|{testing?:boolean}} opts\r\n */\r\nAppBackend.prototype.start = function start(opts){\r\n    var be = this;\r\n    this.getTables().forEach(\r\n        // TODO: quitar, no debería hacer falta poner esto acá\r\n        /**\r\n         * @param {TableItem|string} tableItemOrString\r\n         */\r\n        function(tableItemOrString){\r\n            var generatedDef;\r\n            /** @type {TableItem} */\r\n            var tableItem;\r\n            if(typeof tableItemOrString==='string'){\r\n                tableItem = {name: tableItemOrString};\r\n            }else{\r\n                tableItem = tableItemOrString;\r\n            }\r\n            if(tableItem.mixin){\r\n                generatedDef = be.tableMixin(tableItem.mixin[0],tableItem.mixin[1],{\r\n                    name:tableItem.name,\r\n                    title:tableItem.title\r\n                });\r\n            }else if(tableItem.tableGenerator){\r\n                generatedDef = tableItem.tableGenerator;\r\n            }else{\r\n                tableItem = changing({name: tableItem.name, fileName: tableItem.name}, tableItem);\r\n                tableItem = changing({source: (tableItem.path||be.rootPath+'/'+dist+'server')+'/table-'+tableItem.fileName+'.js'}, tableItem);\r\n                if(!tableItem.source){\r\n                    throw new Error('Need source for tableItem.name:'+tableItem.name);\r\n                }else{\r\n                    generatedDef = require(tableItem.source);\r\n                    if(!(generatedDef instanceof Function)){\r\n                        generatedDef=generatedDef[tableItem.name];\r\n                        var contextForDump=be.getContextForDump();\r\n                        var tableDef = generatedDef(contextForDump);\r\n                        if(!tableDef.adapted){\r\n                            generatedDef = function(generatedDef){\r\n                                /** @param {bp.Context} context  */\r\n                                return function (context){\r\n                                    return be.tableDefAdapt(generatedDef(context), context);\r\n                                }\r\n                            }(generatedDef);\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n            be.tableStructures[tableItem.name] = generatedDef;\r\n        }\r\n    );\r\n    opts=opts||{};\r\n    var iPosDbDump=Array.prototype.indexOf.call(process.argv,'--dump-db')+1;\r\n    if(iPosDbDump>0){\r\n        pg.logExceptions = true;\r\n        var dumps=[];\r\n        while(iPosDbDump && iPosDbDump<process.argv.length && !process.argv[iPosDbDump].startsWith('--')){\r\n            dumps.push(process.argv[iPosDbDump]);\r\n            iPosDbDump++;\r\n        } \r\n        opts[\"dump-db\"]={\r\n            complete:!dumps.length,\r\n            tableNames:dumps instanceof Array?dumps:null,\r\n            forDump:true\r\n        };\r\n    }\r\n    var iPosConfig=Array.prototype.indexOf.call(process.argv,'--config')+1;\r\n    if(iPosConfig && process.argv[iPosConfig] && !process.argv[iPosConfig].startsWith('--')){\r\n        opts.config=process.argv[iPosConfig]\r\n    }\r\n    var be = this;\r\n    [Path.resolve(this.rootPath,'client'), Path.join(__dirname,'../for-client')].forEach(function(pathName){\r\n        Promise.all(['index.js', 'index.html', 'index.jade', 'index.css', 'index.styl'].map(function(fileName){\r\n            if(!fs.constants){\r\n                // @ts-ignore\r\n                fs.constants = fs;\r\n            }\r\n            return fs.access(pathName+'/'+fileName,fs.constants.F_OK).then(function(){\r\n                throw new Error(fileName+\" must not exists in private path: \"+pathName);\r\n            },function(err){\r\n                if(err.code!=='ENOENT'){\r\n                    console.log(\"error\",err);\r\n                    console.log(\" controling not existence of\", fileName,'in path',pathName);\r\n                    throw err;\r\n                }\r\n            });\r\n        })).catch(function(err){\r\n            console.log(\"==============================================\");\r\n            console.log(\"ERROR controling not index.* in privates paths\");\r\n            console.log(err);\r\n            process.exit(1);\r\n        });\r\n    });\r\n    /** @type {Express.Application} */\r\n    var mainApp;\r\n    /** @type {boolean} */\r\n    var verboseStartup;\r\n    opts = opts || {};\r\n    if(opts.testing){\r\n        /** @type {()=>Express.Application} */\r\n        // @ts-ignore : only for testing */\r\n        this.getMainApp = function getMainApp(){ return mainApp; };\r\n    }\r\n    this.shutdownBackend = async function shutdownBackend(opts){\r\n        var shootingDown = opts == null || !opts.onlyTurnOff;\r\n        var turningOff = opts == null || !opts.skipTurnOff;\r\n        if(!shootingDown){\r\n            console.log('shooting down:');\r\n            var waitFor = [\r\n                new Promise(function(resolve,reject){\r\n                    console.log('*','express server');\r\n                    be.server.close(/** @param {Error} err */function(err){\r\n                        if(err){\r\n                            console.log('*', err)\r\n                            reject(err);\r\n                        }else{\r\n                            console.log('*','express server done!')\r\n                            resolve();\r\n                        }\r\n                    });\r\n                }),\r\n                ...(be.shutdownCallbackList.map(x => (async function(){\r\n                    console.log('shut:', x.message)\r\n                    await x.fun()\r\n                    console.log('done:', x.message)\r\n                })())),\r\n            ];\r\n            console.log('*', 'waiting for all')\r\n            await Promise.all(waitFor);\r\n            console.log('*', 'all done')\r\n            mainApp = null;\r\n        }\r\n        if(turningOff){\r\n            console.log('turning off:');\r\n            await pg.shutdown();\r\n            console.log('pg shutdown done!');\r\n            console.log('* logWhy',logWhy)\r\n            logWhy && logWhy();\r\n        }\r\n    };\r\n    return Promise.resolve().then(function(){\r\n        var configList=be.configList();\r\n        if(opts.config){\r\n            configList.push(opts.config)\r\n        }\r\n        return MiniTools.readConfig(configList,opts.readConfig).catch(function(err){\r\n            console.log(\"be: error reading or merging config\");\r\n            throw err;\r\n        });\r\n    }).then(function(config){\r\n        be.config = config;\r\n        be.clientSetup = {config: be.config[\"client-setup\"]};\r\n        be.clientSetup.config.prefix = be.clientSetup.config.prefix || be.config.server[\"base-url\"].substr(1)+':';\r\n        if(config.nodb){\r\n            console.log(\"server without database\");\r\n        }else{\r\n            if(be.config.login[\"double-dragon\"]){\r\n                be.DoubleDragon = {dbParams:{}}\r\n            }\r\n            return Promise.resolve().then(function(){\r\n                if(config.db.which){\r\n                    if(!config.db[config.db.which]){\r\n                        throw new Error('lack of '+config.db.which+' in config.db');\r\n                    }else{\r\n                        config.db = {...config.db, ...config.db[config.db.which]};\r\n                    }\r\n                }\r\n                var sessionStoreName=be.config.server[\"session-store\"];\r\n                if(sessionStoreName){\r\n                    if(config.devel && be.sessionStores[sessionStoreName+'Devel']){\r\n                        sessionStoreName+='Devel';\r\n                    }\r\n                    var storeModule = be.sessionStores[sessionStoreName];\r\n                    be.config.login.plus.store.module = storeModule;\r\n                }else{\r\n                    console.error('###################### DEPRECATED #####################')\r\n                    console.error('LACK OF server.session-store')\r\n                }\r\n                be.config.install.dump.db.owner=coalesce(be.config.db.owner,be.config.install.dump.db.owner,be.config.db.user);\r\n                be.config.install.dump.db[\"owner4special-scripts\"]=coalesce(be.config.install.dump.db[\"owner4special-scripts\"],be.config.install.dump.db.owner)\r\n                be.config.install.dump.db[\"user4special-scripts\"]=coalesce(be.config.install.dump.db[\"user4special-scripts\"],be.config.db.user)\r\n                verboseStartup=!be.config.server[\"silent-startup\"];\r\n                serveContent.logAll = be.config.log[\"serve-content\"];\r\n                MiniTools.logServe =  be.config.log[\"serve-content\"];\r\n                if(be.clientSetup.config.lang in be.i18n.messages){\r\n                    be.messages = {...be.i18n.messages.en, ...be.i18n.messages[be.clientSetup.config.lang]};\r\n                    typeStore.locale = typeStore.i18n.locale[be.clientSetup.config.lang];\r\n                    typeStore.messages = typeStore.i18n.messages[be.clientSetup.config.lang];\r\n                    pg.setLang(be.clientSetup.config.lang);\r\n                }\r\n            }).then(function(){\r\n                if(be.config.db.motor!='postgresql'){\r\n                    throw new Error(\"backend-plus: Motor not recongnized: \"+be.config.db.motor);\r\n                }\r\n                be.db = pg;\r\n                be.dbUserNameExpr=\"get_app_user()\";\r\n                be.dbUserRolExpr=`(select ${be.db.quoteIdent(be.config.login.rolFieldName)} \r\n                    from ${be.config.login.schema?be.db.quoteIdent(be.config.login.schema)+'.':''}${be.db.quoteIdent(be.config.login.table)} \r\n                    where ${be.db.quoteIdent(be.config.login.userFieldName)} = ${be.dbUserNameExpr})`\r\n            }).then(function(){\r\n                if(opts[\"dump-db\"]){\r\n                    return be.dumpDb(opts[\"dump-db\"]).then(function(){\r\n                        var err = new Error('DB DUMP OK');\r\n                        err.dumping='ok';\r\n                        throw err;\r\n                    },function(err){\r\n                        err.dumping='bad';\r\n                        throw err;\r\n                    });\r\n                }\r\n            }).then(function(){\r\n                if(be.config.log.db['last-error'] || be.config.devel || be.config.log.db['on-demand']){\r\n                    if(be.config.devel || be.config.log.db['on-demand']){\r\n                        be.setLog=function(opts){\r\n                            const LOG_MINUTES = 5; // minutes\r\n                            if(opts.until){\r\n                                try{\r\n                                    var ti=bestGlobals.timeInterval.iso(opts.until)\r\n                                    be.config.log.db.until = bestGlobals.datetime.now().add(ti);\r\n                                }catch(err){\r\n                                    try{\r\n                                        be.config.log.db.until = bestGlobals.datetime.iso(opts.until);\r\n                                    }catch(err2){\r\n                                        console.log('invalid log-until format. Setting '+LOG_MINUTES+' minutes');\r\n                                    }\r\n                                }\r\n                            }else{\r\n                                be.config.log.db.until = bestGlobals.datetime.now().add({ms:LOG_MINUTES*60*1000}); // LOG_MIN minutes\r\n                            }\r\n                            be.config.log.db.results=!!opts.results && !/^(0|false|f|no|n|нет|н)$/i.test(opts.results);\r\n                        }\r\n                        be.setLog({until:be.config.log.db.until});\r\n                        var logWaiter=Promise.resolve(); // para mandar todo en orden\r\n                        console.log('SQL: log all until',be.config.log.db.until.toYmdHms())\r\n                        pg.log = function logAll(message, type){\r\n                            if(bestGlobals.datetime.now()<=be.config.log.db.until){\r\n                                logWaiter=logWaiter.then(function(){\r\n                                    if(be.config.log.db.results || !(type=='ROW' || type=='RESULT' || type=='QUERY-A' || type=='QUERY-P')){\r\n                                        fs.appendFile('./local-log-all.sql','-- '+(type||'')+'\\n'+message+'\\n');\r\n                                    }\r\n                                })\r\n                            }else{\r\n                                pg.logLastError(message, type);\r\n                            }\r\n                        }\r\n                    }else{\r\n                        pg.log = pg.logLastError;\r\n                    }\r\n                    pg.log.inFileName = 'last-pg-error-local.sql'\r\n                    pg.logLastError.inFileName = 'last-pg-error-local.sql'\r\n                }\r\n                be.config.db.search_path = be.config.db.search_path ?? [be.config.db.schema, 'public'];\r\n                be.getDbClient = function getDbClient(req){\r\n                    var username = req?.user?.[be.config.login.userFieldName];\r\n                    var paramsDb = be.DoubleDragon?.dbParams?.[username] ?? be.config.db;\r\n                    return pg.connect(paramsDb).then(function(client){\r\n                        var dbAppName=req?(\r\n                            ((req.user||{})[be.config.login.userFieldName]||'!logged')+\r\n                            ' '+(req.machineId||'?')+\r\n                            ' '+(((req.useragent)||{}).shortDescription||'?')\r\n                        ):'!app local internal';\r\n                        return client.executeSentences([\r\n                            \"SET application_name = \"+be.db.quoteLiteral(dbAppName),\r\n                        ]).then(function(){\r\n                            var search_path = be.config.db.search_path;\r\n                            if(search_path.length>0){\r\n                                return client.query(\"set SEARCH_PATH TO \"+be.db.quoteIdentList(search_path)).execute().then(function(){\r\n                                    return client;\r\n                                });\r\n                            }else{\r\n                                return client;\r\n                            }\r\n                        }).then(function(client){\r\n                            if(username){\r\n                                return client.query(`CALL set_app_user(${be.db.quoteLiteral(username)})`).execute().then(function(){\r\n                                    return client;\r\n                                });\r\n                            }else{\r\n                                return client.query(`CALL set_app_user('!login')`).execute().then(function(){\r\n                                    return client;\r\n                                });\r\n                            }\r\n                        }).then(function(client){\r\n                            if(be.config[\"client-setup\"].lang=='es'){\r\n                                return client.query(\"set datestyle TO iso,dmy\").execute().then(function(){\r\n                                    return client;\r\n                                });\r\n                            }else{\r\n                                return client;\r\n                            }\r\n                        });\r\n                    });\r\n                };\r\n                be.inDbClient = async function inDbClient(req, doThisWithDbClient){\r\n                    var be=this;\r\n                    try{\r\n                        var client = await be.getDbClient(req);\r\n                        var result = await doThisWithDbClient.call(be, client /*,req?*/);\r\n                        client.done();\r\n                        return result;\r\n                    }catch(err){\r\n                        if(client && typeof client.done === \"function\"){\r\n                            client.done();\r\n                        }\r\n                        throw err;\r\n                    }\r\n                };\r\n                be.inTransaction = async function inTransaction(req, doThisWithDbTransaction){\r\n                    var be = this;\r\n                    return be.inDbClient(req, async function(client){\r\n                        try{\r\n                            await client.query(\"BEGIN TRANSACTION\").execute();\r\n                            var result = await doThisWithDbTransaction.call(be, client /*,req?*/);\r\n                            await client.query(\"COMMIT\").execute();\r\n                            return result;\r\n                        }catch(err){\r\n                            try{\r\n                                await client.query(\"ROLLBACK\").execute();\r\n                            }catch(err2){\r\n                                console.log(\"Error in database when rollback\",err,\" Error trying to rollback \",err2);\r\n                            }\r\n                            throw err;\r\n                        }\r\n                    });\r\n                };\r\n                return be.inDbClient(null, async function(client){\r\n                    if(verboseStartup){\r\n                        console.log(\r\n                            'db-connected',\r\n                            be.jsonPass(be.config.db)\r\n                        );\r\n                    }\r\n                    try{\r\n                        await be.checkDatabaseStructure(client);\r\n                    }catch(err){\r\n                        console.log('*******************************************')\r\n                        console.error(be.messages.server.ErrorCheckDatabaseStructure)\r\n                        console.log(err);\r\n                        throw err;\r\n                    }\r\n                    var data = await client.query(\"SELECT current_timestamp as cts\").fetchUniqueRow();\r\n                    if(verboseStartup){\r\n                        console.log('NOW in Database',data.row.cts);\r\n                    }\r\n                });\r\n            });\r\n        }\r\n    }).then(function(){\r\n        if(!be.config.nologin){\r\n            return Promise.all([\r\n                fs.stat('unlogged/login.jade').then(function(){\r\n                    throw new Error('login.jade must be in client dir not in unlogged');\r\n                },function(){ /*OK, login.jade must not be here */ }),\r\n                fs.stat('client/login.jade').then(function(){\r\n                    return Path.resolve(be.rootPath,'client/login');\r\n                },function(){ \r\n                    return Path.join(__dirname,'../for-client/login');\r\n                }).then(function(loginFile){\r\n                    be.config.login.plus.loginPageServe=function(req,res,next){\r\n                        return MiniTools.serveJade(loginFile,be.optsGenericForFiles(req,{withFlash:true}).jade)(req,res,next);\r\n                    };\r\n                    be.config.login.plus.newPassPageServe=function(req,res,next){\r\n                        return MiniTools.serveJade(loginFile.replace(/\\blogin\\b/,'new-password'),be.optsGenericForFiles(req,{withFlash:true}).jade)(req,res,next);\r\n                    };\r\n                    be.config.login.plus.newPassPageServe2=function(req,res,next){\r\n                        return MiniTools.serveJade(loginFile.replace(/\\blogin\\b/,'new-password-result'),be.optsGenericForFiles(req,{withFlash:true}).jade)(req,res,next);\r\n                    };\r\n                    be.config.login.plus.newPassPageEnter=function(username, token){\r\n                        return function(req,res,next){\r\n                            return MiniTools.serveJade(loginFile.replace(/\\blogin\\b/,'new-pass-enter'),{...be.optsGenericForFiles(req,{withFlash:true}).jade, username, token})(req,res,next);\r\n                        }\r\n                    };\r\n                })\r\n            ]);\r\n        }\r\n    }).then(async function(){\r\n        mainApp = express();\r\n        //mainApp.use(cookieParser());\r\n        if(be.config.server.allowedHosts){\r\n            if(!Array.isArray(be.config.server.allowedHosts)){\r\n                throw Error('allowedHosts must be an Array')\r\n            }\r\n            const whitelist = ['localhost'].concat(be.config.server.allowedHosts);\r\n            const corsOptions = {\r\n                origin: function (origin, callback) {\r\n                    if (whitelist.some((element)=>origin?.includes(element)) || !origin){\r\n                        callback(null, true);\r\n                    }else{\r\n                        callback(new Error('Not allowed by CORS'));\r\n                    }\r\n                },\r\n                credentials: true\r\n            };\r\n            mainApp.use(cors(corsOptions));\r\n        }\r\n        mainApp.use(bodyParser.urlencoded({extended:true, limit: '50mb'}));\r\n        mainApp.use(function(req,res,next){\r\n            if((req.headers['content-type']||'').match(/^multipart\\/form-data/)){\r\n                var form = new multiparty.Form();\r\n                form.parse(req, function(err, fields, files) {\r\n                    req.multipartErr=err;\r\n                    req.fields=fields;\r\n                    req.files=files;\r\n                    next(err);\r\n                });\r\n            }else{\r\n                next();\r\n            }\r\n        });\r\n        if(be.config.log.req){\r\n            mainApp.use(function(req,res,next){\r\n                if(\r\n                    (!/keep-alive.json$/.test(req.originalUrl) || be.config?.log?.req?.['keep-alive']) &&\r\n                    (!/(.png|.jpg|.js|.jsx|.css|.html)$/.test(req.originalUrl) || be.config?.log?.req?.['all'])\r\n                ){\r\n                    console.log('REQ',req.method,req.protocol,req.hostname,req.originalUrl,'from:',req.ip,req.query);\r\n                }\r\n                next();\r\n            });\r\n        }\r\n        mainApp.use(useragent.express());\r\n        mainApp.use(function(req,res,next){\r\n            be.seenBrowsers=be.seenBrowsers||{};\r\n            if(be.config.devel){\r\n                var jsonBro = req.useragent.source;\r\n                if(!(jsonBro in be.seenBrowsers)){\r\n                    be.seenBrowsers[jsonBro]={first:new Date(), times:0};\r\n                }\r\n            }\r\n            req.useragent.shortDescription = (be._Browsers[req.useragent.browser]||{short:req.useragent.browser}).short+(req.useragent.version||'0').split('.')[0];\r\n            req.machineId = be.getMachineId(req);\r\n            if(be.config.devel){\r\n                be.seenBrowsers[jsonBro].last=new Date();\r\n                be.seenBrowsers[jsonBro].short=req.useragent.shortDescription;\r\n                if(!be.seenBrowsers[jsonBro].times){\r\n                    fs.writeFile('local-browsers',JSON.stringify(be.seenBrowsers,null,'    ')).catch(function(err){\r\n                    });\r\n                    be.seenBrowsers[jsonBro].times++;\r\n                }\r\n            }\r\n            next();\r\n        });\r\n        if(be.config.server[\"kill-9\"]){\r\n            /*eslint global-require: 0 */\r\n            var kill9 = require('kill-9');\r\n            mainApp.use(be.config.server[\"base-url\"], kill9(be.config.server[\"kill-9\"]));\r\n        }\r\n        if(be.config.server[\"base-url\"] && be.config.server[\"base-url\"]!='/'){\r\n            mainApp.get('/favicon.ico', function(req,res,next){\r\n                MiniTools.serveFile(__dirname+'/../for-client/img/warning128.png')(req,res,next)\r\n            })\r\n        }\r\n        be.addUnloggedServices(mainApp, be.config.server[\"base-url\"]);\r\n        var unloggedApp = await be.addProcedureServices(true);\r\n        if(be.config.nologin){\r\n            console.log(\"server without login\");\r\n        }else{\r\n            mainApp.loginPlusManager = new loginPlus.Manager();\r\n            be.config.login.plus.baseUrl = coalesce(be.config.login.plus.baseUrl, be.config.server[\"base-url\"], '/');\r\n            be.config.login.plus.userFieldName = be.config.login.plus.userFieldName || be.config.login.userFieldName;\r\n            if(verboseStartup){\r\n                console.log('-------------------');\r\n                console.log(\r\n                    'be.config.login', \r\n                    be.jsonPass(be.config.login)\r\n                );\r\n            }\r\n            be.config.login.plus=changing(be.config.login.plus,{session:{\r\n                name: 'bp'+(packagejson.name+be.config.server[\"base-url\"]||Math.random()).replace(/\\//g,'#')+'-connect.sid',\r\n                cookie:{\r\n                    path: be.config.server[\"base-url\"]||'/',\r\n                }\r\n            }});\r\n            var loginPlusOpts={\r\n                schrödinger:function(){\r\n                    mainApp.use(be.config.server[\"base-url\"], unloggedApp);\r\n                    be.addSchrödingerServices(mainApp, be.config.server[\"base-url\"]);\r\n                },\r\n                messages: be.messages.unlogged.login\r\n            }\r\n            if(be.config.login.unloggedLandPage){\r\n                loginPlusOpts.noLoggedUrlPath=be.config.login.unloggedLandPage;\r\n            }\r\n            mainApp.loginPlusManager.init(mainApp,changing(be.config.login.plus,loginPlusOpts));\r\n            be.shutdownCallbackListAdd({\r\n                message:'login-plus manager',\r\n                fun:function(){\r\n                    mainApp.loginPlusManager.closeManager();\r\n                }\r\n            });\r\n            const updatePassword = async ({client, username, password, setUpdateDate, errorIfNoResult}) => {\r\n                const {table, passFieldName, userFieldName, passUpdatedAtFieldName, passAlgorithmFieldName, schema} = be.config.login;                \r\n                const hashPass = await generateScramVerifier(password);\r\n                let params = [username, hashPass];\r\n                let setters = [`${be.db.quoteIdent(passFieldName)} = $2`];\r\n                if(passAlgorithmFieldName){\r\n                    setters.push(`${be.db.quoteIdent(passAlgorithmFieldName)} = $3`);\r\n                    params.push('PG-SHA256')\r\n                }\r\n                if(setUpdateDate && passUpdatedAtFieldName){\r\n                    setters.push(`${be.db.quoteIdent(passUpdatedAtFieldName)} = current_timestamp`)\r\n                }\r\n                        \r\n                const result = await client.query(`\r\n                    UPDATE ${(schema ? be.db.quoteIdent(schema) + '.' : '') + be.db.quoteIdent(table)} \r\n                        SET ${setters.join(', ')}\r\n                        WHERE ${be.db.quoteIdent(userFieldName)} = $1\r\n                        returning 1 as ok\r\n                    `, params\r\n                ).fetchOneRowIfExists();\r\n\r\n                if(result.rowCount === 0 && errorIfNoResult){\r\n                    throw Error ('no se encontró el usuario')\r\n                };\r\n                return result\r\n            }\r\n            mainApp.loginPlusManager.setValidatorStrategy(\r\n                async function(req, username, password, done) {\r\n                    try{\r\n                        var client;\r\n                        if(!be.config.login[\"preserve-case\"]){\r\n                            username = username.toLowerCase().trim();\r\n                        }\r\n                        client = await be.getDbClient(req);\r\n                        await client.query(\"CALL set_app_user('!login')\").execute();\r\n                        const {passFieldName, rolFieldName, userFieldName} = be.config.login;\r\n                        var infoFieldList=(\r\n                            be.config.login.infoFieldList||(\r\n                                rolFieldName?\r\n                                    [userFieldName, rolFieldName]\r\n                                :\r\n                                    [userFieldName]\r\n                                )\r\n                            ).concat(passFieldName);\r\n                        \r\n                        const sql = \"SELECT  \"+infoFieldList.map(function(fieldOrPair){ return fieldOrPair.split(' as ').map(function(ident){ return be.db.quoteIdent(ident)}).join(' as '); })+\r\n                                \", \"+be.config.login.activeClausule+\" as active \"+\r\n                                \", \"+be.config.login.lockedClausule+\" as locked \"+\r\n                            \"  FROM  \"+(be.config.login.from ?? (\r\n                                (be.config.login.schema?be.db.quoteIdent(be.config.login.schema)+'.':'')+\r\n                                be.db.quoteIdent(be.config.login.table)\r\n                            ))+\r\n                            \"  WHERE \"+be.db.quoteIdent(be.config.login.userFieldName)+\" = $1 \";\r\n                        const data = await client.query(sql,[username]).fetchOneRowIfExists();\r\n\r\n                        if(data.rowCount != 1){\r\n                            done(null,false,{message:be.messages.unlogged.login.userOrPassFail});\r\n                            return\r\n                        }else{\r\n                            let needsMigration = false;\r\n                            const user = data.row;\r\n                            if(!user[passFieldName]){\r\n                                done(null,false,{message:be.messages.unlogged.login.userOrPassFail});\r\n                                return\r\n                            }\r\n                            const usaScramSha256 = user[passFieldName].startsWith('SCRAM-SHA-256$')\r\n                            if (usaScramSha256){\r\n                                let isScramValid = false;\r\n                                // 1. Intento con formato PG-Compatible (Nuevo)\r\n                                if(await verifyScramPG(password, user[passFieldName])){\r\n                                    isScramValid = true;\r\n                                }\r\n                                \r\n                                // 2. Intento con formato Legacy (64 bytes)\r\n                                else if(await verifyScramLegacy(password, user[passFieldName])){\r\n                                    isScramValid = true;\r\n                                    needsMigration = true;\r\n                                }\r\n                                if(!isScramValid){\r\n                                    done(null,false,{message:be.messages.unlogged.login.userOrPassFail});\r\n                                    return\r\n                                }\r\n                            }else{                         \r\n                                if (md5(password+username.toLowerCase()) === user[passFieldName]){\r\n                                    needsMigration = true;\r\n                                }else{\r\n                                    done(null,false,{message:be.messages.unlogged.login.userOrPassFail});\r\n                                    return\r\n                                }\r\n                            }\r\n                            if(needsMigration){\r\n                                if (be.config.log[\"pass-migration\"]) console.log('Ejecutando migración a SCRAM...');\r\n                                await updatePassword({client, username, password, setUpdateDate:false, errorIfNoResult:true});\r\n                                if (be.config.log[\"pass-migration\"]) console.log('Migración completada.');\r\n                            }\r\n                        }\r\n                        //continua validando                    \r\n                        if(data.rowCount==1){\r\n                            if(!data.row.active){\r\n                                done(null,false,{message:be.messages.unlogged.login.inactiveFail});\r\n                                return\r\n                            }else if(data.row.locked){\r\n                                done(null,false,{message:be.messages.unlogged.login.lockedFail});\r\n                                return\r\n                            }else{\r\n                                if(req.query[\"return-to\"]){\r\n                                    req.session.loginReturnTo = req.query[\"return-to\"];\r\n                                }\r\n                                if(be.config.login[\"double-dragon\"]){\r\n                                    be.DoubleDragon.dbParams[username] = changing(be.config.db, {user:username, password});\r\n                                }\r\n                            }\r\n                        }else{\r\n                            done(null,false,{message:be.messages.unlogged.login.userOrPassFail});\r\n                            return\r\n                        }\r\n\r\n                        const userInfo = data.row;\r\n                        if (!userInfo) return;\r\n                        if (!be.config.login.skipBitacora) {\r\n                            var context = be.getContext(req);\r\n                            var sessionInfo = await client.query(be.generateInsertSQL(be.config.server.bitacoraSchema, be.config.server.bitacoraTableName,{\r\n                                procedure_name: '@login',\r\n                                username,\r\n                                machine_id: context.machineId,\r\n                                navigator: context.navigator,\r\n                                init_date: bestGlobals.datetime.now(),\r\n                                parameters: {}\r\n                            })).fetchUniqueValue();\r\n                            userInfo.bitacoraId = sessionInfo.value;\r\n                        }\r\n                        done(null, userInfo);\r\n                    }catch(err){\r\n                        if(be.config.login[\"double-dragon\"]){\r\n                            done(null,false,{message:be.messages.unlogged.login.userOrPassFail});\r\n                        }\r\n                        console.log('login error',err);\r\n                        console.log(err.stack);\r\n                        done(new Error('internal login error'));\r\n                    } finally {\r\n                        if(client && typeof client.done === \"function\"){\r\n                            client.done();\r\n                        }\r\n                    }\r\n                }\r\n            );\r\n            be.changePassword=async function(client,username,oldPassword,newPassword){\r\n                const { table, passFieldName, userFieldName, schema } = be.config.login;\r\n                let ok = false;\r\n                const data = await client.query(\r\n                    `SELECT *\r\n                        FROM ${(schema ? be.db.quoteIdent(schema) + '.' : '')}${be.db.quoteIdent(table)}\r\n                        WHERE ${be.db.quoteIdent(userFieldName)} = $1`, \r\n                    [username]\r\n                ).fetchOneRowIfExists();\r\n                if (data.rowCount !== 1) {\r\n                    // Usuario no encontrado\r\n                    return false;\r\n                }\r\n                const user = data.row\r\n                const storedHash = user[passFieldName];\r\n                if (oldPassword !== false) {\r\n                    if (storedHash.startsWith('SCRAM-SHA-256$')) {//Intento SCRAM-SHA-256\r\n                        ok = await verifyScramPG(oldPassword, storedHash);\r\n                        if (!ok) {\r\n                            ok = await verifyScramLegacy(oldPassword, storedHash);\r\n                        }\r\n                    } else { //Intento MD5\r\n                        const md5Hash = md5(oldPassword + username.toLowerCase()); \r\n                        ok = (md5Hash === storedHash);\r\n                    }\r\n                    if (!ok) {\r\n                        // La contraseña antigua es incorrecta\r\n                        return false;\r\n                    }\r\n                } else {\r\n                    // Si no se requiere la contraseña antigua continua\r\n                    ok = true;\r\n                }\r\n                // Si la verificación fue exitosa o se omitió (ok == true), generamos el nuevo hash SCRAM\r\n                if (ok) {\r\n                    const updateResult = await updatePassword({client, username, password:newPassword, setUpdateDate:true, errorIfNoResult:false});\r\n                    ok = updateResult.rowCount === 1;\r\n                    if (ok && be.config.login['double-dragon']) {\r\n                        const doubleDragonSql = \"ALTER USER \" + be.db.quoteIdent(username) + \" WITH PASSWORD \" + be.db.quoteLiteral(newPassword);\r\n                        await client.query(doubleDragonSql, []).execute();\r\n                    }\r\n                }\r\n                return ok;\r\n            };\r\n            be.passwordChanger=function(req, username, oldPassword, newPassword, done) {\r\n                if(be.config.login.disableChangePassword){\r\n                    done(null,false,'el cambio de contraseña está deshabilitado');\r\n                }else{\r\n                    be.inTransaction(req,function(client){\r\n                        return be.changePassword(client,username,oldPassword,newPassword)\r\n                    }).then(function(ok){\r\n                        done(null,ok,ok?null:be.messages.server.oldPassDontMatch);\r\n                    }).catch(function(err){\r\n                        console.log('error changing pass',err);\r\n                        console.log('stack',err.stack);\r\n                        throw err;\r\n                    }).catch(done);\r\n                }\r\n            }\r\n            mainApp.loginPlusManager.setPasswordChanger(be.passwordChanger);\r\n            if(be.config.devel.delay){\r\n                mainApp.use(function(req,res,next){\r\n                    if(/^[^.]*$/.test(req.path)){\r\n                        bestGlobals.sleep(be.config.devel.delay/2+Math.random()*be.config.devel.delay).then(next);\r\n                    }else{\r\n                        next();\r\n                    }\r\n                });\r\n            }\r\n            be.addLoggedServices();\r\n        }\r\n        be.app.use(function(err,req,res,next){\r\n            console.log('******************', next);\r\n            console.log(err);\r\n            MiniTools.serveErr(req, res)(err);\r\n        });\r\n        return be.addProcedureServices();\r\n    }).then(function(){\r\n        return new Promise(function(resolve, reject){\r\n            try{\r\n                be.server = mainApp.listen(be.config.server.port, resolve);\r\n            }catch(err){\r\n                reject(err);\r\n            }\r\n        });\r\n    }).then(function(){\r\n        return be.postConfig();\r\n    }).then(function(){\r\n        if(be.config[\"client-setup\"].menu===true){\r\n            var contextForDump = be.getContextForDump();\r\n            // var menuDef=be.getMenu({rol:'admin', be});\r\n            var menuDef=be.getMenu(contextForDump);\r\n            controlMenuDefinition(menuDef.menu);\r\n        }\r\n        mainApp.use(be.config.server[\"base-url\"],be.app);\r\n    }).then(function(){\r\n        if(verboseStartup){\r\n            console.log('listening on','http://localhost:'+be.config.server.port+be.config.server[\"base-url\"]);\r\n            console.log('datetime:',new Date().toISOString());\r\n        }\r\n        if(be.config.server.port == null){\r\n            console.log('backend-plus: Lack of mandatory server.port in config');\r\n            throw new Error('backend-plus: Lack of mandatory server.port in config');\r\n        }\r\n        be.timeReadyBackendPlus = new Date();\r\n        if(verboseStartup){\r\n            console.log('READY',numeral((be.timeReadyBackendPlus-timeStartBackendPlus)/1000).format(\"0.0\"),'s elapsed');\r\n        }\r\n        if (Array.prototype.indexOf.call(process.argv,'--dump-includes')+1) {\r\n            console.log(\"Resolved modules from: \" + process.cwd())\r\n            likeAr(resolved_modules_log).forEach((c,l)=>console.log(`   ${c} ${l}`));\r\n        }\r\n        return be.sendMail({\r\n            to: be.config.mailer?.supervise?.to,\r\n            subject: `npm start ${be.config[\"client-setup\"]?.title || packagejson.name} ok ✔️`,\r\n            text:`Inicio del servicio: ${new Date().toJSON()}\r\n            \r\n            Contexto: ${os.userInfo().username} ${process.cwd()}\r\n            `\r\n        }, {ignoreNoMailer:true, event:'restart-ok'})\r\n    }).catch(function(err){\r\n        if(err.dumping=='ok'){\r\n            console.log('db struct dumped');\r\n            process.exit(0);\r\n            return; \r\n        }\r\n        console.log('ERROR',err.stack || err);\r\n        if(err.context){\r\n            console.log('context', err.context);\r\n        }\r\n        if(err.dumping){\r\n            console.log('error dumping db');\r\n            process.exit(1);\r\n        }\r\n        var mailDeAvisoDeFalla = be.sendMail({\r\n            to: be.config.mailer?.supervise?.to,\r\n            subject: `npm start ${be.config[\"client-setup\"]?.title || packagejson.name} fallido 🛑`,\r\n            text:`Falla en el inicio del servicio: ${new Date().toJSON()}\r\n            \r\n            Contexto: ${os.userInfo().username} ${process.cwd()}\r\n\r\n            Mensaje: ${err.message}\r\n            \r\n            ${err.stack}\r\n            `\r\n        }, {ignoreNoMailer:true, event:'restart-fail'})\r\n        console.log('backend-plus: start up canceled');\r\n        mailDeAvisoDeFalla.then(function(){\r\n            if(be.config.mailer){\r\n                console.log('avisado por mail')\r\n            }\r\n        },function(){\r\n            console.log('no pudo avisarse por mail')\r\n        }).finally(function(){\r\n            process.exit(1);\r\n        });\r\n    });\r\n};\r\n\r\nAppBackend.prototype.rootPath = process.cwd();\r\n\r\nAppBackend.prototype.specialValueWhenInsert = {\r\n    currentUsername:function(context){\r\n        return context.username;\r\n    },\r\n    lineNumberWhenImported:function(_context, _defField, parameters){\r\n        return parameters.lineNumber\r\n    }\r\n}\r\n\r\nAppBackend.prototype.specialSqlDefaultExpressions = {\r\n    'current_user': 'get_app_user()',\r\n}\r\n\r\nAppBackend.prototype.checkDatabaseStructure = async function checkDatabaseStructure(client){\r\n    var be=this;\r\n    var result = await client.query(`select setting from pg_settings where name='server_version';`).fetchUniqueValue();\r\n    if(result.value<be.config.db['min-version']){\r\n        console.log('PARA INSTALACIONES VIEJAS QUE NO USEN generatedAs O NO ACTUALICEN operativos:');\r\n        console.log('se puede agregar en local-config.yaml en db: min-version: 9')\r\n        throw new Error(be.messages.server.dbMinVersionFail.replace('$1',result.value).replace('$2',be.config.db['min-version']))\r\n    }else if(!be.config.server[\"silent-startup\"]){\r\n        console.log('db version',result.value);\r\n    }\r\n    if(be.config.login?.forget){\r\n        if(!be.config.login.forget?.urlPath){\r\n            be.config.login.forget.urlPath = '/new-pass';\r\n        }\r\n        if(!be.config.login.forget?.urlPathOk){\r\n            be.config.login.forget.urlPathOk = '/new-pass-ok';\r\n        }\r\n        if(!be.config.mailer){\r\n            console.log('NO HAY MAILER DEFINIDO');\r\n            throw new Error(be.messages.server.noMailerConfig);\r\n        }\r\n        if(be.config.login?.forget){\r\n            try{\r\n                await client.query(`select tokentype, info, due from his.tokens limit 1`).fetchOneRowIfExists();\r\n            }catch(err){\r\n                var mensaje = `\r\n                    --------quizas falten los campos en la tabla tokens:\r\n                    alter table tokens add column tokentype text;\r\n                    alter table tokens add column info jsonb;\r\n                    alter table tokens add column due timestamp;\r\n                    --------quizas falte moverla al esquema his.\r\n                `;\r\n                err.message += mensaje;\r\n                console.log(mensaje)\r\n                throw err;\r\n            }\r\n            try{\r\n                await client.query(`select ${be.db.quoteIdentList(be.config.login.forget.mailFields)} \r\n                    from ${be.config.login.schema?be.db.quoteIdent(be.config.login.schema)+'.':''}${be.config.login.table} limit 1`).fetchOneRowIfExists();\r\n            }catch(err){\r\n                var mensaje = `\r\n                    -------- quizas falten los campos en la tabla usuarios:\r\n                    ${be.config.login.forget.mailFields.map(name=>`\r\n                    alter table ${be.config.login.schema?be.db.quoteIdent(be.config.login.schema)+'.':''}${be.config.login.table} add column ${name} text;`).join('')}\r\n                `;\r\n                err.message += mensaje;\r\n                console.log(mensaje)\r\n                throw err;\r\n            }\r\n        }\r\n    }\r\n    var bitacoraTableName = be.config.server.bitacoraTableName || 'bitacora';\r\n    var bitacoraId = await client.query(`SELECT data_type \r\n        FROM information_schema.columns\r\n        WHERE /*table_schema = 'his' AND*/ table_name = '${bitacoraTableName}' AND column_name = 'id'\r\n    `).fetchOneRowIfExists();\r\n    if (bitacoraId.row?.data_type != 'bigint') {\r\n        var message = `\r\n            ------- hay que cambiar la bitacora (${bitacoraTableName})de lugar (a his) y agrandar el id (a bigint)\r\n            alter table ${be.config.db.schema}.${bitacoraTableName} set schema his;\r\n            alter table ${be.config.db.schema}.tokens set schema his;\r\n            alter table his.${bitacoraTableName} alter column id type bigint;\r\n            grant usage on schema his to ${be.config.db.user};\r\n            grant select, insert, update on his.${bitacoraTableName} to ${be.config.db.user};\r\n            alter table his.${bitacoraTableName} alter column parameters_definition drop not null;\r\n        `;\r\n        throw new Error(message);\r\n    }\r\n    var {rows: sql_routines} = await client.query(`SELECT routine_name, routine_schema, routine_type, routine_definition\r\n        FROM information_schema.routines\r\n        WHERE routine_schema in (${be.config.db.search_path.map(path => be.db.quoteLiteral(path)).join(', ')})\r\n    `).fetchAll();\r\n    var sqlRoutines = likeAr.createIndex(sql_routines, 'routine_name');\r\n    var set_app_user_RoutineType = sqlRoutines.set_app_user?.routine_type || 'inexsistente';\r\n    if (set_app_user_RoutineType != 'PROCEDURE') {\r\n        throw new Error('ERROR en la DB: set_app_user no es un PROCEDURE es ' + set_app_user_RoutineType);\r\n    }\r\n    var message = ''\r\n    likeAr(AppBackend.prototype.sql_routines).forEach((routine_name, def) => {\r\n        if (sqlRoutines[routine_name] && def.dump.includes(sqlRoutines[routine_name].routine_definition)) {\r\n            message += `\r\n                ----- hay que crear o actualizar la rutina ${routine_name}:\r\n                ${def.dump}\r\n                `;\r\n        }\r\n    })\r\n    if (message) throw new Error(message);\r\n};\r\n\r\nAppBackend.prototype.postConfig = function postConfig(){\r\n    this.fieldDomain={};\r\n    this.scanSkinFiles();\r\n};\r\n\r\nAppBackend.prototype.getContext = function getContext(req){\r\n    var be = this;\r\n    return {\r\n        be, user:req.user, session:req.session, \r\n        username:req.user && req.user[be.config.login.userFieldName], \r\n        machineId:req.machineId, \r\n        navigator:(req.userAgent||{}).shortDescription||'?'\r\n    };\r\n}\r\n\r\nAppBackend.prototype.isThisProcedureAllowed = async function(){\r\n    return true;\r\n}\r\n\r\nAppBackend.prototype.inTransactionProcedureContext = function inTransactionProcedureContext(req, coreFunction, context){\r\n    var be = this;\r\n    context = context ?? be.getContext(req);\r\n    if(be.config.nodb){\r\n        return coreFunction(context);\r\n    }\r\n    if (!context.informProgress) {\r\n        context.informProgress = function informProgress(){}\r\n    }\r\n    return be.inTransaction(req, function(client){\r\n        context.client=client;\r\n        return coreFunction(context);\r\n    });\r\n}\r\n\r\nAppBackend.prototype.generateInsertSQL = function generateInsertSQL(schemaName, tableName, insertElement){\r\n    var {db} = this;\r\n    var cleanKeys = [];\r\n    var cleanValues = [];\r\n    for (var key in insertElement) {\r\n        cleanKeys.push(db.quoteIdent(key));\r\n        cleanValues.push(db.quoteNullable(insertElement[key]));    \r\n    }\r\n    var sql =  `INSERT INTO ${db.quoteIdent(schemaName)}.${db.quoteIdent(tableName)}\r\n        (${cleanKeys.join(',')}) VALUES (${cleanValues.join(',')}) returning id`;\r\n    return sql;\r\n}\r\n\r\nAppBackend.prototype.updateUpdateSQL = function updateUpdateSQL(schemaName, tableName, updateElement, updateConditions){\r\n    var be = this;\r\n    var {db} = this;\r\n    var setPairs = [];\r\n    for (var key in updateElement) {\r\n        setPairs.push(db.quoteIdent(key) + \" = \" + db.quoteNullable(updateElement[key]));\r\n    }\r\n    var filterPairs = [];\r\n    for (var key in updateConditions) {\r\n        filterPairs.push(be.db.quoteIdent(key) + \" = \" + be.db.quoteLiteral(updateConditions[key]));\r\n    };\r\n    var sql =  `UPDATE ${db.quoteIdent(schemaName)}.${db.quoteIdent(tableName)} \r\n        SET ${setPairs.join(',')}\r\n        WHERE ${filterPairs.join(' AND ')}`;\r\n    return sql;\r\n}\r\n\r\n\r\n/** @param {boolean} forUnlogged */\r\nAppBackend.prototype.addProcedureServices = function addProcedureServices(forUnlogged){ \r\n    var be = this;\r\n    if(forUnlogged){\r\n        var app = express();\r\n    }else{\r\n        var app = be.app;\r\n    }\r\n    return this.getProcedures().then(function(defs){\r\n        defs.forEach(function(def){\r\n            if(!def.isCompleted){\r\n                be.procedureDefCompleter(def);\r\n            }\r\n        })\r\n        /** @type { {[key:string]:bp.procedureDef} } */\r\n        be.procedure = be.procedure||{};\r\n        be.procedures = defs;\r\n        be.clientSetup.procedure = be.procedure;\r\n        app.get('/client-setup',async function(req, res, next){\r\n            if(forUnlogged && req.user){ \r\n                // este pedido es para unlogged y está logueado, va al próximo\r\n                next();\r\n            }else{\r\n                var clientSetup = await be.getClientSetupForSendToFrontEnd(req);\r\n                MiniTools.serveJson(clientSetup)(req, res, next);\r\n            }\r\n        });\r\n        if(!be.proceduresPrepared){\r\n            be.proceduresPrepared=true;\r\n            // esto es preparación, debe correrse una sola vez\r\n            be.procedures.forEach(function(procedureDef){\r\n                if(be.procedure[procedureDef.action]){\r\n                    console.log('REDEFINED procedure',procedureDef.action);\r\n                }\r\n                be.procedure[procedureDef.action] = procedureDef;\r\n            });\r\n        }\r\n        likeAr(be.procedure).forEach(function(procedureDef){\r\n            if( (!forUnlogged) !== (!procedureDef.unlogged)){\r\n                return;\r\n            }\r\n            procedureDef.parameters.forEach(function(paramDef){\r\n                if(paramDef.enconding==='plain' && procedureDef.multipart){\r\n                    throw new Error(\"plain enconding in parameters not allowed in multipart procedure\"+procedureDef.action);\r\n                }\r\n            });\r\n            if(!isLowerIdent(procedureDef.action)){\r\n                console.error('**** DEPRECATED ***** procedureDef action '+JSON.stringify(procedureDef.action)+' must be a Lower Ident');\r\n            }\r\n            app[procedureDef.method]('/'+procedureDef.action, \r\n            /**\r\n             * \r\n             * @param {Request} req \r\n             * @param {Response} res \r\n             * @param {import('express').NextFunction} next \r\n             */\r\n            async function(req, res, next){\r\n                const BITACORA_SCHEMA = be.config.server.bitacoraSchema;\r\n                const BITACORA_TABLENAME = be.config.server.bitacoraTableName;\r\n                var getDatetimeString = function getDatetimeString(){\r\n                    return datetime.now().toPlainString()\r\n                }\r\n                var initDatetimeString = getDatetimeString();\r\n                var context=be.getContext(req);\r\n                var getSource = function(){\r\n                    var source=procedureDef.method=='post'?(\r\n                            procedureDef.files?'fields':'body'\r\n                        ):'query';\r\n                    return source;\r\n                }\r\n                var getParams = function(){\r\n                    var source = getSource();\r\n                    var params={};\r\n                    procedureDef.parameters.forEach(function(paramDef){\r\n                        var undecodedValue = req[source][paramDef.name];\r\n                        undecodedValue = paramDef.encoding == 'plain' || undecodedValue === undefined ? undecodedValue : undecodedValue + '';\r\n                        var value = undecodedValue===undefined?undecodedValue:myOwn.encoders[paramDef.encoding].parse(undecodedValue);\r\n                        if(undecodedValue===undefined){\r\n                            if(paramDef.defaultSpecial === 'currentYear'){\r\n                                value = new Date().getFullYear();\r\n                            }else if('defaultValue' in paramDef){\r\n                                value = paramDef.defaultValue;\r\n                            }else{\r\n                                throw new Error(\"internal procedure \"+procedureDef.action+\" error: lack of mandatory paramater \"+paramDef.name);\r\n                            }\r\n                        }\r\n                        if(source==='fields' && false){\r\n                            if(value.length!==1){\r\n                                throw new Error(\"internal procedure \"+procedureDef.action+\" error: non unique paramater \"+paramDef.name+\" in multipart\");\r\n                            }\r\n                            value=value[0];\r\n                        }\r\n                        params[paramDef.name] = value;\r\n                    });\r\n                    return params;\r\n                }\r\n                var processBitacora = async function(hasError, status){\r\n                    var params = getParams();\r\n                    var defInsertBitacoraElement = {\r\n                        procedure_name : procedureDef.action,\r\n                        parameters: JSON.stringify(params),\r\n                        username: context.username,\r\n                        machine_id: context.machineId,\r\n                        navigator: context.navigator,\r\n                        init_date: initDatetimeString,\r\n                    };\r\n                    var getFinalStatusBitacoraElement = function getFinalStatusBitacoraElement(){\r\n                        return { \r\n                            end_date: getDatetimeString(), \r\n                            end_status: status, \r\n                            has_error: hasError\r\n                        }\r\n                    }\r\n                    if(procedureDef.bitacora.always){\r\n                        if(lastBitacoraInsertedId){\r\n                            await be.inTransaction(req, async function(client){\r\n                                var updateConditions = { id: lastBitacoraInsertedId };\r\n                                await client.query(be.updateUpdateSQL(BITACORA_SCHEMA, BITACORA_TABLENAME, getFinalStatusBitacoraElement(), updateConditions)).execute();\r\n                            });\r\n                        }else{\r\n                            await be.inTransaction(req, async function(client){\r\n                                var result = await client.query(be.generateInsertSQL(BITACORA_SCHEMA, BITACORA_TABLENAME, defInsertBitacoraElement)).fetchUniqueRow();\r\n                                lastBitacoraInsertedId = result.row.id;\r\n                            });\r\n                        }\r\n                    }else if(hasError && procedureDef.bitacora.error){\r\n                        await be.inTransaction(req,async function(client){\r\n                            var insertElement = changing(defInsertBitacoraElement, getFinalStatusBitacoraElement());\r\n                            await client.query(be.generateInsertSQL(BITACORA_SCHEMA, BITACORA_TABLENAME, insertElement)).execute();\r\n                        });\r\n                    }\r\n                    //tengo configurada otra tabla para guardar el resultado de la bitacora y tengo la pk de esa tabla\r\n                    if(procedureDef.bitacora.targetTable && procedureDef.bitacora.targetTableUpdateFieldsCondition){\r\n                        var targetTableUpdateFieldsCondition = procedureDef.bitacora.targetTableUpdateFieldsCondition || ['init_date','end_date','has_error', 'end_status'];\r\n                        var updateElement = {};\r\n                        var updateConditions = {};\r\n                        var params = getParams();\r\n                        if(status){\r\n                            //terminó ejecucion\r\n                            updateElement[procedureDef.bitacora.targetTableBitacoraFields.end_date] = getDatetimeString(); \r\n                            updateElement[procedureDef.bitacora.targetTableBitacoraFields.end_status] = status;\r\n                            updateElement[procedureDef.bitacora.targetTableBitacoraFields.has_error] = hasError;\r\n                        }else{\r\n                            //empezó ejecucion\r\n                            updateElement[procedureDef.bitacora.targetTableBitacoraFields.init_date] = initDatetimeString; \r\n                        }\r\n                        await be.inTransaction(req,async function(client){\r\n                            targetTableUpdateFieldsCondition.forEach(function(field){\r\n                                updateConditions[field] = params[field];\r\n                            });\r\n                            await client.query(be.updateUpdateSQL(BITACORA_SCHEMA, procedureDef.bitacora.targetTable, updateElement, updateConditions)).execute();\r\n                        })\r\n                    }\r\n                }\r\n                var processCoreFunction = function(){\r\n                    return Promise.resolve().then(function(){\r\n                        if(procedureDef.roles && procedureDef.roles.indexOf(req.user[be.config.login.rolFieldName])<0){\r\n                            throw changing(new Error(\"Not allowed\"), {status:\"403\"});\r\n                        }\r\n                        var files=[];\r\n                        var params=getParams();\r\n                        if(procedureDef.files){\r\n                            if(procedureDef.cacheable){\r\n                                console.error('DEPRECATE procedure cacheable with files');\r\n                                procedureDef.cacheable=false;\r\n                            }\r\n                            for(var name in req.files){\r\n                                files = files.concat(req.files[name]);\r\n                            }\r\n                            if(\r\n                                'minCount' in procedureDef.files && files.length<procedureDef.files.minCount &&\r\n                                'count' in procedureDef.files && files.length<procedureDef.files.count\r\n                            ){\r\n                                throw new Error(\"internal procedure \"+procedureDef.action+\" error: receiving less than \"+procedureDef.files.minCount+\" files\");\r\n                            }\r\n                            if(\r\n                                'maxCount' in procedureDef.files && files.length<procedureDef.files.maxCount &&\r\n                                'count' in procedureDef.files && files.length<procedureDef.files.count\r\n                            ){\r\n                                throw new Error(\"internal procedure \"+procedureDef.action+\" error: receiving less than \"+procedureDef.files.minCount+\" files\");\r\n                            }\r\n                        }\r\n                        var context=be.getContext(req);\r\n                        if(procedureDef.progress!==false){\r\n                            context.informProgress=function informProgress(progressInfo){\r\n                                var progress2send={};\r\n                                if(progressInfo instanceof Error){\r\n                                    MiniTools.globalOpts.serveErr.propertiesWhiteList.forEach(function(attr){\r\n                                        progress2send[attr] = progressInfo[attr];\r\n                                    });\r\n                                }else{\r\n                                    if(progressInfo.lengthComputable){\r\n                                        if (!context.lastMessageSended) {\r\n                                            context.lastMessageSended = {}\r\n                                        }\r\n                                        if(new Date()-(context.lastMessageSended[progressInfo.idGroup]||0) > 500 || progressInfo.force){\r\n                                            context.lastMessageSended[progressInfo.idGroup]=new Date();\r\n                                            res.write(JSON.stringify({progress:progressInfo})+\"\\n\");\r\n                                            if(progressInfo.total){\r\n                                                var rate100=Math.floor(progressInfo.loaded*100/progressInfo.total);\r\n                                                var rate1000=Math.floor(progressInfo.loaded*1000/progressInfo.total);\r\n                                                var message = rate100<1 && progressInfo.loaded>0 ? '('+(rate1000||'½')+'‰)' : rate100+'%';\r\n                                                progress2send={message, ephemeral:true, idGroup:progressInfo.idGroup};\r\n                                            }\r\n                                        }else{\r\n                                            progress2send=null;\r\n                                        }\r\n                                    }else{\r\n                                        progress2send=progressInfo;\r\n                                    }\r\n                                }\r\n                                // console.log('informProgress J',JSON.stringify(progress2send));\r\n                                // console.log('informProgress J',json4all.stringify(progress2send));\r\n                                // console.log('informProgress',progress2send);\r\n                                if(progress2send){\r\n                                    res.write(JSON.stringify({progress:progress2send})+\"\\n\");\r\n                                }\r\n                            };\r\n                        }\r\n                        if(!req.cookies){\r\n                            context.cookies = myOwn.parseStrCookies(req.headers.cookie, be.clientSetup.config.prefix);\r\n                        }else{\r\n                            context.cookies = req.cookies;\r\n                        }\r\n                        if(procedureDef.setCookies){\r\n                            context.setCookie = function(name, value, opts){\r\n                                res.cookie(be.clientSetup.config.prefix+name, value, {path: be.config['base-url'] , ...opts})\r\n                            }\r\n                            context.clearCookie = function(name, opts){\r\n                                var {expires, maxAge, ...otherOpts} = opts;\r\n                                res.clearCookie(be.clientSetup.config.prefix+name, {path: be.config['base-url'] , ...otherOpts})\r\n                            }\r\n                        }\r\n                        context.regenerateSession = async function regenerateSession(){\r\n                            await new Promise(function(resolve, reject){\r\n                                req.session.regenerate(function(err){\r\n                                    if(err) reject(err);\r\n                                    resolve();\r\n                                })\r\n                            })\r\n                        }\r\n                        var bpClientTs = req.get('BP-Client-TS');\r\n                        if(bpClientTs){\r\n                            res.append('BP-Client-TS', bpClientTs);\r\n                        }\r\n                        res.append('Content-Type', 'application/octet-stream');\r\n                        return Promise.resolve().then(function(){\r\n                            var thisCache;\r\n                            if(procedureDef.cacheable){\r\n                                var jsonParams = JSON.stringify(params);\r\n                                thisCache = be.caches.procedures[jsonParams];\r\n                                if(!thisCache){\r\n                                    thisCache = be.caches.procedures[jsonParams] = {timestamp:new Date().getTime()};\r\n                                }\r\n                                if(thisCache.result !== undefined){\r\n                                    return thisCache.result;\r\n                                }\r\n                            }\r\n                            var keepAliveManager=null;\r\n                            return Promise.resolve().then(function(){\r\n                                return be.isThisProcedureAllowed(context,procedureDef,params)\r\n                            }).then(function(allowed){\r\n                                if(!allowed){\r\n                                    console.log('FORBIDDEN',procedureDef.action,params.table,context.username);\r\n                                    var err = new Error(\"FORBIDDEN\");\r\n                                    err.code=\"403\";\r\n                                    throw err;\r\n                                }\r\n                            }).then(function(){\r\n                                if(procedureDef.progress && be.config.server[\"keep-alive\"]){\r\n                                    keepAliveManager=setInterval(function(){\r\n                                        res.write(JSON.stringify({progress:{keepAlive:true, ts:new Date().getTime()}})+\"\\n\")\r\n                                    },5000)\r\n                                }\r\n                                return be.inTransactionProcedureContext(req, function(context){\r\n                                    return procedureDef.coreFunction(context, params, files);\r\n                                }, context);\r\n                            }).then(function(result){\r\n                                if (procedureDef.forExport) {\r\n                                    return be.exportacionesGenerico(result, procedureDef, context, params, files);\r\n                                } else {\r\n                                    return result;\r\n                                }\r\n                            }).then(function(result){\r\n                                if(thisCache){\r\n                                    thisCache.result = result;\r\n                                    thisCache.timestamp = new Date().getTime();\r\n                                }\r\n                                if(keepAliveManager){\r\n                                    clearInterval(keepAliveManager)\r\n                                }\r\n                                return result;\r\n                            },function(err){\r\n                                if(keepAliveManager){\r\n                                    clearInterval(keepAliveManager)\r\n                                }\r\n                                throw err;\r\n                            });\r\n                        }).then(function(result){\r\n                            if(result===undefined){\r\n                                console.log('undefined in',procedureDef,'for',req[getSource()]);\r\n                                throw new Error(\"Bad return value in procedure. Undefined detected.\");\r\n                            }\r\n                            if(procedureDef.encoding==='download'){\r\n                                res.download(result.path, result.fileName);\r\n                            }else{\r\n                                try{\r\n                                    result = myOwn.encoders[procedureDef.encoding].stringify(result);\r\n                                }catch(err){\r\n                                    throw err;\r\n                                }\r\n                                if(procedureDef.progress!==false){\r\n                                    res.write('--\\n');\r\n                                }\r\n                                res.end(result);\r\n                            }\r\n                            return result;\r\n                        });\r\n                    });\r\n                }\r\n                var lastBitacoraInsertedId = null;\r\n                try{\r\n                    await processBitacora(null,null);\r\n                    var result = await processCoreFunction();\r\n                    await processBitacora(false, json4all.stringify(result));\r\n                }catch(err){\r\n                    await processBitacora(true, err.message);\r\n                    if(procedureDef.progress!==false){\r\n                        var error = {};\r\n                        MiniTools.globalOpts.serveErr.propertiesWhiteList.forEach(function(attrName){\r\n                            if(attrName in err || err[attrName]){\r\n                                error[attrName]=err[attrName];\r\n                            }\r\n                        });\r\n                        res.write(JSON.stringify({error:error})+\"\\n\");\r\n                        res.end();\r\n                    }else{\r\n                        MiniTools.serveErr(req,res,next)(err);\r\n                    }\r\n                };\r\n            });\r\n        });\r\n        return app;\r\n    });\r\n};\r\n\r\n/** @param {bp.Context} context */\r\nAppBackend.prototype.getMenu = function getMenu(context){\r\n    return { menu:[] };\r\n}\r\n\r\nfunction controlMenuDefinition(menuContent){\r\n    var somethingWrong='';\r\n    menuContent.forEach(function(menu){\r\n        if(!isLowerIdent(menu.name)){\r\n            somethingWrong=JSON.stringify(menu.name);\r\n            console.error('*** DEPRECATED *** The menu item name: '+JSON.stringify(menu.name)+' must be a Lower Ident');\r\n        }\r\n        if(menu.label && /\\b[A-Z][a-z]+\\b/.test(menu.label)){\r\n            console.log('** DEPRECATED ** The menu item label: '+JSON.stringify(menu.label)+' must be a in lower case');\r\n        }\r\n    })\r\n    if(somethingWrong){\r\n        throw new Error('The menu item name: '+somethingWrong+' must be a Lower Ident');\r\n    }\r\n}\r\n\r\nAppBackend.prototype.getClientSetupForSendToFrontEnd = function getClientSetupForSendToFrontEnd(req){\r\n    var be=this;\r\n    var clientSetup=changing(be.clientSetup, {username:req.user && req.user[be.config.login.userFieldName]});\r\n    var context=be.getContext(req);\r\n    clientSetup.useragent = req.useragent;\r\n    if(be.config[\"client-setup\"].menu===true){\r\n        var menuDef=be.getMenu(context);\r\n        controlMenuDefinition(menuDef.menu);\r\n        clientSetup=changing(clientSetup, be.getVisibleMenu(menuDef, context));\r\n    }\r\n    clientSetup.procedures = likeAr(be.clientSetup.procedure).filter(function(procedureDef){\r\n        return !procedureDef.roles || procedureDef.unlogged || req.user && procedureDef.roles.indexOf(req.user[be.config.login.rolFieldName])>=0;\r\n    }).array();\r\n    return clientSetup;\r\n};\r\n\r\nvar resolved_modules_log = {}\r\n\r\nfunction require_resolve(moduleName){\r\n    var resolved;\r\n    var ok = 'require';\r\n    try{\r\n        resolved = require.resolve(moduleName);\r\n    }catch(err){\r\n        var ok = 'node_modules';\r\n        var packageJson = fs.readJsonSync(Path.join(process.cwd(),'node_modules',moduleName,'package.json'));\r\n        resolved = Path.join(...[process.cwd(),'node_modules',moduleName,(packageJson.main?packageJson.main:'package.json')])\r\n        if(!fs.existsSync(resolved)){\r\n            ok = err.message\r\n            throw err;\r\n        }\r\n    }finally{\r\n        var resolved_modules_line = `${moduleName} -> ${Path.relative(process.cwd(), Path.dirname(resolved))} -> ${Path.basename(resolved)} : ${ok}`;\r\n        resolved_modules_log[resolved_modules_line] = (resolved_modules_log[resolved_modules_line] ?? 0 ) + 1;\r\n    }\r\n    return resolved;\r\n}\r\n\r\n/* MEJORA:\r\nfunction module_root_dir(file){\r\n    var dir = Path.dirname(file);\r\n    while(!fs.existsSync(Path.join(dir,'package.json'))){\r\n        var parent = Path.dirname(dir);\r\n        if(parent==dir){ return Path.dirname(file); }\r\n        dir = parent;\r\n    }\r\n    return dir;\r\n}\r\n// */\r\n\r\nfunction resolve_module_dir(moduleName,path,fileToCheck){\r\n    var baseDir;\r\n    if(packagejson.name==moduleName){\r\n        baseDir=Path.join(process.cwd(), packagejson.main);\r\n    }else{\r\n        baseDir=require_resolve(moduleName);\r\n    }\r\n//      var resultDir = Path.join(path?module_root_dir(baseDir):Path.dirname(baseDir),path||'');\r\n    var resultDir = Path.join(Path.dirname(baseDir),path||'');\r\n    if (fileToCheck) {\r\n        fs.stat(Path.join(resultDir, fileToCheck)).then(function(status){\r\n            if (!status) {\r\n                console.error('Error resolve_module_dir in:',resultDir,'no:',fileToCheck);\r\n            } else if(!status.isFile() && fileToCheck != '.') {\r\n                console.error('Error resolve_module_dir in:',resultDir,',',fileToCheck,'is not a file');\r\n            }\r\n        },function(err){\r\n            console.error('Error resolve_module_dir in:',resultDir,'err:',err);\r\n        });\r\n    }\r\n    return resultDir;\r\n}\r\n\r\nAppBackend.prototype.optsGenericForFiles = function optsGenericForFiles(req, opts){\r\n    var be = this;\r\n    var title=be.config['client-setup'].formTitle;\r\n    var skin=be.config['client-setup'].skin;\r\n    var skinUrl=(skin?skin+'/':'');\r\n    return changing(be.optsGenericForAll||{},{\r\n        allowedExts:be.exts.normal,\r\n        jade:{\r\n            skin:skin, \r\n            skinUrl:skinUrl,\r\n            formTitle:title,\r\n            ...(opts?.withFlash ? {flash:req?.flash?.()} : {}),\r\n            msgs:changing(be.messages.unlogged, req?.user?be.messages.logged:{chpass:be.messages.logged.chpass}),\r\n            modules:req?.user?be.clientModules():[],\r\n            lang:be.config[\"client-setup\"].lang,\r\n            username:req?.user?req.user[be.config.login.userFieldName]:'',\r\n            forget:be.config.login.forget?.urlPath\r\n        },\r\n    });\r\n}\r\n\r\nAppBackend.prototype.unloggedLandPage = function unloggedLandPage(req){\r\n    var be = this;\r\n    return html.div([\r\n        html.h2({style:'text-align:center; margin-top:15%; font-family:arial, sans-serif'},[be.messages.server.notLoggedIn]),\r\n        html.h2({style:'text-align:center'},[html.code([\r\n            html.a({\r\n                id:'goto-login', \r\n                style:'border:0.5px solid blue; border-radius: 6px; padding: 6px', \r\n                href:Path.posix.join(be.config.server[\"base-url\"],(be.config.login.plus.loginUrlPath||'/login'))\r\n            },'login')\r\n        ])]),\r\n        html.script({src:'auto-login.js'})\r\n    ]);\r\n}\r\n\r\nAppBackend.prototype.addUnloggedServices = function addUnloggedServices(mainApp, baseUrl){\r\n    var be=this;\r\n    if(be.config.login.forget?.urlPath){\r\n        mainApp.get(Path.posix.join(baseUrl,be.config.login.forget.urlPath), be.config.login.plus.newPassPageServe)\r\n        mainApp.get(Path.posix.join(baseUrl,be.config.login.forget.urlPathOk), be.config.login.plus.newPassPageServe2)\r\n        mainApp.post(Path.posix.join(baseUrl,be.config.login.forget.urlPath), function(req,res,next){\r\n            var resultCode;\r\n            if(!req.body.email || !/@/.test(req.body.email)){\r\n                resultCode='error';\r\n            }else{\r\n                resultCode='ok';\r\n                var promise = be.inDbClient(req, async (client)=>{\r\n                    var now = bestGlobals.datetime.now();\r\n                    var token = crypto.randomUUID();\r\n                    var {rows} = await client.query(`select ${be.db.quoteIdent(be.config.login.userFieldName)} as username\r\n                        from ${be.config.login.schema?be.db.quoteIdent(be.config.login.schema)+'.':''}${be.db.quoteIdent(be.config.login.table)} \r\n                        where $1 in (${be.db.quoteIdentList(be.config.login.forget.mailFields)}) \r\n                          and ${be.config.login.activeClausule}\r\n                          and ${be.config.login.lockedClausule} is not true\r\n                    `, [req.body.email.toLowerCase()]).fetchAll();\r\n                    if(rows?.length>0){\r\n                        await client.query(\r\n                            \"insert into his.tokens(token, tokentype, date, username, useragent, due) values ($1, 'new-pass', $2, $3, $4, $5) returning token\",\r\n                            [token, now, rows[0].username, req.useragent, now.add({days:1})]\r\n                        ).fetchUniqueRow();\r\n                        var chpath = (be.config.login.forget?.urlDomainAndRoot ?? req.protocol+'://' +Path.posix.join(req.hostname+baseUrl,'new-pass')) +\r\n                            '?token='+token+'&nueva=clave';\r\n                        // console.log('chpass', chpath)\r\n                        await be.sendMail({\r\n                            to: req.body.email,\r\n                            subject: be.messages.unlogged.newPassword.mailSubject,\r\n                            html: be.messages.unlogged.newPassword.mailHtml.replace(\r\n                                '<a href=\"\"></a>',\r\n                                `<a href=\"${chpath}\">${chpath}</a>`\r\n                            )\r\n                        })\r\n                    }\r\n                })\r\n                promise.catch(err=>{\r\n                    console.log('error in /new-password');\r\n                    console.log(err);\r\n                })\r\n            }\r\n            res.redirect(Path.posix.join(baseUrl, be.config.login.forget?.urlPathOk+'?result'+resultCode));\r\n        })\r\n        mainApp.get(Path.posix.join(baseUrl,'/new-pass'), function(req,res,next){\r\n            var resultCode;\r\n            if(!req.query.token){\r\n                res.send('No token');\r\n                res.end();\r\n            }else{\r\n                var promise = be.inDbClient(req, async (client)=>{\r\n                    var now = bestGlobals.datetime.now();\r\n                    var {row} = await client.query(`select *\r\n                        from his.tokens\r\n                        where tokentype = 'new-pass' and token = $1\r\n                            and due > $2\r\n                        limit 1;\r\n                    `, [req.query.token, now]).fetchOneRowIfExists();\r\n                    if(!row){\r\n                        res.send('Invalid token');\r\n                        res.end();\r\n                    }else{\r\n                        be.config.login.plus.newPassPageEnter(row.username, req.query.token)(req,res,next);\r\n                    }\r\n                })\r\n            }\r\n        })\r\n        mainApp.post(Path.posix.join(baseUrl,'/new-pass-enter'), function(req,res,next){\r\n            var newPassword = req.body.newPassword.trim();\r\n            if(newPassword != req.body.repPassword.trim()){\r\n                res.send(be.messages.server.passDontMatch);\r\n                res.end();\r\n                return;\r\n            }\r\n            if(newPassword.length < 6){\r\n                res.send(be.messages.server.passDontMatch);\r\n                res.end();\r\n                return;\r\n            }\r\n            var promise = be.inDbClient(req, async (client)=>{\r\n                var now = bestGlobals.datetime.now();\r\n                var {row} = await client.query(`select *\r\n                    from his.tokens\r\n                    where tokentype = 'new-pass' and token = $1\r\n                        and $2 < due\r\n                    limit 1;\r\n                `, [req.body.token, now]).fetchOneRowIfExists();\r\n                if(!row){\r\n                    res.send('Invalid token');\r\n                    res.end();\r\n                    return;\r\n                }\r\n                await new Promise((resolve, reject)=>{\r\n                    be.passwordChanger(req, row.username, false, newPassword, function done(err, ok, message){\r\n                        if(err){\r\n                            reject(err)\r\n                        }else if(ok){\r\n                            resolve()\r\n                        }else{\r\n                            // console.log(arguments)\r\n                            reject(message.message)\r\n                        }\r\n                    })\r\n                })\r\n                res.redirect(Path.posix.join(baseUrl, be.config.login.noLoggedUrlPath || '/login'));\r\n                await client.query(`update his.tokens set due = null\r\n                    where tokentype = 'new-pass' and token = $1;\r\n                `, [req.body.token]).execute();\r\n            })\r\n            return promise;\r\n        });\r\n    }\r\n    if(be.config.login.unloggedLandPage){\r\n        mainApp.get(Path.posix.join(baseUrl,be.config.login.unloggedLandPage), function(req, res, next){\r\n            res.status(401);\r\n            return MiniTools.serveText(be.unloggedLandPage(req).toHtmlDoc({\r\n                title:be.messages.server.notLoggedIn\r\n            }),'html')(req,res,next);\r\n        })\r\n    }\r\n    // http://localhost:3033/img/login-logo-icon.png\r\n    mainApp.get(Path.posix.join(baseUrl,'/img/login-logo-icon.png'), async function(req,res,next){\r\n        var buscar = [\r\n            'unlogged/img/login-logo-icon.svg', \r\n            'dist/unlogged/img/login-logo-icon.svg', \r\n            'dist/client/unlogged/img/login-logo-icon.svg', \r\n            'unlogged/img/login-logo-icon.png', \r\n            'dist/unlogged/img/login-logo-icon.png', \r\n            'dist/client/unlogged/img/login-logo-icon.png', \r\n            'unlogged/img/logo.png', \r\n            'dist/unlogged/img/logo.png', \r\n            'dist/client/unlogged/img/logo.png', \r\n            'client/img/logo.png', \r\n            'dist/client/img/logo.png', \r\n            'dist/client/client/img/logo.png', \r\n            'unlogged/img/logo-128.png',\r\n            'dist/unlogged/img/logo-128.png',\r\n            'dist/client/unlogged/img/logo-128.png' \r\n        ];\r\n        buscar = buscar.map(n=>be.rootPath+'/'+n);\r\n        buscar.push(__dirname+'/../for-client/img/login-logo-icon.png');\r\n        for(var nombre of buscar){\r\n            try{\r\n                await fs.stat(nombre)\r\n                break;\r\n            }catch{}\r\n        }\r\n        MiniTools.serveFile(nombre/*,[['Content-Type', 'image/png']]*/)(req,res,next);\r\n    });\r\n    be.clientIncludesCompleted(null).filter(x => x.module).forEach(function (moduleDef) {\r\n        if(baseUrl=='/'){\r\n            baseUrl='';\r\n        }   \r\n        let baseLib = baseUrl + '/' + (moduleDef.path ? moduleDef.path : be.esJavascript(moduleDef.type)? 'lib': 'css');\r\n        resolve_module_dir(moduleDef.module, moduleDef.modPath, moduleDef.file ?? '.')\r\n        try {\r\n            var allowedExts=(moduleDef.type=='js'?['js','map']:[moduleDef.type]);\r\n            mainApp.use(baseLib, serveContent(resolve_module_dir(moduleDef.module, moduleDef.modPath), { allowedExts }));\r\n            if(moduleDef.ts){\r\n                if(typeof moduleDef.ts === \"object\"){\r\n                    console.log('serve:',baseUrl+ '/' + moduleDef.ts.url, resolve_module_dir(moduleDef.module, moduleDef.ts.path));\r\n                    mainApp.use(baseUrl+ '/' + moduleDef.ts.url, serveContent(resolve_module_dir(moduleDef.module, moduleDef.ts.path), { allowedExts: 'ts' }));\r\n                }else{\r\n                    mainApp.use(baseUrl+ '/' + moduleDef.ts, serveContent(resolve_module_dir(moduleDef.module, moduleDef.modPath).replace(Path.sep+'lib'+Path.sep,Path.sep+'src'+Path.sep), { allowedExts: 'ts' }));\r\n                    mainApp.use(baseUrl+ '/lib/' + moduleDef.ts, serveContent(resolve_module_dir(moduleDef.module, moduleDef.modPath).replace(Path.sep+'client'+Path.sep,Path.sep+'src'+Path.sep+'client'), { allowedExts: 'ts' }));\r\n                }\r\n            }\r\n        } catch (error) {\r\n            console.error('ERROR: No se pudo servir el módulo', moduleDef.module);\r\n            throw error;\r\n        }\r\n    })\r\n\r\n    // ----------------------------------------------------\r\n    var skin=be.config['client-setup'].skin;\r\n    var skinUrl=(skin?skin+'/':'');\r\n    var optsGenericForFilesUnlogged=be.optsGenericForFiles(); \r\n    var skinPaths=[Path.join(be.rootPath,'skins')];\r\n    if(be.config.server.skins[skin]['local-path']){\r\n        skinPaths=skinPaths.concat(be.config.server.skins[skin]['local-path']).map(function(path){\r\n            return Path.join(path,skin);\r\n        });\r\n    }else{\r\n        console.log(\"No skin local-path for \"+skin);\r\n        process.exit(1);\r\n    }\r\n    var unloggedPaths=[];\r\n    var dist=/(^|[/\\\\])dist[/\\\\]server[/\\\\]server[/\\\\]/.test(packagejson.main)?'dist/client/':regexpDistCheck.test(packagejson.main)?'dist/':'';\r\n    unloggedPaths.push(Path.join(Path.resolve(be.rootPath),dist));\r\n    if(dist=='dist/client/'){\r\n        if(fs.existsSync('dist/unlogged/unlogged')){\r\n            unloggedPaths.push('dist/unlogged/');\r\n        }else{\r\n            unloggedPaths.push('dist/');\r\n        }\r\n    }\r\n    if(Path.join(__dirname,'..')!=Path.resolve(be.rootPath)){\r\n        unloggedPaths.push(Path.join(__dirname,'..'));\r\n    }\r\n    skinPaths.concat(unloggedPaths).forEach(function(path){\r\n        var pathToNodeModulesSkin=Path.join(path, 'unlogged');\r\n        mainApp.use(baseUrl+(skin?'/'+skin:''),serveContent(pathToNodeModulesSkin,optsGenericForFilesUnlogged));\r\n    });\r\n    unloggedPaths.forEach(function(path){\r\n        var pathToNodeModulesSkin=Path.join(path, 'unlogged');\r\n        mainApp.use(baseUrl,serveContent(pathToNodeModulesSkin,optsGenericForFilesUnlogged));\r\n    });\r\n};\r\n\r\nAppBackend.prototype.sendMail = async function sendMail(mailInfo, options){\r\n    var be = this;\r\n    if(be.config.mailer){\r\n        if(!options || !options.event || be.config.mailer?.supervise?.event[options.event]){\r\n            var transporter = nodemailer.createTransport(be.config.mailer.conn);\r\n            return await transporter.sendMail({...mailInfo, ...be.config.mailer[\"mail-info\"]});\r\n        }\r\n    }else{\r\n        if(!options.ignoreNoMailer){\r\n            throw new Error(\"no mailer configured\");\r\n        }\r\n    }\r\n};\r\n\r\nAppBackend.prototype.getVisibleMenu = function getVisibleMenu(menu, context){\r\n    return menu;\r\n};\r\n\r\nAppBackend.prototype.clientIncludes = function clientIncludes(req, opts) {\r\n    const hideBEPlusInclusions = opts === true || opts && typeof opts == \"object\" && opts.hideBEPlusInclusions;\r\n    opts = opts === true ? {} : opts || {}; \r\n    var list = [];\r\n    if (!hideBEPlusInclusions) {\r\n        list = [\r\n            // { type: 'js', module: 'xlsx', modPath: 'dist', file: 'xlsx.core.min.js' },\r\n            { type: 'js', module: 'xlsx', modPath: 'dist', file: 'xlsx.full.min.js' },\r\n            { type: 'js', module: 'require-bro' },\r\n            { type: 'js', module: 'js-yaml', modPath: 'browser', file: 'js-yaml.umd.min.js' },\r\n            { type: 'js', module: 'cast-error' },\r\n            { type: 'js', module: 'lazy-some' },\r\n            { type: 'js', module: 'like-ar' },\r\n            { type: 'js', module: 'best-globals' },\r\n            { type: 'js', module: 'json4all' },\r\n            { type: 'js', module: 'dialog-promise', path: 'dialog-promise' },\r\n            { type: 'css', module: 'dialog-promise', path: 'dialog-promise' },\r\n            { type: 'js', module: 'js-to-html' },\r\n            { type: 'js', module: 'moment', path: 'moment/min' },\r\n            { type: 'js', module: 'pikaday', path: 'pikaday' },\r\n            { type: 'css', module: 'pikaday', path: 'pikaday', modPath: 'css' },\r\n            { type: 'js', module: 'big.js' },\r\n            { type: 'js', module: 'type-store' },\r\n            { type: 'js', module: 'typed-controls' },\r\n            { type: 'js', module: 'ajax-best-promise' },\r\n            { type: 'js', module: 'sql-tools' },\r\n            // { type: 'js' , module: 'regexplicit'},\r\n            { type: 'js', file: 'my-localdb.js', modPath:'src/for-client', ts:'src/for-client'},\r\n            { type: 'js', file: 'my-websqldb.js', modPath:'src/for-client', ts:'src/for-client'},\r\n            { type: 'js', file: 'my-ajax.js', path:'.', modPath:'unlogged/for-client' },\r\n        ];\r\n        if(opts.skipMenu){\r\n            list.push({ type: 'js', file: 'my-start.js', path:'.', modPath:'unlogged/for-client' });\r\n            list.push({ type: 'js', file: 'my-skin.js'});\r\n        }else{\r\n            list = list.concat([\r\n                { type: 'js', file: 'my-things.js' },\r\n                { type: 'js', file: 'my-skin.js' },\r\n                { type: 'js', file: 'my-tables.js' },\r\n                { type: 'js', file: 'my-inform-net-status.js' },\r\n                { type: 'css', file: \"my-things.css\" },\r\n                { type: 'css', file: \"my-tables.css\" },\r\n                { type: 'css', file: \"my-menu.css\" },\r\n            ])\r\n        };\r\n        var browInfo=req && this._Browsers[req.useragent.browser]||{polly:true};\r\n        if(!req || browInfo.polly === true || (req.useragent.version || '0').split('.')[0] < browInfo.polly){\r\n            list.unshift({ type: 'js', src: 'lib/polyfills-bro.js' })\r\n        }\r\n        var clientConfig = this.config[\"client-setup\"];\r\n        if(clientConfig.menu === true && !opts.skipMenu){\r\n            list.push({ type: 'js', file: 'my-menu.js' });\r\n        }\r\n        if(clientConfig.lang==='es'){\r\n            list.push({ type: 'js', module: 'castellano' });\r\n        }\r\n    }\r\n    return list;\r\n}\r\n\r\nAppBackend.prototype.clientIncludesCompleted = function clientIncludesCompleted(req, opts) {\r\n    let list = this.clientIncludes(req, opts);\r\n    if(opts && opts.extraFiles){\r\n        list = list.concat(opts.extraFiles)\r\n    }\r\n    var be = this;\r\n    if(this.config.devel && this.config.devel.useFileDevelopment){\r\n        list=list.map(includeDef=>{\r\n            if(includeDef.fileProduction){\r\n                // deprecated;\r\n            }\r\n            if(includeDef.fileDevelopment){\r\n                includeDef.file=includeDef.fileDevelopment;\r\n            }\r\n            return includeDef;\r\n        });\r\n    }\r\n    var rPaths={paths:[process.cwd()]};\r\n    return list.map(inclusion =>{\r\n        var filename = inclusion.file? inclusion.file: (inclusion.module? Path.basename(require_resolve(inclusion.module,rPaths)): '');\r\n        return changing({\r\n            src: be.esJavascript(inclusion.type) ? ((inclusion.path ? inclusion.path : 'lib') + '/' + (inclusion.file ? inclusion.file : filename)) : '',\r\n            href: inclusion.type == 'css' ? ((inclusion.path ? inclusion.path : 'css') + '/' + (inclusion.file ? inclusion.file : (inclusion.module + '.css'))) : ''\r\n        }, inclusion);\r\n    });\r\n}\r\n\r\nAppBackend.prototype.clientModules = function clientModules(req, opts) {\r\n    var be = this;\r\n    return { scripts: this.clientIncludesCompleted(req, opts).filter(x => be.esJavascript(x.type)).map(mod => {return { src: mod.src, type:mod.type=='mjs'?\"module\":null }})};\r\n}\r\n\r\n/**\r\n * @param {string} tableName \r\n * @param {(tableDef:typesOpe.TableDefinition, context?:TableContext)=>void} appenderFunction\r\n */\r\nAppBackend.prototype.appendToTableDefinition = function appendToTableDefinition(tableName, appenderFunction){\r\n    var previousDefiniterFunction=this.getTableDefinition[tableName]\r\n    if(previousDefiniterFunction==null){\r\n        throw new Error(tableName+\" does not exists in getTableDefinition\")\r\n    }\r\n    this.getTableDefinition[tableName]=function(context){\r\n        var defTable=previousDefiniterFunction(context);\r\n        defTable.fields          =defTable.fields          ||[];\r\n        defTable.foreignKeys     =defTable.foreignKeys     ||[];\r\n        defTable.softForeignKeys =defTable.softForeignKeys ||[];\r\n        defTable.detailTables    =defTable.detailTables    ||[];\r\n        defTable.constraints     =defTable.constraints     ||[];\r\n        defTable.sql             =defTable.sql             ||{};\r\n        appenderFunction(defTable, context)\r\n        return defTable;\r\n    }\r\n}\r\n\r\n\r\nAppBackend.prototype.prepareGetTables = function prepareGetTables(){\r\n}\r\n\r\nAppBackend.prototype.getTables = function getTables(){\r\n    var be=this;\r\n    this.getTableDefinition=this.getTableDefinition||{};\r\n    var tables=[];\r\n    tables.push({path: __dirname + '/tables', name:'bitacora'});\r\n    tables.push({path: __dirname + '/tables', name:'summary'});\r\n    var gridBuffer = be.staticConfig['client-setup']['grid-buffer'];\r\n    var offlineMode = gridBuffer && (gridBuffer === 'idbx' || gridBuffer === 'wsql');\r\n    if(offlineMode){\r\n        tables.push({path: __dirname + '/tables', name:'locks'});\r\n    }\r\n    tables.push({path: __dirname + '/tables', name:'tokens'});\r\n    this.prepareGetTables();\r\n    return tables.concat(\r\n        likeAr(this.getTableDefinition).map(function(tableDef, tableName){\r\n            if(!tableDef || typeof tableDef !==\"function\"){\r\n                throw new Error(\"ERROR: tableDef of \"+JSON.stringify(tableName)+\" is not a function\")\r\n            }\r\n            return {name:tableName, tableGenerator:function(context){\r\n                return be.tableDefAdapt(tableDef(context), context);\r\n            }};\r\n        }).array()\r\n    );\r\n}\r\n\r\nAppBackend.prototype.csss = function csss(hideBEPlusInclusions){\r\n    return this.clientIncludesCompleted(null, hideBEPlusInclusions).filter(x => x.type == 'css').map(x => x.href);\r\n};\r\n\r\nAppBackend.prototype.scanSkinFiles = function scanSkinFiles() {\r\n    var be = this;\r\n    var skinName = be.config['client-setup'].skin;\r\n    be.activeSkinFiles = new Set(); \r\n\r\n    var skinConfig = be.config.server.skins && be.config.server.skins[skinName];\r\n\r\n    if (skinName && skinConfig && skinConfig['local-path']) {\r\n        try {\r\n            var skinPath = Path.join(Path.resolve(skinConfig['local-path']), skinName);\r\n            \r\n            if (fs.existsSync(skinPath)) {\r\n                \r\n                const walk = (currentPath) => {\r\n                    const entries = fs.readdirSync(currentPath, { withFileTypes: true });\r\n\r\n                    for (var i = 0; i < entries.length; i++) {\r\n                        var entry = entries[i];\r\n                        var fullPath = Path.join(currentPath, entry.name);\r\n\r\n                        if (entry.isDirectory()) {\r\n                            walk(fullPath);\r\n                        } else if (entry.isFile()) {\r\n                            if (entry.name.endsWith('.css') || entry.name.endsWith('.styl')) {\r\n                                var relativePath = Path.relative(skinPath, fullPath)\r\n                                    .replace(/\\\\/g, '/')\r\n                                    .replace(/^\\//, '');\r\n                                \r\n                                be.activeSkinFiles.add(relativePath);\r\n                            }\r\n                        }\r\n                    }\r\n                };\r\n\r\n                walk(skinPath);\r\n            } else {\r\n                console.warn(`[SKIN SCAN] No existe la carpeta del skin: ${skinPath}`);\r\n            }\r\n        } catch (err) {\r\n            console.error(\"[SKIN SCAN] Error al inicializar:\", err);\r\n        }\r\n    }\r\n};\r\n\r\nAppBackend.prototype.mainPage = function mainPage(req, offlineMode, opts){\r\n    var be = this;\r\n    opts = opts||{};\r\n    if(!opts.icons){\r\n        if(!opts.icon){\r\n            opts.icons={\r\n                iconShortcut: \"img/logo-128.png\",\r\n                icon        : \"img/logo.png\",\r\n                iconApple   : \"img/logo.png\",\r\n            }\r\n        }else{\r\n            opts.icons={\r\n                iconShortcut: opts.icon,\r\n                icon        : opts.icon,\r\n                iconApple   : opts.icon,\r\n            }\r\n        }\r\n    }\r\n    var be=this;\r\n    var attr={lang: be.config[\"client-setup\"].lang};\r\n    var viewportAttrs=null;\r\n    if(offlineMode && req && req.user){\r\n        attr.manifest=opts.manifestPath || \"ext/app.manifest\";\r\n    }\r\n    var viewportContent=[];\r\n    viewportContent.push('width=' + (be.config[\"client-setup\"][\"deviceWidthForMobile\"] || 'device-width'));\r\n    var clientSetup = be.config[\"client-setup\"];\r\n    if(clientSetup[\"initial-scale\"]){\r\n        viewportContent.push('initial-scale=' + clientSetup[\"initial-scale\"])\r\n    }\r\n    if(clientSetup[\"minimum-scale\"]){\r\n        viewportContent.push('minimum-scale=' + clientSetup[\"minimum-scale\"])\r\n    }\r\n    if(clientSetup[\"maximum-scale\"]){\r\n        viewportContent.push('maximum-scale=' + clientSetup[\"maximum-scale\"])\r\n    }\r\n    if(clientSetup[\"user-scalable\"]){\r\n        viewportContent.push('user-scalable=' + clientSetup[\"user-scalable\"])\r\n    }\r\n    viewportAttrs={name:\"viewport\", content:viewportContent.join(', ')};\r\n    var cssList = be.csss();\r\n    if(offlineMode){\r\n        cssList.push('css/offline-mode.css');\r\n    }\r\n    cssList = cssList.concat((opts.extraFiles ?? []).filter((extraFile)=>extraFile.type == 'css').map((extraFile)=>extraFile.file));\r\n    return html.html(attr,[\r\n        html.head([\r\n            html.title(be.config[\"client-setup\"]?.title),\r\n            html.meta({charset:\"utf-8\"}),\r\n            viewportAttrs?html.meta(viewportAttrs):null,\r\n            opts.baseUrlForRelativePaths?html.base({href:`${be.config.server[\"base-url\"]}/`}):null,\r\n            html.link({href: opts.icons.iconShortcut , rel: \"shortcut icon\", type: \"image/png\"}),\r\n            html.link({href: opts.icons.icon         , rel: \"icon\", type: \"image/png\"}),\r\n            html.link({href: opts.icons.iconApple    , rel: \"apple-touch-icon\"}),\r\n            html.meta({name:\"format-detection\", content:\"telephone=no\"}),\r\n            opts.webManifestPath?null:html.meta({name:\"apple-mobile-web-app-capable\", content:\"yes\"}),\r\n            opts.webManifestPath?null:html.meta({name:\"apple-mobile-web-app-status-bar-style\", content:\"black\"}),\r\n            opts.webManifestPath?null:html.meta({name:\"mobile-web-app-capable\", content:\"yes\"}),\r\n            opts.webManifestPath?null:html.meta({name:\"mobile-web-app-status-bar-style\", content:\"black\"}),\r\n            opts.webManifestPath?html.link({rel:\"manifest\", crossorigin:\"use-credentials\", href:opts.webManifestPath}):null,\r\n            // html.meta({name:'viewport', content:'user-scalable=no, width=768'})\r\n        ].concat(cssList.map(function(css){\r\n            return html.link({href: css, rel: \"stylesheet\"});\r\n        })).concat(cssList.map(function(css){\r\n            const EXTENSIONES_SKIN = ['.css', '.styl'];\r\n            var skin = be.config['client-setup'].skin;\r\n            if(!skin || !be.activeSkinFiles) return null;\r\n\r\n            var lastDotIndex = css.lastIndexOf('.');\r\n            var cssBase = (lastDotIndex !== -1) ? css.substring(0, lastDotIndex) : css;\r\n            \r\n            var existsInSkin = EXTENSIONES_SKIN.some(function(ext) {\r\n                return be.activeSkinFiles.has(cssBase + ext);\r\n            });\r\n\r\n            if (existsInSkin) {\r\n                var skinUrl = skin + '/';\r\n                return html.link({href: skinUrl + css, rel: \"stylesheet\"});\r\n            }\r\n            return null;\r\n        }))),\r\n        html.body({'app-version':packagejson.version},[\r\n            html.div({id: \"total-layout\"}, [\r\n                html.img({class:\"main-loading\", src: \"img/main-loading.gif\"}),\r\n                html.div(be.messages.unlogged.loading),\r\n                req.useragent.os=='iOS'&&req.useragent.version.split('.')[0]<9?html.div(`La versión del dispositivo ${req.useragent.version} no es compatible`):null\r\n            ]),\r\n            html.div({id: \"total-scripts\"}, be.clientModules(req,opts).scripts.map(function(scriptDef){\r\n                return html.script(scriptDef);\r\n            }).concat([html.script({src:'client/menu.js'})]))\r\n        ]),\r\n    ]);\r\n}\r\n\r\nAppBackend.prototype.addSchrödingerServices = function addSchrödingerServices(mainApp,baseUrl){\r\n    var be=this;\r\n    mainApp.get(baseUrl,function(req, res){\r\n        /*\r\n        'url,originalUrl,path,query'.split(',').forEach(function(name){\r\n            console.log('req.'+name,req[name]);\r\n        });\r\n        */\r\n        if(!req.isAuthenticated || !req.isAuthenticated()){\r\n            res.redirect(Path.posix.join(baseUrl,mainApp.loginPlusManager.opts.noLoggedUrlPath));\r\n        }else{\r\n            res.redirect(Path.posix.join(baseUrl,mainApp.loginPlusManager.opts.successRedirect));\r\n        }\r\n    });\r\n    mainApp.use(baseUrl,function(req,res,next){\r\n        next();\r\n    })\r\n};\r\n\r\nAppBackend.prototype.addLoggedServices = function addLoggedServices(){\r\n    var be = this;\r\n    var skin=be.config['client-setup'].skin;\r\n    var skinUrl=(skin?skin+'/':'');\r\n    var slashSkin=(skin?'/'+skin:'');\r\n    var imgUrl=skinUrl+'img/';\r\n    be.optsGenericForAll={};\r\n    if(!be.config.devel || be.config.devel['cache-content']){\r\n        be.optsGenericForAll.cacheControl='private';\r\n        be.optsGenericForAll.maxAge=1000*60*60*24*15;\r\n    }\r\n    var optsGenericForImg=changing(be.optsGenericForAll,{\r\n        allowedExts:be.exts.img,\r\n    });\r\n    if(be.config[\"client-setup\"].menu){\r\n        be.app.get('/menu',function(req,res,next){\r\n            return MiniTools.serveText(be.mainPage(req, false).toHtmlDoc(),'html')(req,res,next);\r\n        });\r\n        var gridBuffer = be.config['client-setup']['grid-buffer'];\r\n        var offlineMode = gridBuffer && (gridBuffer === 'idbx' || gridBuffer === 'wsql');\r\n        if(offlineMode){\r\n            be.app.get('/ext', function(req,res,next){\r\n                return MiniTools.serveText(be.mainPage(req, true).toHtmlDoc(),'html')(req,res,next);\r\n            });\r\n        }\r\n    }\r\n    be.app.get('/clear-cache', function(req, res){\r\n        if(be.isAdmin(req)){\r\n            be.clearCaches();\r\n            res.end('cache cleared')\r\n        }else{\r\n            res.end(403,'FORBIDEN')\r\n        }\r\n    })\r\n    be.app.get('/lib/my-skin.js',MiniTools.serveText(`\r\n        \"use strict\";\r\n        myOwn.path = myOwn.path || {};\r\n        myOwn.path.img='${imgUrl}';\r\n        myOwn.appName='${packagejson.name}${be.config.server[\"base-url\"]}';\r\n        myOwn.clientVersion='${be.config[\"client-setup\"].version}';\r\n        window.addEventListener('load', function(){\r\n            document.body.setAttribute('my-skin', '${skin}')\r\n        });\r\n    `, 'application/javascript'));\r\n    be.app.use(slashSkin,serveContent(Path.join(be.config.server.skins[skin]['local-path'],skin),{allowedExts:be.exts.img.concat(['css'])}));\r\n    be.app.use(slashSkin,serveContent(Path.join(be.rootPath,'skins',skin),{allowedExts:be.exts.img.concat(['css'])}));\r\n    var dist=/(^|[/\\\\])dist[/\\\\]server[/\\\\]server[/\\\\]/.test(packagejson.main)?'dist/client/':regexpDistCheck.test(packagejson.main)?'dist/':'';\r\n    [Path.resolve(be.rootPath,dist+'client'), Path.join(__dirname,'../for-client')].forEach(function(path){\r\n        if(!fs.existsSync(path)){\r\n            console.error('****************** WARNING!!!!')\r\n            console.log('NO EXISTE EL path PARA EL CLIENT INCLUDES',path)\r\n            if(/client.client/.test(path)){\r\n                console.log('si hay server/server tiene que haber client/client');\r\n            }\r\n        }\r\n        be.app.use(function(req,res,next){\r\n            return serveContent(path,be.optsGenericForFiles(req))(req,res,next);\r\n        });\r\n        be.app.use('/client', function(req,res,next){\r\n            return serveContent(path,be.optsGenericForFiles(req))(req,res,next);\r\n        });\r\n        be.app.use('/lib', function(req,res,next){\r\n            return serveContent(path,be.optsGenericForFiles(req))(req,res,next);\r\n        });\r\n    });\r\n    [\r\n        {client:'client'    , path:Path.resolve(be.rootPath,'src/client'     )},\r\n        {client:'for-client', path:Path.resolve(__dirname,'../src/for-client')},\r\n    ].forEach(function(info){\r\n        var path=info.path;\r\n        be.app.use('/src/'+info.client, function(req,res,next){\r\n            return serveContent(path,changing(be.optsGenericForFiles(req),{allowedExts:['ts']}))(req,res,next);\r\n        });\r\n    });\r\n    be.app.use('/img',serveContent(Path.join(__dirname,'../for-client/img'), optsGenericForImg));\r\n    be.app.use('/img',serveContent(Path.join(Path.dirname(require_resolve('dialog-promise')),'../img'), optsGenericForImg));\r\n    if(be.config.log.session){\r\n        be.app.use(function(req, res, next){\r\n            console.log(new Date().getTime(),req.session,new Date().getTime() - req.session.lastNonKeepAlive > be.config.login.keepAlive*1000?'LOGOUT':'stay-in',req.cookies);\r\n            try{\r\n                console.log(new Date().getTime() - req.session.lastNonKeepAlive, new Date(req.session.cookie._expires).getTime() - new Date().getTime())\r\n            }catch(e){\r\n            }\r\n            next();\r\n        });\r\n    }\r\n    be.app.use('/keep-alive.json', function(req, res, next){\r\n        try{\r\n            if(new Date().getTime() - req.session.lastNonKeepAlive > be.config.login.keepAlive*1000){\r\n                req.logout();\r\n                // res.clearCookie(options.name);\r\n                return next();\r\n            }else{\r\n                res.send(Math.random().toString());\r\n            }\r\n        }catch(err){\r\n            console.log(err);\r\n            console.log(err.stack);\r\n            throw err;\r\n        }\r\n    });\r\n    be.app.get('/--version',async function(req,res,next){\r\n        var simpleGit = require('simple-git');\r\n        var git = simpleGit(process.cwd());\r\n        var info=[\r\n            html.h1(be.messages.server.versions),\r\n            html.h3([packagejson.name,' ',packagejson.version]),\r\n            html.ul([\r\n                html.li([(await git.revparse(['HEAD'])).trim()]),\r\n                ...((git.tags().all || []).map(tag => html.li([tag]))),\r\n            ])\r\n        ];\r\n        Promise.resolve().then(function(){\r\n            if(be.isAdmin(req)){\r\n                info=info.concat([\r\n                    html.h2(be.messages.server.dependences),\r\n                    html.ul(\r\n                        likeAr(packagejson.dependencies).map(function(version, name){\r\n                            return html.li([name,': ',version])\r\n                        }).array()\r\n                    )\r\n                ])\r\n                return Promise.all(\r\n                    ['def-config.yaml', 'local-config.yaml', 'package.json', 'last-pg-error-local.sql']\r\n                    .map(function(fileName){\r\n                        return fs.stat(fileName).then(function(stat){\r\n                            return html.li([fileName, ': ', stat.size/* , ' ', bestGlobals.datetime.ms(stat.mtime.getMilliseconds()).toYmdHms()*/ ]);\r\n                        },function(err){\r\n                            return html.li([fileName, ': ', err.messages]);\r\n                        });\r\n                    })\r\n                ).then(function(htmls){\r\n                    info = info.concat([\r\n                        html.h2(be.messages.server.files),\r\n                        html.ul(htmls)\r\n                    ]);\r\n                    info = info.concat([\r\n                        html.h2('process'),\r\n                        html.ul(\r\n                            ['title','version','execPath','platform','arch'].map(function(attr){\r\n                                return html.li([attr,': ',process[attr]]);\r\n                            })\r\n                        )\r\n                    ]);\r\n                });\r\n            }\r\n        }).then(function(){\r\n            MiniTools.serveText(html.body(info).toHtmlDoc({title:'version'}),'html')(req,res);\r\n        }).catch(MiniTools.serveErr(req,res,next));\r\n    });\r\n    if(be.config.log.db['on-demand']){\r\n        be.app.get('/--log-db',function(req,res,next){\r\n            var info=html.pre('not logging');\r\n            Promise.resolve().then(function(){\r\n                if(be.isAdmin(req)){\r\n                    if(be.setLog){\r\n                        be.setLog(req.query);\r\n                        info=[\r\n                            html.h1('log'),\r\n                            html.pre('until: '+be.config.log.db.until.toYmdHms()),\r\n                            html.pre('results: '+be.config.log.db.results)\r\n                        ];\r\n                    }\r\n                }else{\r\n                    throw new Error('forbiden');\r\n                }\r\n            }).then(function(){\r\n                MiniTools.serveText(html.body(info).toHtmlDoc({title:'loggin'}),'html')(req,res);\r\n            }).catch(MiniTools.serveErr(req,res,next));\r\n        });\r\n    }\r\n    if(be.config.db['downloadable-backup-path']){\r\n        be.app.get('/backup-db.zip', function(req,res,next){\r\n            if (be.can(req, 'DownloadBackup')) {\r\n                MiniTools.serveFile('./local-private/backup-db.zip')(req,res,next);\r\n            }\r\n        })\r\n    }\r\n    be.app.use(function(req,res,next){\r\n        // req != '/keep-alive.json'\r\n        req.session.lastNonKeepAlive = new Date().getTime();\r\n        next();\r\n    });\r\n    this.app.use('/info', async function(req,res,next){\r\n        if(req.path.endsWith('.md')){\r\n            var fileName=__dirname+'/../public-docs/'+req.path;\r\n            var content = await fs.readFile(fileName,'utf8');\r\n            var md = await markdownRender('html', content);\r\n            MiniTools.serveText(md.content, 'html')(req,res);\r\n        }else{\r\n            serveContent(__dirname+'/../docs',be.optsGenericForFiles(req))(req,res,next);\r\n        }\r\n    });\r\n    var logo=this.config.logo;\r\n};\r\n\r\nAppBackend.prototype.getEditableForDump = function getEditableForDump(){\r\n    var be=this;\r\n    var contextForDump={be:be, forDump:true, user:{}};\r\n    if(be.config.login){\r\n        contextForDump.user[be.config.login.userFieldName]='!dump';\r\n        contextForDump.user[be.config.login.rolFieldName]='admin';\r\n    }\r\n    return contextForDump;\r\n};\r\n\r\nAppBackend.prototype.getContextForDump = function getContextForDump(){\r\n    var be=this;\r\n    var contextForDump={be:be, forDump:true, user:{}};\r\n    if(be.config.login){\r\n        contextForDump.user[be.config.login.userFieldName]='!dump';\r\n        contextForDump.user[be.config.login.rolFieldName]='admin';\r\n    }\r\n    return contextForDump;\r\n};\r\n\r\nAppBackend.prototype.validateBitacora = function validateBitacora(procedureDef){\r\n    var be = this;\r\n    if(procedureDef.bitacora.targetTable in be.tableStructures){\r\n        var contextForDump=be.getContextForDump();\r\n        var tableDefFields = be.tableStructures[procedureDef.bitacora.targetTable](contextForDump).fields;\r\n        var targetTableBitacoraFields = procedureDef.bitacora.targetTableBitacoraFields;\r\n        for (var fieldForSearch in targetTableBitacoraFields) {\r\n            var searchResult = tableDefFields.find(function findByName(field) { \r\n                return field.name === targetTableBitacoraFields[fieldForSearch];\r\n            });\r\n            if(!searchResult){\r\n                throw Error(\"Bitacora bad definition in core function '\" + procedureDef.action + \"', targetTableBitacoraField '\" + targetTableBitacoraFields[fieldForSearch] + \"' not exists in table '\" + procedureDef.bitacora.targetTable + \"'.\");\r\n            }\r\n        }\r\n        var targetTableUpdateFieldsCondition = procedureDef.bitacora.targetTableUpdateFieldsCondition || ['init_date','end_date','has_error', 'end_status'];\r\n        if(targetTableUpdateFieldsCondition){  \r\n            if(targetTableUpdateFieldsCondition.length == 0){\r\n                throw Error(\"Bitacora bad definition in core function '\" + procedureDef.action + \"', targetTableUpdateFieldsCondition must to be defined for table '\" + procedureDef.bitacora.targetTable + \"'.\");\r\n            }\r\n            targetTableUpdateFieldsCondition.forEach(function(fieldName){\r\n                var searchResult = tableDefFields.find(function findByName(field) { \r\n                    return field.name === fieldName;\r\n                });\r\n                if(!searchResult){\r\n                    throw Error(\"Bitacora bad definition in core function '\" + procedureDef.action + \"', targetTableUpdateFieldsCondition '\" + fieldName + \"' not exists in table '\" + procedureDef.bitacora.targetTable + \"'.\");\r\n                }\r\n            });\r\n        }else{\r\n            throw Error(\"Bitacora bad definition in core function '\" + procedureDef.action + \"', targetTableUpdateFieldsCondition '\" + fieldName + \"' is null for table '\" + procedureDef.bitacora.targetTable + \"'.\");\r\n        }\r\n    }else{\r\n        throw Error(\"Bitacora bad definition in core function '\" + procedureDef.action + \"'. '\" + procedureDef.bitacora.targetTable + \"' table defined in TargetTable not exists.\");\r\n    }\r\n    return true;\r\n};\r\n\r\nAppBackend.prototype.procedureDefCompleter = function procedureDefCompleter(procedureDef){\r\n    procedureDef.isCompleted=true;\r\n    procedureDef.withFastWindow=procedureDef.withFastWindow||true;\r\n    procedureDef.method=procedureDef.method||this.defaultMethod;\r\n    procedureDef.encoding=procedureDef.encoding||'JSON4all';\r\n    procedureDef.resultOk=procedureDef.resultOk ?? (procedureDef.forExport ? 'showDownloadUrl' : 'showText');\r\n    procedureDef.progress = procedureDef.progress ?? (procedureDef.forExport && true);\r\n    procedureDef.uniqueUse = procedureDef.uniqueUse ?? !!procedureDef.forExport;\r\n    procedureDef.resultErr=procedureDef.resultErr||'showError';\r\n    procedureDef.resultClass=procedureDef.resultClass||'result-div';\r\n    procedureDef.parameters.forEach(function(paramDef){\r\n        paramDef.encoding=paramDef.encoding||'JSON4all';\r\n    });\r\n    procedureDef.bitacora = procedureDef.bitacora || {always: false, error: false};\r\n    if(procedureDef.bitacora.always || procedureDef.bitacora.error){\r\n        procedureDef.bitacora=changing({\r\n            targetTable:'bitacora',\r\n            targetTableBitacoraFields: {end_date: 'end_date', end_status: 'end_status', has_error: 'has_error'}\r\n        },procedureDef.bitacora);\r\n        this.validateBitacora(procedureDef);\r\n    }\r\n    return procedureDef;\r\n};\r\n\r\nAppBackend.prototype.getProcedures = function getProcedures(){\r\n    return Promise.resolve(require('./procedures-table.js'));\r\n};\r\n\r\nAppBackend.prototype.tableDefAdapt = require('./table-def-adapt.js');\r\n\r\nAppBackend.prototype.tableMixin = require('./table-mixin.js');\r\n\r\nvar typeDb={ // pasar a type-store\r\n    integer: 'integer',\r\n    number: 'numeric',\r\n    date: 'date',\r\n    boolean: 'boolean',\r\n    text: 'text'\r\n};\r\nvar test=typeStore.typerFrom\r\nfor(var typeName in typeStore.type){\r\n    typeDb[typeName]= typeStore.typerFrom({typeName}).typeDbPg;\r\n    //typeDb[typeName]=typeStore.type[typeName].typeDbPg;\r\n}\r\n\r\nAppBackend.prototype.dumpDbCreateDatabase = function dumpDbCreateDatabase(){\r\n    var be = this;\r\n    var db=be.db;\r\n    var lines=[];\r\n    var owner=db.quoteIdent(be.config.db.owner||be.config.install.dump.db.owner||be.config.db.user);\r\n    if(be.config.install.dump.db.password || be.config.db[\"owner-password\"] && !be.config.db[\"for-test\"]){\r\n        throw new Error(\"password must not be setted in config\");\r\n    }\r\n    if(be.config.install.dump.db.owner!=be.config.db.user){\r\n        lines.push(`create user ${owner} ${be.config.db[\"for-test\"]?`password ${db.quoteLiteral(be.config.db[\"owner-password\"])}`:`nologin`};`);\r\n    }\r\n    if(!be.config.db.password){\r\n        throw new Error('Lack of config.db.password in local-config');\r\n    }\r\n    lines.push(\"create user \"+db.quoteIdent(be.config.db.user)+\" password \"+db.quoteLiteral(be.config.db.password)+\";\");\r\n    lines.push(\"create database \"+db.quoteIdent(be.config.db.database)+\" owner \"+owner+\r\n        (be.config.db.tablespace?\" tablespace \"+db.quoteIdent(be.config.db.tablespace):\"\")+\r\n    \";\");\r\n    lines.push(\"grant connect, temporary on database \"+db.quoteIdent(be.config.db.database)+\" to \"+db.quoteIdent(be.config.db.user)+\";\");\r\n    lines.push(\"\\\\c \"+db.quoteIdent(be.config.db.database));\r\n    return fs.writeFile('local-db-dump-create-db.sql', lines.join('\\n')+'\\n');\r\n};\r\n\r\nAppBackend.prototype.dumpFkConstraint = function dumpFkConstraint(fk, tableDef, forced){\r\n    var db=this.db;\r\n    var sourceFieldList=fk.fields.map(function(pair){ return db.quoteIdent(pair.source); }).join(', ');\r\n    var targetFieldList=fk.fields.map(function(pair){ return db.quoteIdent(pair.target); }).join(', ');\r\n    var consName=db.quoteIdent(fk.consName?fk.consName:(tableDef.alias||tableDef.sql.tableName)+' '+(fk.alias||fk.references)+' REL');\r\n    var clause =\r\n        'constraint '+consName+' '+\r\n        'foreign key ('+sourceFieldList+') '+\r\n        'references '+db.quoteIdent(fk.references)+' ('+targetFieldList+') '+\r\n        (forced?\r\n            ' on update no action on delete no action':\r\n            (fk.onDelete?' on delete '+fk.onDelete:'')+\r\n            ((fk.onUpdate||this.config.db.fkOnUpdate)?' on update '+(fk.onUpdate||this.config.db.fkOnUpdate):'')+\r\n            (fk.initiallyDeferred?' initially deferred':'')\r\n        );\r\n    return {consName, clause, sourceFieldList};\r\n}\r\n\r\nAppBackend.prototype.isGeneratedSequence = function isGeneratedSequence(sequence, not){\r\n    return sequence && ((!sequence.name && !sequence.madMax) == !not)\r\n}\r\n\r\nAppBackend.prototype.isSequenceNonGenerated = function isSequenceNonGenerated(sequence){\r\n    return this.isGeneratedSequence(sequence, true);\r\n}\r\n\r\nAppBackend.prototype.dumpDbTableFields = function dumpDbTableFields(tableDef, opts = {}, complements = null){\r\n    var be = this;\r\n    var db = this.db;\r\n    var fields=[];\r\n    tableDef.fields.forEach(function(fieldDef){\r\n        if(!fieldDef.clientSide && fieldDef.inTable!==false && !fieldDef.inJoin && !(tableDef.sql.fields[fieldDef.name]||{}).expr || fieldDef.inTable){\r\n            var fieldType=typeDb[fieldDef.typeName]||'\"'+fieldDef.typeName+'\"';\r\n            if(fieldDef.sizeByte==4){\r\n                fieldType = 'integer';\r\n            }\r\n            fields.push(\r\n                '  '+db.quoteIdent(fieldDef.name)+\r\n                ' '+(fieldDef.dataLength?(fieldType=='text'?'varchar':fieldType)+'('+fieldDef.dataLength+')':fieldType)+\r\n                ( be.specialSqlDefaultExpressions[fieldDef.defaultDbValue] != null ? ' default ' + be.specialSqlDefaultExpressions[fieldDef.defaultDbValue]\r\n                : fieldDef.defaultDbValue != null ? ' default ' + fieldDef.defaultDbValue \r\n                : be.specialSqlDefaultExpressions[fieldDef.specialDefaultValue] != null ? ' default ' + be.specialSqlDefaultExpressions[fieldDef.specialDefaultValue]\r\n                : fieldDef.defaultValue != null ? ' default ' + db.quoteLiteral(fieldDef.defaultValue) \r\n                : ''\r\n                ) +\r\n                (be.isGeneratedSequence(fieldDef.sequence)?' generated always as identity':'')+\r\n                (fieldDef.generatedAs!=null?` generated always as (${fieldDef.generatedAs}) stored`:'')\r\n            );\r\n            if(complements){\r\n                complements(fieldDef)\r\n            }\r\n        }\r\n    });\r\n    return fields\r\n}\r\n\r\nAppBackend.prototype.dumpDbSchemaPartial = async function dumpDbSchemaPartial(partialTableStructures, opts = {}){\r\n    var complete = opts.complete;\r\n    var be = this;\r\n    var db=be.db;\r\n    db.quoteInteger = function quoteInteger(integerValue){\r\n        // TODO: Cambiar esta ubicación provisoria. Pasarlo a pg-promise-strict\r\n        if(!/^\\d+$/.test(integerValue.toString())){\r\n            throw new Error('not an integer in quoteInteger');\r\n        }\r\n        return integerValue;\r\n    };\r\n    var linesCreate=[];\r\n    var searchPathline=[];\r\n    var lines=[];\r\n    var dataText=[];\r\n    var fkLines=[];\r\n    var indexLines=[];\r\n    var consLines=[];\r\n    var policyLines=[];\r\n    var enanceLines=[];\r\n    var enancePart='';\r\n    var user=be.config.db.user;\r\n    var owner=be.config.install.dump.db.owner||be.config.db.user;\r\n    if(!isLowerIdent(user)){\r\n        throw new Error(\"user malformed name\")\r\n    }\r\n    if(!isLowerIdent(owner)){\r\n        throw new Error(\"owner malformed name\")\r\n    }\r\n    var schema=db.quoteIdent(be.config.db.schema);\r\n    linesCreate.push(\"set role to \"+owner+\";\");\r\n    var control = `-- CONTROL\r\n    do $do$\r\n    declare\r\n      vExpectedVersion text := '${be.config.db[\"min-version\"]}';\r\n      vCurrentVersion  text := (select setting from pg_settings where name = 'server_version');\r\n    begin\r\n      if semver_to_decimal(vCurrentVersion) < semver_to_decimal(vExpectedVersion) then\r\n        raise exception 'BACKEND-PLUS DUMP: Old PostrgreSQL Version % expected %', vCurrentVersion, vExpectedVersion;\r\n      end if;\r\n    end;\r\n    $do$;\r\n    do $do$\r\n    declare\r\n      vExpected text := 'UTF8';\r\n      vCurrent  text := coalesce((select setting from pg_settings where name = 'server_encoding'),'unknown');\r\n    begin\r\n      if vCurrent is distinct from vExpected then\r\n        raise exception 'BACKEND-PLUS DUMP: PostrgreSQL server_encoding %, expected %', vCurrent, vExpected;\r\n      end if;\r\n    end;\r\n    $do$;\r\n    `;\r\n    linesCreate.push(\"drop schema if exists \"+schema+' cascade;');\r\n    if (be.config.install.dump[\"drop-his\"]) {\r\n        linesCreate.push(\"drop schema if exists his cascade;\");\r\n    }\r\n    linesCreate.push(\"create schema \"+schema+';');\r\n    linesCreate.push(\"grant usage on schema \"+schema+' to '+user+';');\r\n    linesCreate.push(\"create schema if not exists his;\");\r\n    linesCreate.push(\"grant usage on schema his to \"+user+';');\r\n    if(be.config.install.dump[\"admin-can-create-tables\"]){\r\n        linesCreate.push(\"grant create on schema \"+schema+' to '+user+';');\r\n    }\r\n    linesCreate.push('');\r\n\r\n    if(!complete && opts.forDump){\r\n        linesCreate.push(\"set role to \"+owner+\";\");\r\n    }\r\n    searchPathline.push(\"set search_path = \"+schema+', public;');\r\n    searchPathline.push(\"set client_encoding = 'UTF8';\");\r\n    searchPathline.push('');\r\n    /*eslint guard-for-in: 0*/\r\n    /*eslint no-loop-func: 0*/\r\n    /*jshint loopfunc:true */\r\n    var contextForDump=be.getContextForDump();\r\n    var functionLines = (await be.getDbFunctions(opts)).map(fdef=>fdef.dumpText);\r\n    var tablesWithStrictSequence={}\r\n    for(var tableName in partialTableStructures) if(partialTableStructures.hasOwnProperty(tableName)){\r\n        try{\r\n            var tableDef=partialTableStructures[tableName](contextForDump);\r\n            if(!tableDef.adapted){\r\n                if(!tableDef.fields){\r\n                    throw new Error('DUMP ERROR. '+tableName+' without fields')\r\n                }\r\n                tableDef=be.tableDefAdapt(tableDef);\r\n            }\r\n            var fieldsForSequences=[];\r\n            var cualQuoteTableName=(tableDef.schema?db.quoteIdent(tableDef.schema)+'.':'')+db.quoteIdent(tableDef.sql.tableName);\r\n            if(tableDef.sql.isTable){\r\n                if(tableDef.sql.viewBody){\r\n                    throw new Error('table '+tableDef.sql.tableName+' has viewBody. It must has isTable=false');\r\n                }\r\n                lines.push('create table '+cualQuoteTableName+' (');\r\n                var fields = be.dumpDbTableFields(tableDef, opts,\r\n                    function complements(fieldDef){\r\n                        if(be.isGeneratedSequence(fieldDef.sequence)){\r\n                            tablesWithStrictSequence[tableName]={}\r\n                        }\r\n                        if(fieldDef.typeName==='text' && !fieldDef.allowEmptyText){\r\n                            consLines.push(\r\n                                'alter table '+cualQuoteTableName+\r\n                                ' add constraint '+db.quoteIdent(fieldDef.name+\"<>''\")+\r\n                                ' check ('+db.quoteIdent(fieldDef.name)+\"<>'');\"\r\n                            );\r\n                        }\r\n                        if(fieldDef.options){\r\n                            consLines.push(\r\n                                'alter table '+cualQuoteTableName+\r\n                                ' add constraint '+db.quoteIdent(fieldDef.name+\" invalid option\")+\r\n                                ' check ('+db.quoteIdent(fieldDef.name)+\r\n                                    ` in (${fieldDef.options.map(opt=>db.quoteLiteral(opt.option===undefined?opt:opt.option))}) );`\r\n                            );\r\n                        }\r\n                        if(fieldDef.nullable===false || fieldDef.dbNullable===false){\r\n                            consLines.push(\r\n                                'alter table '+cualQuoteTableName+\r\n                                ' alter column '+db.quoteIdent(fieldDef.name)+' set not null;'\r\n                            );\r\n                        }\r\n                        if(be.isSequenceNonGenerated(fieldDef.sequence)){\r\n                            fieldsForSequences.push(fieldDef);\r\n                        }\r\n                    }\r\n                );\r\n                lines.push(fields.join(', \\n'));\r\n                if(tableDef.primaryKey){\r\n                    lines.push(', primary key ('+tableDef.primaryKey.map(function(name){ return db.quoteIdent(name); }).join(', ')+')');\r\n                    if(!opts.skipEnance && !tableDef.sql.skipEnance){\r\n                        enanceLines.push(\r\n                            'PERFORM enance_table('+db.quoteLiteral(tableDef.sql.tableName)+','+db.quoteLiteral(\r\n                                tableDef.primaryKey.join(',')\r\n                            )+');'\r\n                        );\r\n                    }\r\n                }\r\n                lines.push(');');\r\n                //TODO: REFACTOR: Hacerlo mas sencillo\r\n                // este codigo se encarga de convertir a rights de sql nuestros propios rights\r\n                // por ej (import -> [insert, update]) \r\n                var allows = tableDef.allow;\r\n                var appToSqlRights = {'import': ['insert', 'update'], 'export': ['select'], 'deleteAll': ['delete']};\r\n                [ 'import', 'export', 'deleteAll'].filter(function(right){\r\n                    return allows[right];\r\n                }).forEach(function(right){\r\n                    appToSqlRights[right].forEach(function(sqlRight){\r\n                        allows[sqlRight] = true;\r\n                    })\r\n                });\r\n                var sqlRights = ['select', 'insert', 'update', 'delete'].filter(function(right){\r\n                    return allows[right];\r\n                });\r\n                if(tableDef.sql.isReferable){\r\n                    sqlRights.push('references')\r\n                }\r\n                sqlRights=sqlRights.join(', ')\r\n                if(sqlRights){\r\n                    lines.push('grant '+sqlRights+' on '+cualQuoteTableName+' to '+user+';');\r\n                }\r\n                if (user != owner){\r\n                    lines.push('grant all on '+cualQuoteTableName+' to '+owner+';');\r\n                }\r\n                tableDef.foreignKeys.map(function(fk){\r\n                    var { clause:fullClause, sourceFieldList } = be.dumpFkConstraint(fk, tableDef);\r\n                    var indexName=db.quoteIdent(sourceFieldList.replace(/[ \"]/g,'')+' 4 '+tableDef.sql.tableName+' IDX');\r\n                    if(indexName.length>63){\r\n                        indexName=db.quoteIdent(fk.consName?fk.consName+' IDX':(tableDef.alias||tableDef.sql.tableName)+' '+fk.references+' IDX');\r\n                    }\r\n                    indexLines.push('create index '+indexName+' ON '+cualQuoteTableName+' ('+sourceFieldList+');');\r\n                    fkLines.push('alter table '+cualQuoteTableName+\r\n                        ' add '+fullClause+';'\r\n                    );\r\n                });\r\n                if(tableDef.sql.constraintsDeferred){\r\n                    var fkEnabling=tableDef.foreignKeys.filter(fk=>fk.forceDeferrable).map(function(fk){\r\n                        var {consName, clause:clauseFalse} = be.dumpFkConstraint(fk, tableDef, false);\r\n                        return `\r\n                        if enable then\r\n                            ALTER TABLE ${cualQuoteTableName} ADD ${clauseFalse};\r\n                        else\r\n                            ALTER TABLE ${cualQuoteTableName} DROP constraint ${consName};\r\n                        end if;\r\n                        `\r\n                    });\r\n                    if(fkEnabling.length){\r\n                        functionLines.push(\r\n                            `create or replace function ${(tableDef.schema?be.db.quoteIdent(tableDef.schema)+'.':'')+be.db.quoteIdent(`${tableDef.tableName}_toggle_consts`)}(enable boolean) returns text\r\n                            language plpgsql security definer as \\n$BODY$\\nbegin`+fkEnabling.join('')+' return $$ok$$;\\nend;\\n$BODY$;\\n'\r\n                        );\r\n                    }\r\n                }\r\n                tableDef.constraints.map(function(cons){\r\n                    var sql;\r\n                    var prefix = 'alter table '+cualQuoteTableName+' add '+\r\n                        (cons.consName?'constraint '+db.quoteIdent(cons.consName)+' ':'');\r\n                    switch(cons.constraintType){\r\n                    case 'unique': \r\n                        sql='('+cons.fields.map(function(field){ return db.quoteIdent(field); }).join(', ')+')';\r\n                        if(cons.where){\r\n                            if(cons.consName == null){\r\n                                console.error('create unique index constraint: must include consName in ',cons);\r\n                            }\r\n                            prefix = 'create unique index '+db.quoteIdent(cons.consName)+' on '+cualQuoteTableName;\r\n                            sql += 'where ' + cons.where;\r\n                        }else{\r\n                            prefix += 'unique ';\r\n                        }\r\n                    break;\r\n                    case 'check': \r\n                        sql='check ('+cons.expr+')';\r\n                    break;\r\n                    case 'exclude': \r\n                        sql=`exclude using ${cons.using} (${cons.fields.map(f => typeof f == \"string\"?`${f} WITH =`:`${f.fieldName} WITH ${f.operator}`).join(', ')})${cons.where ? ` WHERE (${cons.where})`:``}`;\r\n                    break;\r\n                    default:\r\n                        throw new Error('constraintType not implemented: '+cons.constraintType);\r\n                    }\r\n                    consLines.push(\r\n                        prefix + sql + ';'\r\n                    );\r\n                });\r\n                lines.push(tableDef.sql.postCreateSqls);\r\n                lines.push('');\r\n                await Promise.all(fieldsForSequences.map(async function(fieldDef) {\r\n                    var sequence = fieldDef.sequence;\r\n                    if (sequence.name) {\r\n                        if (sequence.madMax) throw new Error('a sequence with madMax cannot have name');\r\n                        lines.push(\"CREATE SEQUENCE \"+db.quoteIdent(sequence.name)+\" START \"+db.quoteInteger(sequence.firstValue||1)+\";\");\r\n                        lines.push(\r\n                            \"ALTER TABLE \"+cualQuoteTableName+\r\n                            \" ALTER COLUMN \"+db.quoteIdent(fieldDef.name)+\r\n                            (sequence.prefix==null\r\n                            ?\" SET DEFAULT nextval(\"+db.quoteLiteral(sequence.name)+\"::regclass);\"\r\n                            :\" SET DEFAULT (\"+db.quoteLiteral(sequence.prefix)+\" || nextval(\"+db.quoteLiteral(sequence.name)+\"::regclass)::text);\"\r\n                            )\r\n                        );\r\n                        lines.push('GRANT USAGE, SELECT ON SEQUENCE '+db.quoteIdent(sequence.name)+' TO '+user+';');\r\n                    } else if (sequence.madMax) {\r\n                        lines.push(await pgTriggers.dumpMaxIdTrigger(tableDef.sql.tableName, fieldDef.name, {grouping: sequence.madMax.grouping, firstValue: sequence.firstValue}));\r\n                    } else {\r\n                        throw new Error('a sequence without madMax nor name');\r\n                    }\r\n                }));\r\n                lines.push('');\r\n                if(tableDef.sql.policies.enabled){\r\n                    policyLines.push(`ALTER TABLE ${cualQuoteTableName} ENABLE ROW LEVEL SECURITY;`);\r\n                    [null, 'all', 'select', 'insert', 'update', 'delete'].forEach((command)=>{\r\n                        var polcom=tableDef.sql.policies[command] ?? {using: `true`, permissive:true};\r\n                        if(polcom?.using || polcom?.check){\r\n                            policyLines.push(`CREATE POLICY ${be.db.quoteIdent(polcom.name ?? `bp ${command ?? `base`}`)} ON ${cualQuoteTableName} `+\r\n                                `AS ${polcom.permissive ? `PERMISSIVE` : `RESTRICTIVE`} FOR ${command ?? `all`} TO ${be.config.db.user}`+\r\n                                (polcom.using?     ` USING ( ${polcom.using} )`:'')+\r\n                                (polcom.check?` WITH CHECK ( ${polcom.check} )`:'')+';'\r\n                            );\r\n                        }                        \r\n                    });\r\n                }\r\n            }else{\r\n                if(tableDef.sql.viewBody){\r\n                    lines.push('create or replace view '+cualQuoteTableName+' (');\r\n                    var viewFields=[];\r\n                    tableDef.fields.forEach(function(fieldDef){\r\n                        if(!fieldDef.clientSide && fieldDef.inTable!==false && !(tableDef.sql.fields[fieldDef.name]||{}).expr || fieldDef.inView){\r\n                            viewFields.push(db.quoteIdent(fieldDef.name));\r\n                        }\r\n                    });\r\n                    lines.push('  '+viewFields.join(', '));\r\n                    lines.push(') as '+tableDef.sql.viewBody+';');\r\n                    lines.push('grant select on '+cualQuoteTableName+' to '+user+';');\r\n                    lines.push('');\r\n                }\r\n            }\r\n        }catch(err){\r\n            err.context=(err.context||'')+'dumping structure of table '+tableName+' \\n ';\r\n            throw err;\r\n        }\r\n    }\r\n    lines.push(`\r\ncreate or replace procedure set_app_user(p_username text)\r\n  security definer language plpgsql\r\nas\r\n$body$\r\ndeclare\r\n    ${be.config.login.infoFieldList.map(fieldName => `\r\n        ${db.quoteIdent('v_'+fieldName)} text;`\r\n    ).join('')}\r\nbegin\r\n    if p_username = '!login' then\r\n        ${be.config.login.infoFieldList.map(fieldName => `\r\n        set backend_plus._${fieldName} = '!';`).join('')}\r\n\r\n        set backend_plus._mode = login;\r\n    else\r\n        select ${be.config.login.infoFieldList.map(fieldName => db.quoteIdent(fieldName)).join(', ')}\r\n            into ${be.config.login.infoFieldList.map(fieldName => db.quoteIdent('v_'+fieldName)).join(', ')}\r\n            \r\n            from ${(be.config.login.from ?? (\r\n                (be.config.login.schema?be.db.quoteIdent(be.config.login.schema)+'.':'')+\r\n                be.db.quoteIdent(be.config.login.table)))}\r\n                where ${db.quoteIdent(be.config.login.userFieldName)} = p_username;\r\n        ${be.config.login.infoFieldList.map(fieldName => `\r\n        perform set_config('backend_plus._${fieldName}', v_${fieldName}, false);`).join('')}\r\n\r\n        set backend_plus._mode = normal;\r\n    end if;\r\n    perform set_config('backend_plus._user', p_username, false);\r\nend;    \r\n$body$;\r\n\r\n    `)\r\n    var enancePart= 'do $SQL_ENANCE$\\n begin\\n' + enanceLines.join('\\n')+'\\n' + 'end\\n$SQL_ENANCE$;';\r\n    var someNotFound=false;\r\n    try {\r\n        var allTableData = await fs.readFile('install/local-data-dump.psql','utf-8');\r\n    } catch(err) {\r\n        if (err.code != 'ENOENT') throw err;\r\n        try {\r\n            var allTableContent = await fs.readFile('install/local-dump.psql','utf-8');\r\n            var startIndex = allTableContent.indexOf('-- Data for Name: ');\r\n            console.log('startIndex', startIndex);\r\n            var lastUseful = allTableContent.lastIndexOf('\\nSELECT pg_catalog.setval') \r\n            console.log('lastUseful', lastUseful);\r\n            if (lastUseful == -1) lastUseful = allTableContent.lastIndexOf('\\n\\\\.\\n');\r\n            console.log('lastUseful', lastUseful);\r\n            var lastIndex = allTableContent.indexOf('\\n--', lastUseful);\r\n            console.log('lastIndex', lastIndex);\r\n            allTableData = allTableContent.slice(startIndex, lastIndex);\r\n        } catch(err) {\r\n            if (err.code != 'ENOENT') throw err;\r\n            //throw err;\r\n        }\r\n    }\r\n    if (allTableData) {\r\n        var prepa = await be.getDataDumpTransformations(allTableData)\r\n        dataText = [\r\n            '-- BEGIN DATA FROM DUMP',\r\n            ...prepa.prepareTransformationSql,\r\n            prepa.rawData,\r\n            ...prepa.endTransformationSql,\r\n            '-- END DATA FROM DUMP'\r\n        ]\r\n    } else {\r\n        await Promise.all(likeAr(partialTableStructures).map(function(tableDef, tableName, _, i){\r\n            if(tableDef?.sql?.isTable === false) return;\r\n            // TODO: buscar\r\n            var buscarEn=[Path.join('local-install',tableName+'.tab')].concat(\r\n                be.appStack.map(function(stackNode){\r\n                    return Path.join(stackNode.path,'../install',tableName+'.tab').replace(regexpDistReplacer,'$1$2');\r\n                })\r\n            );\r\n            if(be.config.install['table-data-dir'] instanceof Array){\r\n                buscarEn=be.config.install['table-data-dir'].map(path=>Path.join(path,tableName+'.tab')).concat(buscarEn);\r\n            }else if(be.config.install['table-data-dir']){\r\n                buscarEn=[].concat(Path.join(be.config.install['table-data-dir'],tableName+'.tab')).concat(buscarEn);\r\n            }\r\n            if(!i) console.log('buscar en', buscarEn)\r\n            return locatePath(buscarEn).then(function(theTableFileName){\r\n                if(theTableFileName==undefined){\r\n                    var err = new Error('not found');\r\n                    err.code='ENOENT'\r\n                    throw err;\r\n                }\r\n                return fs.readFile(theTableFileName, {encoding:'UTF8'}).then(function(content){\r\n                    return {path:Path.relative(process.cwd(),theTableFileName),content};\r\n                });\r\n            }).then(function({path,content}){\r\n                dataText.push(\"\\n-- table data: \"+path);\r\n                var lines;\r\n                var rows;\r\n                var tableDef=partialTableStructures[tableName](contextForDump);\r\n                var filterField=function(fieldName){\r\n                    if(fieldName==null){\r\n                        throw new Error('ERROR empty name or extra column in '+tableName+'.tab')\r\n                    }\r\n                    var defField=tableDef.field[fieldName];\r\n                    if(!defField && !fieldName.startsWith('!')){\r\n                        throw new Error('field '+fieldName+' does no exists in .tab for '+tableName+' in '+path);\r\n                    }\r\n                    return !fieldName.startsWith('!') && defField.inTable!==false && !defField.inJoin && (!defField.clientSide || defField.serverSide) && !defField.generatedAs;\r\n                }\r\n                if(/[-[]/.test(content[0])){\r\n                    var filterField2=function(_value,fieldName){\r\n                        var fieldDef = tableDef.field[fieldName];\r\n                        if(!fieldDef){\r\n                            console.log('lack of field',fieldName,'in table',tableName,'filtering fields')\r\n                        }\r\n                        return (!fieldDef.sequence || fieldDef.sequence.name) && filterField(fieldName);\r\n                    }\r\n                    lines = jsYaml.load(content);\r\n                    lines.forEach(function(line){\r\n                        var dataString=\"insert into \"+db.quoteIdent(tableName)+\" (\"+\r\n                            likeAr(line).filter(filterField2).keys().map(db.quoteIdent).join(', ')+\r\n                            ') values ('+\r\n                            likeAr(line).filter(filterField2).map(function(value){\r\n                                return db.quoteNullable(value);\r\n                            }).join(', ')+\");\\n\";\r\n                        dataText.push(dataString);\r\n                    });\r\n                    rows=lines;\r\n                }else{\r\n                    var lines=content.split(/\\r?\\n/)\r\n                        .filter(line => !(/^[-| ]*$/.test(line)) )\r\n                        .map(line => splitRawRowIntoRow(line))\r\n                        .filter(line => line.length>1 || line.length==1 && line[0].trim() );\r\n                    if(lines.length>1){\r\n                        if(lines[0][0].startsWith('\\ufeff')){\r\n                            lines[0][0]=lines[0][0].replace('\\ufeff','')\r\n                        }\r\n                        rows=lines.slice(1);\r\n                        var filteredFieldDef = lines[0].filter(filterField);\r\n                        if(tablesWithStrictSequence[tableName]){\r\n                            var dataString=\"COPY \"+db.quoteIdent(tableName)+\" (\"+\r\n                                filteredFieldDef.map(db.quoteIdent).join(', ')+\r\n                                ') FROM stdin;\\n'+\r\n                                rows.map(function(line){\r\n                                    return line.filter(function(_,i){ return filterField(lines[0][i]);}).map(function(value,i){\r\n                                        var def = tableDef.field[filteredFieldDef[i]];\r\n                                        return value==='' ? (\r\n                                                def.allowEmptyText && ('nullable' in def) && !def.nullable ? '' : '\\\\N'\r\n                                            ): value.replace(/\\\\/g,'\\\\\\\\').replace(/\\t/g,'\\\\t').replace(/\\n/g,'\\\\n').replace(/\\r/g,'\\\\r');\r\n                                    }).join('\\t')+'\\n';\r\n                                }).join('')+'\\\\.\\n';\r\n                        }else{\r\n                            var dataString=\"insert into \"+db.quoteIdent(tableName)+\" (\"+\r\n                                filteredFieldDef.map(db.quoteIdent).join(', ')+\r\n                                ') values\\n'+\r\n                                rows.map(function(line){\r\n                                    return \"(\"+line.filter(function(_,i){ return filterField(lines[0][i]);}).map(function(value,i){\r\n                                        var def = tableDef.field[filteredFieldDef[i]];\r\n                                        if(def == null) {\r\n                                            throw Error(\"no se encuentra la columna \"+filteredFieldDef[i]+\" en \"+tableName);\r\n                                        }\r\n                                        return value==='' ? (\r\n                                            def.allowEmptyText && ('nullable' in def) && !def.nullable ? \"''\" : 'null' \r\n                                        ) : db.quoteNullable(value);\r\n                                    }).join(', ')+\")\";\r\n                                }).join(',\\n')+';\\n';\r\n                        }\r\n                        dataText.push(dataString);\r\n                    }\r\n                    // tablesWithStrictSequence[tableName]\r\n                }\r\n            }).catch(function(err){\r\n                if(err.code=='ENOENT'){\r\n                    if(!be.config.install.dump[\"skip-content\"]){\r\n                        console.log('skipping content for','install/'+tableName+'.tab');\r\n                        someNotFound=true;\r\n                    }\r\n                }else{\r\n                    throw err;\r\n                }\r\n            });\r\n        }).array())\r\n        if(someNotFound){\r\n            console.log('silence \"skipping content\" messages in \"local-config.yaml\".install.dump.skip-content=true');\r\n        }\r\n    }\r\n    let installFolders = be.config.install.dump.folders ?? ['install']\r\n    let texts = await Promise.all(\r\n        [\r\n            ['prepare.sql'],\r\n            ['pre-adapt.sql'].concat(be.config.install.dump.scripts['pre-adapt']),\r\n            ['adapt.sql'],\r\n            be.config.install.dump.scripts['prepare'] ?? [],\r\n            be.config.install.dump.scripts['post-adapt'] ?? []\r\n        ]\r\n        .map(async function(fileNames){\r\n            if (!fileNames) return '';\r\n            var i = 0; \r\n            return (await Promise.all(fileNames.map(async fileName => {\r\n                var content;\r\n                do {\r\n                    var folder = installFolders[i];\r\n                    try{\r\n                        content = await fs.readFile(be.rootPath+'/'+folder+'/'+fileName, {encoding:'UTF8'});\r\n                    } catch (err) {\r\n                        if(err.code!='ENOENT') throw err;\r\n                    }\r\n                    i++;\r\n                } while (i < installFolders.length && !content);\r\n                if (!content) {\r\n                    return '-- no '+fileName+'\\n';\r\n                } else {\r\n                    return '-- '+folder+'/'+fileName+'\\n'+content;\r\n                };\r\n            }))).join('\\n')\r\n        })\r\n    );\r\n\r\n    var common = (await Promise.all(be.appStack.map(async function(stackNode){\r\n        var common = [];\r\n        for (var prefix of ['../', '../../']) {\r\n            try {\r\n                var dirName = Path.join(stackNode.path,prefix+'install').replace(regexpDistReplacer,'$1$2')\r\n                var list = await fs.readdir(dirName);\r\n            } catch (err) {\r\n                if (err.code != 'ENOENT') throw err;\r\n                var list = [];\r\n            }\r\n            for(var fileName of list){\r\n                if (fileName.endsWith('-fun.sql') && !opts?.commonFunsToDisable?.includes(fileName)) {\r\n                    common.push(await fs.readFile(Path.join(dirName,fileName), 'utf-8'));\r\n                }\r\n            }\r\n        }\r\n        return common.join('\\n');\r\n    }))).join('\\n');\r\n\r\n    var prepareList=(be.config.install.dump.scripts['prepare']||[]);\r\n    var mainSql=(\r\n        (complete? linesCreate.join('\\n'): '')+\r\n        (complete||opts.forDump? searchPathline.join('\\n'): '')+\r\n        '\\n-- common'+\r\n        common+'\\n'+\r\n        control+'\\n'+\r\n        (complete? '\\n\\n--prepare.sql\\n'+ texts[0]+'\\n\\n' :'' )+\r\n        (complete? texts[3] + '\\n\\n' : '' )+\r\n        '\\n-- functions\\n' + functionLines.join('\\n')+\r\n        '\\n-- lines \\n' + lines.join('\\n')+\r\n        (complete? ('\\n\\n-- pre-ADAPTs\\n'+texts[1]+'\\n\\n') : '' )+\r\n        (complete? ('\\n\\n-- DATA\\n'+ dataText.join('\\n')) : '' )+ \r\n        (complete? ('\\n\\n-- ADAPTs\\n'+ texts[2]+'\\n\\n') : '' )+\r\n        '\\n-- conss\\n' + consLines.join('\\n')+\r\n        '\\n-- FKs\\n' + fkLines.join('\\n')+\r\n        '\\n-- index\\n' + indexLines.join('\\n')+\r\n        '\\n-- policies\\n' + policyLines.join('\\n')+\r\n        (complete? texts[4] + '\\n\\n' : '' )+\r\n        (complete? (be.config.install.dump.enances==='inline'?enancePart:'') :'')\r\n    ).replace(/\\uFEFF/g /*inner BOM replacing*/,'\\n\\n').replace(\r\n        new RegExp(escapeRegExp(db.quoteIdent(be.config.install.dump.db[\"owner4special-scripts\"])),'g'),\r\n        db.quoteIdent(be.config.install.dump.db.owner)\r\n    ).replace(\r\n        new RegExp(escapeRegExp(db.quoteIdent(be.config.install.dump.db[\"user4special-scripts\"])),'g'),\r\n        db.quoteIdent(be.config.db.user)\r\n    );\r\n    if(be.config.install.dump.db[\"apply-generic-user-replaces\"]){\r\n        mainSql=mainSql.replace(/((\\bto\\s|=)\\s*\"?)\\w+(_user\\b)/ig, \"$1\"+user);\r\n        mainSql=mainSql.replace(/((\\bto\\s|=)\\s*\"?)\\w+(_owner\\b)/ig, \"$1\"+owner);\r\n    }\r\n    return {mainSql,enancePart};\r\n}\r\n\r\nAppBackend.prototype.getDbFunctions = async function (){\r\n    return [];\r\n}\r\n\r\n/** @param {{complete:boolean, tableNames:string[]}} opts */\r\nAppBackend.prototype.dumpDbSchema = async function dumpDbSchema(opts){\r\n    var be = this;\r\n    var {mainSql,enancePart} = await be.dumpDbSchemaPartial(\r\n        opts.complete?be.tableStructures:likeAr(be.tableStructures).filter((_, name)=>opts.tableNames.includes(name)), \r\n        opts\r\n    )\r\n    mainSql=be.config.install.dump.db.extensions.map(function(extension){\r\n        return ({\r\n            gist: \"create extension if not exists btree_gist;\",\r\n            pg_trgm: \"create extension if not exists pg_trgm;\",\r\n            pgcrypto: \"create extension if not exists pgcrypto;\"\r\n        }[extension]||('--unknown exension '+extension))+'\\n';\r\n    }).join('')+mainSql;\r\n    await fs.writeFile('local-db-dump.sql', mainSql);\r\n    if(be.config.install.dump.enances==='file'){\r\n        await fs.writeFile('local-db-dump-enances.sql', enancePart);\r\n    }\r\n};\r\n\r\nAppBackend.prototype.getDataDumpTransformations = function getDataDumpTransformations(rawData){\r\n    return Promise.resolve({rawData, prepareTransformationSql:[], endTransformationSql:[]});\r\n}\r\n\r\nAppBackend.prototype.queryValuesOfUniqueRow = function queryValuesOfUniqueRow(context, defTable, pkValues){\r\n    var be=this;\r\n    return context.client.query(\r\n        \"SELECT \"+defTable.sql.select.join(', ')+\r\n        \" FROM \"+defTable.sql.from.replace(/\\/\\*\\{insertIfNotUpdate:[^}]*\\}\\*\\//gm,' true ')+\r\n        \" WHERE \"+defTable.primaryKey.map(function(fieldName, i){\r\n            return be.db.quoteIdent(defTable.alias)+'.'+be.db.quoteIdent(fieldName)+\" = $\"+(i+1);\r\n        }).join(\" AND \"),\r\n        defTable.primaryKey.map(function(fieldName, i){\r\n            return pkValues[fieldName];\r\n        })\r\n    ).fetchUniqueRow().then(function(result){\r\n        return result;\r\n    });\r\n};\r\n\r\n/** @param {{complete:boolean, tableNames:string[]}} opts */\r\nAppBackend.prototype.dumpDb = function dumpDb(opts){\r\n    if(!this.fieldDomain){\r\n        this.fieldDomain={};\r\n    }\r\n    return Promise.all([\r\n        this.dumpDbCreateDatabase(),\r\n        this.dumpDbSchema(opts)\r\n    ]);\r\n};\r\n\r\nAppBackend.prototype.inputTransformers={\r\n    keepAll:{},\r\n    normal:{\r\n        replaceNewLines:' ',\r\n        simplificateSpaces:true\r\n    },\r\n    upper:{\r\n        replaceNewLines:' ',\r\n        simplificateSpaces:true,\r\n        fun:t=>t.toLocaleUpperCase()\r\n    }\r\n}\r\n\r\nAppBackend.prototype.transformInput = function transformInput(fieldDef, value){\r\n    var be = this;\r\n    if(fieldDef.typeName == 'text'){\r\n        var idTransformer = fieldDef.transformer ?? be.config.data.transformers.text;\r\n        var parameters = be.inputTransformers[idTransformer] ?? idTransformer ?? {}\r\n        if(value != null){\r\n            if(parameters.replaceNewLines != null){\r\n                value = value.replace(/\\r|\\n/g,' ').trim()\r\n            }\r\n            if(parameters.simplificateSpaces){\r\n                value = value.replace(/(\\s|\\u00A0)+/g,' ').trim()\r\n            }\r\n            if(parameters.fun){\r\n                value = parameters.fun(value)\r\n            }\r\n        }\r\n    }\r\n    return value;\r\n}\r\n\r\n/** \r\n * xxxparam {{ action:string, parameters:any, conRegistro:boolean, conPadron:boolean, fileName?:string, csvFileName?:string, csvSeparator?:string, queries:{titulo:string, sql:string, params:string[]}[] }}\r\n * @param {{title:string, rows:Record<string, any>[]}[]} result\r\n * @returns {Promise<void>}\r\n */\r\n\r\nAppBackend.prototype.exportacionesGenerico = async function exportacionesGenerico(result, procedureDef, context, params, files){\r\n    var {csvFileName, fileName} = procedureDef.forExport\r\n    if (!(result instanceof Array)) {\r\n        if (!result || !(result instanceof Object)) {\r\n            throw new Error (\"exportacionesGenerico debe recibir {title:string, rows:Record<string, any>[]}[]\")\r\n        }\r\n        result = [result]\r\n    }\r\n    if (typeof result[0].title !== \"string\" || typeof result[0].rows !== \"object\" && !(result[0].rows instanceof Array) ) {\r\n        throw new Error (\"exportacionesGenerico debe recibir {title:string, rows:Record<string, any>[]}\")\r\n    }\r\n    csvFileName = result[0].csvFileName ?? csvFileName;\r\n    fileName = result[0].fileName ?? fileName;\r\n    await bestGlobals.sleep(100);\r\n    context.informProgress({message:`buscando archivos recién generados`})\r\n    /** @type {{url:string, label:string}[]} */\r\n    var hayGenerados = [];\r\n    const MINUTESms = 60*1000;\r\n    var buscarGenerados = async (name) => {\r\n        if(name){\r\n            try{\r\n                var stat = await fs.stat(`dist/client/${name}`);\r\n                if(stat && stat.mtimeMs > new Date().getTime() - 10 * MINUTESms){\r\n                    hayGenerados.push(\r\n                        {url:name, label:name+' generado '+stat.mtime.toLocaleDateString(\"es-ES\")}\r\n                    )\r\n                }\r\n            }catch(err){\r\n                var code = err.code\r\n                if(code != 'ENOENT') throw err;\r\n            }\r\n        }\r\n    }\r\n    if (!procedureDef.forExport.generarInmediato) {\r\n        await buscarGenerados(csvFileName);\r\n        await buscarGenerados(fileName);\r\n    }\r\n    if(hayGenerados.length>0){\r\n        return hayGenerados;\r\n    }\r\n    await bestGlobals.sleep(100);\r\n    if(csvFileName){\r\n        async function writeLine(f, values){\r\n            return f.write(values.map(function q(value){\r\n                if(value==null) return '';\r\n                if(value instanceof Date){\r\n                    return value.toLocaleDateString(\"es-ES\");\r\n                }\r\n                // @ts-expect-error no reconoce el parámetro\r\n                value = value.toLocaleString(\"es-ES\")\r\n                if(/[,\"]/.test(value)){\r\n                    return '\"'+value.replace(/\"/g, '\"\"')+'\"'\r\n                }else{\r\n                    return value\r\n                }\r\n            }).join(',')+\"\\n\", null, 'utf-8');\r\n        }\r\n        context.informProgress({message:`guardando CSV: ${csvFileName}`})\r\n        try {\r\n            var f = await fsP.open(`dist/client/${csvFileName}`,'w')\r\n            await f.write('\\ufeff',null,'utf-8');\r\n            if (result[0].rows.length) {\r\n                await writeLine(f,Object.keys(result[0].rows[0]))\r\n            } else {\r\n                await writeLine(f,['no data']);\r\n            }\r\n            for (var row of result[0].rows) {\r\n                await writeLine(f,Object.values(row));\r\n            }\r\n        } finally {\r\n            await f.close();\r\n        }\r\n    }\r\n    if(fileName){\r\n        context.informProgress({message:'armando XLSX'})\r\n        var wb = XLSX.utils.book_new();\r\n        result.map(({title, rows})=>{\r\n            var rowsA = rows.map(row=>Object.values(row));\r\n            if(rows[0]){\r\n                rowsA.unshift(Object.keys(rows[0]));\r\n            }\r\n            var ws = XLSX.utils.aoa_to_sheet(rowsA);\r\n            XLSX.utils.book_append_sheet(wb, ws, title);\r\n            return ws;\r\n        })\r\n        context.informProgress({message:`guardando XLSX: ${fileName}`})\r\n        await bestGlobals.sleep(100);\r\n        await new Promise((resolve,reject)=>XLSX.writeFileAsync(`dist/client/${fileName}`,wb,{},\r\n            (err)=>err?reject(err):resolve()\r\n        ))\r\n    }\r\n    return [\r\n        ...(fileName?[{url:fileName, label:csvFileName?'xlsx de control':fileName}]:[]), \r\n        ...(csvFileName?[{url:csvFileName, label:fileName?'csv (formato UTF-8)':csvFileName}]:[]),\r\n    ];\r\n}\r\n\r\n\r\nbackendPlus.AppBackend = AppBackend;\r\nbackendPlus.require_resolve = require_resolve;\r\n\r\nmodule.exports = backendPlus;\r\n"]}