underpost 2.95.3 → 2.95.8
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/README.md +2 -2
- package/bin/deploy.js +6 -26
- package/cli.md +13 -13
- package/conf.js +4 -1
- package/examples/{QUICK-REFERENCE.md → static-page/QUICK-REFERENCE.md} +0 -18
- package/examples/{README.md → static-page/README.md} +3 -44
- package/examples/{STATIC-GENERATOR-GUIDE.md → static-page/STATIC-GENERATOR-GUIDE.md} +0 -50
- package/examples/{ssr-components → static-page/ssr-components}/CustomPage.js +0 -13
- package/examples/{static-config-simple.json → static-page/static-config-example.json} +1 -1
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +2 -2
- package/package.json +1 -1
- package/src/cli/baremetal.js +19 -10
- package/src/cli/cloud-init.js +10 -4
- package/src/cli/cron.js +161 -29
- package/src/cli/db.js +59 -92
- package/src/cli/index.js +3 -58
- package/src/cli/repository.js +14 -0
- package/src/cli/run.js +2 -3
- package/src/cli/static.js +99 -194
- package/src/client/services/default/default.management.js +7 -0
- package/src/index.js +1 -1
- package/src/server/backup.js +4 -53
- package/src/server/conf.js +3 -4
- package/examples/static-config-example.json +0 -183
package/src/cli/static.js
CHANGED
|
@@ -2,55 +2,6 @@
|
|
|
2
2
|
* Static site generation module with enhanced customization capabilities
|
|
3
3
|
* @module src/cli/static.js
|
|
4
4
|
* @namespace UnderpostStatic
|
|
5
|
-
*
|
|
6
|
-
* @example
|
|
7
|
-
* // Basic usage - generate a simple page
|
|
8
|
-
* import UnderpostStatic from './static.js';
|
|
9
|
-
*
|
|
10
|
-
* await UnderpostStatic.API.callback({
|
|
11
|
-
* page: './src/client/ssr/body/DefaultSplashScreen.js',
|
|
12
|
-
* title: 'My App',
|
|
13
|
-
* outputPath: './dist/index.html'
|
|
14
|
-
* });
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* // Advanced usage - full customization
|
|
18
|
-
* await UnderpostStatic.API.callback({
|
|
19
|
-
* page: './src/client/ssr/body/CustomPage.js',
|
|
20
|
-
* outputPath: './dist/custom.html',
|
|
21
|
-
* metadata: {
|
|
22
|
-
* title: 'My Custom Page',
|
|
23
|
-
* description: 'A fully customized static page',
|
|
24
|
-
* keywords: ['static', 'generator', 'custom'],
|
|
25
|
-
* author: 'John Doe',
|
|
26
|
-
* themeColor: '#007bff',
|
|
27
|
-
* canonicalURL: 'https://example.com/custom',
|
|
28
|
-
* thumbnail: 'https://example.com/thumb.png'
|
|
29
|
-
* },
|
|
30
|
-
* scripts: {
|
|
31
|
-
* head: [
|
|
32
|
-
* { src: '/vendor/library.js', async: true },
|
|
33
|
-
* { content: 'console.log("Inline script");', type: 'module' }
|
|
34
|
-
* ],
|
|
35
|
-
* body: [
|
|
36
|
-
* { src: '/app.js', defer: true }
|
|
37
|
-
* ]
|
|
38
|
-
* },
|
|
39
|
-
* styles: [
|
|
40
|
-
* { href: '/custom.css' },
|
|
41
|
-
* { content: 'body { margin: 0; }' }
|
|
42
|
-
* ],
|
|
43
|
-
* headComponents: [
|
|
44
|
-
* './src/client/ssr/head/Seo.js',
|
|
45
|
-
* './src/client/ssr/head/Pwa.js'
|
|
46
|
-
* ],
|
|
47
|
-
* icons: {
|
|
48
|
-
* favicon: '/custom-favicon.ico',
|
|
49
|
-
* appleTouchIcon: '/apple-touch-icon.png'
|
|
50
|
-
* },
|
|
51
|
-
* env: 'production',
|
|
52
|
-
* minify: true
|
|
53
|
-
* });
|
|
54
5
|
*/
|
|
55
6
|
|
|
56
7
|
import fs from 'fs-extra';
|
|
@@ -140,6 +91,31 @@ const logger = loggerFactory(import.meta);
|
|
|
140
91
|
* @property {Object} [microdata=[]] - Structured data (JSON-LD)
|
|
141
92
|
*/
|
|
142
93
|
|
|
94
|
+
const DefaultStaticGenerationOptions = {
|
|
95
|
+
page: '',
|
|
96
|
+
title: '',
|
|
97
|
+
outputPath: '',
|
|
98
|
+
deployId: '',
|
|
99
|
+
buildHost: '',
|
|
100
|
+
buildPath: '/',
|
|
101
|
+
env: 'production',
|
|
102
|
+
build: false,
|
|
103
|
+
dev: false,
|
|
104
|
+
minify: true,
|
|
105
|
+
metadata: {},
|
|
106
|
+
scripts: {},
|
|
107
|
+
styles: [],
|
|
108
|
+
headComponents: [],
|
|
109
|
+
bodyComponents: [],
|
|
110
|
+
icons: {},
|
|
111
|
+
customPayload: {},
|
|
112
|
+
templateHelpers: {},
|
|
113
|
+
configFile: '',
|
|
114
|
+
lang: 'en',
|
|
115
|
+
dir: 'ltr',
|
|
116
|
+
microdata: [],
|
|
117
|
+
};
|
|
118
|
+
|
|
143
119
|
/**
|
|
144
120
|
* Template helper functions for common SSR patterns
|
|
145
121
|
* @namespace TemplateHelpers
|
|
@@ -150,19 +126,6 @@ const TemplateHelpers = {
|
|
|
150
126
|
* @param {ScriptOptions} options - Script options
|
|
151
127
|
* @returns {string} HTML script tag
|
|
152
128
|
* @memberof TemplateHelpers
|
|
153
|
-
*
|
|
154
|
-
* @example
|
|
155
|
-
* // External script with async
|
|
156
|
-
* TemplateHelpers.createScriptTag({ src: '/app.js', async: true })
|
|
157
|
-
* // Returns: <script async src="/app.js"></script>
|
|
158
|
-
*
|
|
159
|
-
* @example
|
|
160
|
-
* // Inline module script
|
|
161
|
-
* TemplateHelpers.createScriptTag({
|
|
162
|
-
* content: 'console.log("Hello");',
|
|
163
|
-
* type: 'module'
|
|
164
|
-
* })
|
|
165
|
-
* // Returns: <script type="module">console.log("Hello");</script>
|
|
166
129
|
*/
|
|
167
130
|
createScriptTag(options) {
|
|
168
131
|
const attrs = [];
|
|
@@ -194,16 +157,6 @@ const TemplateHelpers = {
|
|
|
194
157
|
* @param {StyleOptions} options - Style options
|
|
195
158
|
* @returns {string} HTML link or style tag
|
|
196
159
|
* @memberof TemplateHelpers
|
|
197
|
-
*
|
|
198
|
-
* @example
|
|
199
|
-
* // External stylesheet
|
|
200
|
-
* TemplateHelpers.createStyleTag({ href: '/styles.css' })
|
|
201
|
-
* // Returns: <link rel="stylesheet" href="/styles.css" media="all">
|
|
202
|
-
*
|
|
203
|
-
* @example
|
|
204
|
-
* // Inline styles
|
|
205
|
-
* TemplateHelpers.createStyleTag({ content: 'body { margin: 0; }' })
|
|
206
|
-
* // Returns: <style>body { margin: 0; }</style>
|
|
207
160
|
*/
|
|
208
161
|
createStyleTag(options) {
|
|
209
162
|
if (options.content) {
|
|
@@ -224,13 +177,6 @@ const TemplateHelpers = {
|
|
|
224
177
|
* @param {IconOptions} icons - Icon options
|
|
225
178
|
* @returns {string} HTML icon link tags
|
|
226
179
|
* @memberof TemplateHelpers
|
|
227
|
-
*
|
|
228
|
-
* @example
|
|
229
|
-
* TemplateHelpers.createIconTags({
|
|
230
|
-
* favicon: '/favicon.ico',
|
|
231
|
-
* appleTouchIcon: '/apple-touch-icon.png',
|
|
232
|
-
* manifest: '/manifest.json'
|
|
233
|
-
* })
|
|
234
180
|
*/
|
|
235
181
|
createIconTags(icons) {
|
|
236
182
|
const tags = [];
|
|
@@ -261,13 +207,6 @@ const TemplateHelpers = {
|
|
|
261
207
|
* @param {MetadataOptions} metadata - Metadata options
|
|
262
208
|
* @returns {string} HTML meta tags
|
|
263
209
|
* @memberof TemplateHelpers
|
|
264
|
-
*
|
|
265
|
-
* @example
|
|
266
|
-
* TemplateHelpers.createMetaTags({
|
|
267
|
-
* description: 'My page description',
|
|
268
|
-
* keywords: ['web', 'app'],
|
|
269
|
-
* author: 'John Doe'
|
|
270
|
-
* })
|
|
271
210
|
*/
|
|
272
211
|
createMetaTags(metadata) {
|
|
273
212
|
const tags = [];
|
|
@@ -329,16 +268,6 @@ const TemplateHelpers = {
|
|
|
329
268
|
* @param {Object[]} microdata - Array of structured data objects
|
|
330
269
|
* @returns {string} HTML script tags with JSON-LD
|
|
331
270
|
* @memberof TemplateHelpers
|
|
332
|
-
*
|
|
333
|
-
* @example
|
|
334
|
-
* TemplateHelpers.createMicrodataTags([
|
|
335
|
-
* {
|
|
336
|
-
* '@context': 'https://schema.org',
|
|
337
|
-
* '@type': 'WebSite',
|
|
338
|
-
* 'name': 'My Site',
|
|
339
|
-
* 'url': 'https://example.com'
|
|
340
|
-
* }
|
|
341
|
-
* ])
|
|
342
271
|
*/
|
|
343
272
|
createMicrodataTags(microdata) {
|
|
344
273
|
if (!microdata || !Array.isArray(microdata) || microdata.length === 0) {
|
|
@@ -410,19 +339,6 @@ const ConfigLoader = {
|
|
|
410
339
|
* @param {string} configPath - Path to config file
|
|
411
340
|
* @returns {Object} Configuration object
|
|
412
341
|
* @memberof ConfigLoader
|
|
413
|
-
*
|
|
414
|
-
* @example
|
|
415
|
-
* // static-config.json
|
|
416
|
-
* {
|
|
417
|
-
* "metadata": {
|
|
418
|
-
* "title": "My App",
|
|
419
|
-
* "description": "My application description"
|
|
420
|
-
* },
|
|
421
|
-
* "env": "production"
|
|
422
|
-
* }
|
|
423
|
-
*
|
|
424
|
-
* // Usage
|
|
425
|
-
* const config = ConfigLoader.load('./static-config.json');
|
|
426
342
|
*/
|
|
427
343
|
load(configPath) {
|
|
428
344
|
try {
|
|
@@ -466,90 +382,83 @@ class UnderpostStatic {
|
|
|
466
382
|
* Generate static HTML file with enhanced customization options
|
|
467
383
|
*
|
|
468
384
|
* @param {StaticGenerationOptions} options - Options for static generation
|
|
385
|
+
* @param {string} [options.page] - Path to the SSR component to render
|
|
386
|
+
* @param {string} [options.title] - Page title (deprecated: use metadata.title)
|
|
387
|
+
* @param {string} [options.outputPath] - Output file path
|
|
388
|
+
* @param {string} [options.deployId] - Deployment identifier
|
|
389
|
+
* @param {string} [options.buildHost] - Build host URL
|
|
390
|
+
* @param {string} [options.buildPath='/'] - Build path
|
|
391
|
+
* @param {string} [options.env='production'] - Environment (development/production)
|
|
392
|
+
* @param {boolean} [options.build=false] - Whether to trigger build
|
|
393
|
+
* @param {boolean} [options.minify=true] - Minify HTML output
|
|
394
|
+
* @param {MetadataOptions} [options.metadata={}] - Comprehensive metadata options
|
|
395
|
+
* @param {Object} [options.scripts={}] - Script injection options
|
|
396
|
+
* @param {ScriptOptions[]} [options.scripts.head=[]] - Scripts for
|
|
397
|
+
* head section
|
|
398
|
+
* @param {ScriptOptions[]} [options.scripts.body=[]] - Scripts for body section
|
|
399
|
+
* @param {StyleOptions[]} [options.styles=[]] - Stylesheet options
|
|
400
|
+
* @param {string[]} [options.headComponents=[]] - Array of SSR head component paths
|
|
401
|
+
* @param {string[]} [options.bodyComponents=[]] - Array of SSR body component paths
|
|
402
|
+
* @param {IconOptions} [options.icons={}] - Icon configuration
|
|
403
|
+
* @param {Object} [options.customPayload={}] - Custom data to inject into renderPayload
|
|
404
|
+
* @param {string} [options.configFile=''] - Path to JSON config file
|
|
405
|
+
* @param {string} [options.lang='en'] - HTML lang attribute
|
|
406
|
+
* @param {string} [options.dir='ltr'] - HTML dir attribute
|
|
407
|
+
* @param {Object} [options.microdata=[]] - Structured data (JSON-LD)
|
|
469
408
|
* @returns {Promise<void>}
|
|
470
409
|
* @memberof UnderpostStatic
|
|
471
|
-
*
|
|
472
|
-
* @example
|
|
473
|
-
* // Minimal usage
|
|
474
|
-
* await UnderpostStatic.API.callback({
|
|
475
|
-
* page: './src/client/ssr/body/DefaultSplashScreen.js',
|
|
476
|
-
* outputPath: './dist/index.html'
|
|
477
|
-
* });
|
|
478
|
-
*
|
|
479
|
-
* @example
|
|
480
|
-
* // Full customization with metadata and scripts
|
|
481
|
-
* await UnderpostStatic.API.callback({
|
|
482
|
-
* page: './src/client/ssr/body/CustomPage.js',
|
|
483
|
-
* outputPath: './dist/page.html',
|
|
484
|
-
* metadata: {
|
|
485
|
-
* title: 'My Custom Page',
|
|
486
|
-
* description: 'A fully customized page',
|
|
487
|
-
* keywords: ['custom', 'static', 'page'],
|
|
488
|
-
* author: 'Jane Developer',
|
|
489
|
-
* themeColor: '#4CAF50',
|
|
490
|
-
* canonicalURL: 'https://example.com/page',
|
|
491
|
-
* thumbnail: 'https://example.com/images/thumbnail.png',
|
|
492
|
-
* locale: 'en-US',
|
|
493
|
-
* siteName: 'My Website'
|
|
494
|
-
* },
|
|
495
|
-
* scripts: {
|
|
496
|
-
* head: [
|
|
497
|
-
* { src: 'https://cdn.example.com/analytics.js', async: true },
|
|
498
|
-
* { content: 'window.config = { apiUrl: "https://api.example.com" };' }
|
|
499
|
-
* ],
|
|
500
|
-
* body: [
|
|
501
|
-
* { src: '/app.js', type: 'module', defer: true }
|
|
502
|
-
* ]
|
|
503
|
-
* },
|
|
504
|
-
* styles: [
|
|
505
|
-
* { href: '/main.css' },
|
|
506
|
-
* { content: 'body { font-family: sans-serif; }' }
|
|
507
|
-
* ],
|
|
508
|
-
* icons: {
|
|
509
|
-
* favicon: '/favicon.ico',
|
|
510
|
-
* appleTouchIcon: '/apple-touch-icon.png',
|
|
511
|
-
* manifest: '/manifest.json'
|
|
512
|
-
* },
|
|
513
|
-
* headComponents: [
|
|
514
|
-
* './src/client/ssr/head/Seo.js',
|
|
515
|
-
* './src/client/ssr/head/Pwa.js'
|
|
516
|
-
* ],
|
|
517
|
-
* microdata: [
|
|
518
|
-
* {
|
|
519
|
-
* '@context': 'https://schema.org',
|
|
520
|
-
* '@type': 'WebPage',
|
|
521
|
-
* 'name': 'My Custom Page',
|
|
522
|
-
* 'url': 'https://example.com/page'
|
|
523
|
-
* }
|
|
524
|
-
* ],
|
|
525
|
-
* customPayload: {
|
|
526
|
-
* apiEndpoint: 'https://api.example.com',
|
|
527
|
-
* features: ['feature1', 'feature2']
|
|
528
|
-
* },
|
|
529
|
-
* env: 'production',
|
|
530
|
-
* minify: true
|
|
531
|
-
* });
|
|
532
|
-
*
|
|
533
|
-
* @example
|
|
534
|
-
* // Using a config file
|
|
535
|
-
* await UnderpostStatic.API.callback({
|
|
536
|
-
* configFile: './static-config.json',
|
|
537
|
-
* outputPath: './dist/index.html'
|
|
538
|
-
* });
|
|
539
|
-
*
|
|
540
|
-
* @example
|
|
541
|
-
* // Generate with build trigger
|
|
542
|
-
* await UnderpostStatic.API.callback({
|
|
543
|
-
* page: './src/client/ssr/body/DefaultSplashScreen.js',
|
|
544
|
-
* outputPath: './public/index.html',
|
|
545
|
-
* deployId: 'production-v1',
|
|
546
|
-
* buildHost: 'example.com',
|
|
547
|
-
* buildPath: '/',
|
|
548
|
-
* build: true,
|
|
549
|
-
* env: 'production'
|
|
550
|
-
* });
|
|
551
410
|
*/
|
|
552
|
-
async callback(options =
|
|
411
|
+
async callback(options = DefaultStaticGenerationOptions) {
|
|
412
|
+
// Handle config template generation
|
|
413
|
+
if (options.generateConfig) {
|
|
414
|
+
const configPath = typeof options.generateConfig === 'string' ? options.generateConfig : './static-config.json';
|
|
415
|
+
return UnderpostStatic.API.generateConfigTemplate(configPath);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Parse comma-separated options
|
|
419
|
+
if (options.keywords) {
|
|
420
|
+
options.keywords = options.keywords.split(',').map((k) => k.trim());
|
|
421
|
+
}
|
|
422
|
+
if (options.headScripts) {
|
|
423
|
+
options.scripts = options.scripts || {};
|
|
424
|
+
options.scripts.head = options.headScripts.split(',').map((s) => ({ src: s.trim() }));
|
|
425
|
+
}
|
|
426
|
+
if (options.bodyScripts) {
|
|
427
|
+
options.scripts = options.scripts || {};
|
|
428
|
+
options.scripts.body = options.bodyScripts.split(',').map((s) => ({ src: s.trim() }));
|
|
429
|
+
}
|
|
430
|
+
if (options.styles) {
|
|
431
|
+
options.styles = options.styles.split(',').map((s) => ({ href: s.trim() }));
|
|
432
|
+
}
|
|
433
|
+
if (options.headComponents) {
|
|
434
|
+
options.headComponents = options.headComponents.split(',').map((c) => c.trim());
|
|
435
|
+
}
|
|
436
|
+
if (options.bodyComponents) {
|
|
437
|
+
options.bodyComponents = options.bodyComponents.split(',').map((c) => c.trim());
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Build metadata object from individual options
|
|
441
|
+
options.metadata = {
|
|
442
|
+
...(options.title && { title: options.title }),
|
|
443
|
+
...(options.description && { description: options.description }),
|
|
444
|
+
...(options.keywords && { keywords: options.keywords }),
|
|
445
|
+
...(options.author && { author: options.author }),
|
|
446
|
+
...(options.themeColor && { themeColor: options.themeColor }),
|
|
447
|
+
...(options.canonicalUrl && { canonicalURL: options.canonicalUrl }),
|
|
448
|
+
...(options.thumbnail && { thumbnail: options.thumbnail }),
|
|
449
|
+
...(options.locale && { locale: options.locale }),
|
|
450
|
+
...(options.siteName && { siteName: options.siteName }),
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
// Build icons object
|
|
454
|
+
if (options.favicon || options.appleTouchIcon || options.manifest) {
|
|
455
|
+
options.icons = {
|
|
456
|
+
...(options.favicon && { favicon: options.favicon }),
|
|
457
|
+
...(options.appleTouchIcon && { appleTouchIcon: options.appleTouchIcon }),
|
|
458
|
+
...(options.manifest && { manifest: options.manifest }),
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
|
|
553
462
|
// Load config from file if specified
|
|
554
463
|
if (options.configFile) {
|
|
555
464
|
const fileConfig = ConfigLoader.load(options.configFile);
|
|
@@ -717,10 +626,6 @@ class UnderpostStatic {
|
|
|
717
626
|
* @param {string} outputPath - Where to save the template config
|
|
718
627
|
* @returns {void}
|
|
719
628
|
* @memberof UnderpostStatic
|
|
720
|
-
*
|
|
721
|
-
* @example
|
|
722
|
-
* // Generate a template configuration file
|
|
723
|
-
* UnderpostStatic.API.generateConfigTemplate('./my-static-config.json');
|
|
724
629
|
*/
|
|
725
630
|
generateConfigTemplate(outputPath = './static-config.json') {
|
|
726
631
|
const template = {
|
|
@@ -465,6 +465,13 @@ const DefaultManagement = {
|
|
|
465
465
|
const selectedRows = AgGrid.grids[gridId].getSelectedRows();
|
|
466
466
|
logger.info('selectedRows', selectedRows);
|
|
467
467
|
},
|
|
468
|
+
onRowEditingStarted: async (...args) => {
|
|
469
|
+
// Show only save button when editing starts
|
|
470
|
+
s(`.management-table-btn-save-${id}`).classList.remove('hide');
|
|
471
|
+
if (permissions.add) s(`.management-table-btn-add-${id}`).classList.add('hide');
|
|
472
|
+
if (permissions.remove) s(`.management-table-btn-clean-${id}`).classList.add('hide');
|
|
473
|
+
if (permissions.reload) s(`.management-table-btn-reload-${id}`).classList.add('hide');
|
|
474
|
+
},
|
|
468
475
|
onRowValueChanged: async (...args) => {
|
|
469
476
|
const [event] = args;
|
|
470
477
|
logger.info('onRowValueChanged', args);
|
package/src/index.js
CHANGED
package/src/server/backup.js
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
import fs from 'fs-extra';
|
|
8
8
|
import { loggerFactory } from './logger.js';
|
|
9
9
|
import { shellExec } from './process.js';
|
|
10
|
-
import { getCronBackUpFolder } from './conf.js';
|
|
11
10
|
import dotenv from 'dotenv';
|
|
12
11
|
|
|
13
12
|
dotenv.config();
|
|
@@ -25,70 +24,22 @@ class BackUp {
|
|
|
25
24
|
* @description Initiates a backup operation for the specified deployment list.
|
|
26
25
|
* @param {string} deployList - The list of deployments to backup.
|
|
27
26
|
* @param {Object} options - The options for the backup operation.
|
|
28
|
-
* @param {boolean} options.itc - Whether to backup inside container data.
|
|
29
27
|
* @param {boolean} options.git - Whether to backup data using Git.
|
|
30
28
|
* @memberof BackUp
|
|
31
29
|
*/
|
|
32
|
-
static callback = async function (deployList, options = {
|
|
30
|
+
static callback = async function (deployList, options = { git: false }) {
|
|
33
31
|
if ((!deployList || deployList === 'dd') && fs.existsSync(`./engine-private/deploy/dd.router`))
|
|
34
|
-
deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8');
|
|
32
|
+
deployList = fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').trim();
|
|
35
33
|
|
|
36
34
|
logger.info('init backups callback', deployList);
|
|
37
35
|
await logger.setUpInfo();
|
|
38
|
-
const currentDate = new Date().getTime();
|
|
39
|
-
const maxBackupRetention = 5;
|
|
40
|
-
|
|
41
|
-
if (!fs.existsSync('./engine-private/cron-backups'))
|
|
42
|
-
fs.mkdirSync('./engine-private/cron-backups', { recursive: true });
|
|
43
36
|
|
|
44
37
|
for (const _deployId of deployList.split(',')) {
|
|
45
38
|
const deployId = _deployId.trim();
|
|
46
39
|
if (!deployId) continue;
|
|
47
40
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const confServer = JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'));
|
|
54
|
-
|
|
55
|
-
for (const host of Object.keys(confServer))
|
|
56
|
-
for (const path of Object.keys(confServer[host])) {
|
|
57
|
-
// retention policy
|
|
58
|
-
const { db } = confServer[host][path];
|
|
59
|
-
if (!db) continue;
|
|
60
|
-
logger.info('Init backup', { host, path, db });
|
|
61
|
-
|
|
62
|
-
const backUpPath = `${process.cwd()}/engine-private/cron-backups/${getCronBackUpFolder(host, path)}`;
|
|
63
|
-
if (!fs.existsSync(backUpPath)) fs.mkdirSync(`${backUpPath}`, { recursive: true });
|
|
64
|
-
// .isDirectory()
|
|
65
|
-
const files = await fs.readdir(backUpPath, { withFileTypes: true });
|
|
66
|
-
|
|
67
|
-
const currentBackupsDirs = files
|
|
68
|
-
.map((fileObj) => parseInt(fileObj.name))
|
|
69
|
-
.sort((a, b) => a - b)
|
|
70
|
-
.reverse();
|
|
71
|
-
|
|
72
|
-
for (const retentionPath of currentBackupsDirs.filter((t, i) => i >= maxBackupRetention - 1)) {
|
|
73
|
-
const removePathRetention = `${backUpPath}/${retentionPath}`;
|
|
74
|
-
logger.info('Remove backup folder', removePathRetention);
|
|
75
|
-
fs.removeSync(removePathRetention);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
fs.mkdirSync(`${backUpPath}/${currentDate}`, { recursive: true });
|
|
79
|
-
|
|
80
|
-
shellExec(`node bin/db ${host}${path} export ${deployId} ${backUpPath}/${currentDate}`);
|
|
81
|
-
}
|
|
82
|
-
shellExec(
|
|
83
|
-
`cd ./engine-private/cron-backups` +
|
|
84
|
-
` && underpost pull . ${process.env.GITHUB_USERNAME}/cron-backups` +
|
|
85
|
-
` && git add .` +
|
|
86
|
-
` && underpost cmt . backup cron-job '${new Date().toLocaleDateString()}'` +
|
|
87
|
-
` && underpost push . ${process.env.GITHUB_USERNAME}/cron-backups`,
|
|
88
|
-
{
|
|
89
|
-
silent: true,
|
|
90
|
-
},
|
|
91
|
-
);
|
|
41
|
+
logger.info('Executing database export for', deployId);
|
|
42
|
+
shellExec(`node bin db ${options.git ? '--git ' : ''}--export ${deployId}`);
|
|
92
43
|
}
|
|
93
44
|
};
|
|
94
45
|
}
|
package/src/server/conf.js
CHANGED
|
@@ -1227,13 +1227,12 @@ const Cmd = {
|
|
|
1227
1227
|
* @param {string} name - The name.
|
|
1228
1228
|
* @param {string} expression - The expression.
|
|
1229
1229
|
* @param {object} options - The options.
|
|
1230
|
+
* @param {number} instances - The number of PM2 instances (default: 1).
|
|
1230
1231
|
* @returns {string} - The cron command.
|
|
1231
1232
|
* @memberof Cmd
|
|
1232
1233
|
*/
|
|
1233
|
-
cron: (deployList, jobList, name, expression, options) =>
|
|
1234
|
-
`pm2 start ./bin/index.js --no-autorestart --instances
|
|
1235
|
-
options?.itc ? `--itc ` : ''
|
|
1236
|
-
}${options?.git ? `--git ` : ''}${deployList} ${jobList}`,
|
|
1234
|
+
cron: (deployList, jobList, name, expression, options, instances = 1) =>
|
|
1235
|
+
`pm2 start ./bin/index.js --no-autorestart --instances ${instances} --cron "${expression}" --name ${name} -- cron ${options?.git ? `--git ` : ''}${deployList} ${jobList}`,
|
|
1237
1236
|
};
|
|
1238
1237
|
|
|
1239
1238
|
/**
|
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"_comment": "Example static site configuration file for Underpost Static Generator",
|
|
3
|
-
"_usage": "Use with: underpost static --config-file ./static-config-example.json",
|
|
4
|
-
|
|
5
|
-
"page": "./src/client/ssr/body/DefaultSplashScreen.js",
|
|
6
|
-
"outputPath": "./dist/index.html",
|
|
7
|
-
"env": "production",
|
|
8
|
-
"minify": true,
|
|
9
|
-
"lang": "en",
|
|
10
|
-
"dir": "ltr",
|
|
11
|
-
|
|
12
|
-
"metadata": {
|
|
13
|
-
"_comment": "SEO and social media metadata",
|
|
14
|
-
"title": "My Awesome Application",
|
|
15
|
-
"description": "A comprehensive example of a static site with full metadata customization",
|
|
16
|
-
"keywords": ["static site", "generator", "underpost", "seo", "progressive web app"],
|
|
17
|
-
"author": "Your Name or Company",
|
|
18
|
-
"themeColor": "#4CAF50",
|
|
19
|
-
"canonicalURL": "https://example.com",
|
|
20
|
-
"thumbnail": "https://example.com/images/og-thumbnail.png",
|
|
21
|
-
"locale": "en-US",
|
|
22
|
-
"siteName": "My Awesome Site",
|
|
23
|
-
"openGraph": {
|
|
24
|
-
"_comment": "Additional Open Graph properties",
|
|
25
|
-
"type": "website",
|
|
26
|
-
"image:width": "1200",
|
|
27
|
-
"image:height": "630"
|
|
28
|
-
},
|
|
29
|
-
"twitter": {
|
|
30
|
-
"_comment": "Twitter card specific metadata",
|
|
31
|
-
"site": "@yourhandle",
|
|
32
|
-
"creator": "@creatorhandle"
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
|
|
36
|
-
"scripts": {
|
|
37
|
-
"_comment": "Scripts to inject into head and body sections",
|
|
38
|
-
"head": [
|
|
39
|
-
{
|
|
40
|
-
"_comment": "External analytics script with async loading",
|
|
41
|
-
"src": "https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID",
|
|
42
|
-
"async": true
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
"_comment": "Inline configuration script",
|
|
46
|
-
"content": "window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'GA_MEASUREMENT_ID');",
|
|
47
|
-
"type": "text/javascript"
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
"_comment": "App configuration as inline script",
|
|
51
|
-
"content": "window.appConfig = { apiUrl: 'https://api.example.com', version: '1.0.0', features: { analytics: true, debugging: false } };",
|
|
52
|
-
"type": "text/javascript"
|
|
53
|
-
}
|
|
54
|
-
],
|
|
55
|
-
"body": [
|
|
56
|
-
{
|
|
57
|
-
"_comment": "Main application bundle as ES module",
|
|
58
|
-
"src": "/dist/app.js",
|
|
59
|
-
"type": "module",
|
|
60
|
-
"defer": true
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
"_comment": "Service worker registration",
|
|
64
|
-
"content": "if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js').then(reg => console.log('SW registered', reg)).catch(err => console.log('SW error', err)); }",
|
|
65
|
-
"type": "text/javascript"
|
|
66
|
-
}
|
|
67
|
-
]
|
|
68
|
-
},
|
|
69
|
-
|
|
70
|
-
"styles": [
|
|
71
|
-
{
|
|
72
|
-
"_comment": "Main stylesheet",
|
|
73
|
-
"href": "/styles/main.css"
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
"_comment": "External font",
|
|
77
|
-
"href": "https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap"
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
"_comment": "Critical inline CSS for faster rendering",
|
|
81
|
-
"content": "body { margin: 0; padding: 0; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; } * { box-sizing: border-box; }"
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
"_comment": "Print stylesheet",
|
|
85
|
-
"href": "/styles/print.css",
|
|
86
|
-
"media": "print"
|
|
87
|
-
}
|
|
88
|
-
],
|
|
89
|
-
|
|
90
|
-
"icons": {
|
|
91
|
-
"_comment": "Icon configuration for various platforms",
|
|
92
|
-
"favicon": "/favicon.ico",
|
|
93
|
-
"appleTouchIcon": "/apple-touch-icon.png",
|
|
94
|
-
"manifest": "/manifest.json",
|
|
95
|
-
"additional": [
|
|
96
|
-
{
|
|
97
|
-
"rel": "icon",
|
|
98
|
-
"type": "image/png",
|
|
99
|
-
"sizes": "32x32",
|
|
100
|
-
"href": "/favicon-32x32.png"
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
"rel": "icon",
|
|
104
|
-
"type": "image/png",
|
|
105
|
-
"sizes": "16x16",
|
|
106
|
-
"href": "/favicon-16x16.png"
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
"rel": "mask-icon",
|
|
110
|
-
"href": "/safari-pinned-tab.svg",
|
|
111
|
-
"color": "#4CAF50"
|
|
112
|
-
}
|
|
113
|
-
]
|
|
114
|
-
},
|
|
115
|
-
|
|
116
|
-
"_headComponents_comment": "SSR components disabled in this example - they require specific data structures",
|
|
117
|
-
"headComponents": [],
|
|
118
|
-
|
|
119
|
-
"_bodyComponents_comment": "Additional SSR components to include in body section",
|
|
120
|
-
"bodyComponents": [],
|
|
121
|
-
|
|
122
|
-
"microdata": [
|
|
123
|
-
{
|
|
124
|
-
"_comment": "Organization schema for better SEO",
|
|
125
|
-
"@context": "https://schema.org",
|
|
126
|
-
"@type": "Organization",
|
|
127
|
-
"name": "My Organization",
|
|
128
|
-
"url": "https://example.com",
|
|
129
|
-
"logo": "https://example.com/logo.png",
|
|
130
|
-
"contactPoint": {
|
|
131
|
-
"@type": "ContactPoint",
|
|
132
|
-
"telephone": "+1-555-123-4567",
|
|
133
|
-
"contactType": "Customer Service"
|
|
134
|
-
},
|
|
135
|
-
"sameAs": [
|
|
136
|
-
"https://twitter.com/yourhandle",
|
|
137
|
-
"https://linkedin.com/company/yourcompany",
|
|
138
|
-
"https://github.com/yourorg"
|
|
139
|
-
]
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
"_comment": "WebSite schema",
|
|
143
|
-
"@context": "https://schema.org",
|
|
144
|
-
"@type": "WebSite",
|
|
145
|
-
"name": "My Awesome Site",
|
|
146
|
-
"url": "https://example.com",
|
|
147
|
-
"potentialAction": {
|
|
148
|
-
"@type": "SearchAction",
|
|
149
|
-
"target": "https://example.com/search?q={search_term_string}",
|
|
150
|
-
"query-input": "required name=search_term_string"
|
|
151
|
-
}
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
"_comment": "WebPage schema",
|
|
155
|
-
"@context": "https://schema.org",
|
|
156
|
-
"@type": "WebPage",
|
|
157
|
-
"name": "Home Page",
|
|
158
|
-
"description": "Welcome to our awesome site",
|
|
159
|
-
"url": "https://example.com"
|
|
160
|
-
}
|
|
161
|
-
],
|
|
162
|
-
|
|
163
|
-
"customPayload": {
|
|
164
|
-
"_comment": "Custom data injected into window.renderPayload",
|
|
165
|
-
"apiEndpoint": "https://api.example.com",
|
|
166
|
-
"cdnUrl": "https://cdn.example.com",
|
|
167
|
-
"features": {
|
|
168
|
-
"chat": true,
|
|
169
|
-
"notifications": true,
|
|
170
|
-
"darkMode": true
|
|
171
|
-
},
|
|
172
|
-
"externalServices": {
|
|
173
|
-
"analytics": "GA_MEASUREMENT_ID",
|
|
174
|
-
"maps": "GOOGLE_MAPS_API_KEY"
|
|
175
|
-
}
|
|
176
|
-
},
|
|
177
|
-
|
|
178
|
-
"buildPath": "/",
|
|
179
|
-
"deployId": "",
|
|
180
|
-
"buildHost": "",
|
|
181
|
-
"build": false,
|
|
182
|
-
"dev": false
|
|
183
|
-
}
|