@bigtyphoon/melo 1.7.6 → 1.8.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.
@@ -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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