nextjs-cms 0.6.8 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/db-config.d.ts +2 -0
- package/dist/cli/commands/db-config.d.ts.map +1 -0
- package/dist/cli/commands/db-config.js +22 -0
- package/dist/cli/commands/fix-master-admin.d.ts +2 -0
- package/dist/cli/commands/fix-master-admin.d.ts.map +1 -0
- package/dist/cli/commands/fix-master-admin.js +22 -0
- package/dist/cli/commands/set-master-admin.d.ts +2 -0
- package/dist/cli/commands/set-master-admin.d.ts.map +1 -0
- package/dist/cli/commands/set-master-admin.js +25 -0
- package/dist/cli/commands/setup.d.ts +2 -0
- package/dist/cli/commands/setup.d.ts.map +1 -0
- package/dist/cli/commands/setup.js +34 -0
- package/dist/cli/commands/update-sections.d.ts +2 -0
- package/dist/cli/commands/update-sections.d.ts.map +1 -0
- package/dist/cli/commands/update-sections.js +27 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +15 -0
- package/dist/cli/lib/db-config.d.ts +4 -0
- package/dist/cli/lib/db-config.d.ts.map +1 -0
- package/dist/cli/lib/db-config.js +238 -0
- package/dist/cli/lib/db-migrate.d.ts +2 -0
- package/dist/cli/lib/db-migrate.d.ts.map +1 -0
- package/dist/cli/lib/db-migrate.js +83 -0
- package/dist/cli/lib/fix-master-admin.d.ts +2 -0
- package/dist/cli/lib/fix-master-admin.d.ts.map +1 -0
- package/dist/cli/lib/fix-master-admin.js +53 -0
- package/dist/cli/lib/set-master-admin.d.ts +2 -0
- package/dist/cli/lib/set-master-admin.d.ts.map +1 -0
- package/dist/cli/lib/set-master-admin.js +88 -0
- package/dist/cli/lib/update-sections.d.ts +2 -0
- package/dist/cli/lib/update-sections.d.ts.map +1 -0
- package/dist/cli/lib/update-sections.js +915 -0
- package/dist/cli/program/program.d.ts +4 -0
- package/dist/cli/program/program.d.ts.map +1 -0
- package/dist/cli/program/program.js +95 -0
- package/dist/cli/utils/add-table-keys.d.ts +32 -0
- package/dist/cli/utils/add-table-keys.d.ts.map +1 -0
- package/dist/cli/utils/add-table-keys.js +171 -0
- package/dist/cli/utils/check-version.d.ts +3 -0
- package/dist/cli/utils/check-version.d.ts.map +1 -0
- package/dist/cli/utils/check-version.js +125 -0
- package/dist/cli/utils/display-intro.d.ts +6 -0
- package/dist/cli/utils/display-intro.d.ts.map +1 -0
- package/dist/cli/utils/display-intro.js +9 -0
- package/dist/cli/utils/exec-utils.d.ts +19 -0
- package/dist/cli/utils/exec-utils.d.ts.map +1 -0
- package/dist/cli/utils/exec-utils.js +95 -0
- package/dist/cli/utils/get-package-manager.d.ts +4 -0
- package/dist/cli/utils/get-package-manager.d.ts.map +1 -0
- package/dist/cli/utils/get-package-manager.js +22 -0
- package/dist/cli/utils/reload-env.d.ts +16 -0
- package/dist/cli/utils/reload-env.d.ts.map +1 -0
- package/dist/cli/utils/reload-env.js +42 -0
- package/dist/cli/utils/render-title.d.ts +2 -0
- package/dist/cli/utils/render-title.d.ts.map +1 -0
- package/dist/cli/utils/render-title.js +12 -0
- package/dist/cli/utils/schema-generator.d.ts +10 -0
- package/dist/cli/utils/schema-generator.d.ts.map +1 -0
- package/dist/cli/utils/schema-generator.js +171 -0
- package/dist/core/config/config-loader.d.ts +4 -10
- package/dist/core/config/config-loader.d.ts.map +1 -1
- package/dist/core/config/config-loader.js +14 -14
- package/dist/core/factories/section-factory-with-esbuild.d.ts +1 -1
- package/dist/core/factories/section-factory-with-esbuild.js +1 -1
- package/dist/core/factories/section-factory-with-jiti.d.ts +1 -1
- package/dist/core/factories/section-factory-with-jiti.js +1 -1
- package/dist/core/sections/category.d.ts +32 -32
- package/dist/core/sections/hasItems.d.ts +32 -32
- package/dist/core/sections/section.d.ts +16 -16
- package/dist/core/sections/simple.d.ts +8 -8
- package/dist/db/config.js +1 -1
- package/dist/translations/base/en.d.ts +433 -0
- package/dist/translations/base/en.d.ts.map +1 -0
- package/dist/translations/base/en.js +444 -0
- package/dist/translations/client.d.ts +5178 -1
- package/dist/translations/client.d.ts.map +1 -1
- package/dist/translations/client.js +29 -4
- package/dist/translations/dict-store.d.ts +5 -1
- package/dist/translations/dict-store.d.ts.map +1 -1
- package/dist/translations/dict-store.js +31 -4
- package/dist/translations/index.d.ts +1 -1
- package/dist/translations/index.js +1 -1
- package/dist/translations/server.d.ts +5171 -1
- package/dist/translations/server.d.ts.map +1 -1
- package/dist/translations/server.js +26 -4
- package/package.json +18 -10
- package/dist/core/helpers/i18n.d.ts +0 -2
- package/dist/core/helpers/i18n.d.ts.map +0 -1
- package/dist/core/helpers/i18n.js +0 -3
- package/dist/core/localization.d.ts +0 -40
- package/dist/core/localization.d.ts.map +0 -1
- package/dist/core/localization.js +0 -48
- package/dist/logging/audit.d.ts +0 -20
- package/dist/logging/audit.d.ts.map +0 -1
- package/dist/logging/audit.js +0 -48
- package/dist/translations/localized-string.d.ts +0 -17
- package/dist/translations/localized-string.d.ts.map +0 -1
- package/dist/translations/localized-string.js +0 -32
- package/dist/translations/use-project-translation.d.ts +0 -19
- package/dist/translations/use-project-translation.d.ts.map +0 -1
- package/dist/translations/use-project-translation.js +0 -25
- package/dist/validators/types.d.ts +0 -7
- package/dist/validators/types.d.ts.map +0 -1
- package/dist/validators/types.js +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-config.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/db-config.ts"],"names":[],"mappings":"AAGA,wBAAsB,WAAW,CAAC,GAAG,EAAE,OAAO,iBAiB7C"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import * as p from '@clack/prompts';
|
|
3
|
+
export async function runDbConfig(dev) {
|
|
4
|
+
let exitCode = 0;
|
|
5
|
+
try {
|
|
6
|
+
p.log.info(chalk.cyan('Configuring database'));
|
|
7
|
+
// Lazy import to avoid eager database connection
|
|
8
|
+
const { dbConfigSetup } = await import('../lib/db-config.js');
|
|
9
|
+
await dbConfigSetup({ dev });
|
|
10
|
+
p.outro(chalk.inverse(' ✓ Database configuration completed '));
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
console.error(chalk.red('✗ Error during database configuration:'), error);
|
|
14
|
+
exitCode = 1;
|
|
15
|
+
}
|
|
16
|
+
finally {
|
|
17
|
+
// Lazy import for cleanup
|
|
18
|
+
const { dbConnectionClose } = await import('../../db/client.js');
|
|
19
|
+
await dbConnectionClose();
|
|
20
|
+
}
|
|
21
|
+
process.exit(exitCode);
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fix-master-admin.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/fix-master-admin.ts"],"names":[],"mappings":"AAGA,wBAAsB,iBAAiB,kBAiBtC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import * as p from '@clack/prompts';
|
|
3
|
+
export async function runFixMasterAdmin() {
|
|
4
|
+
let exitCode = 0;
|
|
5
|
+
try {
|
|
6
|
+
p.log.info(chalk.cyan('Looking up sections'));
|
|
7
|
+
// Lazy import to avoid eager database connection
|
|
8
|
+
const { fixMasterAdminPrivileges } = await import('../lib/fix-master-admin.js');
|
|
9
|
+
await fixMasterAdminPrivileges();
|
|
10
|
+
p.outro(chalk.inverse(' ✓ Master admin privileges fixed '));
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
console.error(chalk.red('Error fixing master admin privileges:'), error);
|
|
14
|
+
exitCode = 1;
|
|
15
|
+
}
|
|
16
|
+
finally {
|
|
17
|
+
// Lazy import for cleanup
|
|
18
|
+
const { dbConnectionClose } = await import('../../db/client.js');
|
|
19
|
+
await dbConnectionClose();
|
|
20
|
+
}
|
|
21
|
+
process.exit(exitCode);
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"set-master-admin.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/set-master-admin.ts"],"names":[],"mappings":"AAGA,wBAAsB,iBAAiB,kBAoBtC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import * as p from '@clack/prompts';
|
|
3
|
+
export async function runSetMasterAdmin() {
|
|
4
|
+
p.log.info(chalk.cyan('Setting up master admin'));
|
|
5
|
+
let exitCode = 0;
|
|
6
|
+
try {
|
|
7
|
+
const { setMasterAdmin } = await import('../lib/set-master-admin.js');
|
|
8
|
+
await setMasterAdmin();
|
|
9
|
+
p.outro(chalk.inverse(' ✓ Master admin setup completed successfully '));
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
p.log.error(chalk.red('✗ Error resetting master admin:'));
|
|
13
|
+
console.error(error);
|
|
14
|
+
// Lazy import for cleanup
|
|
15
|
+
const { dbConnectionClose } = await import('../../db/client.js');
|
|
16
|
+
await dbConnectionClose();
|
|
17
|
+
exitCode = 1;
|
|
18
|
+
}
|
|
19
|
+
finally {
|
|
20
|
+
// Lazy import for cleanup
|
|
21
|
+
const { dbConnectionClose } = await import('../../db/client.js');
|
|
22
|
+
await dbConnectionClose();
|
|
23
|
+
}
|
|
24
|
+
process.exit(exitCode);
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/setup.ts"],"names":[],"mappings":"AAGA,wBAAsB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,iBAiCjE"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as p from '@clack/prompts';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
export async function runSetup(dev, skipDbConfig) {
|
|
4
|
+
let exitCode = 0;
|
|
5
|
+
try {
|
|
6
|
+
if (!skipDbConfig) {
|
|
7
|
+
p.log.info(chalk.cyan('Configuring database'));
|
|
8
|
+
const { dbConfigSetup } = await import('../lib/db-config.js');
|
|
9
|
+
await dbConfigSetup({ dev });
|
|
10
|
+
}
|
|
11
|
+
p.log.info(chalk.cyan('Generating database tables'));
|
|
12
|
+
const { generateDatabaseTables } = await import('../lib/db-migrate.js');
|
|
13
|
+
await generateDatabaseTables();
|
|
14
|
+
p.log.info(chalk.cyan('Setting up master admin'));
|
|
15
|
+
const { setMasterAdmin } = await import('../lib/set-master-admin.js');
|
|
16
|
+
await setMasterAdmin();
|
|
17
|
+
p.outro(chalk.inverse(' ✓ nextjs-cms setup completed successfully '));
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
console.log('');
|
|
21
|
+
console.error(chalk.red('✗ Error during setup:'), error);
|
|
22
|
+
p.outro(chalk.red('✗ Setup failed'));
|
|
23
|
+
// Lazy import for cleanup
|
|
24
|
+
const { dbConnectionClose } = await import('../../db/client.js');
|
|
25
|
+
await dbConnectionClose();
|
|
26
|
+
exitCode = 1;
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
// Lazy import for cleanup
|
|
30
|
+
const { dbConnectionClose } = await import('../../db/client.js');
|
|
31
|
+
await dbConnectionClose();
|
|
32
|
+
}
|
|
33
|
+
process.exit(exitCode);
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-sections.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/update-sections.ts"],"names":[],"mappings":"AAGA,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,OAAO,iBAsBnD"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import * as p from '@clack/prompts';
|
|
3
|
+
export async function runUpdateSections(dev) {
|
|
4
|
+
let exitCode = 0;
|
|
5
|
+
try {
|
|
6
|
+
p.log.info(chalk.cyan('Updating sections'));
|
|
7
|
+
const { updateSections } = await import('../lib/update-sections.js');
|
|
8
|
+
await updateSections(dev);
|
|
9
|
+
p.log.info(chalk.cyan('Modifying master admin privileges'));
|
|
10
|
+
// Lazy import to avoid eager database connection
|
|
11
|
+
const { fixMasterAdminPrivileges } = await import('../lib/fix-master-admin.js');
|
|
12
|
+
await fixMasterAdminPrivileges();
|
|
13
|
+
p.log.message(chalk.green(' - ✓ Master admin privileges fixed.'));
|
|
14
|
+
p.outro(chalk.inverse(' ✓ Sections updated '));
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
p.log.error(chalk.red('✗ Error updating sections:'));
|
|
18
|
+
console.error(error);
|
|
19
|
+
exitCode = 1;
|
|
20
|
+
}
|
|
21
|
+
finally {
|
|
22
|
+
// Lazy import for cleanup
|
|
23
|
+
const { dbConnectionClose } = await import('../../db/client.js');
|
|
24
|
+
await dbConnectionClose();
|
|
25
|
+
}
|
|
26
|
+
process.exit(exitCode);
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import dotenv from 'dotenv';
|
|
3
|
+
import program from './program/program.js';
|
|
4
|
+
program.parse(process.argv);
|
|
5
|
+
// Load environment file based on parsed dev flag
|
|
6
|
+
if (Boolean(program.opts().dev) === true) {
|
|
7
|
+
dotenv.config({ path: '.env.development', quiet: true });
|
|
8
|
+
// @ts-expect-error -- CLI intentionally sets NODE_ENV before app code runs
|
|
9
|
+
process.env.NODE_ENV = 'development';
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
dotenv.config();
|
|
13
|
+
// @ts-expect-error -- CLI intentionally sets NODE_ENV before app code runs
|
|
14
|
+
process.env.NODE_ENV = 'production';
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-config.d.ts","sourceRoot":"","sources":["../../../src/cli/lib/db-config.ts"],"names":[],"mappings":"AAmCA,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,GAAG,EAAE,OAAO,CAAA;CAAE,iBAyO5D"}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { createConnection } from 'mysql2/promise';
|
|
2
|
+
import * as p from '@clack/prompts';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { cwd } from 'process';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import ora from 'ora';
|
|
8
|
+
/**
|
|
9
|
+
* Removes specific environment variables from the .env file content
|
|
10
|
+
* Removes both the generated comment block and the individual variable lines
|
|
11
|
+
*/
|
|
12
|
+
function removeEnvVariables(content, variables) {
|
|
13
|
+
let result = content;
|
|
14
|
+
// Remove the generated block comment if it exists (including the markers)
|
|
15
|
+
const blockRegex = /\n*####\s*\n#\s*generated by the init script\s*\n####\s*\n?/g;
|
|
16
|
+
result = result.replace(blockRegex, '\n');
|
|
17
|
+
// Remove individual variable lines (entire lines including newline)
|
|
18
|
+
variables.forEach((variable) => {
|
|
19
|
+
result = result.replace(new RegExp(`^${variable}=.*$\\n?`, 'gm'), '');
|
|
20
|
+
});
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Validates if a string is a valid port number
|
|
25
|
+
*/
|
|
26
|
+
function isValidPort(value) {
|
|
27
|
+
const port = parseInt(value, 10);
|
|
28
|
+
return !isNaN(port) && port > 0 && port <= 65535;
|
|
29
|
+
}
|
|
30
|
+
export async function dbConfigSetup(options) {
|
|
31
|
+
const { dev = false } = options;
|
|
32
|
+
const envFileName = dev ? '.env.development' : '.env.production';
|
|
33
|
+
/**
|
|
34
|
+
* Step 1: Ask for connection credentials
|
|
35
|
+
*/
|
|
36
|
+
p.log.info('Database Connection');
|
|
37
|
+
p.log.message('Please provide your MySQL/MariaDB server credentials');
|
|
38
|
+
const { dbHost, dbPort, dbUser, dbPassword } = await p.group({
|
|
39
|
+
dbHost: () => p.text({
|
|
40
|
+
message: 'Database host:',
|
|
41
|
+
placeholder: 'localhost',
|
|
42
|
+
defaultValue: 'localhost',
|
|
43
|
+
validate(value) {
|
|
44
|
+
if (value && value.length < 2)
|
|
45
|
+
return `Database host must be at least 2 characters`;
|
|
46
|
+
},
|
|
47
|
+
}),
|
|
48
|
+
dbPort: () => p.text({
|
|
49
|
+
message: 'Database port:',
|
|
50
|
+
placeholder: '3306',
|
|
51
|
+
defaultValue: '3306',
|
|
52
|
+
validate(value) {
|
|
53
|
+
if (value && !isValidPort(value)) {
|
|
54
|
+
return `Database port must be a valid number between 1 and 65535`;
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
}),
|
|
58
|
+
dbUser: () => p.text({
|
|
59
|
+
message: 'Database username:',
|
|
60
|
+
validate(value) {
|
|
61
|
+
if (value.length < 1)
|
|
62
|
+
return `Database username is required`;
|
|
63
|
+
},
|
|
64
|
+
}),
|
|
65
|
+
dbPassword: () => p.text({
|
|
66
|
+
message: 'Database password:',
|
|
67
|
+
validate(value) {
|
|
68
|
+
if (value.length < 1)
|
|
69
|
+
return `Database password is required`;
|
|
70
|
+
},
|
|
71
|
+
}),
|
|
72
|
+
}, {
|
|
73
|
+
onCancel: () => {
|
|
74
|
+
p.cancel(`Aborted\n`);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
/**
|
|
79
|
+
* Step 2: Test the database connection
|
|
80
|
+
*/
|
|
81
|
+
const s = ora('Testing database connection...').start();
|
|
82
|
+
let migrationClient;
|
|
83
|
+
try {
|
|
84
|
+
/**
|
|
85
|
+
* It's recommended to not use a pool connection for migrations, that's why we're creating a new connection here.
|
|
86
|
+
*/
|
|
87
|
+
migrationClient = await createConnection({
|
|
88
|
+
host: String(dbHost),
|
|
89
|
+
user: String(dbUser),
|
|
90
|
+
password: String(dbPassword),
|
|
91
|
+
database: '',
|
|
92
|
+
port: parseInt(String(dbPort), 10),
|
|
93
|
+
});
|
|
94
|
+
s.stop();
|
|
95
|
+
p.log.success(chalk.green('✓ Connected successfully!'));
|
|
96
|
+
/**
|
|
97
|
+
* Step 3: Now that connection is successful, ask for database name
|
|
98
|
+
*/
|
|
99
|
+
const dbName = await p.text({
|
|
100
|
+
message: 'Database name:',
|
|
101
|
+
placeholder: 'If the database does not exist, it will be created',
|
|
102
|
+
validate(value) {
|
|
103
|
+
if (value.length < 2)
|
|
104
|
+
return `Database name must be at least 2 characters`;
|
|
105
|
+
// Validate database name format (alphanumeric, underscore, hyphen)
|
|
106
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(value)) {
|
|
107
|
+
return `Database name can only contain letters, numbers, underscores, and hyphens`;
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
if (p.isCancel(dbName)) {
|
|
112
|
+
p.cancel(`Aborted\n`);
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Step 4: Create the database
|
|
117
|
+
*/
|
|
118
|
+
s.start('Creating database...');
|
|
119
|
+
/**
|
|
120
|
+
* Let's create the database using parameterized query to prevent SQL injection
|
|
121
|
+
*/
|
|
122
|
+
await migrationClient.query('CREATE DATABASE IF NOT EXISTS ??', [dbName]);
|
|
123
|
+
s.stop();
|
|
124
|
+
p.log.success(chalk.green('✓ Database created successfully!'));
|
|
125
|
+
/**
|
|
126
|
+
* Let's save the database credentials in the .env file
|
|
127
|
+
*/
|
|
128
|
+
const envPath = path.resolve(cwd(), envFileName);
|
|
129
|
+
/**
|
|
130
|
+
* If the .env file does not exist, we'll create it
|
|
131
|
+
*/
|
|
132
|
+
if (!fs.existsSync(envPath)) {
|
|
133
|
+
fs.writeFileSync(envPath, '');
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Read current .env content and remove existing database credentials
|
|
137
|
+
*/
|
|
138
|
+
let currentEnv = fs.readFileSync(envPath, 'utf8');
|
|
139
|
+
currentEnv = removeEnvVariables(currentEnv, ['DB_HOST', 'DB_PORT', 'DB_NAME', 'DB_USER', 'DB_PASSWORD']);
|
|
140
|
+
/**
|
|
141
|
+
* Prepare new environment variables block
|
|
142
|
+
*/
|
|
143
|
+
const newEnvBlock = `
|
|
144
|
+
|
|
145
|
+
####
|
|
146
|
+
# generated by the init script
|
|
147
|
+
####
|
|
148
|
+
DB_HOST=${dbHost}
|
|
149
|
+
DB_PORT=${dbPort}
|
|
150
|
+
DB_NAME=${dbName}
|
|
151
|
+
DB_USER=${dbUser}
|
|
152
|
+
DB_PASSWORD='${dbPassword}'
|
|
153
|
+
`;
|
|
154
|
+
/**
|
|
155
|
+
* Append the new credentials to the .env file
|
|
156
|
+
*/
|
|
157
|
+
let finalEnv = currentEnv + newEnvBlock;
|
|
158
|
+
// Trim multiple consecutive empty lines to a maximum of two empty lines
|
|
159
|
+
finalEnv = finalEnv.replace(/(\n\s*\n){3,}/g, '\n\n');
|
|
160
|
+
// Trim leading whitespace
|
|
161
|
+
finalEnv = finalEnv.trim() + '\n';
|
|
162
|
+
fs.writeFileSync(envPath, finalEnv);
|
|
163
|
+
// Reload environment variables after writing to .env file
|
|
164
|
+
const dbVariables = {
|
|
165
|
+
DB_HOST: String(dbHost),
|
|
166
|
+
DB_PORT: String(dbPort),
|
|
167
|
+
DB_NAME: String(dbName),
|
|
168
|
+
DB_USER: String(dbUser),
|
|
169
|
+
DB_PASSWORD: String(dbPassword),
|
|
170
|
+
};
|
|
171
|
+
const { reloadAndUpdateEnvironmentVariables } = await import('../utils/reload-env.js');
|
|
172
|
+
reloadAndUpdateEnvironmentVariables(dbVariables, envFileName);
|
|
173
|
+
/**
|
|
174
|
+
* Get environment variables from env and check if they are correct
|
|
175
|
+
*/
|
|
176
|
+
const envDbHost = process.env.DB_HOST;
|
|
177
|
+
const envDbPort = process.env.DB_PORT;
|
|
178
|
+
const envDbName = process.env.DB_NAME;
|
|
179
|
+
const envDbUser = process.env.DB_USER;
|
|
180
|
+
const envDbPassword = process.env.DB_PASSWORD;
|
|
181
|
+
// Validate that the values match what we just set
|
|
182
|
+
const mismatches = [];
|
|
183
|
+
if (envDbHost !== String(dbHost))
|
|
184
|
+
mismatches.push('DB_HOST');
|
|
185
|
+
if (envDbPort !== String(dbPort))
|
|
186
|
+
mismatches.push('DB_PORT');
|
|
187
|
+
if (envDbName !== String(dbName))
|
|
188
|
+
mismatches.push('DB_NAME');
|
|
189
|
+
if (envDbUser !== String(dbUser))
|
|
190
|
+
mismatches.push('DB_USER');
|
|
191
|
+
if (envDbPassword !== String(dbPassword))
|
|
192
|
+
mismatches.push('DB_PASSWORD');
|
|
193
|
+
if (mismatches.length > 0) {
|
|
194
|
+
p.log.error(`✗ Couldn't save database credentials to ${envFileName} file}`);
|
|
195
|
+
console.error(`Please save these values manually to the ${envFileName} file:`);
|
|
196
|
+
console.error(`DB_HOST: ${dbHost}`);
|
|
197
|
+
console.error(`DB_PORT: ${dbPort}`);
|
|
198
|
+
console.error(`DB_NAME: ${dbName}`);
|
|
199
|
+
console.error(`DB_USER: ${dbUser}`);
|
|
200
|
+
console.error(`DB_PASSWORD: ${dbPassword}`);
|
|
201
|
+
console.error();
|
|
202
|
+
console.error(chalk.cyan(`and then run: ${chalk.green(`pnpm nextjs-cms ${dev ? '-d' : ''} setup --continue`)} to continue your setup`));
|
|
203
|
+
process.exit(1);
|
|
204
|
+
}
|
|
205
|
+
p.log.message(chalk.cyan(` - Saved database credentials to ${envFileName} file`));
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
s.stop();
|
|
209
|
+
p.log.error(chalk.red('✗ Database setup failed!'));
|
|
210
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
211
|
+
const errorCode = error && typeof error === 'object' && 'code' in error ? error.code : null;
|
|
212
|
+
// Provide specific error messages based on error type
|
|
213
|
+
if (errorCode === 'ER_ACCESS_DENIED_ERROR' || errorCode === 'ECONNREFUSED') {
|
|
214
|
+
console.error('\n❌ Connection Error:', errorMessage);
|
|
215
|
+
console.error('\nPlease verify:');
|
|
216
|
+
console.error(' • Database host and port are correct');
|
|
217
|
+
console.error(' • Username and password are correct');
|
|
218
|
+
console.error(' • Database server is running');
|
|
219
|
+
console.error(' • User has sufficient privileges');
|
|
220
|
+
}
|
|
221
|
+
else if (errorCode === 'ER_BAD_DB_ERROR') {
|
|
222
|
+
console.error('\n❌ Database Error:', errorMessage);
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
console.error('\n❌ Error:', errorMessage);
|
|
226
|
+
}
|
|
227
|
+
p.outro(`\nSetup failed. Please check the errors above and try again.`);
|
|
228
|
+
process.exit(1);
|
|
229
|
+
}
|
|
230
|
+
finally {
|
|
231
|
+
/**
|
|
232
|
+
* Always close the connection, even if an error occurred
|
|
233
|
+
*/
|
|
234
|
+
if (migrationClient) {
|
|
235
|
+
await migrationClient.end();
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-migrate.d.ts","sourceRoot":"","sources":["../../../src/cli/lib/db-migrate.ts"],"names":[],"mappings":"AAOA,wBAAsB,sBAAsB,kBAoF3C"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import * as p from '@clack/prompts';
|
|
2
|
+
import { execWithSpinner } from '../utils/exec-utils.js';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { MysqlTableChecker } from '../../core/db/index.js';
|
|
5
|
+
import { db } from '../../db/client.js';
|
|
6
|
+
import { sql } from '../../db/index.js';
|
|
7
|
+
export async function generateDatabaseTables() {
|
|
8
|
+
/**
|
|
9
|
+
* We should first drop all primary keys from the tables
|
|
10
|
+
*/
|
|
11
|
+
const _existingTables = [];
|
|
12
|
+
const tablesToCheck = [
|
|
13
|
+
'__nextjs_cms_tables',
|
|
14
|
+
'admins',
|
|
15
|
+
'admin_privileges',
|
|
16
|
+
'access_tokens',
|
|
17
|
+
'editor_photos',
|
|
18
|
+
];
|
|
19
|
+
try {
|
|
20
|
+
const result = await MysqlTableChecker.getExistingTables();
|
|
21
|
+
result.forEach((table) => {
|
|
22
|
+
if (tablesToCheck.includes(table)) {
|
|
23
|
+
_existingTables.push(table);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
if (_existingTables.length > 0) {
|
|
27
|
+
const allOrSome = _existingTables.length === tablesToCheck.length ? 'all' : 'some';
|
|
28
|
+
p.log.warn(chalk.yellow(`You already have ${allOrSome === 'some' ? 'a few required tables from' : ''} a previous database schema:`));
|
|
29
|
+
for (const table of _existingTables) {
|
|
30
|
+
p.log.message(chalk.yellow(` - ${table}`));
|
|
31
|
+
}
|
|
32
|
+
p.log.message(chalk.cyan('These tables will be dropped and new ones will be created.'));
|
|
33
|
+
const answer = await p.select({
|
|
34
|
+
message: 'Do you want to continue? (y/n)',
|
|
35
|
+
options: [
|
|
36
|
+
{ value: 'y', label: 'Yes' },
|
|
37
|
+
{ value: 'n', label: 'No' },
|
|
38
|
+
],
|
|
39
|
+
initialValue: 'n',
|
|
40
|
+
});
|
|
41
|
+
if (p.isCancel(answer) || answer !== 'y') {
|
|
42
|
+
p.log.error(chalk.red('Aborted\n'));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
// Disable foreign key checks to allow dropping tables with foreign key constraints
|
|
47
|
+
await db.execute(sql `SET FOREIGN_KEY_CHECKS = 0`);
|
|
48
|
+
// Drop all tables at once
|
|
49
|
+
for (const table of _existingTables) {
|
|
50
|
+
await db.execute(sql `DROP TABLE IF EXISTS \`${sql.raw(table)}\``);
|
|
51
|
+
}
|
|
52
|
+
// Re-enable foreign key checks
|
|
53
|
+
await db.execute(sql `SET FOREIGN_KEY_CHECKS = 1`);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
// Re-enable foreign key checks even if there's an error
|
|
57
|
+
await db.execute(sql `SET FOREIGN_KEY_CHECKS = 1`).catch(() => {
|
|
58
|
+
// Ignore errors when re-enabling
|
|
59
|
+
});
|
|
60
|
+
console.error(chalk.red('✗ Error dropping existing tables:'), error);
|
|
61
|
+
p.log.error(chalk.red('✗ Failed to drop existing tables'));
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const spinner = await execWithSpinner({
|
|
66
|
+
command: 'pnpm',
|
|
67
|
+
args: ['drizzle-kit', 'push', '--force', '--config=drizzle.config.ts'],
|
|
68
|
+
cwd: process.cwd(),
|
|
69
|
+
stdout: 'pipe', // Show output
|
|
70
|
+
stderr: 'inherit', // Show errors
|
|
71
|
+
spinnerText: 'Generating database tables...',
|
|
72
|
+
checkExitCode: true, // Throw on non-zero exit codes
|
|
73
|
+
checkStderrForErrors: true, // Also check for errors in output even if exit code is 0
|
|
74
|
+
});
|
|
75
|
+
spinner?.stop();
|
|
76
|
+
p.log.success(chalk.green(' ✓ Database tables generated'));
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
console.error(chalk.red(' ✗ Error generating database tables:'), error);
|
|
80
|
+
p.log.error(chalk.red('✗ Failed to generate database tables'));
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fix-master-admin.d.ts","sourceRoot":"","sources":["../../../src/cli/lib/fix-master-admin.ts"],"names":[],"mappings":"AAEA,wBAAsB,wBAAwB,kBA2D7C"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { getPluginRoutes } from '../../plugins/server.js';
|
|
2
|
+
export async function fixMasterAdminPrivileges() {
|
|
3
|
+
// Lazy import heavy dependencies to avoid eager database connection initialization
|
|
4
|
+
const { SectionFactory } = await import('../../core/factories/index.js');
|
|
5
|
+
const { db } = await import('../../db/client.js');
|
|
6
|
+
const { AdminPrivilegesTable } = await import('../../db/schema.js');
|
|
7
|
+
// Let's also add privileges for all the sections to the master admin
|
|
8
|
+
// Loop through the sections to get the section ids for the insertion into the admin_privileges table
|
|
9
|
+
const sections = await SectionFactory.getSectionsSilently();
|
|
10
|
+
const rows = sections.map((section) => ({
|
|
11
|
+
adminId: '1',
|
|
12
|
+
sectionName: section.name,
|
|
13
|
+
operations: 'CUD',
|
|
14
|
+
publisher: '1',
|
|
15
|
+
}));
|
|
16
|
+
const pluginRoutes = await getPluginRoutes();
|
|
17
|
+
const pluginNames = new Set(pluginRoutes.map((route) => {
|
|
18
|
+
return route.pluginName;
|
|
19
|
+
}));
|
|
20
|
+
pluginNames.forEach((pluginName) => {
|
|
21
|
+
rows.push({
|
|
22
|
+
adminId: '1',
|
|
23
|
+
sectionName: pluginName,
|
|
24
|
+
operations: 'CUD',
|
|
25
|
+
publisher: '1',
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
/**
|
|
29
|
+
* Add the admins and logs sections to the privileges
|
|
30
|
+
*/
|
|
31
|
+
rows.push({
|
|
32
|
+
adminId: '1',
|
|
33
|
+
sectionName: 'admins',
|
|
34
|
+
operations: 'CUD',
|
|
35
|
+
publisher: '1',
|
|
36
|
+
});
|
|
37
|
+
rows.push({
|
|
38
|
+
adminId: '1',
|
|
39
|
+
sectionName: 'log',
|
|
40
|
+
operations: 'CUD',
|
|
41
|
+
publisher: '1',
|
|
42
|
+
});
|
|
43
|
+
await db
|
|
44
|
+
.insert(AdminPrivilegesTable)
|
|
45
|
+
.values(rows)
|
|
46
|
+
.onDuplicateKeyUpdate({
|
|
47
|
+
set: {
|
|
48
|
+
operations: 'CUD',
|
|
49
|
+
publisher: true,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"set-master-admin.d.ts","sourceRoot":"","sources":["../../../src/cli/lib/set-master-admin.ts"],"names":[],"mappings":"AAGA,wBAAsB,cAAc,kBA+FnC"}
|