@monodog/backend 1.2.3 → 1.2.4
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.js +62 -2
- package/dist/config-loader.js +97 -0
- package/dist/index.js +7 -18
- package/get-db-url.ts +14 -0
- package/package.json +23 -17
- package/prisma/migrations/20251111091920_/migration.sql +16 -0
- package/prisma/schema.prisma +1 -1
- package/src/cli.ts +67 -3
- package/src/config-loader.ts +88 -0
- package/src/index.ts +8 -19
- package/LICENCE +0 -21
package/dist/cli.js
CHANGED
|
@@ -45,12 +45,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
45
45
|
const fs = __importStar(require("fs"));
|
|
46
46
|
const path = __importStar(require("path"));
|
|
47
47
|
const index_1 = require("./index"); // Assume index.ts exports this function
|
|
48
|
+
const config_loader_1 = require("./config-loader");
|
|
49
|
+
const appConfig = (0, config_loader_1.loadConfig)();
|
|
48
50
|
// --- Argument Parsing ---
|
|
49
51
|
// 1. Get arguments excluding the node executable and script name
|
|
50
52
|
const args = process.argv.slice(2);
|
|
51
53
|
// Default settings
|
|
54
|
+
const DEFAULT_PORT = 4000;
|
|
52
55
|
let serve = false;
|
|
53
|
-
let rootPath = process.cwd(); // Default to the current working directory
|
|
56
|
+
let rootPath = path.resolve(appConfig.workspace.root_dir ?? process.cwd()); // Default to the current working directory
|
|
57
|
+
let port = appConfig.server.port ?? DEFAULT_PORT; //Default port
|
|
58
|
+
let host = appConfig.server.host ?? 'localhost'; //Default port
|
|
54
59
|
// Simple argument parsing loop
|
|
55
60
|
for (let i = 0; i < args.length; i++) {
|
|
56
61
|
const arg = args[i];
|
|
@@ -68,6 +73,22 @@ for (let i = 0; i < args.length; i++) {
|
|
|
68
73
|
process.exit(1);
|
|
69
74
|
}
|
|
70
75
|
}
|
|
76
|
+
else if (arg === '--port') {
|
|
77
|
+
// Look at the next argument for the port number
|
|
78
|
+
if (i + 1 < args.length) {
|
|
79
|
+
const portValue = parseInt(args[i + 1], 10);
|
|
80
|
+
if (isNaN(portValue) || portValue <= 0 || portValue > 65535) {
|
|
81
|
+
console.error('Error: --port requires a valid port number (1-65535).');
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
port = portValue;
|
|
85
|
+
i++; // Skip the next argument
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
console.error('Error: --port requires a number argument.');
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
71
92
|
else if (arg === '-h' || arg === '--help') {
|
|
72
93
|
console.log(`
|
|
73
94
|
Monodog CLI - Monorepo Analysis Engine
|
|
@@ -88,10 +109,12 @@ Example:
|
|
|
88
109
|
}
|
|
89
110
|
// --- Execution Logic ---
|
|
90
111
|
if (serve) {
|
|
112
|
+
console.log(`\nInitializing Configurations...`);
|
|
113
|
+
createConfigFileIfMissing(rootPath ?? process.cwd());
|
|
91
114
|
console.log(`Starting Monodog API server...`);
|
|
92
115
|
console.log(`Analyzing monorepo at root: ${rootPath}`);
|
|
93
116
|
// Start the Express server and begin analysis
|
|
94
|
-
(0, index_1.startServer)(rootPath);
|
|
117
|
+
(0, index_1.startServer)(rootPath, port, host);
|
|
95
118
|
copyPackageToWorkspace(rootPath);
|
|
96
119
|
}
|
|
97
120
|
else {
|
|
@@ -167,3 +190,40 @@ function copyPackageToWorkspace(rootDir) {
|
|
|
167
190
|
process.exit(1);
|
|
168
191
|
}
|
|
169
192
|
}
|
|
193
|
+
function createConfigFileIfMissing(rootPath) {
|
|
194
|
+
// --- CONFIGURATION ---
|
|
195
|
+
const configFileName = 'monodog-conf.json';
|
|
196
|
+
const configFilePath = path.resolve(rootPath, configFileName);
|
|
197
|
+
// The default content for the configuration file
|
|
198
|
+
const defaultContent = {
|
|
199
|
+
"workspace": {
|
|
200
|
+
"root_dir": "./packages/backend"
|
|
201
|
+
},
|
|
202
|
+
"database": {
|
|
203
|
+
"path": "./monodog.db"
|
|
204
|
+
},
|
|
205
|
+
"server": {
|
|
206
|
+
"host": "0.0.0.0",
|
|
207
|
+
"port": 4000
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
const contentString = JSON.stringify(defaultContent, null, 2);
|
|
211
|
+
// ---------------------
|
|
212
|
+
console.log(`\n[monodog] Checking for ${configFileName}...`);
|
|
213
|
+
if (fs.existsSync(configFilePath)) {
|
|
214
|
+
console.log(`[monodog] ${configFileName} already exists. Skipping creation.`);
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
try {
|
|
218
|
+
// Write the default content to the file
|
|
219
|
+
fs.writeFileSync(configFilePath, contentString, 'utf-8');
|
|
220
|
+
console.log(`[monodog] Successfully generated default ${configFileName} in the workspace root.`);
|
|
221
|
+
console.log('[monodog] Please review and update settings like "host" and "port".');
|
|
222
|
+
}
|
|
223
|
+
catch (err) {
|
|
224
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
225
|
+
console.error(`[monodog Error] Failed to generate ${configFileName}:`, message);
|
|
226
|
+
process.exit(1);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadConfig = loadConfig;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
// Global variable to hold the loaded config
|
|
40
|
+
let config = null;
|
|
41
|
+
/**
|
|
42
|
+
* Loads the monodog-conf.json file from the monorepo root.
|
|
43
|
+
* This should be called only once during application startup.
|
|
44
|
+
* @returns The application configuration object.
|
|
45
|
+
*/
|
|
46
|
+
function loadConfig() {
|
|
47
|
+
if (config) {
|
|
48
|
+
return config; // Return cached config if already loaded
|
|
49
|
+
}
|
|
50
|
+
// 1. Determine the path to the config file
|
|
51
|
+
// We assume the backend package is running from the monorepo root (cwd is root)
|
|
52
|
+
// or that we can navigate up to the root from the current file's location.
|
|
53
|
+
const rootPath = path.resolve(__dirname, '../../../'); // Adjust based on your folder depth if needed
|
|
54
|
+
const configPath = path.resolve(rootPath, 'monodog-conf.json');
|
|
55
|
+
if (!fs.existsSync(configPath)) {
|
|
56
|
+
console.error(`ERROR: Configuration file not found at ${configPath}`);
|
|
57
|
+
// A missing config is a critical failure, so we exit
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
// 2. Read and parse the JSON file
|
|
62
|
+
const fileContent = fs.readFileSync(configPath, 'utf-8');
|
|
63
|
+
const parsedConfig = JSON.parse(fileContent);
|
|
64
|
+
// 3. Optional: Add validation logic here (e.g., check if ports are numbers)
|
|
65
|
+
// Cache and return
|
|
66
|
+
config = parsedConfig;
|
|
67
|
+
process.stderr.write(`[Config] Loaded configuration from: ${configPath}`);
|
|
68
|
+
return config;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
console.error("ERROR: Failed to read or parse monodog-conf.json.");
|
|
72
|
+
console.error(error);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// --- Example Usage ---
|
|
77
|
+
// In your main application file (e.g., packages/backend/src/index.ts):
|
|
78
|
+
/*
|
|
79
|
+
|
|
80
|
+
import { loadConfig } from './config-loader';
|
|
81
|
+
|
|
82
|
+
// Load configuration on startup
|
|
83
|
+
const appConfig = loadConfig();
|
|
84
|
+
|
|
85
|
+
// Access the variables easily
|
|
86
|
+
const dbHost = appConfig.database.host;
|
|
87
|
+
const serverPort = appConfig.server.port;
|
|
88
|
+
const workspaceRoot = appConfig.workspace.root_dir;
|
|
89
|
+
|
|
90
|
+
console.log(`\nStarting server on port: ${serverPort}`);
|
|
91
|
+
console.log(`Database connecting to host: ${dbHost}`);
|
|
92
|
+
|
|
93
|
+
// Example server start logic
|
|
94
|
+
// app.listen(serverPort, appConfig.server.host, () => {
|
|
95
|
+
// console.log(`Server running at http://${appConfig.server.host}:${serverPort}`);
|
|
96
|
+
// });
|
|
97
|
+
*/
|
package/dist/index.js
CHANGED
|
@@ -18,11 +18,9 @@ const client_1 = require("@prisma/client");
|
|
|
18
18
|
// import { validateConfig } from '../../apps/dashboard/src/components/modules/config-inspector/utils/config.utils';
|
|
19
19
|
const gitService_1 = require("./gitService");
|
|
20
20
|
const prisma = new client_1.PrismaClient();
|
|
21
|
-
const DEFAULT_PORT = 4000;
|
|
22
21
|
// The main function exported and called by the CLI
|
|
23
|
-
function startServer(rootPath) {
|
|
22
|
+
function startServer(rootPath, port, host) {
|
|
24
23
|
const app = (0, express_1.default)();
|
|
25
|
-
const port = process.env.PORT ? parseInt(process.env.PORT) : DEFAULT_PORT;
|
|
26
24
|
// --- Middleware ---
|
|
27
25
|
// 1. Logging Middleware
|
|
28
26
|
app.use((_req, _res, next) => {
|
|
@@ -31,17 +29,6 @@ function startServer(rootPath) {
|
|
|
31
29
|
});
|
|
32
30
|
app.use((0, cors_1.default)());
|
|
33
31
|
app.use((0, body_parser_1.json)());
|
|
34
|
-
// // 2. CORS (Critical for the frontend app to talk to this local server)
|
|
35
|
-
// // In a production setup, this would be highly restricted, but for local monorepo tools,
|
|
36
|
-
// // we often allow all origins or restrict to a known local hostname/port.
|
|
37
|
-
// app.use((_req: Request, res: Response, next: NextFunction) => {
|
|
38
|
-
// res.setHeader('Access-Control-Allow-Origin', '*'); // Adjust this in production
|
|
39
|
-
// res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
|
|
40
|
-
// res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
41
|
-
// next();
|
|
42
|
-
// });
|
|
43
|
-
// // 3. JSON body parser
|
|
44
|
-
// app.use(express.json());
|
|
45
32
|
// Health check
|
|
46
33
|
app.get('/api/health', (_, res) => {
|
|
47
34
|
res.json({
|
|
@@ -1233,9 +1220,11 @@ function startServer(rootPath) {
|
|
|
1233
1220
|
timestamp: Date.now(),
|
|
1234
1221
|
});
|
|
1235
1222
|
});
|
|
1236
|
-
const PORT =
|
|
1237
|
-
app.listen(PORT, () => {
|
|
1238
|
-
|
|
1223
|
+
const PORT = parseInt(port ? port.toString() : '4000');
|
|
1224
|
+
app.listen(PORT, host, async () => {
|
|
1225
|
+
const pcount = await prisma.package.count();
|
|
1226
|
+
console.log(`[Database] Total packages found: ${pcount}`);
|
|
1227
|
+
console.log(`🚀 Backend server running on http://${host}:${PORT}`);
|
|
1239
1228
|
console.log(`📊 API endpoints available:`);
|
|
1240
1229
|
console.log(` - GET /api/health`);
|
|
1241
1230
|
console.log(` - GET /api/packages/refresh`);
|
|
@@ -1254,7 +1243,7 @@ function startServer(rootPath) {
|
|
|
1254
1243
|
}).on('error', (err) => {
|
|
1255
1244
|
// Handle common errors like EADDRINUSE (port already in use)
|
|
1256
1245
|
if (err.message.includes('EADDRINUSE')) {
|
|
1257
|
-
console.error(`Error: Port ${port} is already in use. Please specify a different port via
|
|
1246
|
+
console.error(`Error: Port ${port} is already in use. Please specify a different port via configuration file.`);
|
|
1258
1247
|
process.exit(1);
|
|
1259
1248
|
}
|
|
1260
1249
|
else {
|
package/get-db-url.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { loadConfig } from './src/config-loader';
|
|
2
|
+
|
|
3
|
+
function generateUrl() {
|
|
4
|
+
const appConfig = loadConfig();
|
|
5
|
+
|
|
6
|
+
const DATABASE_URL = `${appConfig.database.path}`;
|
|
7
|
+
process.env.DATABASE_URL = DATABASE_URL;
|
|
8
|
+
process.env.DATABASE_PORT = `${appConfig.database.port}`;
|
|
9
|
+
|
|
10
|
+
process.stdout.write(DATABASE_URL);
|
|
11
|
+
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
generateUrl();
|
package/package.json
CHANGED
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@monodog/backend",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.4",
|
|
4
4
|
"description": "Backend API server for monodog monorepo dashboard",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"bin": {
|
|
8
|
-
"monodog-cli": "
|
|
8
|
+
"monodog-cli": "src/cli.ts"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"dev": "tsx watch src/index.ts",
|
|
12
|
+
"start": "tsx index.ts",
|
|
13
|
+
"prepublishOnly": "pnpm run build",
|
|
14
|
+
"build": "rm -rf dist && tsc -p tsconfig.json",
|
|
15
|
+
"prestart": "npm run build",
|
|
16
|
+
"cli": "pnpm run build && node dist/cli.js",
|
|
17
|
+
"test": "jest --coverage",
|
|
18
|
+
"clean": "rm -rf dist node_modules/.cache",
|
|
19
|
+
"test:coverage": "jest --coverage",
|
|
20
|
+
"lint": "eslint .",
|
|
21
|
+
"lint:fix": "eslint . --fix",
|
|
22
|
+
"db:url": "npx ts-node get-db-url.ts",
|
|
23
|
+
"migrate": "DATABASE_URL=$(npm run db:url --silent 2>/dev/null | tr -d '\\n') npx prisma migrate dev",
|
|
24
|
+
"serve": "DATABASE_URL=$(npm run db:url --silent 2>/dev/null | tr -d '\\n') ts-node src/cli.ts --serve "
|
|
9
25
|
},
|
|
10
26
|
"dependencies": {
|
|
11
27
|
"@monodog/ci-status": "1.1.1",
|
|
@@ -19,24 +35,14 @@
|
|
|
19
35
|
"prisma": "^5.22.0"
|
|
20
36
|
},
|
|
21
37
|
"devDependencies": {
|
|
22
|
-
"typescript": "^5.3.8",
|
|
23
38
|
"@types/body-parser": "^1.19.5",
|
|
24
39
|
"@types/cors": "^2.8.17",
|
|
25
40
|
"@types/dotenv": "^8.2.0",
|
|
26
41
|
"@types/express": "^4.17.21",
|
|
27
42
|
"@types/node": "^20.10.0",
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
"start": "tsx index.ts",
|
|
33
|
-
"build": "rm -rf dist && tsc -p tsconfig.json",
|
|
34
|
-
"prestart": "npm run build",
|
|
35
|
-
"cli": "pnpm run build && node dist/cli.js",
|
|
36
|
-
"test": "jest --coverage",
|
|
37
|
-
"clean": "rm -rf dist node_modules/.cache",
|
|
38
|
-
"test:coverage": "jest --coverage",
|
|
39
|
-
"lint": "eslint .",
|
|
40
|
-
"lint:fix": "eslint . --fix"
|
|
43
|
+
"cross-env": "^10.1.0",
|
|
44
|
+
"ts-node": "^10.0.0",
|
|
45
|
+
"tsx": "^4.6.0",
|
|
46
|
+
"typescript": "^5.3.8"
|
|
41
47
|
}
|
|
42
|
-
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Warnings:
|
|
3
|
+
|
|
4
|
+
- You are about to drop the `Post` table. If the table is not empty, all the data it contains will be lost.
|
|
5
|
+
- You are about to drop the `User` table. If the table is not empty, all the data it contains will be lost.
|
|
6
|
+
|
|
7
|
+
*/
|
|
8
|
+
-- DropTable
|
|
9
|
+
PRAGMA foreign_keys=off;
|
|
10
|
+
DROP TABLE "Post";
|
|
11
|
+
PRAGMA foreign_keys=on;
|
|
12
|
+
|
|
13
|
+
-- DropTable
|
|
14
|
+
PRAGMA foreign_keys=off;
|
|
15
|
+
DROP TABLE "User";
|
|
16
|
+
PRAGMA foreign_keys=on;
|
package/prisma/schema.prisma
CHANGED
package/src/cli.ts
CHANGED
|
@@ -13,14 +13,21 @@ import * as fs from 'fs';
|
|
|
13
13
|
import * as path from 'path';
|
|
14
14
|
import { startServer } from './index'; // Assume index.ts exports this function
|
|
15
15
|
|
|
16
|
+
import { loadConfig } from './config-loader';
|
|
17
|
+
|
|
18
|
+
const appConfig = loadConfig();
|
|
19
|
+
|
|
16
20
|
// --- Argument Parsing ---
|
|
17
21
|
|
|
18
22
|
// 1. Get arguments excluding the node executable and script name
|
|
19
23
|
const args = process.argv.slice(2);
|
|
20
24
|
|
|
21
25
|
// Default settings
|
|
26
|
+
const DEFAULT_PORT = 4000;
|
|
22
27
|
let serve = false;
|
|
23
|
-
let rootPath = process.cwd(); // Default to the current working directory
|
|
28
|
+
let rootPath = path.resolve(appConfig.workspace.root_dir ?? process.cwd()); // Default to the current working directory
|
|
29
|
+
let port = appConfig.server.port ?? DEFAULT_PORT; //Default port
|
|
30
|
+
let host = appConfig.server.host ?? 'localhost'; //Default port
|
|
24
31
|
|
|
25
32
|
// Simple argument parsing loop
|
|
26
33
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -37,7 +44,21 @@ for (let i = 0; i < args.length; i++) {
|
|
|
37
44
|
console.error('Error: --root requires a path argument.');
|
|
38
45
|
process.exit(1);
|
|
39
46
|
}
|
|
40
|
-
} else if (arg === '
|
|
47
|
+
} else if (arg === '--port') {
|
|
48
|
+
// Look at the next argument for the port number
|
|
49
|
+
if (i + 1 < args.length) {
|
|
50
|
+
const portValue = parseInt(args[i + 1], 10);
|
|
51
|
+
if (isNaN(portValue) || portValue <= 0 || portValue > 65535) {
|
|
52
|
+
console.error('Error: --port requires a valid port number (1-65535).');
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
port = portValue;
|
|
56
|
+
i++; // Skip the next argument
|
|
57
|
+
} else {
|
|
58
|
+
console.error('Error: --port requires a number argument.');
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
} else if (arg === '-h' || arg === '--help') {
|
|
41
62
|
console.log(`
|
|
42
63
|
Monodog CLI - Monorepo Analysis Engine
|
|
43
64
|
|
|
@@ -59,10 +80,13 @@ Example:
|
|
|
59
80
|
// --- Execution Logic ---
|
|
60
81
|
|
|
61
82
|
if (serve) {
|
|
83
|
+
console.log(`\nInitializing Configurations...`);
|
|
84
|
+
createConfigFileIfMissing(rootPath ?? process.cwd());
|
|
85
|
+
|
|
62
86
|
console.log(`Starting Monodog API server...`);
|
|
63
87
|
console.log(`Analyzing monorepo at root: ${rootPath}`);
|
|
64
88
|
// Start the Express server and begin analysis
|
|
65
|
-
startServer(rootPath);
|
|
89
|
+
startServer(rootPath, port, host);
|
|
66
90
|
copyPackageToWorkspace(rootPath);
|
|
67
91
|
} else {
|
|
68
92
|
// Default mode: print usage or run a default report if no command is specified
|
|
@@ -151,3 +175,43 @@ function copyPackageToWorkspace(rootDir: string): void {
|
|
|
151
175
|
}
|
|
152
176
|
}
|
|
153
177
|
|
|
178
|
+
function createConfigFileIfMissing(rootPath: string): void {
|
|
179
|
+
// --- CONFIGURATION ---
|
|
180
|
+
const configFileName = 'monodog-conf.json';
|
|
181
|
+
const configFilePath = path.resolve(rootPath, configFileName);
|
|
182
|
+
|
|
183
|
+
// The default content for the configuration file
|
|
184
|
+
const defaultContent = {
|
|
185
|
+
"workspace": {
|
|
186
|
+
"root_dir": "./packages/backend"
|
|
187
|
+
},
|
|
188
|
+
"database": {
|
|
189
|
+
"path": "./monodog.db"
|
|
190
|
+
},
|
|
191
|
+
"server": {
|
|
192
|
+
"host": "0.0.0.0",
|
|
193
|
+
"port": 4000
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const contentString = JSON.stringify(defaultContent, null, 2);
|
|
198
|
+
// ---------------------
|
|
199
|
+
|
|
200
|
+
console.log(`\n[monodog] Checking for ${configFileName}...`);
|
|
201
|
+
|
|
202
|
+
if (fs.existsSync(configFilePath)) {
|
|
203
|
+
console.log(`[monodog] ${configFileName} already exists. Skipping creation.`);
|
|
204
|
+
} else {
|
|
205
|
+
try {
|
|
206
|
+
// Write the default content to the file
|
|
207
|
+
fs.writeFileSync(configFilePath, contentString, 'utf-8');
|
|
208
|
+
console.log(`[monodog] Successfully generated default ${configFileName} in the workspace root.`);
|
|
209
|
+
console.log('[monodog] Please review and update settings like "host" and "port".');
|
|
210
|
+
} catch (err: unknown) {
|
|
211
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
212
|
+
console.error(`[monodog Error] Failed to generate ${configFileName}:`, message);
|
|
213
|
+
process.exit(1);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
|
|
4
|
+
// Define a type/interface for your configuration structure
|
|
5
|
+
interface MonodogConfig {
|
|
6
|
+
workspace: {
|
|
7
|
+
root_dir: string;
|
|
8
|
+
};
|
|
9
|
+
database: {
|
|
10
|
+
type: 'postgres' | 'mysql' | 'sqlite';
|
|
11
|
+
host: string;
|
|
12
|
+
port: number;
|
|
13
|
+
user: string;
|
|
14
|
+
path: string; // Used for SQLite path or general data storage path
|
|
15
|
+
};
|
|
16
|
+
server: {
|
|
17
|
+
host: string;
|
|
18
|
+
port: number;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Global variable to hold the loaded config
|
|
23
|
+
let config: MonodogConfig | null = null;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Loads the monodog-conf.json file from the monorepo root.
|
|
27
|
+
* This should be called only once during application startup.
|
|
28
|
+
* @returns The application configuration object.
|
|
29
|
+
*/
|
|
30
|
+
export function loadConfig(): MonodogConfig {
|
|
31
|
+
if (config) {
|
|
32
|
+
return config; // Return cached config if already loaded
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 1. Determine the path to the config file
|
|
36
|
+
// We assume the backend package is running from the monorepo root (cwd is root)
|
|
37
|
+
// or that we can navigate up to the root from the current file's location.
|
|
38
|
+
const rootPath = path.resolve(__dirname, '../../../'); // Adjust based on your folder depth if needed
|
|
39
|
+
const configPath = path.resolve(rootPath, 'monodog-conf.json');
|
|
40
|
+
|
|
41
|
+
if (!fs.existsSync(configPath)) {
|
|
42
|
+
console.error(`ERROR: Configuration file not found at ${configPath}`);
|
|
43
|
+
// A missing config is a critical failure, so we exit
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
// 2. Read and parse the JSON file
|
|
49
|
+
const fileContent = fs.readFileSync(configPath, 'utf-8');
|
|
50
|
+
const parsedConfig = JSON.parse(fileContent) as MonodogConfig;
|
|
51
|
+
|
|
52
|
+
// 3. Optional: Add validation logic here (e.g., check if ports are numbers)
|
|
53
|
+
|
|
54
|
+
// Cache and return
|
|
55
|
+
config = parsedConfig;
|
|
56
|
+
process.stderr.write(`[Config] Loaded configuration from: ${configPath}`);
|
|
57
|
+
return config;
|
|
58
|
+
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error("ERROR: Failed to read or parse monodog-conf.json.");
|
|
61
|
+
console.error(error);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// --- Example Usage ---
|
|
67
|
+
|
|
68
|
+
// In your main application file (e.g., packages/backend/src/index.ts):
|
|
69
|
+
/*
|
|
70
|
+
|
|
71
|
+
import { loadConfig } from './config-loader';
|
|
72
|
+
|
|
73
|
+
// Load configuration on startup
|
|
74
|
+
const appConfig = loadConfig();
|
|
75
|
+
|
|
76
|
+
// Access the variables easily
|
|
77
|
+
const dbHost = appConfig.database.host;
|
|
78
|
+
const serverPort = appConfig.server.port;
|
|
79
|
+
const workspaceRoot = appConfig.workspace.root_dir;
|
|
80
|
+
|
|
81
|
+
console.log(`\nStarting server on port: ${serverPort}`);
|
|
82
|
+
console.log(`Database connecting to host: ${dbHost}`);
|
|
83
|
+
|
|
84
|
+
// Example server start logic
|
|
85
|
+
// app.listen(serverPort, appConfig.server.host, () => {
|
|
86
|
+
// console.log(`Server running at http://${appConfig.server.host}:${serverPort}`);
|
|
87
|
+
// });
|
|
88
|
+
*/
|
package/src/index.ts
CHANGED
|
@@ -40,11 +40,9 @@ export interface HealthMetric {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
const prisma = new PrismaClient();
|
|
43
|
-
const DEFAULT_PORT = 4000;
|
|
44
43
|
// The main function exported and called by the CLI
|
|
45
|
-
export function startServer(rootPath: string) {
|
|
44
|
+
export function startServer(rootPath: string, port: number|string, host: string): void {
|
|
46
45
|
const app = express();
|
|
47
|
-
const port = process.env.PORT ? parseInt(process.env.PORT) : DEFAULT_PORT;
|
|
48
46
|
|
|
49
47
|
// --- Middleware ---
|
|
50
48
|
|
|
@@ -55,18 +53,6 @@ const app = express();
|
|
|
55
53
|
});
|
|
56
54
|
app.use(cors());
|
|
57
55
|
app.use(json());
|
|
58
|
-
// // 2. CORS (Critical for the frontend app to talk to this local server)
|
|
59
|
-
// // In a production setup, this would be highly restricted, but for local monorepo tools,
|
|
60
|
-
// // we often allow all origins or restrict to a known local hostname/port.
|
|
61
|
-
// app.use((_req: Request, res: Response, next: NextFunction) => {
|
|
62
|
-
// res.setHeader('Access-Control-Allow-Origin', '*'); // Adjust this in production
|
|
63
|
-
// res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
|
|
64
|
-
// res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
65
|
-
// next();
|
|
66
|
-
// });
|
|
67
|
-
|
|
68
|
-
// // 3. JSON body parser
|
|
69
|
-
// app.use(express.json());
|
|
70
56
|
|
|
71
57
|
// Health check
|
|
72
58
|
app.get('/api/health', (_, res) => {
|
|
@@ -1424,10 +1410,13 @@ app.use('*', (_, res) => {
|
|
|
1424
1410
|
});
|
|
1425
1411
|
});
|
|
1426
1412
|
|
|
1427
|
-
const PORT =
|
|
1413
|
+
const PORT = parseInt(port ? port.toString() : '4000');
|
|
1428
1414
|
|
|
1429
|
-
app.listen(PORT, () => {
|
|
1430
|
-
|
|
1415
|
+
app.listen(PORT, host ,async () => {
|
|
1416
|
+
const pcount = await prisma.package.count();
|
|
1417
|
+
console.log(`[Database] Total packages found: ${pcount}`);
|
|
1418
|
+
|
|
1419
|
+
console.log(`🚀 Backend server running on http://${host}:${PORT}`);
|
|
1431
1420
|
console.log(`📊 API endpoints available:`);
|
|
1432
1421
|
console.log(` - GET /api/health`);
|
|
1433
1422
|
console.log(` - GET /api/packages/refresh`);
|
|
@@ -1446,7 +1435,7 @@ app.listen(PORT, () => {
|
|
|
1446
1435
|
}).on('error', (err) => {
|
|
1447
1436
|
// Handle common errors like EADDRINUSE (port already in use)
|
|
1448
1437
|
if (err.message.includes('EADDRINUSE')) {
|
|
1449
|
-
console.error(`Error: Port ${port} is already in use. Please specify a different port via
|
|
1438
|
+
console.error(`Error: Port ${port} is already in use. Please specify a different port via configuration file.`);
|
|
1450
1439
|
process.exit(1);
|
|
1451
1440
|
} else {
|
|
1452
1441
|
console.error('Server failed to start:', err);
|
package/LICENCE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2024 Lakin Mohapatra
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|