cyberia 3.2.9 → 3.2.22
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/.github/workflows/engine-cyberia.cd.yml +7 -0
- package/.github/workflows/engine-cyberia.ci.yml +14 -2
- package/.github/workflows/ghpkg.ci.yml +1 -0
- package/.github/workflows/npmpkg.ci.yml +10 -5
- package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
- package/.github/workflows/release.cd.yml +1 -0
- package/.vscode/extensions.json +9 -9
- package/.vscode/settings.json +20 -4
- package/CHANGELOG.md +363 -1
- package/CLI-HELP.md +975 -1061
- package/README.md +190 -348
- package/bin/build.js +102 -125
- package/bin/build.template.js +33 -0
- package/bin/cyberia.js +238 -56
- package/bin/deploy.js +16 -3
- package/bin/index.js +238 -56
- package/bump.config.js +26 -0
- package/conf.js +131 -24
- package/deployment.yaml +76 -2
- package/hardhat/package-lock.json +113 -144
- package/hardhat/package.json +4 -3
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +2 -2
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
- package/manifests/deployment/dd-cyberia-development/deployment.yaml +76 -2
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/kind-config-dev.yaml +8 -0
- package/manifests/lxd/lxd-admin-profile.yaml +12 -3
- package/manifests/mongodb/pv-pvc.yaml +44 -8
- package/manifests/mongodb/statefulset.yaml +55 -68
- package/manifests/mongodb-4.4/headless-service.yaml +10 -0
- package/manifests/mongodb-4.4/kustomization.yaml +3 -1
- package/manifests/mongodb-4.4/mongodb-nodeport.yaml +17 -0
- package/manifests/mongodb-4.4/pv-pvc.yaml +10 -14
- package/manifests/mongodb-4.4/statefulset.yaml +79 -0
- package/manifests/mongodb-4.4/storage-class.yaml +9 -0
- package/manifests/valkey/statefulset.yaml +1 -1
- package/manifests/valkey/valkey-nodeport.yaml +17 -0
- package/package.json +31 -19
- package/scripts/ipxe-setup.sh +52 -49
- package/scripts/k3s-node-setup.sh +81 -46
- package/scripts/link-local-underpost-cli.sh +6 -0
- package/scripts/lxd-vm-setup.sh +193 -8
- package/scripts/maas-nat-firewalld.sh +145 -0
- package/scripts/test-monitor.sh +250 -0
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +38 -33
- package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +16 -16
- package/src/api/core/core.router.js +19 -14
- package/src/api/core/core.service.js +5 -5
- package/src/api/crypto/crypto.router.js +18 -12
- package/src/api/crypto/crypto.service.js +3 -3
- package/src/api/cyberia-action/cyberia-action.model.js +1 -1
- package/src/api/cyberia-action/cyberia-action.router.js +22 -18
- package/src/api/cyberia-action/cyberia-action.service.js +5 -5
- package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +74 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +99 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +98 -0
- package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +152 -0
- package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +25 -20
- package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +6 -6
- package/src/api/cyberia-entity/cyberia-entity.router.js +22 -18
- package/src/api/cyberia-entity/cyberia-entity.service.js +5 -5
- package/src/api/cyberia-instance/cyberia-fallback-world.js +79 -4
- package/src/api/cyberia-instance/cyberia-instance.router.js +57 -52
- package/src/api/cyberia-instance/cyberia-instance.service.js +10 -10
- package/src/api/cyberia-instance/cyberia-world-generator.js +3 -3
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +14 -48
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +22 -18
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +5 -5
- package/src/api/cyberia-map/cyberia-map.router.js +35 -30
- package/src/api/cyberia-map/cyberia-map.service.js +7 -7
- package/src/api/cyberia-quest/cyberia-quest.model.js +1 -1
- package/src/api/cyberia-quest/cyberia-quest.router.js +22 -18
- package/src/api/cyberia-quest/cyberia-quest.service.js +5 -5
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +22 -18
- package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +5 -5
- package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +458 -0
- package/src/api/default/default.router.js +22 -18
- package/src/api/default/default.service.js +5 -5
- package/src/api/document/document.router.js +28 -23
- package/src/api/document/document.service.js +100 -23
- package/src/api/file/file.router.js +19 -13
- package/src/api/file/file.service.js +9 -7
- package/src/api/instance/instance.router.js +29 -24
- package/src/api/instance/instance.service.js +6 -6
- package/src/api/ipfs/ipfs.router.js +21 -16
- package/src/api/ipfs/ipfs.service.js +8 -8
- package/src/api/object-layer/object-layer.router.js +512 -507
- package/src/api/object-layer/object-layer.service.js +17 -14
- package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +22 -18
- package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +5 -5
- package/src/api/test/test.router.js +17 -12
- package/src/api/types.js +24 -0
- package/src/api/user/guest.service.js +5 -4
- package/src/api/user/user.router.js +297 -288
- package/src/api/user/user.service.js +100 -35
- package/src/cli/baremetal.js +132 -101
- package/src/cli/cluster.js +700 -232
- package/src/cli/db.js +59 -60
- package/src/cli/deploy.js +291 -294
- package/src/cli/env.js +1 -4
- package/src/cli/fs.js +13 -3
- package/src/cli/image.js +58 -4
- package/src/cli/index.js +127 -15
- package/src/cli/ipfs.js +4 -6
- package/src/cli/kubectl.js +4 -1
- package/src/cli/lxd.js +1099 -223
- package/src/cli/monitor.js +396 -9
- package/src/cli/release.js +355 -146
- package/src/cli/repository.js +169 -30
- package/src/cli/run.js +347 -117
- package/src/cli/secrets.js +11 -2
- package/src/cli/test.js +9 -3
- package/src/client/Default.index.js +9 -3
- package/src/client/components/core/Auth.js +5 -0
- package/src/client/components/core/ClientEvents.js +76 -0
- package/src/client/components/core/EventBus.js +4 -0
- package/src/client/components/core/Modal.js +82 -41
- package/src/client/components/core/PanelForm.js +14 -10
- package/src/client/components/core/Worker.js +162 -363
- package/src/client/components/cyberia/MapEngineCyberia.js +1 -1
- package/src/client/components/cyberia/SharedDefaultsCyberia.js +330 -0
- package/src/client/public/cyberia-docs/ACTION-SYSTEM.md +55 -1
- package/src/client/public/cyberia-docs/ARCHITECTURE.md +223 -361
- package/src/client/public/cyberia-docs/CYBERIA-CLI.md +114 -327
- package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +200 -222
- package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +212 -185
- package/src/client/public/cyberia-docs/CYBERIA.md +259 -0
- package/src/client/public/cyberia-docs/OFF-CHAIN-ECONOMY.md +2 -2
- package/src/client/public/cyberia-docs/QUEST-SYSTEM.md +23 -1
- package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
- package/src/client/public/cyberia-docs/UNDERPOST-PLATFORM.md +106 -0
- package/src/client/public/cyberia-docs/WHITE-PAPER.md +1 -1
- package/src/client/services/cyberia-client-hints/cyberia-client-hints.service.js +99 -0
- package/src/client/ssr/views/CyberiaServerMetrics.js +982 -0
- package/src/client/sw/core.sw.js +174 -112
- package/src/db/DataBaseProvider.js +115 -15
- package/src/db/mariadb/MariaDB.js +2 -1
- package/src/db/mongo/MongoBootstrap.js +657 -0
- package/src/db/mongo/MongooseDB.js +130 -21
- package/src/grpc/cyberia/grpc-server.js +25 -57
- package/src/index.js +1 -1
- package/src/runtime/cyberia-client/Dockerfile +10 -7
- package/src/runtime/cyberia-client/Dockerfile.dev +67 -0
- package/src/runtime/cyberia-server/Dockerfile +11 -6
- package/src/runtime/cyberia-server/Dockerfile.dev +47 -0
- package/src/runtime/express/Express.js +2 -2
- package/src/runtime/wp/Dockerfile +3 -3
- package/src/runtime/wp/Wp.js +8 -5
- package/src/server/auth.js +2 -2
- package/src/server/catalog-underpost.js +61 -0
- package/src/server/catalog.js +77 -0
- package/src/server/client-build-docs.js +1 -1
- package/src/server/client-build.js +94 -129
- package/src/server/conf.js +496 -135
- package/src/server/ipfs-client.js +5 -3
- package/src/server/process.js +180 -19
- package/src/server/proxy.js +9 -2
- package/src/server/runtime-status.js +235 -0
- package/src/server/runtime.js +1 -1
- package/src/server/start.js +44 -11
- package/src/server/valkey.js +2 -0
- package/src/ws/IoInterface.js +16 -16
- package/src/ws/core/channels/core.ws.chat.js +11 -11
- package/src/ws/core/channels/core.ws.mailer.js +29 -29
- package/src/ws/core/channels/core.ws.stream.js +19 -19
- package/src/ws/core/core.ws.connection.js +8 -8
- package/src/ws/core/core.ws.server.js +6 -5
- package/src/ws/default/channels/default.ws.main.js +10 -10
- package/src/ws/default/default.ws.connection.js +4 -4
- package/src/ws/default/default.ws.server.js +4 -3
- package/test/deploy-monitor.test.js +251 -0
- package/bin/file.js +0 -202
- package/bin/vs.js +0 -74
- package/bin/zed.js +0 -84
- package/manifests/deployment/dd-test-development/deployment.yaml +0 -254
- package/manifests/deployment/dd-test-development/proxy.yaml +0 -102
- package/src/api/cyberia-instance-conf/cyberia-instance-conf.defaults.js +0 -574
- package/src/client/components/cyberia-portal/CommonCyberiaPortal.js +0 -467
- package/src/client/ssr/email/DefaultRecoverEmail.js +0 -21
- package/src/client/ssr/email/DefaultVerifyEmail.js +0 -17
- package/src/client/ssr/pages/CyberiaServerMetrics.js +0 -461
- /package/src/client/ssr/{offline → views}/Maintenance.js +0 -0
- /package/src/client/ssr/{offline → views}/NoNetworkConnection.js +0 -0
- /package/src/client/ssr/{pages → views}/Test.js +0 -0
package/src/server/conf.js
CHANGED
|
@@ -10,6 +10,7 @@ import dotenv from 'dotenv';
|
|
|
10
10
|
import {
|
|
11
11
|
capFirst,
|
|
12
12
|
getCapVariableName,
|
|
13
|
+
getDirname,
|
|
13
14
|
newInstance,
|
|
14
15
|
orderAbc,
|
|
15
16
|
orderArrayFromAttrInt,
|
|
@@ -41,6 +42,20 @@ const logger = loggerFactory(import.meta);
|
|
|
41
42
|
*/
|
|
42
43
|
const ENV_REF_PREFIX = 'env:';
|
|
43
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Resolves a standardized context key from host/path descriptors.
|
|
47
|
+
* The key is used across DB, WS, mailer, and cache registries.
|
|
48
|
+
*
|
|
49
|
+
* @method resolveHostKeyContext
|
|
50
|
+
* @param {{host?: string, path?: string}|string} [context={ host: '', path: '' }] - Context object or prebuilt key.
|
|
51
|
+
* @returns {string} Host key context string.
|
|
52
|
+
* @memberof ServerConfBuilder
|
|
53
|
+
*/
|
|
54
|
+
const resolveHostKeyContext = (context = { host: '', path: '' }) => {
|
|
55
|
+
if (typeof context === 'string') return context;
|
|
56
|
+
return `${context.host || ''}${context.path || ''}`;
|
|
57
|
+
};
|
|
58
|
+
|
|
44
59
|
/**
|
|
45
60
|
* Recursively walks a configuration object and replaces every string value that
|
|
46
61
|
* starts with {@link ENV_REF_PREFIX} (`"env:"`) with the corresponding
|
|
@@ -320,25 +335,29 @@ const Config = {
|
|
|
320
335
|
|
|
321
336
|
if (!fs.existsSync(folder)) fs.mkdirSync(folder, { recursive: true });
|
|
322
337
|
|
|
323
|
-
const
|
|
338
|
+
const sharedEnvTemplate = fs.existsSync('./.env.example')
|
|
324
339
|
? fs.readFileSync('./.env.example', 'utf8')
|
|
325
340
|
: fs.existsSync('./.env.production')
|
|
326
341
|
? fs.readFileSync('./.env.production', 'utf8')
|
|
327
342
|
: '';
|
|
328
343
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
fs.
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
)
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
344
|
+
const envTemplates = {
|
|
345
|
+
production: fs.existsSync('./.env.production') ? fs.readFileSync('./.env.production', 'utf8') : sharedEnvTemplate,
|
|
346
|
+
development: fs.existsSync('./.env.development')
|
|
347
|
+
? fs.readFileSync('./.env.development', 'utf8')
|
|
348
|
+
: sharedEnvTemplate
|
|
349
|
+
? sharedEnvTemplate.replace('NODE_ENV=production', 'NODE_ENV=development').replace('PORT=3000', 'PORT=4000')
|
|
350
|
+
: '',
|
|
351
|
+
test: fs.existsSync('./.env.test')
|
|
352
|
+
? fs.readFileSync('./.env.test', 'utf8')
|
|
353
|
+
: sharedEnvTemplate
|
|
354
|
+
? sharedEnvTemplate.replace('NODE_ENV=production', 'NODE_ENV=test').replace('PORT=3000', 'PORT=5000')
|
|
355
|
+
: '',
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
for (const [envName, envTemplate] of Object.entries(envTemplates)) {
|
|
359
|
+
if (!envTemplate) continue;
|
|
360
|
+
fs.writeFileSync(`${folder}/.env.${envName}`, envTemplate.replaceAll('dd-default', deployId), 'utf8');
|
|
342
361
|
}
|
|
343
362
|
|
|
344
363
|
fs.writeFileSync(
|
|
@@ -1067,13 +1086,9 @@ const buildPortProxyRouter = (
|
|
|
1067
1086
|
|
|
1068
1087
|
if (Object.keys(router).length === 0) return router;
|
|
1069
1088
|
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
`./engine-private/conf/${process.argv[3]}/conf.server.dev.${process.argv[4]}-dev-api.json`,
|
|
1074
|
-
'utf8',
|
|
1075
|
-
),
|
|
1076
|
-
);
|
|
1089
|
+
const devApiConfPath = `./engine-private/conf/${process.argv[3]}/conf.server.dev.${process.argv[4]}-dev-api.json`;
|
|
1090
|
+
if (options.devProxyContext === true && process.env.NODE_ENV === 'development' && fs.existsSync(devApiConfPath)) {
|
|
1091
|
+
const confDevApiServer = JSON.parse(fs.readFileSync(devApiConfPath, 'utf8'));
|
|
1077
1092
|
let devApiHosts = [];
|
|
1078
1093
|
let origins = [];
|
|
1079
1094
|
for (const _host of Object.keys(confDevApiServer))
|
|
@@ -1208,7 +1223,11 @@ const validateTemplatePath = (absolutePath = '') => {
|
|
|
1208
1223
|
const confSsr = DefaultConf.ssr[ssr];
|
|
1209
1224
|
const clients = DefaultConf.client.default.services;
|
|
1210
1225
|
|
|
1211
|
-
if (
|
|
1226
|
+
if (
|
|
1227
|
+
absolutePath.match('src/api') &&
|
|
1228
|
+
!absolutePath.match('src/api/types.js') &&
|
|
1229
|
+
!confServer.apis.find((p) => absolutePath.match(`src/api/${p}/`))
|
|
1230
|
+
) {
|
|
1212
1231
|
return false;
|
|
1213
1232
|
}
|
|
1214
1233
|
if (absolutePath.match('conf.dd-') && absolutePath.match('.js')) return false;
|
|
@@ -1250,14 +1269,8 @@ const validateTemplatePath = (absolutePath = '') => {
|
|
|
1250
1269
|
return false;
|
|
1251
1270
|
}
|
|
1252
1271
|
if (
|
|
1253
|
-
absolutePath.match('src/client/ssr/
|
|
1254
|
-
!confSsr.
|
|
1255
|
-
) {
|
|
1256
|
-
return false;
|
|
1257
|
-
}
|
|
1258
|
-
if (
|
|
1259
|
-
absolutePath.match('src/client/ssr/pages') &&
|
|
1260
|
-
!confSsr.pages.find((p) => absolutePath.match(`src/client/ssr/pages/${p.client}.js`))
|
|
1272
|
+
absolutePath.match('src/client/ssr/views') &&
|
|
1273
|
+
!(confSsr.views || []).find((p) => absolutePath.match(`src/client/ssr/views/${p.client}.js`))
|
|
1261
1274
|
) {
|
|
1262
1275
|
return false;
|
|
1263
1276
|
}
|
|
@@ -1279,15 +1292,19 @@ const validateTemplatePath = (absolutePath = '') => {
|
|
|
1279
1292
|
/**
|
|
1280
1293
|
* @method awaitDeployMonitor
|
|
1281
1294
|
* @description Waits for the deploy monitor.
|
|
1282
|
-
* @param {boolean} [
|
|
1295
|
+
* @param {boolean} [isFinal=false] - If true, logs when the final (non-replica) deployment completes.
|
|
1283
1296
|
* @param {number} [deltaMs=1000] - The delta ms.
|
|
1284
|
-
* @
|
|
1297
|
+
* @param {boolean} [callback=false] - The callback.
|
|
1298
|
+
* @returns {Promise<boolean>} - `false` if `container-status=error` was detected, `true` on clean completion.
|
|
1285
1299
|
* @memberof ServerConfBuilder
|
|
1286
1300
|
*/
|
|
1287
|
-
const awaitDeployMonitor = async (
|
|
1288
|
-
if (
|
|
1301
|
+
const awaitDeployMonitor = async (isFinal = false, deltaMs = 1000, callback = false) => {
|
|
1302
|
+
if (!callback) Underpost.env.set('await-deploy', new Date().toISOString());
|
|
1303
|
+
if (isFinal) logger.info('Final deployment running (no replica)');
|
|
1289
1304
|
await timer(deltaMs);
|
|
1290
|
-
if (Underpost.env.get('
|
|
1305
|
+
if (Underpost.env.get('container-status') === 'error') return false;
|
|
1306
|
+
if (Underpost.env.get('await-deploy')) return await awaitDeployMonitor(false, deltaMs, true);
|
|
1307
|
+
return true;
|
|
1291
1308
|
};
|
|
1292
1309
|
|
|
1293
1310
|
/**
|
|
@@ -1312,59 +1329,6 @@ const mergeFile = async (parts = [], outputFilePath) => {
|
|
|
1312
1329
|
});
|
|
1313
1330
|
};
|
|
1314
1331
|
|
|
1315
|
-
/**
|
|
1316
|
-
* @method rebuildConfFactory
|
|
1317
|
-
* @description Rebuilds the conf factory.
|
|
1318
|
-
* @param {object} options - The options.
|
|
1319
|
-
* @param {string} options.deployId - The deploy ID.
|
|
1320
|
-
* @param {string} options.valkey - The valkey.
|
|
1321
|
-
* @param {boolean} [options.mongo=false] - The mongo.
|
|
1322
|
-
* @returns {object} - The rebuild conf factory.
|
|
1323
|
-
* @memberof ServerConfBuilder
|
|
1324
|
-
*/
|
|
1325
|
-
const rebuildConfFactory = ({ deployId, valkey, mongo }) => {
|
|
1326
|
-
const confServer = loadReplicas(deployId, loadConfServerJson(`./engine-private/conf/${deployId}/conf.server.json`));
|
|
1327
|
-
const hosts = {};
|
|
1328
|
-
for (const host of Object.keys(confServer)) {
|
|
1329
|
-
hosts[host] = {};
|
|
1330
|
-
for (const path of Object.keys(confServer[host])) {
|
|
1331
|
-
if (!confServer[host][path].db) continue;
|
|
1332
|
-
const { singleReplica, replicas, db } = confServer[host][path];
|
|
1333
|
-
const { provider } = db;
|
|
1334
|
-
if (singleReplica) {
|
|
1335
|
-
for (const replica of replicas) {
|
|
1336
|
-
const deployIdReplica = buildReplicaId({ replica, deployId });
|
|
1337
|
-
const confServerReplica = loadConfServerJson(`./engine-private/replica/${deployIdReplica}/conf.server.json`);
|
|
1338
|
-
for (const _host of Object.keys(confServerReplica)) {
|
|
1339
|
-
for (const _path of Object.keys(confServerReplica[_host])) {
|
|
1340
|
-
hosts[host][_path] = { replica: { host, path } };
|
|
1341
|
-
confServerReplica[_host][_path].valkey = valkey;
|
|
1342
|
-
switch (provider) {
|
|
1343
|
-
case 'mongoose':
|
|
1344
|
-
confServerReplica[_host][_path].db.host = mongo.host;
|
|
1345
|
-
break;
|
|
1346
|
-
}
|
|
1347
|
-
}
|
|
1348
|
-
}
|
|
1349
|
-
fs.writeFileSync(
|
|
1350
|
-
`./engine-private/replica/${deployIdReplica}/conf.server.json`,
|
|
1351
|
-
JSON.stringify(confServerReplica, null, 4),
|
|
1352
|
-
'utf8',
|
|
1353
|
-
);
|
|
1354
|
-
}
|
|
1355
|
-
} else hosts[host][path] = {};
|
|
1356
|
-
confServer[host][path].valkey = valkey;
|
|
1357
|
-
switch (provider) {
|
|
1358
|
-
case 'mongoose':
|
|
1359
|
-
confServer[host][path].db.host = mongo.host;
|
|
1360
|
-
break;
|
|
1361
|
-
}
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
fs.writeFileSync(`./engine-private/conf/${deployId}/conf.server.json`, JSON.stringify(confServer, null, 4), 'utf8');
|
|
1365
|
-
return { hosts };
|
|
1366
|
-
};
|
|
1367
|
-
|
|
1368
1332
|
/**
|
|
1369
1333
|
* @method getPathsSSR
|
|
1370
1334
|
* @description Gets the paths SSR.
|
|
@@ -1377,8 +1341,7 @@ const getPathsSSR = (conf) => {
|
|
|
1377
1341
|
for (const o of conf.head) paths.push(`src/client/ssr/head/${o}.js`);
|
|
1378
1342
|
for (const o of conf.body) paths.push(`src/client/ssr/body/${o}.js`);
|
|
1379
1343
|
for (const o of Object.keys(conf.mailer)) paths.push(`src/client/ssr/mailer/${conf.mailer[o]}.js`);
|
|
1380
|
-
for (const o of conf.
|
|
1381
|
-
for (const o of conf.pages) paths.push(`src/client/ssr/pages/${o.client}.js`);
|
|
1344
|
+
for (const o of conf.views || []) paths.push(`src/client/ssr/views/${o.client}.js`);
|
|
1382
1345
|
return paths;
|
|
1383
1346
|
};
|
|
1384
1347
|
|
|
@@ -1457,65 +1420,131 @@ const writeEnv = (envPath, envObj) =>
|
|
|
1457
1420
|
|
|
1458
1421
|
/**
|
|
1459
1422
|
* @method buildCliDoc
|
|
1460
|
-
* @description
|
|
1461
|
-
*
|
|
1462
|
-
*
|
|
1463
|
-
*
|
|
1423
|
+
* @description Scrapes `node bin help` (and `node bin help <command>` for every
|
|
1424
|
+
* registered command) and renders a structured Markdown reference: a command
|
|
1425
|
+
* index with anchor links, plus a per-command section with its description,
|
|
1426
|
+
* usage, and Arguments/Options rendered as tables. Writes
|
|
1427
|
+
* `CLI-HELP.md` + the served reference doc, and refreshes the README CLI index.
|
|
1428
|
+
* @param {object} program - The commander program.
|
|
1429
|
+
* @param {string} oldVersion - The old version string to replace.
|
|
1430
|
+
* @param {string} newVersion - The new version string.
|
|
1464
1431
|
* @memberof ServerConfBuilder
|
|
1465
1432
|
*/
|
|
1466
1433
|
const buildCliDoc = (program, oldVersion, newVersion) => {
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
'
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1434
|
+
const help = (args = '') => shellExec(`node bin help${args ? ` ${args}` : ''}`, { silent: true, stdout: true });
|
|
1435
|
+
// Escape table-breaking pipes and collapse wrapped whitespace for a Markdown cell.
|
|
1436
|
+
const cell = (s) => String(s).replace(/\s+/g, ' ').replaceAll('|', '\\|').trim();
|
|
1437
|
+
const anchor = (name) => `underpost-${name}`.toLowerCase().replace(/[^a-z0-9-]/g, '');
|
|
1438
|
+
|
|
1439
|
+
// Parse a commander help block into { usage, description, sections: { Options, Arguments, Commands } }.
|
|
1440
|
+
const parseHelp = (text) => {
|
|
1441
|
+
const lines = text.split('\n');
|
|
1442
|
+
const usageMatch = lines[0].match(/^Usage:\s*(.*)$/);
|
|
1443
|
+
const usage = usageMatch ? usageMatch[1].trim() : '';
|
|
1444
|
+
const sections = {};
|
|
1445
|
+
const descLines = [];
|
|
1446
|
+
let current = null;
|
|
1447
|
+
let buf = [];
|
|
1448
|
+
const flush = () => {
|
|
1449
|
+
if (current) sections[current] = buf.join('\n');
|
|
1450
|
+
buf = [];
|
|
1451
|
+
};
|
|
1452
|
+
for (let i = 1; i < lines.length; i++) {
|
|
1453
|
+
const line = lines[i];
|
|
1454
|
+
const head = line.match(/^([A-Za-z][\w ]*):\s*$/); // top-level "Options:", "Arguments:", "Commands:"
|
|
1455
|
+
if (head) {
|
|
1456
|
+
flush();
|
|
1457
|
+
current = head[1].trim();
|
|
1458
|
+
} else if (current !== null) {
|
|
1459
|
+
buf.push(line);
|
|
1460
|
+
} else {
|
|
1461
|
+
descLines.push(line);
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
flush();
|
|
1465
|
+
return { usage, description: descLines.join('\n').trim(), sections };
|
|
1466
|
+
};
|
|
1467
|
+
|
|
1468
|
+
// Parse a columnar " <term> <description>" section (descriptions may wrap onto
|
|
1469
|
+
// indented continuation lines) into [{ term, desc }].
|
|
1470
|
+
const parseEntries = (text = '') => {
|
|
1471
|
+
const entries = [];
|
|
1472
|
+
for (const line of text.split('\n')) {
|
|
1473
|
+
if (!line.trim()) continue;
|
|
1474
|
+
const leading = line.length - line.trimStart().length;
|
|
1475
|
+
if (leading <= 2) {
|
|
1476
|
+
const rest = line.trim();
|
|
1477
|
+
const gap = rest.search(/\s{2,}/);
|
|
1478
|
+
entries.push(gap === -1 ? { term: rest, desc: '' } : { term: rest.slice(0, gap), desc: rest.slice(gap) });
|
|
1479
|
+
} else if (entries.length) {
|
|
1480
|
+
entries[entries.length - 1].desc += ` ${line.trim()}`;
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
return entries;
|
|
1484
|
+
};
|
|
1485
|
+
|
|
1486
|
+
const table = (head, entries) =>
|
|
1487
|
+
!entries.length
|
|
1488
|
+
? ''
|
|
1489
|
+
: `| ${head[0]} | ${head[1]} |\n| --- | --- |\n` +
|
|
1490
|
+
entries.map(({ term, desc }) => `| \`${cell(term)}\` | ${cell(desc)} |`).join('\n') +
|
|
1491
|
+
'\n';
|
|
1492
|
+
|
|
1493
|
+
const detailSection = (sections, name, head) => {
|
|
1494
|
+
const t = table(head, parseEntries(sections[name]));
|
|
1495
|
+
return t ? `\n#### ${name}\n\n${t}` : '';
|
|
1496
|
+
};
|
|
1497
|
+
|
|
1498
|
+
// ── Top-level index ──
|
|
1499
|
+
const root = parseHelp(help());
|
|
1500
|
+
const commandEntries = parseEntries(root.sections['Commands']).filter((e) => e.term.split(' ')[0] !== 'help');
|
|
1501
|
+
|
|
1502
|
+
const index =
|
|
1503
|
+
`## Underpost CLI\n\n` +
|
|
1504
|
+
(root.description ? `> ${root.description.replace(/\s+/g, ' ')}\n\n` : '') +
|
|
1505
|
+
`**Usage:** \`${root.usage}\`\n\n` +
|
|
1506
|
+
`### Global options\n\n${table(['Option', 'Description'], parseEntries(root.sections['Options']))}\n` +
|
|
1507
|
+
`### Commands\n\n| Command | Description |\n| --- | --- |\n` +
|
|
1508
|
+
commandEntries
|
|
1509
|
+
.map((e) => {
|
|
1510
|
+
const name = e.term.split(' ')[0];
|
|
1511
|
+
return `| [\`${name}\`](#${anchor(name)}) | ${cell(e.desc)} |`;
|
|
1512
|
+
})
|
|
1513
|
+
.join('\n') +
|
|
1514
|
+
'\n';
|
|
1515
|
+
|
|
1516
|
+
// ── Per-command detail ──
|
|
1517
|
+
let details = `\n## Command reference\n`;
|
|
1518
|
+
for (const cmd of program.commands) {
|
|
1519
|
+
const name = cmd._name;
|
|
1520
|
+
if (name === 'help') continue;
|
|
1521
|
+
const cmdHelp = parseHelp(help(name));
|
|
1522
|
+
details +=
|
|
1523
|
+
`\n### underpost ${name}\n\n` +
|
|
1524
|
+
(cmdHelp.description ? `${cmdHelp.description.replace(/\s+/g, ' ')}\n\n` : '') +
|
|
1525
|
+
`**Usage:** \`${cmdHelp.usage}\`\n` +
|
|
1526
|
+
detailSection(cmdHelp.sections, 'Arguments', ['Argument', 'Description']) +
|
|
1527
|
+
detailSection(cmdHelp.sections, 'Options', ['Option', 'Description']) +
|
|
1528
|
+
`\n---\n`;
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
const md = `${index}${details}`.replaceAll(oldVersion, newVersion);
|
|
1503
1532
|
fs.writeFileSync(`./src/client/public/nexodev/docs/references/Command Line Interface.md`, md, 'utf8');
|
|
1504
1533
|
fs.writeFileSync(`./CLI-HELP.md`, md, 'utf8');
|
|
1505
1534
|
|
|
1506
|
-
// Update README.md:
|
|
1507
|
-
let readme = fs.readFileSync(`./README.md`, 'utf8');
|
|
1508
|
-
readme = readme.replaceAll(oldVersion, newVersion);
|
|
1535
|
+
// Update README.md: bump version and refresh the CLI index between the comment tags.
|
|
1536
|
+
let readme = fs.readFileSync(`./README.md`, 'utf8').replaceAll(oldVersion, newVersion);
|
|
1509
1537
|
const cliStartTag = '<!-- cli-index-start -->';
|
|
1510
1538
|
const cliEndTag = '<!-- cli-index-end -->';
|
|
1511
1539
|
const startIdx = readme.indexOf(cliStartTag);
|
|
1512
1540
|
const endIdx = readme.indexOf(cliEndTag);
|
|
1513
1541
|
if (startIdx !== -1 && endIdx !== -1) {
|
|
1542
|
+
const readmeIndex = index.replace(/\(#(underpost-[a-z0-9-]+)\)/g, '(CLI-HELP.md#$1)');
|
|
1514
1543
|
readme =
|
|
1515
1544
|
readme.substring(0, startIdx) +
|
|
1516
1545
|
cliStartTag +
|
|
1517
1546
|
'\n' +
|
|
1518
|
-
|
|
1547
|
+
readmeIndex.replaceAll(oldVersion, newVersion) +
|
|
1519
1548
|
'\n' +
|
|
1520
1549
|
cliEndTag +
|
|
1521
1550
|
readme.substring(endIdx + cliEndTag.length);
|
|
@@ -1746,6 +1775,331 @@ const loadConfServerJson = (jsonPath, options) => {
|
|
|
1746
1775
|
return options && options.resolve === true ? resolveConfSecrets(raw) : raw;
|
|
1747
1776
|
};
|
|
1748
1777
|
|
|
1778
|
+
/**
|
|
1779
|
+
* Creates and writes the /etc/hosts file for a deployment.
|
|
1780
|
+
* @method etcHostFactory
|
|
1781
|
+
* @param {Array<string>} hosts - List of hosts to be added to the hosts file.
|
|
1782
|
+
* @param {object} options - Options for the hosts file creation.
|
|
1783
|
+
* @param {boolean} options.append - Whether to append to the existing hosts file.
|
|
1784
|
+
* @returns {object} - Object containing the rendered hosts file.
|
|
1785
|
+
* @memberof ServerConfBuilder
|
|
1786
|
+
*/
|
|
1787
|
+
const etcHostFactory = (hosts = [], options = { append: false }) => {
|
|
1788
|
+
hosts = hosts.map((host) => {
|
|
1789
|
+
try {
|
|
1790
|
+
if (!host.startsWith('http')) host = `http://${host}`;
|
|
1791
|
+
const hostname = new URL(host).hostname;
|
|
1792
|
+
logger.info('Hostname extract valid', { host, hostname });
|
|
1793
|
+
return hostname;
|
|
1794
|
+
} catch (e) {
|
|
1795
|
+
logger.warn('No hostname extract valid', host);
|
|
1796
|
+
return host;
|
|
1797
|
+
}
|
|
1798
|
+
});
|
|
1799
|
+
const renderHosts = `127.0.0.1 ${hosts.join(
|
|
1800
|
+
' ',
|
|
1801
|
+
)} localhost localhost.localdomain localhost4 localhost4.localdomain4
|
|
1802
|
+
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6`;
|
|
1803
|
+
|
|
1804
|
+
if (options && options.append && fs.existsSync(`/etc/hosts`)) {
|
|
1805
|
+
fs.writeFileSync(
|
|
1806
|
+
`/etc/hosts`,
|
|
1807
|
+
fs.readFileSync(`/etc/hosts`, 'utf8') +
|
|
1808
|
+
`
|
|
1809
|
+
${renderHosts}`,
|
|
1810
|
+
'utf8',
|
|
1811
|
+
);
|
|
1812
|
+
} else fs.writeFileSync(`/etc/hosts`, renderHosts, 'utf8');
|
|
1813
|
+
return { renderHosts };
|
|
1814
|
+
};
|
|
1815
|
+
|
|
1816
|
+
/**
|
|
1817
|
+
* Resolves the concrete deploy ids a build or conf-sync run should iterate over.
|
|
1818
|
+
*
|
|
1819
|
+
* The meta deploy id `dd` fans out to the comma separated ids declared in
|
|
1820
|
+
* `engine-private/deploy/dd.router`; any other value is parsed as a comma separated list.
|
|
1821
|
+
* Entries are trimmed and empties dropped.
|
|
1822
|
+
*
|
|
1823
|
+
* @method resolveDeployList
|
|
1824
|
+
* @param {string} deployId - A deploy id, a comma separated list, or the `dd` meta id.
|
|
1825
|
+
* @returns {string[]} Ordered list of concrete deploy ids.
|
|
1826
|
+
* @memberof ServerConfBuilder
|
|
1827
|
+
*/
|
|
1828
|
+
const resolveDeployList = (deployId) =>
|
|
1829
|
+
(deployId === 'dd' ? fs.readFileSync('./engine-private/deploy/dd.router', 'utf8') : deployId)
|
|
1830
|
+
.split(',')
|
|
1831
|
+
.map((id) => id.trim())
|
|
1832
|
+
.filter(Boolean);
|
|
1833
|
+
|
|
1834
|
+
/**
|
|
1835
|
+
* Syncs a single deploy id's private configuration into its dedicated
|
|
1836
|
+
* `engine-<suffix>-private` repository and pushes the result.
|
|
1837
|
+
*
|
|
1838
|
+
* Idempotent and safe to rerun: the private repo is cloned when missing or reset to a clean
|
|
1839
|
+
* checkout when present, then the deploy id's `conf` folder, matching `replica` and
|
|
1840
|
+
* `itc-scripts` entries, and any caller-supplied `extraPaths` payloads are mirrored. The
|
|
1841
|
+
* commit/push step is a no-op when nothing changed (`silentOnError`).
|
|
1842
|
+
*
|
|
1843
|
+
* @method syncPrivateConf
|
|
1844
|
+
* @param {string} deployId - A concrete deploy id (e.g. `dd-cyberia`), not the `dd` meta id.
|
|
1845
|
+
* @param {string[]} [extraPaths=[]] - Extra `./engine-private` payload paths to mirror (from the
|
|
1846
|
+
* deploy's product catalog), kept out of this module so it stays product-agnostic.
|
|
1847
|
+
* @returns {void}
|
|
1848
|
+
* @memberof ServerConfBuilder
|
|
1849
|
+
*/
|
|
1850
|
+
const syncPrivateConf = (deployId, extraPaths = []) => {
|
|
1851
|
+
const suffix = deployId.split('dd-')[1];
|
|
1852
|
+
const privateRepoName = `engine-${suffix}-private`;
|
|
1853
|
+
const privateGitUri = `${process.env.GITHUB_USERNAME}/${privateRepoName}`;
|
|
1854
|
+
const privateRepoPath = `../${privateRepoName}`;
|
|
1855
|
+
|
|
1856
|
+
if (!fs.existsSync(privateRepoPath)) {
|
|
1857
|
+
shellExec(`cd .. && underpost clone ${privateGitUri}`, { silent: true });
|
|
1858
|
+
} else {
|
|
1859
|
+
shellExec(`git config --global --add safe.directory '${dir.resolve(privateRepoPath)}'`);
|
|
1860
|
+
shellExec(`cd ${privateRepoPath} && git checkout . && git clean -f -d && underpost pull . ${privateGitUri}`, {
|
|
1861
|
+
silent: true,
|
|
1862
|
+
});
|
|
1863
|
+
}
|
|
1864
|
+
|
|
1865
|
+
const confDest = `${privateRepoPath}/conf/${deployId}`;
|
|
1866
|
+
fs.removeSync(confDest);
|
|
1867
|
+
fs.mkdirSync(confDest, { recursive: true });
|
|
1868
|
+
fs.copySync(`./engine-private/conf/${deployId}`, confDest);
|
|
1869
|
+
|
|
1870
|
+
fs.removeSync(`${privateRepoPath}/replica`);
|
|
1871
|
+
for (const payloadDir of ['replica', 'itc-scripts']) {
|
|
1872
|
+
const srcDir = `./engine-private/${payloadDir}`;
|
|
1873
|
+
if (!fs.existsSync(srcDir)) continue;
|
|
1874
|
+
for (const entry of fs.readdirSync(srcDir))
|
|
1875
|
+
if (entry.match(deployId)) fs.copySync(`${srcDir}/${entry}`, `${privateRepoPath}/${payloadDir}/${entry}`);
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
for (const extraPath of extraPaths) fs.copySync(`./engine-private/${extraPath}`, `${privateRepoPath}/${extraPath}`);
|
|
1879
|
+
|
|
1880
|
+
shellExec(
|
|
1881
|
+
`cd ${privateRepoPath}` +
|
|
1882
|
+
` && git add .` +
|
|
1883
|
+
` && underpost cmt . ci engine-core-conf 'Update ${deployId} conf'` +
|
|
1884
|
+
` && underpost push . ${privateGitUri}`,
|
|
1885
|
+
{ silent: true, silentOnError: true },
|
|
1886
|
+
);
|
|
1887
|
+
};
|
|
1888
|
+
|
|
1889
|
+
/**
|
|
1890
|
+
* Moves a deploy's public template sources into the engine working tree ahead of
|
|
1891
|
+
* the build copy step. Idempotent and safe to rerun: each move is guarded by
|
|
1892
|
+
* `existsSync`, so already-moved or absent sources are skipped rather than throwing.
|
|
1893
|
+
* The `[src, dest]` pairs come from the deploy's product catalog (passed in), so
|
|
1894
|
+
* this module stays product-agnostic.
|
|
1895
|
+
*
|
|
1896
|
+
* @method syncDeployIdSources
|
|
1897
|
+
* @param {Array<[string, string]>} [sourceMoves=[]] - Public `[src, dest]` move pairs.
|
|
1898
|
+
* @returns {boolean} `true` when any sources were declared, else `false`.
|
|
1899
|
+
* @memberof ServerConfBuilder
|
|
1900
|
+
*/
|
|
1901
|
+
const syncDeployIdSources = (sourceMoves = []) => {
|
|
1902
|
+
if (!sourceMoves.length) return false;
|
|
1903
|
+
for (const dir of ['src/api', 'src/client/components', 'src/client/public', 'src/client/services'])
|
|
1904
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
1905
|
+
for (const [src, dest] of sourceMoves) if (fs.existsSync(src)) fs.moveSync(src, dest, { overwrite: true });
|
|
1906
|
+
return true;
|
|
1907
|
+
};
|
|
1908
|
+
|
|
1909
|
+
/**
|
|
1910
|
+
* Rebuilds the standalone `pwa-microservices-template` from scratch out of the current
|
|
1911
|
+
* engine source tree.
|
|
1912
|
+
*
|
|
1913
|
+
* Clones the template repo next to the engine when missing, otherwise resets it to a clean
|
|
1914
|
+
* pristine checkout, then syncs every engine-tracked file the template is allowed to carry
|
|
1915
|
+
* ({@link validateTemplatePath}), strips engine-only + product modules, restores the template's
|
|
1916
|
+
* own CI workflows + guest services, and rewrites `package.json` / `package-lock.json` / `README`
|
|
1917
|
+
* so the result is a standalone, installable project. Throws on failure; callers own exit codes.
|
|
1918
|
+
*
|
|
1919
|
+
* Product catalogs are read dynamically ({@link module:src/server/catalog} `loadProductCatalogs`),
|
|
1920
|
+
* so this stays decoupled from — and survives removal of — any product module.
|
|
1921
|
+
*
|
|
1922
|
+
* @method buildTemplate
|
|
1923
|
+
* @param {object} [options]
|
|
1924
|
+
* @param {string} [options.srcPath='./'] - Engine source root to sync from.
|
|
1925
|
+
* @param {string} [options.toPath='../pwa-microservices-template'] - Template output path.
|
|
1926
|
+
* @returns {Promise<void>}
|
|
1927
|
+
* @memberof ServerConfBuilder
|
|
1928
|
+
*/
|
|
1929
|
+
const buildTemplate = async ({ srcPath = './', toPath = '../pwa-microservices-template' } = {}) => {
|
|
1930
|
+
const walk = (await import('ignore-walk')).default;
|
|
1931
|
+
const { TEMPLATE_RESTORE_PATHS, TEMPLATE_KEYWORDS, TEMPLATE_DESCRIPTION } = await import('./catalog-underpost.js');
|
|
1932
|
+
const { loadProductCatalogs } = await import('./catalog.js');
|
|
1933
|
+
const githubUsername = process.env.GITHUB_USERNAME;
|
|
1934
|
+
|
|
1935
|
+
logger.info('Build template', { srcPath, toPath });
|
|
1936
|
+
|
|
1937
|
+
const sourceFiles = (
|
|
1938
|
+
await new Promise((resolve) =>
|
|
1939
|
+
walk({ path: srcPath, ignoreFiles: [`.gitignore`], includeEmpty: false, follow: false }, (...args) =>
|
|
1940
|
+
resolve(args[1]),
|
|
1941
|
+
),
|
|
1942
|
+
)
|
|
1943
|
+
).filter((p) => !p.startsWith('.git'));
|
|
1944
|
+
|
|
1945
|
+
fs.removeSync(`${githubUsername}/pwa-microservices-template`);
|
|
1946
|
+
shellExec(`cd .. && node engine/bin clone ${githubUsername}/pwa-microservices-template`);
|
|
1947
|
+
|
|
1948
|
+
shellExec(`cd ${toPath} && git config core.filemode false`);
|
|
1949
|
+
|
|
1950
|
+
for (const copyPath of sourceFiles) {
|
|
1951
|
+
if (copyPath === 'NaN') continue;
|
|
1952
|
+
const absolutePath = `${srcPath}/${copyPath}`;
|
|
1953
|
+
if (!validateTemplatePath(absolutePath)) continue;
|
|
1954
|
+
|
|
1955
|
+
const folder = getDirname(`${toPath}/${copyPath}`);
|
|
1956
|
+
if (!fs.existsSync(folder)) fs.mkdirSync(folder, { recursive: true });
|
|
1957
|
+
|
|
1958
|
+
logger.info('build', `${toPath}/${copyPath}`);
|
|
1959
|
+
fs.copyFileSync(absolutePath, `${toPath}/${copyPath}`);
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
fs.copySync(`./.vscode`, `${toPath}/.vscode`);
|
|
1963
|
+
fs.copySync(`./src/client/public/default`, `${toPath}/src/client/public/default`);
|
|
1964
|
+
|
|
1965
|
+
// Preserve the template's own README + package.json identity before merging engine metadata.
|
|
1966
|
+
for (const checkoutPath of ['README.md', 'package.json']) shellExec(`cd ${toPath} && git checkout ${checkoutPath}`);
|
|
1967
|
+
|
|
1968
|
+
// Strip each product catalog's `stripPaths` (aggregated dynamically) plus the engine-only
|
|
1969
|
+
// workflows, deploy manifests, and product catalog modules.
|
|
1970
|
+
const productStripPaths = (await loadProductCatalogs()).flatMap((c) => c.stripPaths);
|
|
1971
|
+
for (const deletePath of productStripPaths) {
|
|
1972
|
+
const target = `${toPath}/${deletePath}`;
|
|
1973
|
+
if (fs.existsSync(target)) fs.removeSync(target);
|
|
1974
|
+
}
|
|
1975
|
+
shellExec(`rm -rf ${toPath}/.github`);
|
|
1976
|
+
shellExec(`rm -rf ${toPath}/manifests/deployment/dd-*`);
|
|
1977
|
+
shellExec(`rm -rf ${toPath}/src/server/catalog-*`);
|
|
1978
|
+
|
|
1979
|
+
fs.mkdirSync(`${toPath}/.github/workflows`, { recursive: true });
|
|
1980
|
+
for (const restorePath of TEMPLATE_RESTORE_PATHS) {
|
|
1981
|
+
const dest = `${toPath}/${restorePath}`;
|
|
1982
|
+
if (fs.statSync(restorePath).isDirectory()) fs.copySync(restorePath, dest, { overwrite: true });
|
|
1983
|
+
else fs.copyFileSync(restorePath, dest);
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
// ── package.json: take engine deps/scripts/version, keep template identity. ──
|
|
1987
|
+
const originPackageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
|
|
1988
|
+
const templatePackageJson = JSON.parse(fs.readFileSync(`${toPath}/package.json`, 'utf8'));
|
|
1989
|
+
const templateName = templatePackageJson.name;
|
|
1990
|
+
|
|
1991
|
+
templatePackageJson.dependencies = originPackageJson.dependencies;
|
|
1992
|
+
templatePackageJson.devDependencies = originPackageJson.devDependencies;
|
|
1993
|
+
templatePackageJson.version = originPackageJson.version;
|
|
1994
|
+
templatePackageJson.scripts = originPackageJson.scripts;
|
|
1995
|
+
templatePackageJson.overrides = originPackageJson.overrides;
|
|
1996
|
+
templatePackageJson.name = templateName;
|
|
1997
|
+
templatePackageJson.description = TEMPLATE_DESCRIPTION;
|
|
1998
|
+
templatePackageJson.keywords = TEMPLATE_KEYWORDS;
|
|
1999
|
+
delete templatePackageJson.scripts['build:template'];
|
|
2000
|
+
fs.writeFileSync(`${toPath}/package.json`, JSON.stringify(templatePackageJson, null, 4), 'utf8');
|
|
2001
|
+
|
|
2002
|
+
// ── package-lock.json: mirror engine packages, keep template name/version on the root entry. ──
|
|
2003
|
+
const originPackageLockJson = JSON.parse(fs.readFileSync('./package-lock.json', 'utf8'));
|
|
2004
|
+
const templatePackageLockJson = JSON.parse(fs.readFileSync(`${toPath}/package-lock.json`, 'utf8'));
|
|
2005
|
+
const originBasePackageLock = newInstance(templatePackageLockJson.packages['']);
|
|
2006
|
+
templatePackageLockJson.name = templateName;
|
|
2007
|
+
templatePackageLockJson.version = originPackageLockJson.version;
|
|
2008
|
+
templatePackageLockJson.packages = originPackageLockJson.packages;
|
|
2009
|
+
templatePackageLockJson.packages[''].name = templateName;
|
|
2010
|
+
templatePackageLockJson.packages[''].version = originPackageLockJson.version;
|
|
2011
|
+
templatePackageLockJson.packages[''].hasInstallScript = originBasePackageLock.hasInstallScript;
|
|
2012
|
+
templatePackageLockJson.packages[''].license = originBasePackageLock.license;
|
|
2013
|
+
fs.writeFileSync(`${toPath}/package-lock.json`, JSON.stringify(templatePackageLockJson, null, 4), 'utf8');
|
|
2014
|
+
|
|
2015
|
+
fs.writeFileSync(
|
|
2016
|
+
`${toPath}/README.md`,
|
|
2017
|
+
fs
|
|
2018
|
+
.readFileSync('./README.md', 'utf8')
|
|
2019
|
+
.replace('<!-- template-title -->', '#### Base template for pwa/api-rest projects.'),
|
|
2020
|
+
'utf8',
|
|
2021
|
+
);
|
|
2022
|
+
};
|
|
2023
|
+
|
|
2024
|
+
const updatePrivateTemplateRepo = async () => {
|
|
2025
|
+
const templatePath = '/home/dd/pwa-microservices-template';
|
|
2026
|
+
shellExec(`sudo rm -rf ${templatePath}
|
|
2027
|
+
cd /home/dd/engine && npm run build:template
|
|
2028
|
+
cd /home/dd
|
|
2029
|
+
underpost clone --bare underpostnet/pwa-microservices-template-private
|
|
2030
|
+
sudo rm -rf ${templatePath}/.git
|
|
2031
|
+
mv ./pwa-microservices-template-private.git ${templatePath}/.git
|
|
2032
|
+
cd ${templatePath}
|
|
2033
|
+
npm install --omit=dev --ignore-scripts
|
|
2034
|
+
git init
|
|
2035
|
+
git config user.name 'underpostnet'
|
|
2036
|
+
git config user.email 'development@underpost.net'
|
|
2037
|
+
git add .`);
|
|
2038
|
+
const hasChanges = shellExec(`node bin cmt ${templatePath} --has-changes`, {
|
|
2039
|
+
stdout: true,
|
|
2040
|
+
silent: true,
|
|
2041
|
+
disableLog: true,
|
|
2042
|
+
}).trim();
|
|
2043
|
+
if (hasChanges === '1') {
|
|
2044
|
+
shellExec(
|
|
2045
|
+
`cd ${templatePath} && git commit -m 'Update template' && underpost push . underpostnet/pwa-microservices-template-private`,
|
|
2046
|
+
);
|
|
2047
|
+
}
|
|
2048
|
+
};
|
|
2049
|
+
|
|
2050
|
+
/**
|
|
2051
|
+
* @method updatePrivateEngineTestRepo
|
|
2052
|
+
* @description Publishes a deploy id's freshly assembled template to its private
|
|
2053
|
+
* **test** source repo `engine-test-<idPart>` (separate from the production
|
|
2054
|
+
* `engine-<idPart>`). A pod started with `underpost start --build --private-test-repo`
|
|
2055
|
+
* clones this repo, so work-in-progress engine source can be tested end to end
|
|
2056
|
+
* without touching the production source. Mirrors {@link updatePrivateTemplateRepo}
|
|
2057
|
+
* but per-deploy-id and against the test repo.
|
|
2058
|
+
*
|
|
2059
|
+
* Assumes the deploy id template has already been assembled at the template path
|
|
2060
|
+
* (run `node bin/build <deployId>` first, or use `node bin/build <deployId> --update-private`).
|
|
2061
|
+
* @param {string} deployId - Concrete deploy id (e.g. `dd-core`).
|
|
2062
|
+
* @returns {Promise<void>}
|
|
2063
|
+
* @memberof ServerConfBuilder
|
|
2064
|
+
*/
|
|
2065
|
+
const updatePrivateEngineTestRepo = async (deployId) => {
|
|
2066
|
+
const username = process.env.GITHUB_USERNAME || 'underpostnet';
|
|
2067
|
+
const repoName = `engine-test-${deployId.split('-')[1]}`;
|
|
2068
|
+
const templatePath = '/home/dd/pwa-microservices-template';
|
|
2069
|
+
if (!fs.existsSync(templatePath))
|
|
2070
|
+
throw new Error(`updatePrivateEngineTestRepo: assemble the template first (node bin/build ${deployId})`);
|
|
2071
|
+
|
|
2072
|
+
// Detach the assembled working tree from any engine-build git history.
|
|
2073
|
+
shellExec(`sudo rm -rf ${templatePath}/.git`);
|
|
2074
|
+
|
|
2075
|
+
// Adopt the test repo's existing history when present (so the push is a delta);
|
|
2076
|
+
// otherwise publish a fresh history on first push.
|
|
2077
|
+
shellExec(`cd /home/dd && sudo rm -rf ./${repoName}.git && underpost clone --bare ${username}/${repoName}`, {
|
|
2078
|
+
silent: true,
|
|
2079
|
+
disableLog: true,
|
|
2080
|
+
silentOnError: true,
|
|
2081
|
+
});
|
|
2082
|
+
if (fs.existsSync(`/home/dd/${repoName}.git`)) shellExec(`mv /home/dd/${repoName}.git ${templatePath}/.git`);
|
|
2083
|
+
|
|
2084
|
+
// `git init` converts the moved bare repo into a normal work-tree repo (bare
|
|
2085
|
+
// clones have no work tree, so `git add` would fail), and bootstraps a fresh
|
|
2086
|
+
// repo on first publish. Idempotent — mirrors updatePrivateTemplateRepo.
|
|
2087
|
+
shellExec(`cd ${templatePath}
|
|
2088
|
+
git init
|
|
2089
|
+
git config user.name '${username}'
|
|
2090
|
+
git config user.email 'development@underpost.net'
|
|
2091
|
+
git add .`);
|
|
2092
|
+
|
|
2093
|
+
const hasChanges = shellExec(`node bin cmt ${templatePath} --has-changes`, {
|
|
2094
|
+
stdout: true,
|
|
2095
|
+
silent: true,
|
|
2096
|
+
disableLog: true,
|
|
2097
|
+
}).trim();
|
|
2098
|
+
if (hasChanges === '1')
|
|
2099
|
+
shellExec(`cd ${templatePath} && git commit -m 'Update ${repoName}' && underpost push . ${username}/${repoName}`);
|
|
2100
|
+
else logger.info('No changes to publish', { repoName });
|
|
2101
|
+
};
|
|
2102
|
+
|
|
1749
2103
|
export {
|
|
1750
2104
|
Config,
|
|
1751
2105
|
loadConf,
|
|
@@ -1774,7 +2128,6 @@ export {
|
|
|
1774
2128
|
pathPortAssignmentFactory,
|
|
1775
2129
|
deployRangePortFactory,
|
|
1776
2130
|
awaitDeployMonitor,
|
|
1777
|
-
rebuildConfFactory,
|
|
1778
2131
|
buildCliDoc,
|
|
1779
2132
|
getInstanceContext,
|
|
1780
2133
|
buildApiConf,
|
|
@@ -1784,6 +2137,7 @@ export {
|
|
|
1784
2137
|
devProxyHostFactory,
|
|
1785
2138
|
isTlsDevProxy,
|
|
1786
2139
|
getTlsHosts,
|
|
2140
|
+
resolveHostKeyContext,
|
|
1787
2141
|
resolveConfSecrets,
|
|
1788
2142
|
loadConfServerJson,
|
|
1789
2143
|
getConfFolder,
|
|
@@ -1792,4 +2146,11 @@ export {
|
|
|
1792
2146
|
DEFAULT_DEPLOY_ID,
|
|
1793
2147
|
loadCronDeployEnv,
|
|
1794
2148
|
cronDeployIdResolve,
|
|
2149
|
+
etcHostFactory,
|
|
2150
|
+
resolveDeployList,
|
|
2151
|
+
syncPrivateConf,
|
|
2152
|
+
syncDeployIdSources,
|
|
2153
|
+
buildTemplate,
|
|
2154
|
+
updatePrivateTemplateRepo,
|
|
2155
|
+
updatePrivateEngineTestRepo,
|
|
1795
2156
|
};
|