underpost 2.85.1 → 2.89.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.development +2 -1
- package/.env.production +2 -1
- package/.env.test +2 -1
- package/.github/workflows/release.cd.yml +3 -3
- package/.vscode/zed.keymap.json +22 -0
- package/README.md +3 -3
- package/bin/build.js +8 -10
- package/bin/deploy.js +4 -2
- package/bin/file.js +4 -0
- package/bin/vs.js +4 -4
- package/cli.md +16 -11
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +50 -50
- package/manifests/deployment/dd-test-development/proxy.yaml +4 -4
- package/package.json +2 -2
- package/src/api/file/file.service.js +29 -3
- package/src/cli/baremetal.js +4 -5
- package/src/cli/deploy.js +26 -4
- package/src/cli/index.js +8 -3
- package/src/cli/repository.js +42 -45
- package/src/cli/run.js +217 -48
- package/src/client/components/core/AgGrid.js +42 -3
- package/src/client/components/core/CommonJs.js +5 -0
- package/src/client/components/core/Css.js +95 -48
- package/src/client/components/core/CssCore.js +0 -1
- package/src/client/components/core/LoadingAnimation.js +2 -2
- package/src/client/components/core/Logger.js +2 -9
- package/src/client/components/core/Modal.js +22 -14
- package/src/client/components/core/ObjectLayerEngine.js +300 -9
- package/src/client/components/core/ObjectLayerEngineModal.js +686 -148
- package/src/client/components/core/ObjectLayerEngineViewer.js +1061 -0
- package/src/client/components/core/Pagination.js +15 -5
- package/src/client/components/core/Router.js +5 -1
- package/src/client/components/core/SocketIo.js +5 -1
- package/src/client/components/core/Translate.js +4 -0
- package/src/client/components/core/Worker.js +8 -1
- package/src/client/services/default/default.management.js +86 -16
- package/src/client/sw/default.sw.js +193 -97
- package/src/client.dev.js +1 -1
- package/src/db/mariadb/MariaDB.js +2 -2
- package/src/index.js +1 -1
- package/src/proxy.js +1 -1
- package/src/runtime/express/Express.js +4 -1
- package/src/server/auth.js +2 -1
- package/src/server/client-build.js +57 -2
- package/src/server/conf.js +132 -15
- package/src/server/object-layer.js +44 -0
- package/src/server/proxy.js +53 -26
- package/src/server/start.js +25 -3
- package/src/server/tls.js +1 -1
- package/src/ws/IoInterface.js +2 -3
- package/AUTHORS.md +0 -21
- package/src/server/network.js +0 -72
package/src/proxy.js
CHANGED
|
@@ -23,6 +23,7 @@ import { applySecurity, authMiddlewareFactory } from '../../server/auth.js';
|
|
|
23
23
|
import { ssrMiddlewareFactory } from '../../server/ssr.js';
|
|
24
24
|
import { TLS } from '../../server/tls.js';
|
|
25
25
|
import { shellExec } from '../../server/process.js';
|
|
26
|
+
import { devProxyHostFactory, isDevProxyContext, isTlsDevProxy } from '../../server/conf.js';
|
|
26
27
|
|
|
27
28
|
const logger = loggerFactory(import.meta);
|
|
28
29
|
|
|
@@ -94,7 +95,9 @@ class ExpressService {
|
|
|
94
95
|
|
|
95
96
|
const app = express();
|
|
96
97
|
|
|
97
|
-
if (
|
|
98
|
+
if (origins && isDevProxyContext())
|
|
99
|
+
origins.push(devProxyHostFactory({ host, includeHttp: true, tls: isTlsDevProxy() }));
|
|
100
|
+
app.set('trust proxy', true);
|
|
98
101
|
|
|
99
102
|
app.use((req, res, next) => {
|
|
100
103
|
res.on('finish', () => {
|
package/src/server/auth.js
CHANGED
|
@@ -17,6 +17,7 @@ import slowDown from 'express-slow-down';
|
|
|
17
17
|
import cors from 'cors';
|
|
18
18
|
import cookieParser from 'cookie-parser';
|
|
19
19
|
import { DataBaseProvider } from '../db/DataBaseProvider.js';
|
|
20
|
+
import { isDevProxyContext } from './conf.js';
|
|
20
21
|
|
|
21
22
|
dotenv.config();
|
|
22
23
|
const logger = loggerFactory(import.meta);
|
|
@@ -348,7 +349,7 @@ const cookieOptionsFactory = (req, host) => {
|
|
|
348
349
|
secure,
|
|
349
350
|
sameSite,
|
|
350
351
|
path: '/',
|
|
351
|
-
domain: process.env.NODE_ENV === 'production' ? host : 'localhost',
|
|
352
|
+
domain: process.env.NODE_ENV === 'production' || isDevProxyContext() ? host : 'localhost',
|
|
352
353
|
maxAge,
|
|
353
354
|
};
|
|
354
355
|
|
|
@@ -32,6 +32,51 @@ dotenv.config();
|
|
|
32
32
|
|
|
33
33
|
// Static Site Generation (SSG)
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Recursively copies files from source to destination, but only files that don't exist in destination.
|
|
37
|
+
* @function copyNonExistingFiles
|
|
38
|
+
* @param {string} src - Source directory path
|
|
39
|
+
* @param {string} dest - Destination directory path
|
|
40
|
+
* @returns {void}
|
|
41
|
+
* @memberof clientBuild
|
|
42
|
+
*/
|
|
43
|
+
const copyNonExistingFiles = (src, dest) => {
|
|
44
|
+
// Ensure source exists
|
|
45
|
+
if (!fs.existsSync(src)) {
|
|
46
|
+
throw new Error(`Source directory does not exist: ${src}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Get stats for source
|
|
50
|
+
const srcStats = fs.statSync(src);
|
|
51
|
+
|
|
52
|
+
// If source is a file, copy only if it doesn't exist in destination
|
|
53
|
+
if (srcStats.isFile()) {
|
|
54
|
+
if (!fs.existsSync(dest)) {
|
|
55
|
+
const destDir = dir.dirname(dest);
|
|
56
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
57
|
+
fs.copyFileSync(src, dest);
|
|
58
|
+
}
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// If source is a directory, create destination if it doesn't exist
|
|
63
|
+
if (srcStats.isDirectory()) {
|
|
64
|
+
if (!fs.existsSync(dest)) {
|
|
65
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Read all items in source directory
|
|
69
|
+
const items = fs.readdirSync(src);
|
|
70
|
+
|
|
71
|
+
// Recursively process each item
|
|
72
|
+
for (const item of items) {
|
|
73
|
+
const srcPath = dir.join(src, item);
|
|
74
|
+
const destPath = dir.join(dest, item);
|
|
75
|
+
copyNonExistingFiles(srcPath, destPath);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
35
80
|
/**
|
|
36
81
|
* @async
|
|
37
82
|
* @function buildClient
|
|
@@ -83,6 +128,7 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
83
128
|
* @param {string} options.publicClientId - Public client ID.
|
|
84
129
|
* @param {boolean} options.iconsBuild - Whether to build icons.
|
|
85
130
|
* @param {Object} options.metadata - Metadata for the client.
|
|
131
|
+
* @param {boolean} options.publicCopyNonExistingFiles - Whether to copy non-existing files from public directory.
|
|
86
132
|
* @returns {Promise<void>} - Promise that resolves when the full build is complete.
|
|
87
133
|
* @throws {Error} - If the full build fails.
|
|
88
134
|
* @memberof clientBuild
|
|
@@ -98,6 +144,7 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
98
144
|
publicClientId,
|
|
99
145
|
iconsBuild,
|
|
100
146
|
metadata,
|
|
147
|
+
publicCopyNonExistingFiles,
|
|
101
148
|
}) => {
|
|
102
149
|
logger.warn('Full build', rootClientPath);
|
|
103
150
|
|
|
@@ -169,11 +216,15 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
169
216
|
fs.copySync(dist.styles, `${rootClientPath}${dist.public_styles_folder}`);
|
|
170
217
|
}
|
|
171
218
|
}
|
|
219
|
+
|
|
220
|
+
if (publicCopyNonExistingFiles)
|
|
221
|
+
copyNonExistingFiles(`./src/client/public/${publicCopyNonExistingFiles}`, rootClientPath);
|
|
172
222
|
};
|
|
173
223
|
|
|
174
224
|
// { srcBuildPath, publicBuildPath }
|
|
175
225
|
const enableLiveRebuild =
|
|
176
226
|
options && options.liveClientBuildPaths && options.liveClientBuildPaths.length > 0 ? true : false;
|
|
227
|
+
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
177
228
|
|
|
178
229
|
let currentPort = parseInt(process.env.PORT) + 1;
|
|
179
230
|
for (const host of Object.keys(confServer)) {
|
|
@@ -205,7 +256,8 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
205
256
|
} = confServer[host][path];
|
|
206
257
|
if (singleReplica) continue;
|
|
207
258
|
if (!confClient[client]) confClient[client] = {};
|
|
208
|
-
const { components, dists, views, services, metadata, publicRef } =
|
|
259
|
+
const { components, dists, views, services, metadata, publicRef, publicCopyNonExistingFiles } =
|
|
260
|
+
confClient[client];
|
|
209
261
|
let backgroundImage;
|
|
210
262
|
if (metadata) {
|
|
211
263
|
backgroundImage = metadata.backgroundImage;
|
|
@@ -240,6 +292,7 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
240
292
|
publicClientId,
|
|
241
293
|
iconsBuild,
|
|
242
294
|
metadata,
|
|
295
|
+
publicCopyNonExistingFiles,
|
|
243
296
|
});
|
|
244
297
|
|
|
245
298
|
if (components)
|
|
@@ -520,6 +573,7 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
520
573
|
apiBaseHost,
|
|
521
574
|
apiBasePath: process.env.BASE_API,
|
|
522
575
|
version: Underpost.version,
|
|
576
|
+
dev: isDevelopment,
|
|
523
577
|
},
|
|
524
578
|
renderApi: {
|
|
525
579
|
JSONweb,
|
|
@@ -613,6 +667,7 @@ Sitemap: https://${host}${path === '/' ? '' : path}/sitemap.xml`,
|
|
|
613
667
|
apiBaseHost,
|
|
614
668
|
apiBasePath: process.env.BASE_API,
|
|
615
669
|
version: Underpost.version,
|
|
670
|
+
dev: isDevelopment,
|
|
616
671
|
},
|
|
617
672
|
renderApi: {
|
|
618
673
|
JSONweb,
|
|
@@ -687,4 +742,4 @@ ${fs.readFileSync(`${rootClientPath}/sw.js`, 'utf8')}`,
|
|
|
687
742
|
}
|
|
688
743
|
};
|
|
689
744
|
|
|
690
|
-
export { buildClient };
|
|
745
|
+
export { buildClient, copyNonExistingFiles };
|
package/src/server/conf.js
CHANGED
|
@@ -66,11 +66,11 @@ const Config = {
|
|
|
66
66
|
/**
|
|
67
67
|
* @method deployIdFactory
|
|
68
68
|
* @description Creates a new deploy ID.
|
|
69
|
-
* @param {string} [deployId='dd-default
|
|
70
|
-
* @param {object} [options={ cluster: false }] - The options.
|
|
69
|
+
* @param {string} [deployId='dd-default
|
|
70
|
+
* @param {object} [options={ subConf: '', cluster: false }] - The options.
|
|
71
71
|
* @memberof ServerConfBuilder
|
|
72
72
|
*/
|
|
73
|
-
deployIdFactory: function (deployId = 'dd-default', options = { cluster: false }) {
|
|
73
|
+
deployIdFactory: function (deployId = 'dd-default', options = { subConf: '', cluster: false }) {
|
|
74
74
|
if (!deployId.startsWith('dd-')) deployId = `dd-${deployId}`;
|
|
75
75
|
|
|
76
76
|
logger.info('Build deployId', deployId);
|
|
@@ -102,6 +102,17 @@ const Config = {
|
|
|
102
102
|
|
|
103
103
|
this.buildTmpConf(folder);
|
|
104
104
|
|
|
105
|
+
if (options.subConf) {
|
|
106
|
+
logger.info('Creating sub conf', {
|
|
107
|
+
deployId: deployId,
|
|
108
|
+
subConf: options.subConf,
|
|
109
|
+
});
|
|
110
|
+
fs.copySync(
|
|
111
|
+
`./engine-private/conf/${deployId}/conf.server.json`,
|
|
112
|
+
`./engine-private/conf/${deployId}/conf.server.dev.${options.subConf}.json`,
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
105
116
|
if (options.cluster === true) {
|
|
106
117
|
fs.writeFileSync(
|
|
107
118
|
`./.github/workflows/${repoName}.cd.yml`,
|
|
@@ -640,6 +651,8 @@ const buildProxyRouter = () => {
|
|
|
640
651
|
for (const path of Object.keys(confServer[host])) {
|
|
641
652
|
if (confServer[host][path].singleReplica) continue;
|
|
642
653
|
|
|
654
|
+
if (isDevProxyContext()) confServer[host][path].proxy = [isTlsDevProxy() ? 443 : 80];
|
|
655
|
+
|
|
643
656
|
confServer[host][path].port = newInstance(currentPort);
|
|
644
657
|
for (const port of confServer[host][path].proxy) {
|
|
645
658
|
if (!(port in proxyRouter)) proxyRouter[port] = {};
|
|
@@ -784,14 +797,21 @@ const buildKindPorts = (from, to) =>
|
|
|
784
797
|
/**
|
|
785
798
|
* @method buildPortProxyRouter
|
|
786
799
|
* @description Builds the port proxy router.
|
|
787
|
-
* @param {
|
|
788
|
-
* @param {
|
|
789
|
-
* @param {object}
|
|
800
|
+
* @param {object} options - The options.
|
|
801
|
+
* @param {number} [options.port=4000] - The port.
|
|
802
|
+
* @param {object} options.proxyRouter - The proxy router.
|
|
803
|
+
* @param {object} [options.hosts] - The hosts.
|
|
804
|
+
* @param {boolean} [options.orderByPathLength=false] - Whether to order by path length.
|
|
805
|
+
* @param {boolean} [options.devProxyContext=false] - Whether to use dev proxy context.
|
|
790
806
|
* @returns {object} - The port proxy router.
|
|
791
807
|
* @memberof ServerConfBuilder
|
|
792
808
|
*/
|
|
793
|
-
const buildPortProxyRouter = (
|
|
794
|
-
|
|
809
|
+
const buildPortProxyRouter = (
|
|
810
|
+
options = { port: 4000, proxyRouter, hosts, orderByPathLength: false, devProxyContext: false },
|
|
811
|
+
) => {
|
|
812
|
+
let { port, proxyRouter, hosts, orderByPathLength } = options;
|
|
813
|
+
hosts = hosts || proxyRouter[port] || {};
|
|
814
|
+
|
|
795
815
|
const router = {};
|
|
796
816
|
// build router
|
|
797
817
|
Object.keys(hosts).map((hostKey) => {
|
|
@@ -804,7 +824,7 @@ const buildPortProxyRouter = (port, proxyRouter, options = { orderByPathLength:
|
|
|
804
824
|
return;
|
|
805
825
|
}
|
|
806
826
|
}
|
|
807
|
-
|
|
827
|
+
// ${process.env.NODE_ENV === 'development' && !isDevProxyContext() ? `:${port}` : ''}
|
|
808
828
|
const absoluteHost = [80, 443].includes(port)
|
|
809
829
|
? `${host}${path === '/' ? '' : path}`
|
|
810
830
|
: `${host}:${port}${path === '/' ? '' : path}`;
|
|
@@ -812,12 +832,48 @@ const buildPortProxyRouter = (port, proxyRouter, options = { orderByPathLength:
|
|
|
812
832
|
if (absoluteHost in router)
|
|
813
833
|
logger.warn('Overwrite: Absolute host already exists on router', { absoluteHost, target });
|
|
814
834
|
|
|
815
|
-
|
|
835
|
+
if (options.devProxyContext === true) {
|
|
836
|
+
const appDevPort = parseInt(target.split(':')[2]) - process.env.DEV_PROXY_PORT_OFFSET;
|
|
837
|
+
router[absoluteHost] = `http://localhost:${appDevPort}`;
|
|
838
|
+
} else router[absoluteHost] = target;
|
|
816
839
|
}); // order router
|
|
817
840
|
|
|
818
841
|
if (Object.keys(router).length === 0) return router;
|
|
819
842
|
|
|
820
|
-
if (options.
|
|
843
|
+
if (options.devProxyContext === true && process.env.NODE_ENV === 'development') {
|
|
844
|
+
const confDevApiServer = JSON.parse(
|
|
845
|
+
fs.readFileSync(`./engine-private/conf/${process.argv[3]}/conf.server.dev.${process.argv[4]}-dev-api.json`),
|
|
846
|
+
'utf8',
|
|
847
|
+
);
|
|
848
|
+
let devApiHosts = [];
|
|
849
|
+
let origins = [];
|
|
850
|
+
for (const _host of Object.keys(confDevApiServer))
|
|
851
|
+
for (const _path of Object.keys(confDevApiServer[_host])) {
|
|
852
|
+
if (confDevApiServer[_host][_path].origins && confDevApiServer[_host][_path].origins.length) {
|
|
853
|
+
origins.push(...confDevApiServer[_host][_path].origins);
|
|
854
|
+
if (_path !== 'peer' && devApiHosts.length === 0)
|
|
855
|
+
devApiHosts.push(
|
|
856
|
+
`${_host}${[80, 443].includes(port) && isDevProxyContext() ? '' : `:${port}`}${_path == '/' ? '' : _path}`,
|
|
857
|
+
);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
origins = Array.from(new Set(origins));
|
|
861
|
+
console.log({
|
|
862
|
+
origins,
|
|
863
|
+
devApiHosts,
|
|
864
|
+
});
|
|
865
|
+
for (const devApiHost of devApiHosts) {
|
|
866
|
+
if (devApiHost in router) {
|
|
867
|
+
const target = router[devApiHost];
|
|
868
|
+
delete router[devApiHost];
|
|
869
|
+
router[`${devApiHost}/${process.env.BASE_API}`] = target;
|
|
870
|
+
router[`${devApiHost}/socket.io`] = target;
|
|
871
|
+
for (const origin of origins) router[devApiHost] = origin;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
if (orderByPathLength === true) {
|
|
821
877
|
const reOrderRouter = {};
|
|
822
878
|
for (const absoluteHostKey of orderArrayFromAttrInt(Object.keys(router), 'length'))
|
|
823
879
|
reOrderRouter[absoluteHostKey] = router[absoluteHostKey];
|
|
@@ -1409,11 +1465,14 @@ const buildApiConf = async (options = { deployId: '', subConf: '', host: '', pat
|
|
|
1409
1465
|
* @param {string} options.apiBaseHost - The API base host.
|
|
1410
1466
|
* @param {string} options.host - The host.
|
|
1411
1467
|
* @param {string} options.path - The path.
|
|
1468
|
+
* @param {boolean} options.devProxy - The dev proxy flag.
|
|
1412
1469
|
* @returns {void}
|
|
1413
1470
|
* @memberof ServerConfBuilder
|
|
1414
1471
|
*/
|
|
1415
|
-
const buildClientStaticConf = async (
|
|
1416
|
-
|
|
1472
|
+
const buildClientStaticConf = async (
|
|
1473
|
+
options = { deployId: '', subConf: '', apiBaseHost: '', host: '', path: '', devProxy: false },
|
|
1474
|
+
) => {
|
|
1475
|
+
let { deployId, subConf, host, path, devProxy } = options;
|
|
1417
1476
|
if (!deployId) deployId = process.argv[2].trim();
|
|
1418
1477
|
if (!subConf) subConf = process.argv[3].trim();
|
|
1419
1478
|
if (!host) host = process.argv[4].trim();
|
|
@@ -1425,10 +1484,14 @@ const buildClientStaticConf = async (options = { deployId: '', subConf: '', apiB
|
|
|
1425
1484
|
fs.readFileSync(`./engine-private/conf/${deployId}/.env.${process.env.NODE_ENV}.${subConf}-dev-api`, 'utf8'),
|
|
1426
1485
|
);
|
|
1427
1486
|
envObj.PORT = parseInt(envObj.PORT);
|
|
1428
|
-
const apiBaseHost =
|
|
1487
|
+
const apiBaseHost = devProxy
|
|
1488
|
+
? devProxyHostFactory({ host, tls: isTlsDevProxy() })
|
|
1489
|
+
: options?.apiBaseHost
|
|
1490
|
+
? options.apiBaseHost
|
|
1491
|
+
: `localhost:${envObj.PORT + 1}`;
|
|
1429
1492
|
confServer[host][path].apiBaseHost = apiBaseHost;
|
|
1430
1493
|
confServer[host][path].apiBaseProxyPath = path;
|
|
1431
|
-
logger.
|
|
1494
|
+
logger.warn('Build client static conf', { host, path, apiBaseHost });
|
|
1432
1495
|
envObj.PORT = parseInt(confServer[host][path].origins[0].split(':')[2]) - 1;
|
|
1433
1496
|
writeEnv(`./engine-private/conf/${deployId}/.env.${process.env.NODE_ENV}.${subConf}-dev-client`, envObj);
|
|
1434
1497
|
fs.writeFileSync(
|
|
@@ -1448,6 +1511,56 @@ const buildClientStaticConf = async (options = { deployId: '', subConf: '', apiB
|
|
|
1448
1511
|
*/
|
|
1449
1512
|
const isDeployRunnerContext = (path, options) => !options.build && path && path !== 'template-deploy';
|
|
1450
1513
|
|
|
1514
|
+
/**
|
|
1515
|
+
* @method isDevProxyContext
|
|
1516
|
+
* @description Checks if the dev proxy context is valid.
|
|
1517
|
+
* @returns {boolean} - The dev proxy context.
|
|
1518
|
+
* @memberof ServerConfBuilder
|
|
1519
|
+
*/
|
|
1520
|
+
const isDevProxyContext = () => {
|
|
1521
|
+
try {
|
|
1522
|
+
if (process.argv[2] === 'proxy') return true;
|
|
1523
|
+
if (!process.argv[6].startsWith('localhost')) return false;
|
|
1524
|
+
return new URL('http://' + process.argv[6]).hostname ? true : false;
|
|
1525
|
+
} catch {
|
|
1526
|
+
return false;
|
|
1527
|
+
}
|
|
1528
|
+
};
|
|
1529
|
+
|
|
1530
|
+
/**
|
|
1531
|
+
* @method devProxyHostFactory
|
|
1532
|
+
* @description Creates the dev proxy host.
|
|
1533
|
+
* @param {object} options - The options.
|
|
1534
|
+
* @param {string} [options.host='default.net'] - The host.
|
|
1535
|
+
* @param {boolean} [options.includeHttp=false] - Whether to include HTTP.
|
|
1536
|
+
* @param {number} [options.port=443] - The port.
|
|
1537
|
+
* @param {boolean} [options.tls=false] - Whether to use TLS.
|
|
1538
|
+
* @returns {string} - The dev proxy host.
|
|
1539
|
+
* @memberof ServerConfBuilder
|
|
1540
|
+
*/
|
|
1541
|
+
const devProxyHostFactory = (options = { host: 'default.net', includeHttp: false, port: 80, tls: false }) =>
|
|
1542
|
+
`${options.includeHttp ? (options.tls ? 'https://' : 'http://') : ''}${options.host ? options.host : 'localhost'}:${
|
|
1543
|
+
(options.port ? options.port : options.tls ? 443 : 80) + parseInt(process.env.DEV_PROXY_PORT_OFFSET)
|
|
1544
|
+
}`;
|
|
1545
|
+
|
|
1546
|
+
/**
|
|
1547
|
+
* @method isTlsDevProxy
|
|
1548
|
+
* @description Checks if TLS is used in the dev proxy.
|
|
1549
|
+
* @returns {boolean} - The TLS dev proxy status.
|
|
1550
|
+
* @memberof ServerConfBuilder
|
|
1551
|
+
*/
|
|
1552
|
+
const isTlsDevProxy = () => process.env.NODE_ENV !== 'production' && process.argv[7] === 'tls';
|
|
1553
|
+
|
|
1554
|
+
/**
|
|
1555
|
+
* @method getTlsHosts
|
|
1556
|
+
* @description Gets the TLS hosts.
|
|
1557
|
+
* @param {object} confServer - The server configuration.
|
|
1558
|
+
* @returns {Array} - The TLS hosts.
|
|
1559
|
+
* @memberof ServerConfBuilder
|
|
1560
|
+
*/
|
|
1561
|
+
const getTlsHosts = (confServer) =>
|
|
1562
|
+
Array.from(new Set(Object.keys(confServer).map((h) => new URL('https://' + h).hostname)));
|
|
1563
|
+
|
|
1451
1564
|
export {
|
|
1452
1565
|
Cmd,
|
|
1453
1566
|
Config,
|
|
@@ -1484,4 +1597,8 @@ export {
|
|
|
1484
1597
|
buildApiConf,
|
|
1485
1598
|
buildClientStaticConf,
|
|
1486
1599
|
isDeployRunnerContext,
|
|
1600
|
+
isDevProxyContext,
|
|
1601
|
+
devProxyHostFactory,
|
|
1602
|
+
isTlsDevProxy,
|
|
1603
|
+
getTlsHosts,
|
|
1487
1604
|
};
|
|
@@ -192,6 +192,49 @@ export class ObjectLayerEngine {
|
|
|
192
192
|
return objectLayerFrameDirections;
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
+
/**
|
|
196
|
+
* @memberof CyberiaObjectLayer
|
|
197
|
+
* @static
|
|
198
|
+
* @description Processes an image file through frameFactory and adds the resulting frame to the render data structure.
|
|
199
|
+
* Updates the color palette and pushes the frame to all keyframe directions corresponding to the given direction code.
|
|
200
|
+
* Initializes colors array, frames object, and direction arrays if they don't exist.
|
|
201
|
+
* @param {Object} renderData - The render data object containing frames and colors.
|
|
202
|
+
* @param {string} imagePath - The path to the image file to process.
|
|
203
|
+
* @param {string} directionCode - The numerical direction code (e.g., '08', '14').
|
|
204
|
+
* @returns {Promise<Object>} - The updated render data object.
|
|
205
|
+
* @memberof CyberiaObjectLayer
|
|
206
|
+
*/
|
|
207
|
+
static async processAndPushFrame(renderData, imagePath, directionCode) {
|
|
208
|
+
// Initialize colors array if it doesn't exist
|
|
209
|
+
if (!renderData.colors) {
|
|
210
|
+
renderData.colors = [];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Initialize frames object if it doesn't exist
|
|
214
|
+
if (!renderData.frames) {
|
|
215
|
+
renderData.frames = {};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Process the image and extract frame matrix and updated colors
|
|
219
|
+
const frameFactoryResult = await ObjectLayerEngine.frameFactory(imagePath, renderData.colors);
|
|
220
|
+
|
|
221
|
+
// Update the colors palette
|
|
222
|
+
renderData.colors = frameFactoryResult.colors;
|
|
223
|
+
|
|
224
|
+
// Get all keyframe directions for this direction code
|
|
225
|
+
const keyframeDirections = ObjectLayerEngine.getKeyFramesDirectionsFromNumberFolderDirection(directionCode);
|
|
226
|
+
|
|
227
|
+
// Push the frame to all corresponding directions
|
|
228
|
+
for (const keyframeDirection of keyframeDirections) {
|
|
229
|
+
if (!renderData.frames[keyframeDirection]) {
|
|
230
|
+
renderData.frames[keyframeDirection] = [];
|
|
231
|
+
}
|
|
232
|
+
renderData.frames[keyframeDirection].push(frameFactoryResult.frame);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return renderData;
|
|
236
|
+
}
|
|
237
|
+
|
|
195
238
|
/**
|
|
196
239
|
* @memberof CyberiaObjectLayer
|
|
197
240
|
* @static
|
|
@@ -290,5 +333,6 @@ export const readPngAsync = ObjectLayerEngine.readPngAsync;
|
|
|
290
333
|
export const frameFactory = ObjectLayerEngine.frameFactory;
|
|
291
334
|
export const getKeyFramesDirectionsFromNumberFolderDirection =
|
|
292
335
|
ObjectLayerEngine.getKeyFramesDirectionsFromNumberFolderDirection;
|
|
336
|
+
export const processAndPushFrame = ObjectLayerEngine.processAndPushFrame;
|
|
293
337
|
export const buildImgFromTile = ObjectLayerEngine.buildImgFromTile;
|
|
294
338
|
export const generateRandomStats = ObjectLayerEngine.generateRandomStats;
|
package/src/server/proxy.js
CHANGED
|
@@ -11,9 +11,12 @@ import dotenv from 'dotenv';
|
|
|
11
11
|
|
|
12
12
|
import { createProxyMiddleware } from 'http-proxy-middleware';
|
|
13
13
|
import { loggerFactory, loggerMiddleware } from './logger.js';
|
|
14
|
-
import {
|
|
15
|
-
import { buildPortProxyRouter, buildProxyRouter } from './conf.js';
|
|
14
|
+
import { buildPortProxyRouter, buildProxyRouter, getTlsHosts, isDevProxyContext, isTlsDevProxy } from './conf.js';
|
|
16
15
|
import UnderpostStartUp from './start.js';
|
|
16
|
+
import UnderpostDeploy from '../cli/deploy.js';
|
|
17
|
+
import { SSL_BASE, TLS } from './tls.js';
|
|
18
|
+
import { shellExec } from './process.js';
|
|
19
|
+
import fs from 'fs-extra';
|
|
17
20
|
|
|
18
21
|
dotenv.config();
|
|
19
22
|
|
|
@@ -22,28 +25,27 @@ const logger = loggerFactory(import.meta);
|
|
|
22
25
|
/**
|
|
23
26
|
* Main class for building and running the proxy server.
|
|
24
27
|
* All utility methods are implemented as static to serve as a namespace container.
|
|
25
|
-
* @class
|
|
26
|
-
* @augments Proxy
|
|
28
|
+
* @class ProxyService
|
|
27
29
|
* @memberof ProxyService
|
|
28
30
|
*/
|
|
29
|
-
class
|
|
31
|
+
class ProxyService {
|
|
30
32
|
/**
|
|
31
|
-
*
|
|
32
|
-
* @async
|
|
33
|
+
* Builds and starts the proxy server with appropriate routing and SSL configuration.
|
|
33
34
|
* @static
|
|
34
|
-
* @
|
|
35
|
-
* @returns {Promise<void>}
|
|
36
|
-
* @memberof ProxyService
|
|
35
|
+
* @returns {Promise<void>} Resolves when the server is successfully started.
|
|
37
36
|
*/
|
|
38
|
-
static async
|
|
37
|
+
static async build() {
|
|
38
|
+
if (process.env.NODE_ENV === 'production') process.env.DEV_PROXY_PORT_OFFSET = 0;
|
|
39
|
+
|
|
39
40
|
// Start a default Express listener on process.env.PORT (potentially unused, but ensures Express is initialized)
|
|
41
|
+
process.env.PORT = parseInt(process.env.PORT) + parseInt(process.env.DEV_PROXY_PORT_OFFSET);
|
|
40
42
|
express().listen(process.env.PORT);
|
|
41
43
|
|
|
42
44
|
const proxyRouter = buildProxyRouter();
|
|
43
45
|
|
|
44
46
|
for (let port of Object.keys(proxyRouter)) {
|
|
45
|
-
port = parseInt(port);
|
|
46
47
|
const hosts = proxyRouter[port];
|
|
48
|
+
port = parseInt(port) + parseInt(process.env.DEV_PROXY_PORT_OFFSET);
|
|
47
49
|
const proxyPath = '/';
|
|
48
50
|
const proxyHost = 'localhost';
|
|
49
51
|
const runningData = { host: proxyHost, path: proxyPath, client: null, runtime: 'nodejs', meta: import.meta };
|
|
@@ -56,19 +58,22 @@ class Proxy {
|
|
|
56
58
|
/** @type {import('http-proxy-middleware/dist/types').Options} */
|
|
57
59
|
const options = {
|
|
58
60
|
ws: true, // Enable websocket proxying
|
|
59
|
-
target: `http://localhost:${process.env.PORT}`, // Default target (should be overridden by router)
|
|
61
|
+
target: `http://localhost:${parseInt(process.env.PORT - 1)}`, // Default target (should be overridden by router)
|
|
60
62
|
router: {},
|
|
63
|
+
// changeOrigin: true,
|
|
64
|
+
logLevel: 'debug',
|
|
61
65
|
xfwd: true, // Adds x-forward headers (Host, Proto, etc.)
|
|
62
|
-
onProxyReq: (proxyReq, req, res, options) => {
|
|
63
|
-
|
|
64
|
-
TLS.sslRedirectMiddleware(req, res, port, proxyRouter);
|
|
65
|
-
},
|
|
66
|
-
pathRewrite: {
|
|
67
|
-
// Add path rewrite rules here if necessary
|
|
68
|
-
},
|
|
66
|
+
onProxyReq: (proxyReq, req, res, options) => {},
|
|
67
|
+
pathRewrite: {},
|
|
69
68
|
};
|
|
70
69
|
|
|
71
|
-
options.router = buildPortProxyRouter(
|
|
70
|
+
options.router = buildPortProxyRouter({
|
|
71
|
+
port,
|
|
72
|
+
proxyRouter,
|
|
73
|
+
hosts,
|
|
74
|
+
orderByPathLength: true,
|
|
75
|
+
devProxyContext: process.env.NODE_ENV !== 'production',
|
|
76
|
+
});
|
|
72
77
|
|
|
73
78
|
const filter = proxyPath; // Use '/' as the general filter
|
|
74
79
|
app.use(proxyPath, createProxyMiddleware(filter, options));
|
|
@@ -91,11 +96,33 @@ class Proxy {
|
|
|
91
96
|
break;
|
|
92
97
|
|
|
93
98
|
default:
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
switch (port) {
|
|
100
|
+
case 443: {
|
|
101
|
+
let tlsHosts = hosts;
|
|
102
|
+
if (isDevProxyContext() && isTlsDevProxy()) {
|
|
103
|
+
tlsHosts = {};
|
|
104
|
+
for (const tlsHost of getTlsHosts(hosts)) {
|
|
105
|
+
if (fs.existsSync(SSL_BASE(tlsHost))) fs.removeSync(SSL_BASE(tlsHost));
|
|
106
|
+
if (!TLS.validateSecureContext(tlsHost)) shellExec(`node bin/deploy tls "${tlsHost}"`);
|
|
107
|
+
tlsHosts[tlsHost] = {};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const { ServerSSL } = await TLS.createSslServer(app, tlsHosts);
|
|
111
|
+
await UnderpostStartUp.API.listenPortController(ServerSSL, port, runningData);
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
default: // In non-production, always use standard HTTP listener
|
|
115
|
+
await UnderpostStartUp.API.listenPortController(app, port, runningData);
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
97
118
|
}
|
|
98
119
|
logger.info('Proxy running', { port, options });
|
|
120
|
+
if (process.env.NODE_ENV === 'development')
|
|
121
|
+
logger.info(
|
|
122
|
+
UnderpostDeploy.API.etcHostFactory(Object.keys(options.router), {
|
|
123
|
+
append: true,
|
|
124
|
+
}).renderHosts,
|
|
125
|
+
);
|
|
99
126
|
}
|
|
100
127
|
}
|
|
101
128
|
}
|
|
@@ -105,6 +132,6 @@ class Proxy {
|
|
|
105
132
|
* @type {function(): Promise<void>}
|
|
106
133
|
* @memberof ProxyService
|
|
107
134
|
*/
|
|
108
|
-
const buildProxy =
|
|
135
|
+
const buildProxy = ProxyService.build;
|
|
109
136
|
|
|
110
|
-
export {
|
|
137
|
+
export { ProxyService, buildProxy };
|
package/src/server/start.js
CHANGED
|
@@ -53,7 +53,7 @@ class UnderpostStartUp {
|
|
|
53
53
|
throw new Error(message);
|
|
54
54
|
}
|
|
55
55
|
}, msDelta);
|
|
56
|
-
return logic ? await logic(...args) : undefined, args[1]();
|
|
56
|
+
return (logic ? await logic(...args) : undefined, args[1]());
|
|
57
57
|
},
|
|
58
58
|
};
|
|
59
59
|
},
|
|
@@ -95,8 +95,8 @@ class UnderpostStartUp {
|
|
|
95
95
|
port === 80
|
|
96
96
|
? `http://${host}${path}`
|
|
97
97
|
: port === 443
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
? `https://${host}${path}`
|
|
99
|
+
: `http://${host}:${port}${path}`,
|
|
100
100
|
local: `http://localhost:${port}${path}`,
|
|
101
101
|
apis: metadata.apis,
|
|
102
102
|
};
|
|
@@ -122,6 +122,12 @@ class UnderpostStartUp {
|
|
|
122
122
|
if (options.build === true) await UnderpostStartUp.API.build(deployId, env);
|
|
123
123
|
if (options.run === true) await UnderpostStartUp.API.run(deployId, env);
|
|
124
124
|
},
|
|
125
|
+
/**
|
|
126
|
+
* Run itc-scripts and builds client bundle.
|
|
127
|
+
* @param {string} deployId - The ID of the deployment.
|
|
128
|
+
* @param {string} env - The environment of the deployment.
|
|
129
|
+
* @memberof UnderpostStartUp
|
|
130
|
+
*/
|
|
125
131
|
async build(deployId = 'dd-default', env = 'development') {
|
|
126
132
|
const buildBasePath = `/home/dd`;
|
|
127
133
|
const repoName = `engine-${deployId.split('-')[1]}`;
|
|
@@ -139,6 +145,12 @@ class UnderpostStartUp {
|
|
|
139
145
|
}
|
|
140
146
|
shellExec(`node bin/deploy build-full-client ${deployId}`);
|
|
141
147
|
},
|
|
148
|
+
/**
|
|
149
|
+
* Runs a deployment.
|
|
150
|
+
* @param {string} deployId - The ID of the deployment.
|
|
151
|
+
* @param {string} env - The environment of the deployment.
|
|
152
|
+
* @memberof UnderpostStartUp
|
|
153
|
+
*/
|
|
142
154
|
async run(deployId = 'dd-default', env = 'development') {
|
|
143
155
|
const runCmd = env === 'production' ? 'run prod-img' : 'run dev-img';
|
|
144
156
|
if (fs.existsSync(`./engine-private/replica`)) {
|
|
@@ -158,4 +170,14 @@ class UnderpostStartUp {
|
|
|
158
170
|
};
|
|
159
171
|
}
|
|
160
172
|
|
|
173
|
+
/**
|
|
174
|
+
* Creates a keep-alive process to maintain server activity.
|
|
175
|
+
* @memberof UnderpostStartUp
|
|
176
|
+
* @returns
|
|
177
|
+
*/
|
|
178
|
+
const createKeepAliveProcess = async () =>
|
|
179
|
+
await UnderpostStartUp.API.listenPortController(UnderpostStartUp.API.listenServerFactory(), ':');
|
|
180
|
+
|
|
161
181
|
export default UnderpostStartUp;
|
|
182
|
+
|
|
183
|
+
export { createKeepAliveProcess, UnderpostStartUp };
|
package/src/server/tls.js
CHANGED
|
@@ -248,4 +248,4 @@ const validateSecureContext = TLS.validateSecureContext;
|
|
|
248
248
|
const createSslServer = TLS.createSslServer;
|
|
249
249
|
const sslRedirectMiddleware = TLS.sslRedirectMiddleware;
|
|
250
250
|
|
|
251
|
-
export { TLS, buildSSL, buildSecureContext, validateSecureContext, createSslServer, sslRedirectMiddleware };
|
|
251
|
+
export { TLS, SSL_BASE, buildSSL, buildSecureContext, validateSecureContext, createSslServer, sslRedirectMiddleware };
|
package/src/ws/IoInterface.js
CHANGED
|
@@ -21,11 +21,10 @@ const logger = loggerFactory(import.meta);
|
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
+
* Manages the logic, client map, and event listeners for a specific WebSocket channel,
|
|
25
|
+
* ensuring robust message handling and lifecycle management.
|
|
24
26
|
* @class IoChannel
|
|
25
|
-
* @alias IoChannel
|
|
26
27
|
* @memberof SocketIoInterface
|
|
27
|
-
* @classdesc Manages the logic, client map, and event listeners for a specific WebSocket channel,
|
|
28
|
-
* ensuring robust message handling and lifecycle management.
|
|
29
28
|
*/
|
|
30
29
|
class IoChannel {
|
|
31
30
|
/**
|