underpost 2.8.47 → 2.8.51
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/Dockerfile +1 -1
- package/bin/build.js +32 -191
- package/bin/deploy.js +9 -28
- package/bin/index.js +19 -5
- package/bin/util.js +0 -8
- package/docker-compose.yml +1 -1
- package/manifests/mongodb/backup-cronjob.yaml +14 -12
- package/package.json +1 -1
- package/src/api/core/core.service.js +1 -1
- package/src/cli/cron.js +90 -0
- package/src/cli/deploy.js +183 -1
- package/src/cli/image.js +22 -3
- package/src/cli/repository.js +5 -13
- package/src/cli/test.js +7 -4
- package/src/client/components/core/CommonJs.js +9 -0
- package/src/client/components/core/Css.js +1 -0
- package/src/client/components/core/Modal.js +0 -1
- package/src/client/components/core/VanillaJs.js +0 -9
- package/src/client/components/core/Worker.js +34 -31
- package/src/index.js +9 -1
- package/src/server/backup.js +49 -93
- package/src/server/conf.js +58 -24
- package/src/server/dns.js +48 -65
- package/src/server/network.js +7 -4
- package/src/dns.js +0 -22
package/src/server/conf.js
CHANGED
|
@@ -40,21 +40,26 @@ const logger = loggerFactory(import.meta);
|
|
|
40
40
|
|
|
41
41
|
const Config = {
|
|
42
42
|
default: DefaultConf,
|
|
43
|
-
build: async function (options = { folder: '' }) {
|
|
43
|
+
build: async function (options = { folder: '' }, deployContext, deployList, subConf) {
|
|
44
|
+
if (!deployContext) deployContext = process.argv[2];
|
|
44
45
|
if (!fs.existsSync(`./tmp`)) fs.mkdirSync(`./tmp`, { recursive: true });
|
|
45
46
|
fs.writeFileSync(`./tmp/await-deploy`, '', 'utf8');
|
|
46
|
-
if (fs.existsSync(`./engine-private/conf/${
|
|
47
|
-
|
|
47
|
+
if (fs.existsSync(`./engine-private/conf/${deployContext}`))
|
|
48
|
+
return loadConf(deployContext, process.env.NODE_ENV, subConf);
|
|
49
|
+
if (fs.existsSync(`./engine-private/replica/${deployContext}`))
|
|
50
|
+
return loadConf(deployContext, process.env.NODE_ENV, subConf);
|
|
48
51
|
|
|
49
|
-
if (
|
|
52
|
+
if (deployContext === 'deploy') return;
|
|
50
53
|
|
|
51
|
-
if (
|
|
54
|
+
if (deployContext === 'proxy') {
|
|
55
|
+
if (!deployList) deployList = process.argv[3];
|
|
56
|
+
if (!subConf) subConf = process.argv[4];
|
|
52
57
|
this.default.server = {};
|
|
53
|
-
for (const deployId of
|
|
58
|
+
for (const deployId of deployList.split(',')) {
|
|
54
59
|
let confPath = `./engine-private/conf/${deployId}/conf.server.json`;
|
|
55
60
|
const privateConfDevPath = fs.existsSync(`./engine-private/replica/${deployId}/conf.server.json`)
|
|
56
61
|
? `./engine-private/replica/${deployId}/conf.server.json`
|
|
57
|
-
: `./engine-private/conf/${deployId}/conf.server.dev.${
|
|
62
|
+
: `./engine-private/conf/${deployId}/conf.server.dev.${subConf}.json`;
|
|
58
63
|
const confDevPath = fs.existsSync(privateConfDevPath)
|
|
59
64
|
? privateConfDevPath
|
|
60
65
|
: `./engine-private/conf/${deployId}/conf.server.dev.json`;
|
|
@@ -62,7 +67,7 @@ const Config = {
|
|
|
62
67
|
if (process.env.NODE_ENV === 'development' && fs.existsSync(confDevPath)) confPath = confDevPath;
|
|
63
68
|
const serverConf = JSON.parse(fs.readFileSync(confPath, 'utf8'));
|
|
64
69
|
|
|
65
|
-
for (const host of Object.keys(loadReplicas(serverConf))) {
|
|
70
|
+
for (const host of Object.keys(loadReplicas(serverConf, deployContext, subConf))) {
|
|
66
71
|
if (serverConf[host]['/'])
|
|
67
72
|
this.default.server[host] = {
|
|
68
73
|
...this.default.server[host],
|
|
@@ -92,7 +97,15 @@ const Config = {
|
|
|
92
97
|
},
|
|
93
98
|
};
|
|
94
99
|
|
|
95
|
-
const loadConf = (deployId, envInput) => {
|
|
100
|
+
const loadConf = (deployId, envInput, subConf) => {
|
|
101
|
+
if (deployId === 'clean') {
|
|
102
|
+
shellExec(`git checkout package.json`);
|
|
103
|
+
shellExec(`git checkout .env.production`);
|
|
104
|
+
shellExec(`git checkout .env.development`);
|
|
105
|
+
shellExec(`git checkout .env.test`);
|
|
106
|
+
shellExec(`git checkout jsdoc.json`);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
96
109
|
const folder = fs.existsSync(`./engine-private/replica/${deployId}`)
|
|
97
110
|
? `./engine-private/replica/${deployId}`
|
|
98
111
|
: `./engine-private/conf/${deployId}`;
|
|
@@ -109,7 +122,8 @@ const loadConf = (deployId, envInput) => {
|
|
|
109
122
|
? fs.readFileSync(`${folder}/conf.${typeConf}.json`, 'utf8')
|
|
110
123
|
: JSON.stringify(Config.default[typeConf]);
|
|
111
124
|
if (process.env.NODE_ENV === 'development' && typeConf === 'server') {
|
|
112
|
-
|
|
125
|
+
if (!subConf) subConf = process.argv[3];
|
|
126
|
+
const devConfPath = `${folder}/conf.${typeConf}.dev${subConf ? `.${subConf}` : ''}.json`;
|
|
113
127
|
if (fs.existsSync(devConfPath)) srcConf = fs.readFileSync(devConfPath, 'utf8');
|
|
114
128
|
}
|
|
115
129
|
if (typeConf === 'server') srcConf = JSON.stringify(loadReplicas(JSON.parse(srcConf)), null, 4);
|
|
@@ -135,15 +149,17 @@ const loadConf = (deployId, envInput) => {
|
|
|
135
149
|
return { folder, deployId };
|
|
136
150
|
};
|
|
137
151
|
|
|
138
|
-
const loadReplicas = (confServer) => {
|
|
152
|
+
const loadReplicas = (confServer, deployContext, subConf) => {
|
|
153
|
+
if (!deployContext) deployContext = process.argv[2];
|
|
154
|
+
if (!subConf) subConf = process.argv[3];
|
|
139
155
|
for (const host of Object.keys(confServer)) {
|
|
140
156
|
for (const path of Object.keys(confServer[host])) {
|
|
141
157
|
const { replicas, singleReplica } = confServer[host][path];
|
|
142
158
|
if (
|
|
143
159
|
replicas &&
|
|
144
|
-
(
|
|
160
|
+
(deployContext === 'proxy' ||
|
|
145
161
|
!singleReplica ||
|
|
146
|
-
(singleReplica && process.env.NODE_ENV === 'development' && !
|
|
162
|
+
(singleReplica && process.env.NODE_ENV === 'development' && !subConf))
|
|
147
163
|
)
|
|
148
164
|
for (const replicaPath of replicas) {
|
|
149
165
|
confServer[host][replicaPath] = newInstance(confServer[host][path]);
|
|
@@ -513,14 +529,16 @@ const buildPortProxyRouter = (port, proxyRouter) => {
|
|
|
513
529
|
// build router
|
|
514
530
|
Object.keys(hosts).map((hostKey) => {
|
|
515
531
|
let { host, path, target, proxy, peer } = hosts[hostKey];
|
|
516
|
-
if (process.env.NODE_ENV === 'development') host = `localhost`;
|
|
532
|
+
if (process.argv.includes('localhost') && process.env.NODE_ENV === 'development') host = `localhost`;
|
|
517
533
|
|
|
518
534
|
if (!proxy.includes(port)) return;
|
|
519
535
|
const absoluteHost = [80, 443].includes(port)
|
|
520
536
|
? `${host}${path === '/' ? '' : path}`
|
|
521
537
|
: `${host}:${port}${path === '/' ? '' : path}`;
|
|
522
538
|
|
|
523
|
-
if (
|
|
539
|
+
if (process.argv.includes('localhost')) {
|
|
540
|
+
if (!(absoluteHost in router)) router[absoluteHost] = target;
|
|
541
|
+
} else router[absoluteHost] = target;
|
|
524
542
|
}); // order router
|
|
525
543
|
|
|
526
544
|
if (Object.keys(router).length === 0) return router;
|
|
@@ -580,9 +598,25 @@ const cliSpinner = async (time = 5000, message0, message1, color, type = 'dots')
|
|
|
580
598
|
const buildReplicaId = ({ deployId, replica }) => `${deployId}-${replica.slice(1)}`;
|
|
581
599
|
|
|
582
600
|
const getDataDeploy = (
|
|
583
|
-
options = {
|
|
601
|
+
options = {
|
|
602
|
+
buildSingleReplica: false,
|
|
603
|
+
deployGroupId: '',
|
|
604
|
+
deployId: '',
|
|
605
|
+
disableSyncEnvPort: false,
|
|
606
|
+
deployIdConcat: [],
|
|
607
|
+
},
|
|
584
608
|
) => {
|
|
585
|
-
let dataDeploy =
|
|
609
|
+
let dataDeploy =
|
|
610
|
+
options.deployGroupId === 'dd'
|
|
611
|
+
? fs.readFileSync(`./engine-private/deploy/${options.deployGroupId}.router`, 'utf8')
|
|
612
|
+
: fs.readFileSync(`./engine-private/deploy/${options.deployGroupId}`, 'utf8');
|
|
613
|
+
|
|
614
|
+
dataDeploy = dataDeploy
|
|
615
|
+
.split(',')
|
|
616
|
+
.map((deployId) => deployId.trim())
|
|
617
|
+
.filter((deployId) => deployId);
|
|
618
|
+
|
|
619
|
+
if (options.deployIdConcat) dataDeploy = dataDeploy.concat(options.deployIdConcat);
|
|
586
620
|
|
|
587
621
|
if (options.deployId) dataDeploy = dataDeploy.filter((d) => d === options.deployId);
|
|
588
622
|
|
|
@@ -817,7 +851,7 @@ const deployRun = async (dataDeploy, currentAttempt = 1) => {
|
|
|
817
851
|
if (failed.length > 0) {
|
|
818
852
|
for (const deploy of failed) logger.error(deploy.deployId, Cmd.run(deploy.deployId));
|
|
819
853
|
if (currentAttempt === maxAttempts) return logger.error(`max deploy attempts exceeded`);
|
|
820
|
-
|
|
854
|
+
await read({ prompt: 'Press enter to retry failed processes\n' });
|
|
821
855
|
currentAttempt++;
|
|
822
856
|
await deployRun(failed, currentAttempt);
|
|
823
857
|
} else logger.info(`Deploy process successfully`);
|
|
@@ -963,15 +997,15 @@ const getPathsSSR = (conf) => {
|
|
|
963
997
|
|
|
964
998
|
const Cmd = {
|
|
965
999
|
delete: (deployId) => `pm2 delete ${deployId}`,
|
|
966
|
-
run: (
|
|
1000
|
+
run: () => `npm start`,
|
|
967
1001
|
build: (deployId) => `node bin/deploy build-full-client ${deployId}${process.argv.includes('l') ? ' l' : ''}`,
|
|
968
1002
|
conf: (deployId, env) => `node bin/deploy conf ${deployId} ${env ? env : 'production'}`,
|
|
969
1003
|
replica: (deployId, host, path) => `node bin/deploy build-single-replica ${deployId} ${host} ${path}`,
|
|
970
1004
|
syncPorts: (deployGroupId) => `node bin/deploy sync-env-port ${deployGroupId}`,
|
|
971
|
-
cron: (
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1005
|
+
cron: (deployList, jobList, name, expression, options) =>
|
|
1006
|
+
`pm2 start ./bin/index.js --no-autorestart --instances 1 --cron "${expression}" --name ${name} -- cron ${
|
|
1007
|
+
options?.disableKindCluster ? `--disable-kind-cluster ` : ''
|
|
1008
|
+
}${deployList} ${jobList}`,
|
|
975
1009
|
};
|
|
976
1010
|
|
|
977
1011
|
const fixDependencies = async () => {
|
|
@@ -1038,7 +1072,7 @@ const setUpProxyMaintenanceServer = ({ deployGroupId }) => {
|
|
|
1038
1072
|
shellExec(`node bin/deploy valkey-service`);
|
|
1039
1073
|
const proxyDeployId = fs.readFileSync(`./engine-private/deploy/${deployGroupId}.proxy`, 'utf8').trim();
|
|
1040
1074
|
shellExec(`node bin/deploy conf ${proxyDeployId} production`);
|
|
1041
|
-
shellExec(`
|
|
1075
|
+
shellExec(`npm start ${proxyDeployId} maintenance`);
|
|
1042
1076
|
};
|
|
1043
1077
|
|
|
1044
1078
|
const getNpmRootPath = () =>
|
package/src/server/dns.js
CHANGED
|
@@ -17,10 +17,8 @@ dotenv.config();
|
|
|
17
17
|
|
|
18
18
|
const logger = loggerFactory(import.meta);
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
callback: () => null,
|
|
23
|
-
InitIpDaemon: async function ({ deployId }) {
|
|
20
|
+
class Dns {
|
|
21
|
+
static callback = async function (deployList) {
|
|
24
22
|
// NAT-VPS modem/router device configuration:
|
|
25
23
|
// LAN --> [NAT-VPS] --> WAN
|
|
26
24
|
// enabled DMZ Host to proxy IP 80-443 (79-444) sometimes router block first port
|
|
@@ -30,56 +28,55 @@ const Dns = {
|
|
|
30
28
|
// LAN server or device's local servers port -> 3000-3100 (2999-3101)
|
|
31
29
|
// DNS Records: [ANAME](Address Dynamic) -> [A](ipv4) host | [AAAA](ipv6) host -> [public-ip]
|
|
32
30
|
// Forward the router's TCP/UDP ports to the LAN device's IP address
|
|
33
|
-
|
|
31
|
+
for (const _deployId of deployList.split(',')) {
|
|
32
|
+
const deployId = _deployId.trim();
|
|
34
33
|
const privateCronConfPath = `./engine-private/conf/${deployId}/conf.cron.json`;
|
|
35
|
-
|
|
36
34
|
const confCronPath = fs.existsSync(privateCronConfPath) ? privateCronConfPath : './conf/conf.cron.json';
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (testIp && typeof testIp === 'string' && validator.isIP(testIp) && Dns.ip !== testIp) {
|
|
51
|
-
logger.info(`New ip`, testIp);
|
|
52
|
-
for (const recordType of Object.keys(confCronData.records)) {
|
|
53
|
-
switch (recordType) {
|
|
54
|
-
case 'A':
|
|
55
|
-
for (const dnsProvider of confCronData.records[recordType]) {
|
|
56
|
-
if (typeof Dns.services.updateIp[dnsProvider.dns] === 'function')
|
|
57
|
-
await Dns.services.updateIp[dnsProvider.dns]({ ...dnsProvider, ip: testIp });
|
|
58
|
-
}
|
|
59
|
-
break;
|
|
35
|
+
const confCronData = JSON.parse(fs.readFileSync(confCronPath, 'utf8'));
|
|
36
|
+
|
|
37
|
+
let testIp;
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
testIp = await ip.public.ipv4();
|
|
41
|
+
} catch (error) {
|
|
42
|
+
logger.error(error, { testIp, stack: error.stack });
|
|
43
|
+
}
|
|
44
|
+
const ipFileName = `${deployId}.ip`;
|
|
45
|
+
const currentIp = fs.existsSync(`./engine-private/deploy/${ipFileName}`)
|
|
46
|
+
? fs.readFileSync(`./engine-private/deploy/${ipFileName}`, 'utf8')
|
|
47
|
+
: undefined;
|
|
60
48
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
49
|
+
if (testIp && typeof testIp === 'string' && validator.isIP(testIp) && currentIp !== testIp) {
|
|
50
|
+
logger.info(`new ip`, testIp);
|
|
51
|
+
for (const recordType of Object.keys(confCronData.records)) {
|
|
52
|
+
switch (recordType) {
|
|
53
|
+
case 'A':
|
|
54
|
+
for (const dnsProvider of confCronData.records[recordType]) {
|
|
55
|
+
if (typeof Dns.services.updateIp[dnsProvider.dns] === 'function')
|
|
56
|
+
await Dns.services.updateIp[dnsProvider.dns]({ ...dnsProvider, ip: testIp });
|
|
57
|
+
}
|
|
58
|
+
break;
|
|
59
|
+
|
|
60
|
+
default:
|
|
61
|
+
break;
|
|
64
62
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
const ipUrlTest = `https://${process.env.DEFAULT_DEPLOY_HOST}`;
|
|
66
|
+
const response = await axios.get(ipUrlTest);
|
|
67
|
+
const verifyIp = response.request.socket.remoteAddress;
|
|
68
|
+
logger.info(ipUrlTest + ' IP', verifyIp);
|
|
69
|
+
if (verifyIp === testIp) {
|
|
70
|
+
fs.writeFileSync(`./engine-private/deploy/${ipFileName}`, testIp, 'utf8');
|
|
71
|
+
} else logger.error('ip not updated');
|
|
72
|
+
} catch (error) {
|
|
73
|
+
logger.error(error), 'ip not updated';
|
|
75
74
|
}
|
|
76
75
|
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
},
|
|
82
|
-
services: {
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
static services = {
|
|
83
80
|
updateIp: {
|
|
84
81
|
dondominio: (options) => {
|
|
85
82
|
const { user, api_key, host, dns, ip } = options;
|
|
@@ -100,21 +97,7 @@ const Dns = {
|
|
|
100
97
|
});
|
|
101
98
|
},
|
|
102
99
|
},
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
Dns.ip = ip;
|
|
106
|
-
confCronData.ipDaemon.ip = ip;
|
|
107
|
-
fs.writeFileSync(confCronPath, JSON.stringify(confCronData, null, 4), 'utf8');
|
|
108
|
-
shellExec(
|
|
109
|
-
`cd ./engine-private` +
|
|
110
|
-
` && git pull ${Dns.repoUrl}` +
|
|
111
|
-
` && git add . && git commit -m "update ip ${new Date().toLocaleDateString()}"` +
|
|
112
|
-
` && git push ${Dns.repoUrl}`,
|
|
113
|
-
{
|
|
114
|
-
disableLog: true,
|
|
115
|
-
},
|
|
116
|
-
);
|
|
117
|
-
},
|
|
118
|
-
};
|
|
100
|
+
};
|
|
101
|
+
}
|
|
119
102
|
|
|
120
|
-
export
|
|
103
|
+
export default Dns;
|
package/src/server/network.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'fs-extra';
|
|
2
2
|
|
|
3
3
|
import { publicIp, publicIpv4, publicIpv6 } from 'public-ip';
|
|
4
|
-
import { loggerFactory } from './logger.js';
|
|
4
|
+
import { actionInitLog, loggerFactory } from './logger.js';
|
|
5
5
|
import { DataBaseProvider } from '../db/DataBaseProvider.js';
|
|
6
6
|
import { getDeployId } from './conf.js';
|
|
7
7
|
|
|
@@ -77,7 +77,7 @@ const saveRuntimeRouter = async () => {
|
|
|
77
77
|
|
|
78
78
|
if (closeConn) await DataBaseProvider.instance[`${host}${path}`].mongoose.close();
|
|
79
79
|
} catch (error) {
|
|
80
|
-
logger.error(error);
|
|
80
|
+
logger.error(error, error.stack);
|
|
81
81
|
}
|
|
82
82
|
};
|
|
83
83
|
|
|
@@ -114,7 +114,7 @@ const saveRuntimeCron = async () => {
|
|
|
114
114
|
|
|
115
115
|
if (closeConn) await DataBaseProvider.instance[`${host}${path}`].mongoose.close();
|
|
116
116
|
} catch (error) {
|
|
117
|
-
logger.error(error);
|
|
117
|
+
logger.error(error, error.stack);
|
|
118
118
|
}
|
|
119
119
|
};
|
|
120
120
|
|
|
@@ -134,7 +134,10 @@ const listenServerFactory = (logic = async () => {}) => {
|
|
|
134
134
|
const listenPortController = async (server, port, metadata) =>
|
|
135
135
|
new Promise((resolve) => {
|
|
136
136
|
try {
|
|
137
|
-
if (
|
|
137
|
+
if (port === ':') {
|
|
138
|
+
server.listen(port, actionInitLog);
|
|
139
|
+
return resolve(true);
|
|
140
|
+
}
|
|
138
141
|
|
|
139
142
|
const { host, path, client, runtime, meta } = metadata;
|
|
140
143
|
const error = [];
|
package/src/dns.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// https://nodejs.org/api
|
|
4
|
-
// https://expressjs.com/en/4x/api.html
|
|
5
|
-
|
|
6
|
-
import dotenv from 'dotenv';
|
|
7
|
-
import { loggerFactory } from './server/logger.js';
|
|
8
|
-
import { Dns } from './server/dns.js';
|
|
9
|
-
import { ProcessController } from './server/process.js';
|
|
10
|
-
import { Config } from './server/conf.js';
|
|
11
|
-
|
|
12
|
-
dotenv.config();
|
|
13
|
-
|
|
14
|
-
await Config.build();
|
|
15
|
-
|
|
16
|
-
const logger = loggerFactory(import.meta);
|
|
17
|
-
|
|
18
|
-
await logger.setUpInfo();
|
|
19
|
-
|
|
20
|
-
await Dns.InitIpDaemon();
|
|
21
|
-
|
|
22
|
-
ProcessController.init(logger);
|