backend-plus 2.5.13 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1593,6 +1593,7 @@ AppBackend.prototype.checkDatabaseStructure = async function checkDatabaseStruct
1593
1593
 
1594
1594
  AppBackend.prototype.postConfig = function postConfig(){
1595
1595
  this.fieldDomain={};
1596
+ this.scanSkinFiles();
1596
1597
  };
1597
1598
 
1598
1599
  AppBackend.prototype.getContext = function getContext(req){
@@ -2492,7 +2493,52 @@ AppBackend.prototype.csss = function csss(hideBEPlusInclusions){
2492
2493
  return this.clientIncludesCompleted(null, hideBEPlusInclusions).filter(x => x.type == 'css').map(x => x.href);
2493
2494
  };
2494
2495
 
2496
+ AppBackend.prototype.scanSkinFiles = function scanSkinFiles() {
2497
+ var be = this;
2498
+ var skinName = be.config['client-setup'].skin;
2499
+ be.activeSkinFiles = new Set();
2500
+
2501
+ var skinConfig = be.config.server.skins && be.config.server.skins[skinName];
2502
+
2503
+ if (skinConfig && skinConfig['local-path']) {
2504
+ try {
2505
+ var skinPath = Path.join(Path.resolve(skinConfig['local-path']), skinName);
2506
+
2507
+ if (fs.existsSync(skinPath)) {
2508
+
2509
+ const walk = (currentPath) => {
2510
+ const entries = fs.readdirSync(currentPath, { withFileTypes: true });
2511
+
2512
+ for (var i = 0; i < entries.length; i++) {
2513
+ var entry = entries[i];
2514
+ var fullPath = Path.join(currentPath, entry.name);
2515
+
2516
+ if (entry.isDirectory()) {
2517
+ walk(fullPath);
2518
+ } else if (entry.isFile()) {
2519
+ if (entry.name.endsWith('.css') || entry.name.endsWith('.styl')) {
2520
+ var relativePath = Path.relative(skinPath, fullPath)
2521
+ .replace(/\\/g, '/')
2522
+ .replace(/^\//, '');
2523
+
2524
+ be.activeSkinFiles.add(relativePath);
2525
+ }
2526
+ }
2527
+ }
2528
+ };
2529
+
2530
+ walk(skinPath);
2531
+ } else {
2532
+ console.warn(`[SKIN SCAN] No existe la carpeta del skin: ${skinPath}`);
2533
+ }
2534
+ } catch (err) {
2535
+ console.error("[SKIN SCAN] Error al inicializar:", err);
2536
+ }
2537
+ }
2538
+ };
2539
+
2495
2540
  AppBackend.prototype.mainPage = function mainPage(req, offlineMode, opts){
2541
+ var be = this;
2496
2542
  opts = opts||{};
2497
2543
  if(!opts.icons){
2498
2544
  if(!opts.icon){
@@ -2555,9 +2601,22 @@ AppBackend.prototype.mainPage = function mainPage(req, offlineMode, opts){
2555
2601
  ].concat(cssList.map(function(css){
2556
2602
  return html.link({href: css, rel: "stylesheet"});
2557
2603
  })).concat(cssList.map(function(css){
2558
- var skin=be.config['client-setup'].skin;
2559
- var skinUrl=(skin?skin+'/':'');
2560
- return skin?html.link({href: skinUrl+css, rel: "stylesheet"}):null;
2604
+ const EXTENSIONES_SKIN = ['.css', '.styl'];
2605
+ var skin = be.config['client-setup'].skin;
2606
+ if(!skin || !be.activeSkinFiles) return null;
2607
+
2608
+ var lastDotIndex = css.lastIndexOf('.');
2609
+ var cssBase = (lastDotIndex !== -1) ? css.substring(0, lastDotIndex) : css;
2610
+
2611
+ var existsInSkin = EXTENSIONES_SKIN.some(function(ext) {
2612
+ return be.activeSkinFiles.has(cssBase + ext);
2613
+ });
2614
+
2615
+ if (existsInSkin) {
2616
+ var skinUrl = skin + '/';
2617
+ return html.link({href: skinUrl + css, rel: "stylesheet"});
2618
+ }
2619
+ return null;
2561
2620
  }))),
2562
2621
  html.body({'app-version':packagejson.version},[
2563
2622
  html.div({id: "total-layout"}, [
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "backend-plus",
3
3
  "description": "Backend for the anti Pareto rule",
4
- "version": "2.5.13",
4
+ "version": "2.6.1",
5
5
  "author": "Codenautas <codenautas@googlegroups.com>",
6
6
  "license": "MIT",
7
7
  "repository": "codenautas/backend-plus",
@@ -31,7 +31,7 @@
31
31
  "dependencies": {
32
32
  "@upgraded/locate-path": "^6.0.0-alfa.1",
33
33
  "ajax-best-promise": "^0.4.3",
34
- "backend-skins": "^0.1.33",
34
+ "backend-skins": "^0.1.34",
35
35
  "best-globals": "^2.0.7",
36
36
  "big.js": "^7.0.1",
37
37
  "body-parser": "^2.2.2",
@@ -45,7 +45,7 @@
45
45
  "express": "^5.2.1",
46
46
  "express-session": "^1.19.0",
47
47
  "express-useragent": "^2.1.0",
48
- "fs-extra": "^11.3.3",
48
+ "fs-extra": "^11.3.4",
49
49
  "js-to-html": "^1.3.5",
50
50
  "js-yaml": "^4.1.1",
51
51
  "json4all": "^1.4.2",
@@ -56,19 +56,19 @@
56
56
  "mini-tools": "^1.13.5",
57
57
  "moment": "^2.30.1",
58
58
  "multiparty": "^4.2.3",
59
- "nodemailer": "^7.0.13",
59
+ "nodemailer": "^8.0.4",
60
60
  "numeral": "^2.0.6",
61
61
  "pg-promise-strict": "^1.4.5",
62
62
  "pg-triggers": "0.4.6",
63
63
  "pikaday": "^1.8.2",
64
- "pug": "^3.0.3",
64
+ "pug": "^3.0.4",
65
65
  "read-yaml-promise": "^1.0.2",
66
66
  "regexplicit": "^0.1.3",
67
67
  "require-bro": "^0.3.4",
68
68
  "self-explain": "^0.11.0",
69
69
  "serve-content": "^1.0.4",
70
70
  "session-file-store": "^1.5.0",
71
- "simple-git": "^3.30.0",
71
+ "simple-git": "^3.33.0",
72
72
  "sql-tools": "^0.1.7",
73
73
  "stack-trace": "^0.0.10",
74
74
  "stylus": "0.64.0",
@@ -85,8 +85,8 @@
85
85
  "@types/js-yaml": "^4.0.9",
86
86
  "@types/mocha": "^10.0.10",
87
87
  "@types/multiparty": "~4.2.1",
88
- "@types/node": "^25.2.0",
89
- "@types/nodemailer": "^7.0.9",
88
+ "@types/node": "^25.5.0",
89
+ "@types/nodemailer": "^7.0.11",
90
90
  "@types/numeral": "~2.0.5",
91
91
  "@types/session-file-store": "^1.2.6",
92
92
  "@types/stack-trace": "~0.0.33",
@@ -101,9 +101,9 @@
101
101
  "karma-mocha": "^2.0.1",
102
102
  "kill-9": "~0.4.3",
103
103
  "mocha": "^11.7.5",
104
- "nyc": "^17.1.0",
105
- "puppeteer": "^24.36.1",
106
- "sinon": "^21.0.1",
104
+ "nyc": "^18.0.0",
105
+ "puppeteer": "^24.40.0",
106
+ "sinon": "^21.0.3",
107
107
  "supertest": "^7.2.2",
108
108
  "types.d.ts": "~0.6.22",
109
109
  "typescript": "^5.9.3",
@@ -68,26 +68,44 @@ myAjax.parseStrCookies = function parseStrCookies(cookieString, prefix){
68
68
 
69
69
  myAjax.readProcedureDefinitions=function readProcedureDefinitions(){
70
70
  var my = this;
71
- var promise;
72
- var getStored=function(setupOrError){
73
- if(setupOrError && !(setupOrError instanceof Error) && !setupOrError.isoffline){
74
- localStorage.setItem('setup', JSON.stringify(setupOrError));
71
+ const NETWORK_TIMEOUT = 1800;
72
+ var cachedSetupStr = my.getLocalVar('setup');
73
+
74
+ var getStored = function(setupOrError) {
75
+ if (setupOrError && !(setupOrError instanceof Error) && !setupOrError.isoffline) {
76
+ my.setLocalVar('setup', setupOrError);
75
77
  return setupOrError;
76
78
  }
77
- var setupJson=localStorage.getItem('setup');
78
- if(setupJson){
79
- return JSON.parse(setupJson);
79
+ if (cachedSetupStr) {
80
+ console.warn('setup obtenido de cache')
81
+ return cachedSetupStr;
80
82
  }
81
- throw new Error("NOT CLIENT-CONFIGURED")
83
+ var finalError = setupOrError instanceof Error ? setupOrError : new Error("NOT CLIENT-CONFIGURED");
84
+ throw finalError;
85
+ };
86
+
87
+ var networkPromise = my.ajaxPromise({
88
+ action: 'client-setup',
89
+ method: 'get',
90
+ encoding: 'JSON',
91
+ parameters: [],
92
+ progress: false
93
+ });
94
+
95
+ var promise;
96
+
97
+ if (cachedSetupStr) {
98
+ var timeoutPromise = new Promise(function(_, reject) {
99
+ setTimeout(function() {
100
+ reject(new Error("NETWORK_TIMEOUT"));
101
+ }, NETWORK_TIMEOUT);
102
+ });
103
+ promise = Promise.race([networkPromise, timeoutPromise]);
104
+ } else {
105
+ promise = networkPromise;
82
106
  }
83
- promise = my.ajaxPromise({
84
- action:'client-setup',
85
- method:'get',
86
- encoding:'JSON',
87
- parameters:[],
88
- progress:false
89
- }).then(getStored, getStored);
90
- return promise.then(function(setup){
107
+
108
+ return promise.then(getStored,getStored).then(function(setup){
91
109
  my.config = setup;
92
110
  if(typeof document !== "undefined"){
93
111
  var backgroundUrl