@bigtyphoon/melo 1.7.6 → 1.8.1
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/bin/commands/add-server.ts +288 -0
- package/bin/commands/doctor.ts +514 -0
- package/bin/utils/constants.ts +4 -0
- package/dist/bin/commands/add-server.js +248 -0
- package/dist/bin/commands/doctor.js +439 -0
- package/dist/bin/utils/constants.js +5 -2
- package/dist/lib/melo.js +1 -1
- package/lib/melo.ts +0 -1
- package/package.json +2 -2
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* Add a new server type to the project
|
|
5
|
+
* Creates templates and updates all necessary configuration files
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
const fs = require("fs");
|
|
9
|
+
const path = require("path");
|
|
10
|
+
const constants_1 = require("../utils/constants");
|
|
11
|
+
function default_1(program) {
|
|
12
|
+
program.command('add-server <server-name>')
|
|
13
|
+
.description('Add a new server type with templates and configurations')
|
|
14
|
+
.option('-f, --frontend', 'mark as frontend server', false)
|
|
15
|
+
.option('-p, --port <port>', 'default port number', '3050')
|
|
16
|
+
.option('-c, --client-port <port>', 'client port (for frontend)', '3010')
|
|
17
|
+
.action(function (serverName, opts) {
|
|
18
|
+
addServerType(serverName, opts);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
exports.default = default_1;
|
|
22
|
+
function addServerType(serverName, opts) {
|
|
23
|
+
const cwd = process.cwd();
|
|
24
|
+
// Check if we're in a valid melo project
|
|
25
|
+
if (!isMeloProject(cwd)) {
|
|
26
|
+
console.error('Error: Not a valid melo project directory.');
|
|
27
|
+
console.info('Please run this command in a melo project root directory.');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
// Check if server type already exists
|
|
31
|
+
if (serverTypeExists(cwd, serverName)) {
|
|
32
|
+
console.warn(`Server type '${serverName}' already exists.`);
|
|
33
|
+
console.info(constants_1.ADD_SERVER_TYPE_EXISTS);
|
|
34
|
+
// Ask if user wants to overwrite or update
|
|
35
|
+
const readline = require('readline');
|
|
36
|
+
const rl = readline.createInterface({
|
|
37
|
+
input: process.stdin,
|
|
38
|
+
output: process.stdout
|
|
39
|
+
});
|
|
40
|
+
rl.question(`Do you want to update existing '${serverName}' configuration? (y/N): `, (answer) => {
|
|
41
|
+
if (answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
|
|
42
|
+
updateServerType(cwd, serverName, opts);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
console.info('Operation cancelled.');
|
|
46
|
+
}
|
|
47
|
+
rl.close();
|
|
48
|
+
});
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
// Create new server type
|
|
52
|
+
createServerType(cwd, serverName, opts);
|
|
53
|
+
console.info(constants_1.ADD_SERVER_TYPE_INFO.replace('${serverName}', serverName));
|
|
54
|
+
}
|
|
55
|
+
function isMeloProject(cwd) {
|
|
56
|
+
// Check for key files/directories that indicate a melo project
|
|
57
|
+
const requiredPaths = [
|
|
58
|
+
'app.ts',
|
|
59
|
+
'config',
|
|
60
|
+
'app/servers'
|
|
61
|
+
];
|
|
62
|
+
return requiredPaths.every(p => fs.existsSync(path.join(cwd, p)));
|
|
63
|
+
}
|
|
64
|
+
function serverTypeExists(cwd, serverName) {
|
|
65
|
+
const serverDir = path.join(cwd, 'app', 'servers', serverName);
|
|
66
|
+
return fs.existsSync(serverDir);
|
|
67
|
+
}
|
|
68
|
+
function createServerType(cwd, serverName, opts) {
|
|
69
|
+
// 1. Create directory structure
|
|
70
|
+
const serverDir = path.join(cwd, 'app', 'servers', serverName);
|
|
71
|
+
const handlerDir = path.join(serverDir, 'handler');
|
|
72
|
+
const remoteDir = path.join(serverDir, 'remote');
|
|
73
|
+
fs.mkdirSync(handlerDir, { recursive: true });
|
|
74
|
+
fs.mkdirSync(remoteDir, { recursive: true });
|
|
75
|
+
// 2. Create handler template
|
|
76
|
+
createHandlerTemplate(handlerDir, serverName);
|
|
77
|
+
// 3. Create remote template
|
|
78
|
+
createRemoteTemplate(remoteDir, serverName);
|
|
79
|
+
// 4. Update adminServer.json
|
|
80
|
+
updateAdminServerJson(cwd, serverName);
|
|
81
|
+
// 5. Update servers.json
|
|
82
|
+
updateServersJson(cwd, serverName, opts);
|
|
83
|
+
// 6. Update app.ts (add configuration block if it doesn't exist)
|
|
84
|
+
updateAppTs(cwd, serverName, opts);
|
|
85
|
+
}
|
|
86
|
+
function updateServerType(cwd, serverName, opts) {
|
|
87
|
+
// Only update configuration files, don't overwrite handler/remote files
|
|
88
|
+
updateServersJson(cwd, serverName, opts);
|
|
89
|
+
updateAppTs(cwd, serverName, opts);
|
|
90
|
+
console.info(`Updated '${serverName}' configuration.`);
|
|
91
|
+
}
|
|
92
|
+
function createHandlerTemplate(handlerDir, serverName) {
|
|
93
|
+
const content = `import { Application, BackendSession, FrontendSession } from '@bigtyphoon/melo';
|
|
94
|
+
|
|
95
|
+
export default function (app: Application) {
|
|
96
|
+
return new Handler(app);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export class Handler {
|
|
100
|
+
constructor(private app: Application) {
|
|
101
|
+
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Example handler method
|
|
106
|
+
*
|
|
107
|
+
* @param {Object} msg request message
|
|
108
|
+
* @param {Object} session current session object
|
|
109
|
+
*/
|
|
110
|
+
async example(msg: any, session: BackendSession | FrontendSession) {
|
|
111
|
+
return { code: 200, msg: '${serverName} handler is working.' };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
`;
|
|
115
|
+
fs.writeFileSync(path.join(handlerDir, `${serverName}Handler.ts`), content);
|
|
116
|
+
}
|
|
117
|
+
function createRemoteTemplate(remoteDir, serverName) {
|
|
118
|
+
const content = `import { Application, BackendSession, RemoterClass } from '@bigtyphoon/melo';
|
|
119
|
+
|
|
120
|
+
export default function (app: Application) {
|
|
121
|
+
return new Remoter(app);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export class Remoter implements RemoterClass {
|
|
125
|
+
constructor(private app: Application) {
|
|
126
|
+
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Example remote method
|
|
131
|
+
*
|
|
132
|
+
* @param {Object} msg request message
|
|
133
|
+
* @param {Object} session current session object
|
|
134
|
+
*/
|
|
135
|
+
async example(msg: any, session: BackendSession): Promise<any> {
|
|
136
|
+
return { code: 200, msg: '${serverName} remote is working.' };
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
`;
|
|
140
|
+
fs.writeFileSync(path.join(remoteDir, `${serverName}Remote.ts`), content);
|
|
141
|
+
}
|
|
142
|
+
function updateAdminServerJson(cwd, serverName) {
|
|
143
|
+
const adminServerPath = path.join(cwd, 'config', 'adminServer.json');
|
|
144
|
+
let adminServers = [];
|
|
145
|
+
if (fs.existsSync(adminServerPath)) {
|
|
146
|
+
try {
|
|
147
|
+
adminServers = JSON.parse(fs.readFileSync(adminServerPath, 'utf8'));
|
|
148
|
+
}
|
|
149
|
+
catch (e) {
|
|
150
|
+
adminServers = [];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Check if server type already exists
|
|
154
|
+
const exists = adminServers.some(s => s.type === serverName);
|
|
155
|
+
if (!exists) {
|
|
156
|
+
adminServers.push({
|
|
157
|
+
type: serverName,
|
|
158
|
+
token: generateToken()
|
|
159
|
+
});
|
|
160
|
+
fs.writeFileSync(adminServerPath, JSON.stringify(adminServers, null, 2));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function updateServersJson(cwd, serverName, opts) {
|
|
164
|
+
var _a, _b, _c, _d;
|
|
165
|
+
const serversPath = path.join(cwd, 'config', 'servers.json');
|
|
166
|
+
let servers = {};
|
|
167
|
+
if (fs.existsSync(serversPath)) {
|
|
168
|
+
try {
|
|
169
|
+
servers = JSON.parse(fs.readFileSync(serversPath, 'utf8'));
|
|
170
|
+
}
|
|
171
|
+
catch (e) {
|
|
172
|
+
servers = {};
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Ensure development and production exist
|
|
176
|
+
if (!servers.development)
|
|
177
|
+
servers.development = {};
|
|
178
|
+
if (!servers.production)
|
|
179
|
+
servers.production = {};
|
|
180
|
+
const port = parseInt(((_b = (_a = opts.args) === null || _a === void 0 ? void 0 : _a.find(a => a.startsWith('--port'))) === null || _b === void 0 ? void 0 : _b.split('=')[1]) || '3050');
|
|
181
|
+
const clientPort = parseInt(((_d = (_c = opts.args) === null || _c === void 0 ? void 0 : _c.find(a => a.startsWith('--client-port'))) === null || _d === void 0 ? void 0 : _d.split('=')[1]) || '3010');
|
|
182
|
+
const serverConfig = {
|
|
183
|
+
id: `${serverName}-server-1`,
|
|
184
|
+
host: '127.0.0.1',
|
|
185
|
+
port: port,
|
|
186
|
+
frontend: opts.frontend || false,
|
|
187
|
+
args: ' --inspect=10003'
|
|
188
|
+
};
|
|
189
|
+
if (opts.frontend) {
|
|
190
|
+
serverConfig.clientHost = '127.0.0.1';
|
|
191
|
+
serverConfig.clientPort = clientPort;
|
|
192
|
+
}
|
|
193
|
+
// Add to both environments
|
|
194
|
+
servers.development[serverName] = [serverConfig];
|
|
195
|
+
// Production uses slightly different inspect port
|
|
196
|
+
const prodConfig = Object.assign({}, serverConfig);
|
|
197
|
+
prodConfig.args = ' --inspect=10004';
|
|
198
|
+
servers.production[serverName] = [prodConfig];
|
|
199
|
+
fs.writeFileSync(serversPath, JSON.stringify(servers, null, 2));
|
|
200
|
+
}
|
|
201
|
+
function updateAppTs(cwd, serverName, opts) {
|
|
202
|
+
const appTsPath = path.join(cwd, 'app.ts');
|
|
203
|
+
if (!fs.existsSync(appTsPath)) {
|
|
204
|
+
console.warn('Warning: app.ts not found, skipping app.ts update.');
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
let content = fs.readFileSync(appTsPath, 'utf8');
|
|
208
|
+
// Check if configuration block already exists
|
|
209
|
+
const configPattern = new RegExp(`app\\.configure\\(['"].*['"],\\s*['"]${serverName}['"]`);
|
|
210
|
+
if (configPattern.test(content)) {
|
|
211
|
+
console.info(`Configuration for '${serverName}' already exists in app.ts`);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
// Find the last app.configure block and add after it
|
|
215
|
+
const configurePattern = /app\.configure\(['"].*['"],\s*['"].*['"],\s*function\s*\(\)\s*\{[\s\S]*?\}\);/g;
|
|
216
|
+
const matches = content.match(configurePattern);
|
|
217
|
+
let insertPosition = content.length;
|
|
218
|
+
if (matches && matches.length > 0) {
|
|
219
|
+
const lastMatch = matches[matches.length - 1];
|
|
220
|
+
insertPosition = content.lastIndexOf(lastMatch) + lastMatch.length;
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
// Find position before // start app comment
|
|
224
|
+
const startAppMatch = content.match(/\/\/\s*start app/);
|
|
225
|
+
if (startAppMatch) {
|
|
226
|
+
insertPosition = content.indexOf(startAppMatch[0]);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const newConfig = `
|
|
230
|
+
|
|
231
|
+
// ${serverName} server configuration
|
|
232
|
+
app.configure('production|development', '${serverName}', function () {
|
|
233
|
+
// Add ${serverName} specific configuration here
|
|
234
|
+
// Example: app.set('${serverName}Config', { /* config */ });
|
|
235
|
+
});
|
|
236
|
+
`;
|
|
237
|
+
content = content.slice(0, insertPosition) + newConfig + content.slice(insertPosition);
|
|
238
|
+
fs.writeFileSync(appTsPath, content);
|
|
239
|
+
}
|
|
240
|
+
function generateToken() {
|
|
241
|
+
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
|
242
|
+
let token = '';
|
|
243
|
+
for (let i = 0; i < 40; i++) {
|
|
244
|
+
token += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
245
|
+
}
|
|
246
|
+
return token;
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWRkLXNlcnZlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2Jpbi9jb21tYW5kcy9hZGQtc2VydmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBRUE7OztHQUdHOztBQUVILHlCQUF5QjtBQUN6Qiw2QkFBNkI7QUFFN0Isa0RBQWlIO0FBU2pILG1CQUF5QixPQUFnQjtJQUNyQyxPQUFPLENBQUMsT0FBTyxDQUFDLDBCQUEwQixDQUFDO1NBQ3RDLFdBQVcsQ0FBQyx5REFBeUQsQ0FBQztTQUN0RSxNQUFNLENBQUMsZ0JBQWdCLEVBQUUseUJBQXlCLEVBQUUsS0FBSyxDQUFDO1NBQzFELE1BQU0sQ0FBQyxtQkFBbUIsRUFBRSxxQkFBcUIsRUFBRSxNQUFNLENBQUM7U0FDMUQsTUFBTSxDQUFDLDBCQUEwQixFQUFFLDRCQUE0QixFQUFFLE1BQU0sQ0FBQztTQUN4RSxNQUFNLENBQUMsVUFBVSxVQUFrQixFQUFFLElBQW1CO1FBQ3JELGFBQWEsQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDcEMsQ0FBQyxDQUFDLENBQUM7QUFDWCxDQUFDO0FBVEQsNEJBU0M7QUFFRCxTQUFTLGFBQWEsQ0FBQyxVQUFrQixFQUFFLElBQW1CO0lBQzFELE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUUxQix5Q0FBeUM7SUFDekMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsRUFBRTtRQUNyQixPQUFPLENBQUMsS0FBSyxDQUFDLDRDQUE0QyxDQUFDLENBQUM7UUFDNUQsT0FBTyxDQUFDLElBQUksQ0FBQywyREFBMkQsQ0FBQyxDQUFDO1FBQzFFLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7S0FDbkI7SUFFRCxzQ0FBc0M7SUFDdEMsSUFBSSxnQkFBZ0IsQ0FBQyxHQUFHLEVBQUUsVUFBVSxDQUFDLEVBQUU7UUFDbkMsT0FBTyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsVUFB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
|