mango-cms 0.3.35 → 0.3.37
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/cli.js +77 -30
- package/default/package.json +1 -1
- package/default/public/index.js +13 -0
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { Command } from 'commander';
|
|
4
|
-
import { execSync, spawn } from 'child_process';
|
|
4
|
+
import { execSync, spawn, spawnSync } from 'child_process';
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import { fileURLToPath } from 'url';
|
|
7
7
|
import inquirer from 'inquirer';
|
|
@@ -14,6 +14,22 @@ import os from 'os';
|
|
|
14
14
|
const __filename = fileURLToPath(import.meta.url);
|
|
15
15
|
const __dirname = path.dirname(__filename);
|
|
16
16
|
|
|
17
|
+
// When `mango` is invoked from a global install (npm i -g mango-cms) inside a
|
|
18
|
+
// project that has its own mango-cms in node_modules, defer to the project-local
|
|
19
|
+
// CLI so the version pinned in package.json always wins. This is what lets users
|
|
20
|
+
// type plain `mango dev` / `mango deploy` instead of prefixing with `yarn`/`npx`.
|
|
21
|
+
const localCli = path.join(process.cwd(), 'node_modules', 'mango-cms', 'cli.js');
|
|
22
|
+
if (fs.existsSync(localCli)) {
|
|
23
|
+
let isSelf = false;
|
|
24
|
+
try {
|
|
25
|
+
isSelf = fs.realpathSync(localCli) === fs.realpathSync(__filename);
|
|
26
|
+
} catch (e) { /* fall through and run this copy */ }
|
|
27
|
+
if (!isSelf) {
|
|
28
|
+
const result = spawnSync(process.execPath, [localCli, ...process.argv.slice(2)], { stdio: 'inherit' });
|
|
29
|
+
process.exit(result.status ?? 0);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
17
33
|
const program = new Command();
|
|
18
34
|
|
|
19
35
|
// Helper function to download and extract versioned src zip file
|
|
@@ -521,16 +537,31 @@ async function detectWebServer() {
|
|
|
521
537
|
}
|
|
522
538
|
}
|
|
523
539
|
|
|
540
|
+
// Deploy-identity key for pm2 process names and web server config filenames.
|
|
541
|
+
// Defaults to `database` for backward compatibility (matches every existing
|
|
542
|
+
// deployed site today), but `database` is meant to be safely shareable across
|
|
543
|
+
// projects (e.g. a multi-tenant setup), while deploy identity must be unique
|
|
544
|
+
// per project on a given box. Set "deployId" in settings.json to override
|
|
545
|
+
// when a project intentionally shares its database with another deployed
|
|
546
|
+
// project — otherwise `mango deploy`/`mango launch` will silently skip
|
|
547
|
+
// creating a web server config for the second project (path already exists)
|
|
548
|
+
// and reload the FIRST project's live pm2 processes instead of starting its
|
|
549
|
+
// own (HAP-1990).
|
|
550
|
+
function deployId(settings) {
|
|
551
|
+
return (settings.deployId || settings.database).toLowerCase();
|
|
552
|
+
}
|
|
553
|
+
|
|
524
554
|
// Helper function to generate nginx config
|
|
525
|
-
function generateNginxConfig(settings, buildPath) {
|
|
555
|
+
function generateNginxConfig(settings, buildPath, deployUi = false) {
|
|
526
556
|
const domain = settings.mangoDomain;
|
|
527
557
|
const port = settings.port || 3002;
|
|
528
558
|
const frontPort = settings.frontPort || 3001;
|
|
529
559
|
const uiDomain = settings.uiDomain;
|
|
530
560
|
const uiPort = settings.uiPort || 3001;
|
|
531
561
|
|
|
532
|
-
// Reverse-proxy the Mango UI (Nuxt SSR server) on its own subdomain,
|
|
533
|
-
|
|
562
|
+
// Reverse-proxy the Mango UI (Nuxt SSR server) on its own subdomain,
|
|
563
|
+
// only when the UI is part of this deploy and a uiDomain is configured.
|
|
564
|
+
const uiServerBlock = (deployUi && uiDomain) ? `
|
|
534
565
|
server {
|
|
535
566
|
server_name ${uiDomain};
|
|
536
567
|
|
|
@@ -617,15 +648,16 @@ ${uiServerBlock}`;
|
|
|
617
648
|
}
|
|
618
649
|
|
|
619
650
|
// Helper function to generate apache config
|
|
620
|
-
function generateApacheConfig(settings, buildPath) {
|
|
651
|
+
function generateApacheConfig(settings, buildPath, deployUi = false) {
|
|
621
652
|
const domain = settings.mangoDomain;
|
|
622
653
|
const port = settings.port || 3002;
|
|
623
654
|
const frontPort = settings.frontPort || 3001;
|
|
624
655
|
const uiDomain = settings.uiDomain;
|
|
625
656
|
const uiPort = settings.uiPort || 3001;
|
|
626
657
|
|
|
627
|
-
// Reverse-proxy the Mango UI (Nuxt SSR server) on its own subdomain,
|
|
628
|
-
|
|
658
|
+
// Reverse-proxy the Mango UI (Nuxt SSR server) on its own subdomain,
|
|
659
|
+
// only when the UI is part of this deploy and a uiDomain is configured.
|
|
660
|
+
const uiVirtualHost = (deployUi && uiDomain) ? `
|
|
629
661
|
<VirtualHost *:80>
|
|
630
662
|
ServerName ${uiDomain}
|
|
631
663
|
|
|
@@ -697,7 +729,7 @@ ${uiVirtualHost}`;
|
|
|
697
729
|
}
|
|
698
730
|
|
|
699
731
|
// Helper function to configure web server
|
|
700
|
-
async function configureWebServer(settings, buildPath) {
|
|
732
|
+
async function configureWebServer(settings, buildPath, deployUi = false) {
|
|
701
733
|
let webServer = await detectWebServer();
|
|
702
734
|
|
|
703
735
|
if (!webServer) {
|
|
@@ -713,12 +745,12 @@ async function configureWebServer(settings, buildPath) {
|
|
|
713
745
|
}
|
|
714
746
|
|
|
715
747
|
const config = webServer === 'nginx' ?
|
|
716
|
-
generateNginxConfig(settings, buildPath) :
|
|
717
|
-
generateApacheConfig(settings, buildPath);
|
|
748
|
+
generateNginxConfig(settings, buildPath, deployUi) :
|
|
749
|
+
generateApacheConfig(settings, buildPath, deployUi);
|
|
718
750
|
|
|
719
751
|
const configPath = webServer === 'nginx' ?
|
|
720
|
-
`/etc/nginx/sites-available/${settings
|
|
721
|
-
`/etc/apache2/sites-available/${settings
|
|
752
|
+
`/etc/nginx/sites-available/${deployId(settings)}` :
|
|
753
|
+
`/etc/apache2/sites-available/${deployId(settings)}.conf`;
|
|
722
754
|
|
|
723
755
|
try {
|
|
724
756
|
// Check if config already exists
|
|
@@ -731,7 +763,7 @@ async function configureWebServer(settings, buildPath) {
|
|
|
731
763
|
|
|
732
764
|
if (webServer === 'nginx') {
|
|
733
765
|
// Create symlink if it doesn't exist
|
|
734
|
-
const enabledPath = `/etc/nginx/sites-enabled/${settings
|
|
766
|
+
const enabledPath = `/etc/nginx/sites-enabled/${deployId(settings)}`;
|
|
735
767
|
if (!fs.existsSync(enabledPath)) {
|
|
736
768
|
execSync(`sudo ln -s ${configPath} ${enabledPath}`);
|
|
737
769
|
}
|
|
@@ -739,7 +771,7 @@ async function configureWebServer(settings, buildPath) {
|
|
|
739
771
|
execSync('sudo systemctl reload nginx');
|
|
740
772
|
} else {
|
|
741
773
|
// Enable apache site
|
|
742
|
-
execSync(`sudo a2ensite ${settings
|
|
774
|
+
execSync(`sudo a2ensite ${deployId(settings)}`);
|
|
743
775
|
execSync('sudo systemctl reload apache2');
|
|
744
776
|
}
|
|
745
777
|
console.log(`${webServer} configuration has been updated and service reloaded`);
|
|
@@ -764,8 +796,8 @@ async function checkPM2() {
|
|
|
764
796
|
|
|
765
797
|
// Helper function to manage PM2 process
|
|
766
798
|
async function managePM2Process(settings) {
|
|
767
|
-
const processName = `${settings
|
|
768
|
-
const name = settings
|
|
799
|
+
const processName = `${deployId(settings)}-mango`;
|
|
800
|
+
const name = deployId(settings)
|
|
769
801
|
|
|
770
802
|
try {
|
|
771
803
|
// Check if process exists
|
|
@@ -796,7 +828,9 @@ async function managePM2Process(settings) {
|
|
|
796
828
|
}
|
|
797
829
|
}
|
|
798
830
|
|
|
799
|
-
// Helper function to build and (re)start the Mango UI (Nuxt) under PM2
|
|
831
|
+
// Helper function to build and (re)start the Mango UI (Nuxt) under PM2.
|
|
832
|
+
// Only called when the UI deploy is explicitly enabled (--ui flag or
|
|
833
|
+
// "deployUi": true in settings.json) — the admin UI is opt-in on deploy.
|
|
800
834
|
async function manageUiPM2Process(settings, mangoCmsRoot, userProjectRoot) {
|
|
801
835
|
if (!settings.uiDomain) {
|
|
802
836
|
console.log('No uiDomain configured, skipping Mango UI deploy.');
|
|
@@ -805,7 +839,7 @@ async function manageUiPM2Process(settings, mangoCmsRoot, userProjectRoot) {
|
|
|
805
839
|
|
|
806
840
|
const { dir: uiDir, ejected } = resolveUiDir(mangoCmsRoot, userProjectRoot);
|
|
807
841
|
const uiPort = settings.uiPort || 3001;
|
|
808
|
-
const processName = `${settings
|
|
842
|
+
const processName = `${deployId(settings)}-ui`;
|
|
809
843
|
|
|
810
844
|
// Install deps + build the Nuxt app (reads this project's mango/config).
|
|
811
845
|
if (!fs.existsSync(path.join(uiDir, 'node_modules'))) {
|
|
@@ -843,29 +877,39 @@ async function manageUiPM2Process(settings, mangoCmsRoot, userProjectRoot) {
|
|
|
843
877
|
program
|
|
844
878
|
.command('deploy')
|
|
845
879
|
.description('Build and deploy Mango CMS using PM2')
|
|
846
|
-
.
|
|
880
|
+
.option('--ui', 'also build and deploy the Mango admin UI (off by default; or set "deployUi": true in settings.json)')
|
|
881
|
+
.action(async (options) => {
|
|
847
882
|
try {
|
|
848
883
|
const configPath = path.join(process.cwd(), 'mango/config/settings.json');
|
|
849
884
|
const settings = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
850
885
|
const mangoCmsRoot = path.resolve(__dirname);
|
|
851
886
|
const userProjectRoot = process.cwd();
|
|
852
887
|
|
|
888
|
+
// The admin UI is opt-in: deployed only with --ui or "deployUi": true.
|
|
889
|
+
const deployUi = Boolean(options.ui || settings.deployUi);
|
|
890
|
+
|
|
853
891
|
// Run build command
|
|
854
892
|
console.log('Building Mango CMS...');
|
|
855
893
|
execSync('npm run mango build', { stdio: 'inherit' });
|
|
856
894
|
|
|
857
|
-
// Make sure a UI bundle is available for deploy.
|
|
858
|
-
|
|
895
|
+
// Make sure a UI bundle is available for deploy (only when deploying it).
|
|
896
|
+
if (deployUi) {
|
|
897
|
+
await ensureUiExists(mangoCmsRoot);
|
|
898
|
+
}
|
|
859
899
|
|
|
860
900
|
// Check if PM2 is installed
|
|
861
901
|
if (await checkPM2()) {
|
|
862
902
|
await managePM2Process(settings);
|
|
863
|
-
|
|
903
|
+
if (deployUi) {
|
|
904
|
+
await manageUiPM2Process(settings, mangoCmsRoot, userProjectRoot);
|
|
905
|
+
} else {
|
|
906
|
+
console.log('Skipping Mango UI deploy (opt in with "mango deploy --ui" or "deployUi": true in settings.json).');
|
|
907
|
+
}
|
|
864
908
|
|
|
865
909
|
// Configure web server
|
|
866
910
|
const buildPath = path.join(process.cwd(), 'build');
|
|
867
911
|
try {
|
|
868
|
-
await configureWebServer(settings, buildPath);
|
|
912
|
+
await configureWebServer(settings, buildPath, deployUi);
|
|
869
913
|
} catch (error) {
|
|
870
914
|
console.warn('Warning: Could not configure web server:', error.message);
|
|
871
915
|
console.warn('You may need to configure your web server manually.');
|
|
@@ -881,8 +925,9 @@ program
|
|
|
881
925
|
|
|
882
926
|
program
|
|
883
927
|
.command('launch')
|
|
884
|
-
.description('One-shot server deploy: git pull, install, build the site, and deploy backend
|
|
885
|
-
.
|
|
928
|
+
.description('One-shot server deploy: git pull, install, build the site, and deploy the backend (add --ui for the admin UI)')
|
|
929
|
+
.option('--ui', 'also build and deploy the Mango admin UI (off by default; or set "deployUi": true in settings.json)')
|
|
930
|
+
.action(async (options) => {
|
|
886
931
|
try {
|
|
887
932
|
const cwd = process.cwd();
|
|
888
933
|
const useYarn = fs.existsSync(path.join(cwd, 'yarn.lock'));
|
|
@@ -909,12 +954,14 @@ program
|
|
|
909
954
|
console.log('\n→ Skipping site build (no "build" script found)');
|
|
910
955
|
}
|
|
911
956
|
|
|
912
|
-
// 4. Deploy backend + UI + web server config via the
|
|
913
|
-
// `mango deploy` builds the backend
|
|
914
|
-
//
|
|
915
|
-
|
|
957
|
+
// 4. Deploy backend (+ UI when opted in) + web server config via the
|
|
958
|
+
// freshly installed mango. `mango deploy` builds the backend and
|
|
959
|
+
// (re)starts PM2 for {db}-mango and {db}; with --ui it also builds
|
|
960
|
+
// the admin UI, starts {db}-ui, and writes its web server block.
|
|
961
|
+
const deployCmd = options.ui ? 'npx mango deploy --ui' : 'npx mango deploy';
|
|
962
|
+
run(options.ui ? 'Deploying backend + UI' : 'Deploying backend', deployCmd);
|
|
916
963
|
|
|
917
|
-
console.log(
|
|
964
|
+
console.log(`\n✨ Launch complete! Backend and site are deployed${options.ui ? ', along with the admin UI' : ''}.`);
|
|
918
965
|
} catch (error) {
|
|
919
966
|
console.error('\nLaunch failed:', error.message);
|
|
920
967
|
process.exit(1);
|
package/default/package.json
CHANGED
package/default/public/index.js
CHANGED
|
@@ -54,6 +54,19 @@ let appPlaceholder = '<!--SSR-->'
|
|
|
54
54
|
|
|
55
55
|
let serve = async function (req, res) {
|
|
56
56
|
|
|
57
|
+
// Check for a short url redirect
|
|
58
|
+
let shortUrl = req.path.split('/').slice(1).join('/').split('?')[0]
|
|
59
|
+
if (shortUrl) {
|
|
60
|
+
let redirect = (await axios.get(`http://localhost:${settings.port}/shortUrls/?search={"short":"${shortUrl}"}`))?.data?.response?.[0]
|
|
61
|
+
if (redirect?.target) {
|
|
62
|
+
let target = redirect.target.includes('http') ? redirect.target : `https://${settings.siteDomain}/${redirect.target}`
|
|
63
|
+
let redirectUrl = redirect.referralSource ? `${target}?referral=${redirect.referralSource}&referralType=Page&utm_source=${redirect.referralSource}` : target
|
|
64
|
+
// Increment the visit count
|
|
65
|
+
await axios.put(`http://localhost:${settings.port}/shortUrls/${redirect.id}`, { visits: redirect.visits + 1 })
|
|
66
|
+
return res.redirect(redirectUrl)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
57
70
|
let index = fs.readFileSync('./index.html', 'utf8')
|
|
58
71
|
|
|
59
72
|
// Cookies
|