kythia-core 0.9.5-beta → 0.11.0-beta
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 +99 -4
- package/changelog.md +7 -0
- package/index.js +1 -3
- package/package.json +67 -44
- package/src/Kythia.js +532 -449
- package/src/KythiaClient.js +90 -49
- package/src/cli/Command.js +68 -0
- package/src/cli/commands/CacheClearCommand.js +136 -0
- package/src/cli/commands/LangCheckCommand.js +367 -0
- package/src/cli/commands/LangTranslateCommand.js +336 -0
- package/src/cli/commands/MakeMigrationCommand.js +82 -0
- package/src/cli/commands/MakeModelCommand.js +81 -0
- package/src/cli/commands/MigrateCommand.js +259 -0
- package/src/cli/commands/NamespaceCommand.js +112 -0
- package/src/cli/commands/StructureCommand.js +70 -0
- package/src/cli/commands/UpversionCommand.js +94 -0
- package/src/cli/index.js +69 -0
- package/src/cli/utils/db.js +117 -0
- package/src/database/KythiaMigrator.js +116 -0
- package/src/database/KythiaModel.js +1518 -1050
- package/src/database/KythiaSequelize.js +104 -95
- package/src/database/KythiaStorage.js +117 -0
- package/src/database/ModelLoader.js +79 -0
- package/src/managers/AddonManager.js +1199 -946
- package/src/managers/EventManager.js +80 -75
- package/src/managers/InteractionManager.js +794 -589
- package/src/managers/ShutdownManager.js +200 -179
- package/src/structures/BaseCommand.js +40 -36
- package/src/utils/color.js +157 -153
- package/src/utils/formatter.js +81 -81
- package/src/utils/index.js +2 -2
- package/src/database/KythiaORM.js +0 -520
package/src/cli/index.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ⚡ Kythia CLI Entry Point
|
|
5
|
+
*
|
|
6
|
+
* @file src/cli/index.js
|
|
7
|
+
* @copyright © 2025 kenndeclouv
|
|
8
|
+
* @assistant chaa & graa
|
|
9
|
+
* @version 0.11.0-beta
|
|
10
|
+
*
|
|
11
|
+
* @description
|
|
12
|
+
* The main bootstrap entry point for the Kythia CLI.
|
|
13
|
+
* It dynamically scans, loads, and registers all command classes found in the
|
|
14
|
+
* `commands` directory, orchestrating the `commander` program execution.
|
|
15
|
+
*
|
|
16
|
+
* ✨ Core Features:
|
|
17
|
+
* - Dynamic Loading: Automatically finds new commands without manual import.
|
|
18
|
+
* - Class-Based Architecture: Supports standard `Command` class structure.
|
|
19
|
+
* - Error Handling: Gracefully handles malformed commands during boot.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const { version } = require('../../package.json');
|
|
23
|
+
const { Command } = require('commander');
|
|
24
|
+
const BaseCommand = require('./Command');
|
|
25
|
+
const path = require('node:path');
|
|
26
|
+
const pc = require('picocolors');
|
|
27
|
+
const fs = require('node:fs');
|
|
28
|
+
|
|
29
|
+
const program = new Command();
|
|
30
|
+
|
|
31
|
+
program
|
|
32
|
+
.name('kythia')
|
|
33
|
+
.description(pc.cyan('🌸 Kythia Framework CLI'))
|
|
34
|
+
.version(version);
|
|
35
|
+
|
|
36
|
+
const commandsDir = path.join(__dirname, 'commands');
|
|
37
|
+
|
|
38
|
+
if (fs.existsSync(commandsDir)) {
|
|
39
|
+
const commandFiles = fs
|
|
40
|
+
.readdirSync(commandsDir)
|
|
41
|
+
.filter((file) => file.endsWith('.js'));
|
|
42
|
+
|
|
43
|
+
for (const file of commandFiles) {
|
|
44
|
+
const filePath = path.join(commandsDir, file);
|
|
45
|
+
try {
|
|
46
|
+
const CommandClass = require(filePath);
|
|
47
|
+
|
|
48
|
+
if (
|
|
49
|
+
typeof CommandClass === 'function' &&
|
|
50
|
+
CommandClass.prototype instanceof BaseCommand
|
|
51
|
+
) {
|
|
52
|
+
const commandInstance = new CommandClass();
|
|
53
|
+
commandInstance.register(program);
|
|
54
|
+
} else if (typeof CommandClass.register === 'function') {
|
|
55
|
+
CommandClass.register(program);
|
|
56
|
+
} else {
|
|
57
|
+
console.warn(
|
|
58
|
+
pc.yellow(
|
|
59
|
+
`⚠️ Skipped ${file}: Not a valid Command class or missing 'register' function.`,
|
|
60
|
+
),
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
} catch (err) {
|
|
64
|
+
console.error(pc.red(`❌ Failed to load command ${file}:`), err);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
program.parse(process.argv);
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🔌 CLI Database & Migration Bootstrapper
|
|
3
|
+
*
|
|
4
|
+
* @file src/cli/utils/db.js
|
|
5
|
+
* @copyright © 2025 kenndeclouv
|
|
6
|
+
* @assistant chaa & graa
|
|
7
|
+
* @version 0.11.0-beta
|
|
8
|
+
*
|
|
9
|
+
* @description
|
|
10
|
+
* Initializes the database connection and migration engine (Umzug) specifically
|
|
11
|
+
* for CLI operations. It dynamically loads the project configuration and
|
|
12
|
+
* discovers migration files across all addons.
|
|
13
|
+
*
|
|
14
|
+
* ✨ Core Features:
|
|
15
|
+
* - Dynamic Config: Loads `kythia.config.js` from the user's project root.
|
|
16
|
+
* - Auto-Discovery: Scans `addons` directory for migration files.
|
|
17
|
+
* - Pretty Logging: Custom console output using `picocolors` for migration status.
|
|
18
|
+
* - Singleton-like: Exports shared instances of Sequelize and Umzug.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
require('@dotenvx/dotenvx/config');
|
|
22
|
+
const fs = require('node:fs');
|
|
23
|
+
const path = require('node:path');
|
|
24
|
+
const { Umzug } = require('umzug');
|
|
25
|
+
const createSequelizeInstance = require('../../database/KythiaSequelize');
|
|
26
|
+
const KythiaStorage = require('../../database/KythiaStorage');
|
|
27
|
+
const pc = require('picocolors');
|
|
28
|
+
|
|
29
|
+
const configPath = path.resolve(process.cwd(), 'kythia.config.js');
|
|
30
|
+
|
|
31
|
+
if (!fs.existsSync(configPath)) {
|
|
32
|
+
console.error('❌ kythia.config.js not found in root directory!');
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const config = require(configPath);
|
|
37
|
+
|
|
38
|
+
const logger = {
|
|
39
|
+
info: () => {},
|
|
40
|
+
error: console.error,
|
|
41
|
+
debug: () => {},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const sequelize = createSequelizeInstance(config, logger);
|
|
45
|
+
|
|
46
|
+
function getMigrationFiles() {
|
|
47
|
+
const rootDir = process.cwd();
|
|
48
|
+
const addonsDir = path.join(rootDir, 'addons');
|
|
49
|
+
|
|
50
|
+
if (!fs.existsSync(addonsDir)) return [];
|
|
51
|
+
|
|
52
|
+
const migrationFiles = [];
|
|
53
|
+
const addonFolders = fs
|
|
54
|
+
.readdirSync(addonsDir)
|
|
55
|
+
.filter((f) => fs.statSync(path.join(addonsDir, f)).isDirectory());
|
|
56
|
+
|
|
57
|
+
for (const addon of addonFolders) {
|
|
58
|
+
const migrationDir = path.join(addonsDir, addon, 'database', 'migrations');
|
|
59
|
+
if (fs.existsSync(migrationDir)) {
|
|
60
|
+
const files = fs
|
|
61
|
+
.readdirSync(migrationDir)
|
|
62
|
+
.filter((f) => f.endsWith('.js'))
|
|
63
|
+
.map((f) => ({
|
|
64
|
+
name: f,
|
|
65
|
+
path: path.join(migrationDir, f),
|
|
66
|
+
}));
|
|
67
|
+
migrationFiles.push(...files);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return migrationFiles.sort((a, b) => a.name.localeCompare(b.name));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const storage = new KythiaStorage({ sequelize });
|
|
74
|
+
|
|
75
|
+
const umzugLogger = {
|
|
76
|
+
info: (event) => {
|
|
77
|
+
if (typeof event === 'object') {
|
|
78
|
+
if (event.event === 'migrated') {
|
|
79
|
+
console.log(
|
|
80
|
+
pc.green(`✅ Migrated: ${event.name} `) +
|
|
81
|
+
pc.gray(`(${event.durationSeconds}s)`),
|
|
82
|
+
);
|
|
83
|
+
} else if (event.event === 'reverting') {
|
|
84
|
+
console.log(pc.yellow(`↩️ Reverting: ${event.name}`));
|
|
85
|
+
} else if (event.event === 'reverted') {
|
|
86
|
+
console.log(
|
|
87
|
+
pc.red(`❌ Reverted: ${event.name} `) +
|
|
88
|
+
pc.gray(`(${event.durationSeconds}s)`),
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
console.log(pc.dim(event));
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
warn: (msg) => console.warn(pc.yellow(`⚠️ ${msg}`)),
|
|
96
|
+
error: (msg) => console.error(pc.red(`🔥 ${msg}`)),
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const umzug = new Umzug({
|
|
100
|
+
migrations: getMigrationFiles().map((m) => ({
|
|
101
|
+
name: m.name,
|
|
102
|
+
path: m.path,
|
|
103
|
+
up: async ({ context }) => {
|
|
104
|
+
const migration = require(m.path);
|
|
105
|
+
return migration.up(context, require('sequelize').DataTypes);
|
|
106
|
+
},
|
|
107
|
+
down: async ({ context }) => {
|
|
108
|
+
const migration = require(m.path);
|
|
109
|
+
return migration.down(context, require('sequelize').DataTypes);
|
|
110
|
+
},
|
|
111
|
+
})),
|
|
112
|
+
context: sequelize.getQueryInterface(),
|
|
113
|
+
storage: storage,
|
|
114
|
+
logger: umzugLogger,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
module.exports = { sequelize, umzug, storage };
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🚜 Addon-based Database Migration Manager
|
|
3
|
+
*
|
|
4
|
+
* @file src/database/KythiaMigrator.js
|
|
5
|
+
* @copyright © 2025 kenndeclouv
|
|
6
|
+
* @assistant chaa & graa
|
|
7
|
+
* @version 0.11.0-beta
|
|
8
|
+
*
|
|
9
|
+
* @description
|
|
10
|
+
* Scans 'addons' folder for migration files and executes them using Umzug.
|
|
11
|
+
* It integrates with KythiaStorage (Laravel-style) to track migration batches.
|
|
12
|
+
*
|
|
13
|
+
* ✨ Core Features:
|
|
14
|
+
* - Auto-Discovery: Recursively finds migrations in `addons/{AddonName}/database/migrations`.
|
|
15
|
+
* - Sorting: Ensures migrations run in correct order (YYYYMMDD format).
|
|
16
|
+
* - Custom Logger: Clean, non-intrusive logging for the bot console.
|
|
17
|
+
* - Batch Integration: Uses KythiaStorage to support rollback by batch.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const KythiaStorage = require('./KythiaStorage');
|
|
21
|
+
const { DataTypes } = require('sequelize');
|
|
22
|
+
const { Umzug } = require('umzug');
|
|
23
|
+
const path = require('node:path');
|
|
24
|
+
const fs = require('node:fs');
|
|
25
|
+
|
|
26
|
+
function getMigrationFiles(rootDir) {
|
|
27
|
+
const addonsDir = path.join(rootDir, 'addons');
|
|
28
|
+
if (!fs.existsSync(addonsDir)) return [];
|
|
29
|
+
|
|
30
|
+
const migrationFiles = [];
|
|
31
|
+
|
|
32
|
+
const addonFolders = fs
|
|
33
|
+
.readdirSync(addonsDir)
|
|
34
|
+
.filter((f) => fs.statSync(path.join(addonsDir, f)).isDirectory());
|
|
35
|
+
|
|
36
|
+
for (const addon of addonFolders) {
|
|
37
|
+
const migrationDir = path.join(addonsDir, addon, 'database', 'migrations');
|
|
38
|
+
if (fs.existsSync(migrationDir)) {
|
|
39
|
+
const files = fs
|
|
40
|
+
.readdirSync(migrationDir)
|
|
41
|
+
.filter((f) => f.endsWith('.js'))
|
|
42
|
+
.map((f) => ({
|
|
43
|
+
name: f,
|
|
44
|
+
path: path.join(migrationDir, f),
|
|
45
|
+
folder: migrationDir,
|
|
46
|
+
}));
|
|
47
|
+
migrationFiles.push(...files);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return migrationFiles.sort((a, b) => a.name.localeCompare(b.name));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function KythiaMigrator({ sequelize, container, logger }) {
|
|
55
|
+
const rootDir = container.appRoot;
|
|
56
|
+
const migrations = getMigrationFiles(rootDir);
|
|
57
|
+
|
|
58
|
+
if (migrations.length === 0) {
|
|
59
|
+
logger.info('📭 No migrations found in addons.');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const umzugLogger = {
|
|
64
|
+
info: (event) => {
|
|
65
|
+
if (typeof event === 'object') {
|
|
66
|
+
if (event.event === 'migrating') {
|
|
67
|
+
} else if (event.event === 'migrated') {
|
|
68
|
+
logger.info(`✅ Migrated: ${event.name}`);
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
logger.info(event);
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
warn: (msg) => logger.warn(msg),
|
|
75
|
+
error: (msg) => logger.error(msg),
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const umzug = new Umzug({
|
|
79
|
+
migrations: migrations.map((m) => ({
|
|
80
|
+
name: m.name,
|
|
81
|
+
path: m.path,
|
|
82
|
+
up: async ({ context }) => {
|
|
83
|
+
const migration = require(m.path);
|
|
84
|
+
return migration.up(context, DataTypes);
|
|
85
|
+
},
|
|
86
|
+
down: async ({ context }) => {
|
|
87
|
+
const migration = require(m.path);
|
|
88
|
+
return migration.down(context, DataTypes);
|
|
89
|
+
},
|
|
90
|
+
})),
|
|
91
|
+
context: sequelize.getQueryInterface(),
|
|
92
|
+
|
|
93
|
+
storage: new KythiaStorage({ sequelize }),
|
|
94
|
+
logger: umzugLogger,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
logger.info(`🚜 Checking migrations for ${migrations.length} files...`);
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
const pending = await umzug.pending();
|
|
101
|
+
|
|
102
|
+
if (pending.length > 0) {
|
|
103
|
+
const executed = await umzug.up();
|
|
104
|
+
if (executed.length > 0) {
|
|
105
|
+
logger.info(`✨ Successfully applied ${executed.length} migrations.`);
|
|
106
|
+
}
|
|
107
|
+
} else {
|
|
108
|
+
logger.info('✨ Database is already up to date.');
|
|
109
|
+
}
|
|
110
|
+
} catch (error) {
|
|
111
|
+
logger.error('🔥 Migration Failed:', error);
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
module.exports = KythiaMigrator;
|