@underpostnet/underpost 3.0.3 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{.env.production → .env.example} +20 -2
- package/.github/workflows/ghpkg.ci.yml +1 -1
- package/.github/workflows/gitlab.ci.yml +1 -1
- package/.github/workflows/npmpkg.ci.yml +22 -7
- package/.github/workflows/publish.ci.yml +5 -5
- package/.github/workflows/pwa-microservices-template-page.cd.yml +3 -3
- package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
- package/.github/workflows/release.cd.yml +3 -2
- package/.vscode/extensions.json +9 -8
- package/.vscode/settings.json +3 -2
- package/CHANGELOG.md +146 -1
- package/CLI-HELP.md +71 -52
- package/README.md +2 -2
- package/bin/build.js +4 -1
- package/bin/deploy.js +150 -208
- package/bin/file.js +2 -1
- package/bin/vs.js +3 -3
- package/conf.js +30 -13
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +52 -52
- package/manifests/deployment/dd-test-development/proxy.yaml +4 -4
- package/manifests/pv-pvc-dd.yaml +1 -1
- package/package.json +48 -43
- package/scripts/k3s-node-setup.sh +1 -1
- package/src/api/document/document.service.js +1 -1
- package/src/api/file/file.controller.js +3 -1
- package/src/api/file/file.service.js +28 -5
- package/src/api/user/user.router.js +10 -5
- package/src/api/user/user.service.js +7 -7
- package/src/cli/baremetal.js +6 -10
- package/src/cli/cloud-init.js +0 -3
- package/src/cli/db.js +54 -71
- package/src/cli/deploy.js +64 -12
- package/src/cli/env.js +4 -4
- package/src/cli/fs.js +0 -2
- package/src/cli/image.js +0 -3
- package/src/cli/index.js +27 -13
- package/src/cli/monitor.js +5 -6
- package/src/cli/repository.js +322 -35
- package/src/cli/run.js +118 -69
- package/src/cli/secrets.js +0 -3
- package/src/cli/ssh.js +1 -1
- package/src/client/components/core/AgGrid.js +20 -5
- package/src/client/components/core/Content.js +22 -3
- package/src/client/components/core/Docs.js +21 -4
- package/src/client/components/core/FileExplorer.js +71 -4
- package/src/client/components/core/Input.js +1 -1
- package/src/client/components/core/Modal.js +20 -6
- package/src/client/public/default/sitemap +3 -3
- package/src/client/public/test/sitemap +3 -3
- package/src/client.build.js +0 -3
- package/src/client.dev.js +0 -3
- package/src/db/DataBaseProvider.js +17 -2
- package/src/db/mariadb/MariaDB.js +14 -9
- package/src/db/mongo/MongooseDB.js +17 -1
- package/src/index.js +1 -1
- package/src/proxy.js +0 -3
- package/src/runtime/express/Express.js +7 -1
- package/src/runtime/lampp/Lampp.js +6 -13
- package/src/server/auth.js +6 -9
- package/src/server/backup.js +2 -3
- package/src/server/client-build-docs.js +178 -3
- package/src/server/client-build-live.js +9 -18
- package/src/server/client-build.js +175 -38
- package/src/server/client-dev-server.js +14 -13
- package/src/server/conf.js +357 -149
- package/src/server/cron.js +2 -1
- package/src/server/dns.js +28 -12
- package/src/server/downloader.js +0 -2
- package/src/server/logger.js +27 -9
- package/src/server/peer.js +0 -2
- package/src/server/process.js +1 -50
- package/src/server/proxy.js +4 -8
- package/src/server/runtime.js +5 -8
- package/src/server/ssr.js +0 -3
- package/src/server/start.js +5 -5
- package/src/server/tls.js +0 -2
- package/src/server.js +0 -4
- package/.env.development +0 -43
- package/.env.test +0 -43
|
@@ -544,10 +544,13 @@ const FileExplorer = {
|
|
|
544
544
|
this.eGui = document.createElement('div');
|
|
545
545
|
const isPublic = params.data.isPublic;
|
|
546
546
|
const toggleId = `toggle-public-${params.data._id}`;
|
|
547
|
+
const hasGenericFile = !!params.data.hasGenericFile;
|
|
548
|
+
const hasMdFile = !!params.data.hasMdFile;
|
|
549
|
+
|
|
547
550
|
this.eGui.innerHTML = html`
|
|
548
551
|
<div class="fl">
|
|
549
552
|
${await BtnIcon.Render({
|
|
550
|
-
class: `in fll management-table-btn-mini btn-file-download-${params.data._id}`,
|
|
553
|
+
class: `in fll management-table-btn-mini btn-file-download-${params.data._id}${!hasGenericFile ? ' btn-disabled' : ''}`,
|
|
551
554
|
label: html` <i class="fas fa-download"></i>`,
|
|
552
555
|
type: 'button',
|
|
553
556
|
})}
|
|
@@ -562,10 +565,15 @@ const FileExplorer = {
|
|
|
562
565
|
type: 'button',
|
|
563
566
|
})}
|
|
564
567
|
${await BtnIcon.Render({
|
|
565
|
-
class: `in fll management-table-btn-mini btn-file-copy-content-link-${params.data._id}`,
|
|
568
|
+
class: `in fll management-table-btn-mini btn-file-copy-content-link-${params.data._id}${!hasGenericFile ? ' btn-disabled' : ''}`,
|
|
566
569
|
label: html`<i class="fas fa-copy"></i>`,
|
|
567
570
|
type: 'button',
|
|
568
571
|
})}
|
|
572
|
+
${await BtnIcon.Render({
|
|
573
|
+
class: `in fll management-table-btn-mini btn-file-copy-md-link-${params.data._id}${!hasMdFile ? ' btn-disabled' : ''}`,
|
|
574
|
+
label: html`<i class="fas fa-file-code"></i>`,
|
|
575
|
+
type: 'button',
|
|
576
|
+
})}
|
|
569
577
|
${await BtnIcon.Render({
|
|
570
578
|
class: `in fll management-table-btn-mini btn-file-edit-${params.data._id}`,
|
|
571
579
|
label: html`<i class="fas fa-edit"></i>`,
|
|
@@ -591,11 +599,46 @@ const FileExplorer = {
|
|
|
591
599
|
? getApiBaseUrl({ id: originObj.fileId._id, endpoint: 'file/blob' })
|
|
592
600
|
: undefined;
|
|
593
601
|
|
|
602
|
+
const mdBlobUri =
|
|
603
|
+
originObj && originObj.mdFileId
|
|
604
|
+
? getApiBaseUrl({ id: originObj.mdFileId._id, endpoint: 'file/blob' })
|
|
605
|
+
: undefined;
|
|
606
|
+
|
|
594
607
|
if (!originObj) {
|
|
595
608
|
s(`.btn-file-view-${params.data._id}`).classList.add('hide');
|
|
596
609
|
s(`.btn-file-copy-content-link-${params.data._id}`).classList.add('hide');
|
|
597
610
|
}
|
|
598
611
|
|
|
612
|
+
// Disable download button if no generic file
|
|
613
|
+
if (!hasGenericFile) {
|
|
614
|
+
const dlBtn = s(`.btn-file-download-${params.data._id}`);
|
|
615
|
+
if (dlBtn) {
|
|
616
|
+
dlBtn.style.opacity = '0.4';
|
|
617
|
+
dlBtn.style.cursor = 'not-allowed';
|
|
618
|
+
dlBtn.style.pointerEvents = 'none';
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// Disable copy generic file link button if no generic file
|
|
623
|
+
if (!hasGenericFile) {
|
|
624
|
+
const copyBtn = s(`.btn-file-copy-content-link-${params.data._id}`);
|
|
625
|
+
if (copyBtn) {
|
|
626
|
+
copyBtn.style.opacity = '0.4';
|
|
627
|
+
copyBtn.style.cursor = 'not-allowed';
|
|
628
|
+
copyBtn.style.pointerEvents = 'none';
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// Disable copy md file link button if no md file
|
|
633
|
+
if (!hasMdFile) {
|
|
634
|
+
const mdCopyBtn = s(`.btn-file-copy-md-link-${params.data._id}`);
|
|
635
|
+
if (mdCopyBtn) {
|
|
636
|
+
mdCopyBtn.style.opacity = '0.4';
|
|
637
|
+
mdCopyBtn.style.cursor = 'not-allowed';
|
|
638
|
+
mdCopyBtn.style.pointerEvents = 'none';
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
599
642
|
EventsUI.onClick(`.btn-file-view-${params.data._id}`, async (e) => {
|
|
600
643
|
e.preventDefault();
|
|
601
644
|
if (location.href !== url) {
|
|
@@ -606,6 +649,7 @@ const FileExplorer = {
|
|
|
606
649
|
|
|
607
650
|
EventsUI.onClick(`.btn-file-copy-content-link-${params.data._id}`, async (e) => {
|
|
608
651
|
e.preventDefault();
|
|
652
|
+
if (!hasGenericFile || !blobUri) return;
|
|
609
653
|
await copyData(blobUri);
|
|
610
654
|
NotificationManager.Push({
|
|
611
655
|
html: Translate.Render('success-copy-data'),
|
|
@@ -613,10 +657,21 @@ const FileExplorer = {
|
|
|
613
657
|
});
|
|
614
658
|
});
|
|
615
659
|
|
|
660
|
+
EventsUI.onClick(`.btn-file-copy-md-link-${params.data._id}`, async (e) => {
|
|
661
|
+
e.preventDefault();
|
|
662
|
+
if (!hasMdFile || !mdBlobUri) return;
|
|
663
|
+
await copyData(mdBlobUri);
|
|
664
|
+
NotificationManager.Push({
|
|
665
|
+
html: Translate.Render('success-copy-data'),
|
|
666
|
+
status: 'success',
|
|
667
|
+
});
|
|
668
|
+
});
|
|
669
|
+
|
|
616
670
|
EventsUI.onClick(`.btn-file-download-${params.data._id}`, async (e) => {
|
|
617
671
|
e.preventDefault();
|
|
672
|
+
if (!hasGenericFile) return;
|
|
618
673
|
try {
|
|
619
|
-
// Use FileService with blob/ prefix for
|
|
674
|
+
// Use FileService with blob/ prefix for blob fetching
|
|
620
675
|
const { data: blobArray, status } = await FileService.get({ id: `blob/${params.data.fileId}` });
|
|
621
676
|
if (status === 'success' && blobArray && blobArray[0]) {
|
|
622
677
|
downloadFile(blobArray[0], params.data.name);
|
|
@@ -721,6 +776,12 @@ const FileExplorer = {
|
|
|
721
776
|
documentInstance[docIndex].isPublic = data.isPublic;
|
|
722
777
|
}
|
|
723
778
|
|
|
779
|
+
// Refresh the isPublic column cell in the grid
|
|
780
|
+
const rowNode = AgGrid.grids[gridFileId].getRowNode(params.node.id);
|
|
781
|
+
if (rowNode) {
|
|
782
|
+
rowNode.setDataValue('isPublic', data.isPublic);
|
|
783
|
+
}
|
|
784
|
+
|
|
724
785
|
// Update button icon
|
|
725
786
|
const btnElement = s(`.${toggleId}`);
|
|
726
787
|
if (btnElement) {
|
|
@@ -1347,7 +1408,13 @@ const FileExplorer = {
|
|
|
1347
1408
|
{ field: 'name', flex: 2, headerName: 'Title', cellRenderer: LoadFileNameRenderer },
|
|
1348
1409
|
{ field: 'mdFileName', flex: 1, headerName: 'MD File Name' },
|
|
1349
1410
|
{ field: 'fileName', flex: 1, headerName: 'Generic File Name' },
|
|
1350
|
-
{
|
|
1411
|
+
{
|
|
1412
|
+
field: 'isPublic',
|
|
1413
|
+
headerName: 'Public',
|
|
1414
|
+
width: 90,
|
|
1415
|
+
cellDataType: 'boolean',
|
|
1416
|
+
},
|
|
1417
|
+
{ headerName: '', width: 180, cellRenderer: LoadFileActionsRenderer },
|
|
1351
1418
|
],
|
|
1352
1419
|
},
|
|
1353
1420
|
})}
|
|
@@ -101,7 +101,7 @@ const getFileFromFileData = (fileData) => {
|
|
|
101
101
|
/**
|
|
102
102
|
* Fetch file content from blob endpoint and create File object.
|
|
103
103
|
* Used for metadata-only format files during edit mode.
|
|
104
|
-
* Uses FileService with blob/ prefix for
|
|
104
|
+
* Uses FileService with blob/ prefix for blob fetching.
|
|
105
105
|
*
|
|
106
106
|
* @async
|
|
107
107
|
* @function getFileFromBlobEndpoint
|
|
@@ -2424,20 +2424,34 @@ const Modal = {
|
|
|
2424
2424
|
},
|
|
2425
2425
|
};
|
|
2426
2426
|
|
|
2427
|
-
const renderMenuLabel = ({ img, text, icon }) => {
|
|
2428
|
-
if (!img) return html`<span class="inl menu-btn-icon">${icon}</span> ${text}`;
|
|
2429
|
-
|
|
2427
|
+
const renderMenuLabel = ({ img, src, text, icon }) => {
|
|
2428
|
+
if (!img && !src) return html`<span class="inl menu-btn-icon">${icon}</span> ${text}`;
|
|
2429
|
+
const imgSrc = src ? src : `${getProxyPath()}assets/ui-icons/${img}`;
|
|
2430
|
+
return html`<img class="abs center img-btn-square-menu" src="${imgSrc}" />
|
|
2430
2431
|
<div class="abs center main-btn-menu-text">${text}</div>`;
|
|
2431
2432
|
};
|
|
2432
2433
|
|
|
2433
2434
|
const renderViewTitle = (
|
|
2434
|
-
options = {
|
|
2435
|
+
options = {
|
|
2436
|
+
icon: '',
|
|
2437
|
+
img: '',
|
|
2438
|
+
text: '',
|
|
2439
|
+
assetFolder: '',
|
|
2440
|
+
'ui-icon': '',
|
|
2441
|
+
imgClass: '',
|
|
2442
|
+
textClass: '',
|
|
2443
|
+
dim,
|
|
2444
|
+
top,
|
|
2445
|
+
topText: '',
|
|
2446
|
+
},
|
|
2435
2447
|
) => {
|
|
2436
2448
|
if (options.dim === undefined) options.dim = 30;
|
|
2437
2449
|
const { img, text, icon, dim, top } = options;
|
|
2438
2450
|
if (!img && !options['ui-icon']) return html`<span class="view-title-icon">${icon}</span> ${text}`;
|
|
2451
|
+
const imgClass = options.imgClass || 'abs img-btn-square-view-title';
|
|
2452
|
+
const textClass = options.textClass || 'in text-btn-square-view-title';
|
|
2439
2453
|
return html`<img
|
|
2440
|
-
class="
|
|
2454
|
+
class="${imgClass}"
|
|
2441
2455
|
style="${renderCssAttr({
|
|
2442
2456
|
style: {
|
|
2443
2457
|
width: `${dim}px`,
|
|
@@ -2450,7 +2464,7 @@ const renderViewTitle = (
|
|
|
2450
2464
|
: img}"
|
|
2451
2465
|
/>
|
|
2452
2466
|
<div
|
|
2453
|
-
class="
|
|
2467
|
+
class="${textClass}"
|
|
2454
2468
|
style="${renderCssAttr({
|
|
2455
2469
|
style: {
|
|
2456
2470
|
// 'padding-left': `${20 + dim}px`,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<xsl:stylesheet version="
|
|
2
|
+
<xsl:stylesheet version="1.0"
|
|
3
3
|
xmlns:html="http://www.w3.org/TR/REC-html40"
|
|
4
4
|
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
|
|
5
5
|
xmlns:sitemap="http://www.sitemaps.org/schemas/sitemap/0.9"
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
<div id="content">
|
|
68
68
|
<h1>XML Sitemap</h1>
|
|
69
69
|
<p class="desc"> This is a sitemap generated by <a
|
|
70
|
-
href="
|
|
70
|
+
href="{{web-url}}">{{web-url}}</a>
|
|
71
71
|
</p>
|
|
72
72
|
<xsl:if test="count(sitemap:sitemapindex/sitemap:sitemap) > 0">
|
|
73
73
|
<table id="sitemap" cellpadding="3">
|
|
@@ -145,4 +145,4 @@
|
|
|
145
145
|
</html>
|
|
146
146
|
|
|
147
147
|
</xsl:template>
|
|
148
|
-
</xsl:stylesheet>
|
|
148
|
+
</xsl:stylesheet>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<xsl:stylesheet version="
|
|
2
|
+
<xsl:stylesheet version="1.0"
|
|
3
3
|
xmlns:html="http://www.w3.org/TR/REC-html40"
|
|
4
4
|
xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
|
|
5
5
|
xmlns:sitemap="http://www.sitemaps.org/schemas/sitemap/0.9"
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
<div id="content">
|
|
68
68
|
<h1>XML Sitemap</h1>
|
|
69
69
|
<p class="desc"> This is a sitemap generated by <a
|
|
70
|
-
href="
|
|
70
|
+
href="{{web-url}}">{{web-url}}</a>
|
|
71
71
|
</p>
|
|
72
72
|
<xsl:if test="count(sitemap:sitemapindex/sitemap:sitemap) > 0">
|
|
73
73
|
<table id="sitemap" cellpadding="3">
|
|
@@ -145,4 +145,4 @@
|
|
|
145
145
|
</html>
|
|
146
146
|
|
|
147
147
|
</xsl:template>
|
|
148
|
-
</xsl:stylesheet>
|
|
148
|
+
</xsl:stylesheet>
|
package/src/client.build.js
CHANGED
|
@@ -3,14 +3,11 @@
|
|
|
3
3
|
// https://nodejs.org/api
|
|
4
4
|
// https://expressjs.com/en/4x/api.html
|
|
5
5
|
|
|
6
|
-
import dotenv from 'dotenv';
|
|
7
6
|
import { loggerFactory } from './server/logger.js';
|
|
8
7
|
import { Config } from './server/conf.js';
|
|
9
8
|
import { ProcessController } from './server/process.js';
|
|
10
9
|
import { clientLiveBuild } from './server/client-build-live.js';
|
|
11
10
|
|
|
12
|
-
dotenv.config();
|
|
13
|
-
|
|
14
11
|
await Config.build();
|
|
15
12
|
|
|
16
13
|
const logger = loggerFactory(import.meta);
|
package/src/client.dev.js
CHANGED
|
@@ -3,14 +3,11 @@
|
|
|
3
3
|
// https://nodejs.org/api
|
|
4
4
|
// https://expressjs.com/en/4x/api.html
|
|
5
5
|
|
|
6
|
-
import dotenv from 'dotenv';
|
|
7
6
|
import { loggerFactory } from './server/logger.js';
|
|
8
7
|
import { ProcessController } from './server/process.js';
|
|
9
8
|
import { Config, buildClientStaticConf } from './server/conf.js';
|
|
10
9
|
import { createClientDevServer } from './server/client-dev-server.js';
|
|
11
10
|
|
|
12
|
-
dotenv.config();
|
|
13
|
-
|
|
14
11
|
const logger = loggerFactory(import.meta);
|
|
15
12
|
|
|
16
13
|
await logger.setUpInfo();
|
|
@@ -13,7 +13,7 @@ const logger = loggerFactory(import.meta);
|
|
|
13
13
|
* @class
|
|
14
14
|
* @alias DataBaseProviderService
|
|
15
15
|
* @memberof DataBaseProviderService
|
|
16
|
-
* @classdesc
|
|
16
|
+
* @classdesc Service for loading, managing, and accessing multiple database connections
|
|
17
17
|
* based on application configuration (host, path, provider type).
|
|
18
18
|
*/
|
|
19
19
|
class DataBaseProviderService {
|
|
@@ -81,7 +81,22 @@ class DataBaseProviderService {
|
|
|
81
81
|
}
|
|
82
82
|
return this.#instance[key][db.provider];
|
|
83
83
|
} catch (error) {
|
|
84
|
-
|
|
84
|
+
// Sanitize options to prevent credential exposure in logs
|
|
85
|
+
const safeOptions = {
|
|
86
|
+
apis: options.apis,
|
|
87
|
+
host: options.host,
|
|
88
|
+
path: options.path,
|
|
89
|
+
db: options.db
|
|
90
|
+
? {
|
|
91
|
+
provider: options.db.provider,
|
|
92
|
+
name: options.db.name ? '***' : undefined,
|
|
93
|
+
host: options.db.host ? '***' : undefined,
|
|
94
|
+
user: options.db.user ? '***' : undefined,
|
|
95
|
+
password: options.db.password ? '***' : undefined,
|
|
96
|
+
}
|
|
97
|
+
: {},
|
|
98
|
+
};
|
|
99
|
+
logger.error(error.message, { safeOptions });
|
|
85
100
|
return undefined;
|
|
86
101
|
}
|
|
87
102
|
}
|
|
@@ -16,6 +16,11 @@ const logger = loggerFactory(import.meta);
|
|
|
16
16
|
* @memberof MariaDBService
|
|
17
17
|
* @classdesc Provides a simplified interface for executing queries against a MariaDB/MySQL database
|
|
18
18
|
* using a connection pool, ensuring connection management (acquisition and release).
|
|
19
|
+
*
|
|
20
|
+
* Connection credentials are resolved in the following order:
|
|
21
|
+
* 1. Explicit values passed in the `options` parameter.
|
|
22
|
+
* 2. Environment variables (`MARIADB_HOST`, `MARIADB_PORT`, `MARIADB_USER`, `MARIADB_PASSWORD`).
|
|
23
|
+
* 3. Safe built-in defaults (`127.0.0.1`, `3306`, `root`, empty password).
|
|
19
24
|
*/
|
|
20
25
|
class MariaDBService {
|
|
21
26
|
/**
|
|
@@ -23,20 +28,20 @@ class MariaDBService {
|
|
|
23
28
|
*
|
|
24
29
|
* @async
|
|
25
30
|
* @param {object} options - The database connection and query options.
|
|
26
|
-
* @param {string} [options.host
|
|
27
|
-
* @param {number} [options.port
|
|
28
|
-
* @param {string} [options.user
|
|
29
|
-
* @param {string} [options.password
|
|
31
|
+
* @param {string} [options.host] - The database host. Falls back to `process.env.MARIADB_HOST` then `'127.0.0.1'`.
|
|
32
|
+
* @param {number} [options.port] - The database port. Falls back to `process.env.MARIADB_PORT` then `3306`.
|
|
33
|
+
* @param {string} [options.user] - The database user. Falls back to `process.env.MARIADB_USER` then `'root'`.
|
|
34
|
+
* @param {string} [options.password] - The database password. Falls back to `process.env.MARIADB_PASSWORD` then `''`.
|
|
30
35
|
* @param {string} options.query - The SQL query string to execute.
|
|
31
36
|
* @returns {Promise<any>} The result of the database query.
|
|
32
37
|
*/
|
|
33
38
|
async query(options) {
|
|
34
39
|
const { host, port, user, password, query } = options;
|
|
35
40
|
const pool = createPool({
|
|
36
|
-
host: 'host' in options ? host : '127.0.0.1',
|
|
37
|
-
port: 'port' in options ? port : 3306,
|
|
38
|
-
user: 'user' in options ? user : 'root',
|
|
39
|
-
password: 'password' in options ? password : '',
|
|
41
|
+
host: 'host' in options ? host : process.env.MARIADB_HOST || '127.0.0.1',
|
|
42
|
+
port: 'port' in options ? port : parseInt(process.env.MARIADB_PORT, 10) || 3306,
|
|
43
|
+
user: 'user' in options ? user : process.env.MARIADB_USER || 'root',
|
|
44
|
+
password: 'password' in options ? password : process.env.MARIADB_PASSWORD || '',
|
|
40
45
|
});
|
|
41
46
|
let conn, result;
|
|
42
47
|
try {
|
|
@@ -45,7 +50,7 @@ class MariaDBService {
|
|
|
45
50
|
logger.info('query');
|
|
46
51
|
console.log(result);
|
|
47
52
|
} catch (error) {
|
|
48
|
-
logger.error(
|
|
53
|
+
logger.error('MariaDB query failed', { error: error.message });
|
|
49
54
|
} finally {
|
|
50
55
|
if (conn) conn.release(); // release to pool
|
|
51
56
|
await pool.end();
|
|
@@ -16,17 +16,33 @@ const logger = loggerFactory(import.meta);
|
|
|
16
16
|
* @memberof MongooseDBService
|
|
17
17
|
* @classdesc Manages the Mongoose connection lifecycle and dynamic loading of database models
|
|
18
18
|
* based on API configuration.
|
|
19
|
+
*
|
|
20
|
+
* Connection parameters are resolved in the following order:
|
|
21
|
+
* 1. Explicit values passed as arguments to {@link MongooseDBService#connect}.
|
|
22
|
+
* 2. Environment variables (`DB_HOST` for host, `DB_NAME` for database name).
|
|
23
|
+
* 3. No built-in defaults — both `host` and `name` are required from the caller or environment.
|
|
19
24
|
*/
|
|
20
25
|
class MongooseDBService {
|
|
21
26
|
/**
|
|
22
27
|
* Establishes a Mongoose connection to the specified MongoDB instance.
|
|
23
28
|
*
|
|
24
29
|
* @async
|
|
25
|
-
* @param {string} host - The MongoDB host (e.g., 'mongodb://localhost:27017').
|
|
30
|
+
* @param {string} host - The MongoDB host URI (e.g., `'mongodb://localhost:27017'`).
|
|
31
|
+
* Falls back to `process.env.DB_HOST` when not provided.
|
|
26
32
|
* @param {string} name - The database name.
|
|
33
|
+
* Falls back to `process.env.DB_NAME` when not provided.
|
|
27
34
|
* @returns {Promise<mongoose.Connection>} A promise that resolves to the established Mongoose connection object.
|
|
35
|
+
* @throws {Error} If neither the argument nor the corresponding environment variable supplies a value.
|
|
28
36
|
*/
|
|
29
37
|
async connect(host, name) {
|
|
38
|
+
host = host || process.env.DB_HOST;
|
|
39
|
+
name = name || process.env.DB_NAME;
|
|
40
|
+
|
|
41
|
+
if (!host || !name) {
|
|
42
|
+
const missing = [!host && 'host (DB_HOST)', !name && 'name (DB_NAME)'].filter(Boolean).join(', ');
|
|
43
|
+
throw new Error(`MongooseDBService.connect: missing required parameter(s): ${missing}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
30
46
|
const uri = `${host}/${name}`;
|
|
31
47
|
// logger.info('MongooseDB connect', { host, name, uri });
|
|
32
48
|
return await mongoose
|
package/src/index.js
CHANGED
package/src/proxy.js
CHANGED
|
@@ -3,14 +3,11 @@
|
|
|
3
3
|
// https://nodejs.org/api
|
|
4
4
|
// https://expressjs.com/en/4x/api.html
|
|
5
5
|
|
|
6
|
-
import dotenv from 'dotenv';
|
|
7
6
|
import { loggerFactory } from './server/logger.js';
|
|
8
7
|
import { buildProxy } from './server/proxy.js';
|
|
9
8
|
import { ProcessController } from './server/process.js';
|
|
10
9
|
import { Config } from './server/conf.js';
|
|
11
10
|
|
|
12
|
-
dotenv.config();
|
|
13
|
-
|
|
14
11
|
await Config.build(process.argv[2], process.argv[3], process.argv[4]);
|
|
15
12
|
|
|
16
13
|
const logger = loggerFactory(import.meta);
|
|
@@ -249,7 +249,13 @@ class ExpressService {
|
|
|
249
249
|
for (const [_, ssrMiddleware] of Object.entries(ssr)) app.use(ssrMiddleware);
|
|
250
250
|
|
|
251
251
|
// Start listening on the main port
|
|
252
|
-
|
|
252
|
+
// When behind a dev proxy (isDevProxyContext), the proxy handles TLS termination,
|
|
253
|
+
// so backend servers should listen on plain HTTP to be reachable via http://localhost:PORT
|
|
254
|
+
if (
|
|
255
|
+
(useLocalSsl || process.argv.find((arg) => arg === 'tls')) &&
|
|
256
|
+
process.env.NODE_ENV === 'development' &&
|
|
257
|
+
!isDevProxyContext()
|
|
258
|
+
) {
|
|
253
259
|
if (!Underpost.tls.validateSecureContext()) shellExec(`node bin/deploy tls`);
|
|
254
260
|
const { ServerSSL } = await Underpost.tls.createSslServer(app);
|
|
255
261
|
await Underpost.start.listenPortController(ServerSSL, port, runningData);
|
|
@@ -21,11 +21,11 @@ const logger = loggerFactory(import.meta);
|
|
|
21
21
|
class LamppService {
|
|
22
22
|
/**
|
|
23
23
|
* @method
|
|
24
|
-
* @type {string
|
|
24
|
+
* @type {string}
|
|
25
25
|
* @description Stores the accumulated Apache virtual host configuration (router definition).
|
|
26
26
|
* @memberof LamppService
|
|
27
27
|
*/
|
|
28
|
-
router;
|
|
28
|
+
router = '';
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* @public
|
|
@@ -42,7 +42,7 @@ class LamppService {
|
|
|
42
42
|
* @memberof LamppService
|
|
43
43
|
*/
|
|
44
44
|
constructor() {
|
|
45
|
-
this.router =
|
|
45
|
+
this.router = '';
|
|
46
46
|
this.ports = [];
|
|
47
47
|
}
|
|
48
48
|
|
|
@@ -125,7 +125,6 @@ class LamppService {
|
|
|
125
125
|
|
|
126
126
|
// 6. Start the service
|
|
127
127
|
cmd = `sudo /opt/lampp/lampp start`;
|
|
128
|
-
if (this.router) fs.writeFileSync(`./tmp/lampp-router.conf`, this.router, 'utf-8');
|
|
129
128
|
shellExec(cmd);
|
|
130
129
|
}
|
|
131
130
|
|
|
@@ -139,13 +138,7 @@ class LamppService {
|
|
|
139
138
|
* @memberof LamppService
|
|
140
139
|
*/
|
|
141
140
|
appendRouter(render) {
|
|
142
|
-
if (!this.router)
|
|
143
|
-
if (fs.existsSync(`./tmp/lampp-router.conf`)) {
|
|
144
|
-
this.router = fs.readFileSync(`./tmp/lampp-router.conf`, 'utf-8');
|
|
145
|
-
return this.router + render;
|
|
146
|
-
}
|
|
147
|
-
return (this.router = render);
|
|
148
|
-
}
|
|
141
|
+
if (!this.router) return (this.router = render);
|
|
149
142
|
return (this.router += render);
|
|
150
143
|
}
|
|
151
144
|
|
|
@@ -154,10 +147,10 @@ class LamppService {
|
|
|
154
147
|
*
|
|
155
148
|
* @memberof LamppService
|
|
156
149
|
* @returns {void}
|
|
150
|
+
* @method removeRouter
|
|
157
151
|
*/
|
|
158
152
|
removeRouter() {
|
|
159
|
-
this.router =
|
|
160
|
-
if (fs.existsSync(`./tmp/lampp-router.conf`)) fs.rmSync(`./tmp/lampp-router.conf`);
|
|
153
|
+
this.router = '';
|
|
161
154
|
}
|
|
162
155
|
|
|
163
156
|
/**
|
package/src/server/auth.js
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
* @namespace Auth
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import dotenv from 'dotenv';
|
|
8
7
|
import jwt from 'jsonwebtoken';
|
|
9
8
|
import { loggerFactory } from './logger.js';
|
|
10
9
|
import crypto from 'crypto';
|
|
@@ -19,7 +18,6 @@ import cookieParser from 'cookie-parser';
|
|
|
19
18
|
import { DataBaseProvider } from '../db/DataBaseProvider.js';
|
|
20
19
|
import { isDevProxyContext } from './conf.js';
|
|
21
20
|
|
|
22
|
-
dotenv.config();
|
|
23
21
|
const logger = loggerFactory(import.meta);
|
|
24
22
|
|
|
25
23
|
// Promisified crypto functions
|
|
@@ -349,12 +347,7 @@ const cookieOptionsFactory = (req, host) => {
|
|
|
349
347
|
secure,
|
|
350
348
|
sameSite,
|
|
351
349
|
path: '/',
|
|
352
|
-
domain:
|
|
353
|
-
process.env.NODE_ENV === 'production' ||
|
|
354
|
-
isDevProxyContext() ||
|
|
355
|
-
(req.headers.host && req.headers.host.toLocaleLowerCase().match(host))
|
|
356
|
-
? host
|
|
357
|
-
: 'localhost',
|
|
350
|
+
domain: process.env.NODE_ENV === 'production' || isDevProxyContext() ? host : 'localhost',
|
|
358
351
|
maxAge,
|
|
359
352
|
};
|
|
360
353
|
|
|
@@ -389,7 +382,11 @@ async function createSessionAndUserToken(user, User, req, res, options = { host:
|
|
|
389
382
|
};
|
|
390
383
|
|
|
391
384
|
// push session
|
|
392
|
-
const updatedUser = await User.findByIdAndUpdate(
|
|
385
|
+
const updatedUser = await User.findByIdAndUpdate(
|
|
386
|
+
user._id,
|
|
387
|
+
{ $push: { activeSessions: newSession } },
|
|
388
|
+
{ returnDocument: 'after' },
|
|
389
|
+
);
|
|
393
390
|
const session = updatedUser.activeSessions[updatedUser.activeSessions.length - 1];
|
|
394
391
|
const jwtid = session._id.toString();
|
|
395
392
|
|
package/src/server/backup.js
CHANGED
|
@@ -7,10 +7,8 @@
|
|
|
7
7
|
import fs from 'fs-extra';
|
|
8
8
|
import { loggerFactory } from './logger.js';
|
|
9
9
|
import { shellExec } from './process.js';
|
|
10
|
-
import dotenv from 'dotenv';
|
|
11
10
|
import Underpost from '../index.js';
|
|
12
|
-
|
|
13
|
-
dotenv.config();
|
|
11
|
+
import { loadCronDeployEnv } from './conf.js';
|
|
14
12
|
|
|
15
13
|
const logger = loggerFactory(import.meta);
|
|
16
14
|
|
|
@@ -33,6 +31,7 @@ class BackUp {
|
|
|
33
31
|
* @memberof UnderpostBakcUp
|
|
34
32
|
*/
|
|
35
33
|
static callback = async function (deployList, options = { git: false }) {
|
|
34
|
+
loadCronDeployEnv();
|
|
36
35
|
if ((!deployList || deployList === 'dd') && fs.existsSync(`./engine-private/deploy/dd.router`))
|
|
37
36
|
deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').trim();
|
|
38
37
|
|