express-genix 4.4.1 → 4.5.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/index.js +10 -46
- package/lib/features.js +0 -6
- package/lib/generator.js +1 -29
- package/package.json +1 -1
- package/templates/core/env.ejs +1 -14
- package/templates/core/env.example.ejs +1 -14
- package/templates/core/package.json.ejs +2 -8
- package/templates/routes/index.js.ejs +0 -2
package/index.js
CHANGED
|
@@ -15,14 +15,14 @@ const prompt = inquirer.createPromptModule();
|
|
|
15
15
|
const generateSecret = (length = 64) => crypto.randomBytes(length).toString('hex');
|
|
16
16
|
|
|
17
17
|
const CODA_EXTENSION_ID = 'express-genix.coda-ai';
|
|
18
|
-
const CODA_VSIX_URL = 'https://github.com/LambdaAI001/coda/releases/download/v0.
|
|
18
|
+
const CODA_VSIX_URL = 'https://github.com/LambdaAI001/coda/releases/download/v0.3.0/coda-ai-0.3.0.vsix';
|
|
19
19
|
|
|
20
20
|
async function promptCodaExtension() {
|
|
21
21
|
const inquirerPrompt = inquirer.createPromptModule();
|
|
22
22
|
console.log('');
|
|
23
|
-
console.log('🤖
|
|
24
|
-
console.log('
|
|
25
|
-
console.log(' directly from VS Code
|
|
23
|
+
console.log('🤖 The Coda VS Code extension is an AI coding assistant');
|
|
24
|
+
console.log(' that understands your project — ask questions, search code,');
|
|
25
|
+
console.log(' and get workspace-aware help directly from VS Code.');
|
|
26
26
|
console.log('');
|
|
27
27
|
|
|
28
28
|
const { installCoda } = await inquirerPrompt([
|
|
@@ -128,7 +128,6 @@ async function main() {
|
|
|
128
128
|
{ name: 'Background Jobs (BullMQ)', value: 'backgroundJobs' },
|
|
129
129
|
{ name: 'GraphQL (Apollo Server)', value: 'graphql' },
|
|
130
130
|
{ name: 'MCP Server (AI Agent Tools)', value: 'mcp' },
|
|
131
|
-
{ name: 'AI / LLM Service (LangChain)', value: 'ai' },
|
|
132
131
|
],
|
|
133
132
|
when: (ans) => ans.db !== 'none',
|
|
134
133
|
},
|
|
@@ -149,7 +148,6 @@ async function main() {
|
|
|
149
148
|
{ name: 'API Versioning (/api/v1)', value: 'apiVersioning' },
|
|
150
149
|
{ name: 'GraphQL (Apollo Server)', value: 'graphql' },
|
|
151
150
|
{ name: 'MCP Server (AI Agent Tools)', value: 'mcp' },
|
|
152
|
-
{ name: 'AI / LLM Service (LangChain)', value: 'ai' },
|
|
153
151
|
],
|
|
154
152
|
when: (ans) => ans.db === 'none',
|
|
155
153
|
},
|
|
@@ -162,18 +160,6 @@ async function main() {
|
|
|
162
160
|
{ name: 'Pino (fast, low overhead)', value: 'pino' },
|
|
163
161
|
],
|
|
164
162
|
},
|
|
165
|
-
{
|
|
166
|
-
type: 'list',
|
|
167
|
-
name: 'aiProvider',
|
|
168
|
-
message: 'AI / LLM Provider:',
|
|
169
|
-
choices: [
|
|
170
|
-
{ name: 'OpenAI (GPT-4o, GPT-4o-mini)', value: 'openai' },
|
|
171
|
-
{ name: 'Anthropic (Claude)', value: 'anthropic' },
|
|
172
|
-
{ name: 'Google Gemini', value: 'gemini' },
|
|
173
|
-
{ name: 'Ollama (local, no API key needed)', value: 'ollama' },
|
|
174
|
-
],
|
|
175
|
-
when: (ans) => (ans.features || []).includes('ai'),
|
|
176
|
-
},
|
|
177
163
|
]);
|
|
178
164
|
|
|
179
165
|
const features = answers.features || [];
|
|
@@ -203,8 +189,6 @@ async function main() {
|
|
|
203
189
|
hasBackgroundJobs: features.includes('backgroundJobs'),
|
|
204
190
|
hasGraphQL: features.includes('graphql'),
|
|
205
191
|
hasMCP: features.includes('mcp'),
|
|
206
|
-
hasAI: features.includes('ai'),
|
|
207
|
-
aiProvider: answers.aiProvider || 'openai',
|
|
208
192
|
jwtSecret: generateSecret(),
|
|
209
193
|
jwtRefreshSecret: generateSecret(),
|
|
210
194
|
};
|
|
@@ -247,7 +231,7 @@ async function main() {
|
|
|
247
231
|
To get started:
|
|
248
232
|
cd ${config.projectName}
|
|
249
233
|
npm run dev
|
|
250
|
-
${config.hasSwagger ? `\nAPI Documentation: http://localhost:3000/api-docs` : ''}${config.hasGraphQL ? `\nGraphQL Playground: http://localhost:3000/graphql` : ''}${config.hasMetrics ? `\nPrometheus Metrics: http://localhost:3000/metrics` : ''}${config.hasMCP ? `\nMCP Server: npm run mcp:start` : ''}
|
|
234
|
+
${config.hasSwagger ? `\nAPI Documentation: http://localhost:3000/api-docs` : ''}${config.hasGraphQL ? `\nGraphQL Playground: http://localhost:3000/graphql` : ''}${config.hasMetrics ? `\nPrometheus Metrics: http://localhost:3000/metrics` : ''}${config.hasMCP ? `\nMCP Server: npm run mcp:start` : ''}
|
|
251
235
|
Health Check: http://localhost:3000/health
|
|
252
236
|
|
|
253
237
|
Available scripts:
|
|
@@ -263,17 +247,11 @@ Configuration:
|
|
|
263
247
|
Database: ${config.isNoDatabase ? 'None' : config.db}
|
|
264
248
|
Authentication: ${config.hasAuth ? 'JWT with refresh tokens' : 'None'}
|
|
265
249
|
Logger: ${config.logger}
|
|
266
|
-
Features: ${features.join(', ') || 'base'}
|
|
250
|
+
Features: ${features.join(', ') || 'base'}
|
|
267
251
|
`);
|
|
268
252
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
console.log(`\x1b[33mâš Don't forget to set your API key in .env:\x1b[0m`);
|
|
272
|
-
console.log(` ${keyMap[config.aiProvider]}=your-key-here\n`);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// Prompt to install Coda VS Code extension for AI/MCP projects
|
|
276
|
-
if (config.hasAI || config.hasMCP) {
|
|
253
|
+
// Prompt to install Coda VS Code extension
|
|
254
|
+
if (config.hasMCP) {
|
|
277
255
|
await promptCodaExtension();
|
|
278
256
|
}
|
|
279
257
|
|
|
@@ -336,18 +314,6 @@ Configuration:
|
|
|
336
314
|
message: 'Generate project with this configuration?',
|
|
337
315
|
default: true,
|
|
338
316
|
},
|
|
339
|
-
{
|
|
340
|
-
type: 'list',
|
|
341
|
-
name: 'aiProvider',
|
|
342
|
-
message: 'AI / LLM Provider:',
|
|
343
|
-
choices: [
|
|
344
|
-
{ name: 'OpenAI (GPT-4o, GPT-4o-mini)', value: 'openai' },
|
|
345
|
-
{ name: 'Anthropic (Claude)', value: 'anthropic' },
|
|
346
|
-
{ name: 'Google Gemini', value: 'gemini' },
|
|
347
|
-
{ name: 'Ollama (local, no API key needed)', value: 'ollama' },
|
|
348
|
-
],
|
|
349
|
-
when: (ans) => ans.confirmed && (aiConfig.features || []).includes('ai'),
|
|
350
|
-
},
|
|
351
317
|
]);
|
|
352
318
|
|
|
353
319
|
if (!aiFollowUp.confirmed) {
|
|
@@ -383,8 +349,6 @@ Configuration:
|
|
|
383
349
|
hasBackgroundJobs: features.includes('backgroundJobs'),
|
|
384
350
|
hasGraphQL: features.includes('graphql'),
|
|
385
351
|
hasMCP: features.includes('mcp'),
|
|
386
|
-
hasAI: features.includes('ai'),
|
|
387
|
-
aiProvider: aiConfig.aiProvider || 'openai',
|
|
388
352
|
jwtSecret: generateSecret(),
|
|
389
353
|
jwtRefreshSecret: generateSecret(),
|
|
390
354
|
};
|
|
@@ -422,8 +386,8 @@ Configuration:
|
|
|
422
386
|
console.log(` cd ${config.projectName}`);
|
|
423
387
|
console.log(' npm run dev\n');
|
|
424
388
|
|
|
425
|
-
// Prompt to install Coda VS Code extension
|
|
426
|
-
if (config.
|
|
389
|
+
// Prompt to install Coda VS Code extension
|
|
390
|
+
if (config.hasMCP) {
|
|
427
391
|
await promptCodaExtension();
|
|
428
392
|
}
|
|
429
393
|
|
package/lib/features.js
CHANGED
|
@@ -241,12 +241,6 @@ const inferConfig = (projectDir, pkg) => {
|
|
|
241
241
|
hasBackgroundJobs: !!(pkg.dependencies && pkg.dependencies.bullmq),
|
|
242
242
|
hasGraphQL: !!(pkg.dependencies && pkg.dependencies['@apollo/server']),
|
|
243
243
|
hasMCP: !!(pkg.dependencies && pkg.dependencies['@modelcontextprotocol/sdk']),
|
|
244
|
-
hasAI: !!(pkg.dependencies && pkg.dependencies['@langchain/core']),
|
|
245
|
-
aiProvider: pkg.dependencies && pkg.dependencies['@langchain/openai'] ? 'openai'
|
|
246
|
-
: pkg.dependencies && pkg.dependencies['@langchain/anthropic'] ? 'anthropic'
|
|
247
|
-
: pkg.dependencies && pkg.dependencies['@langchain/google-genai'] ? 'gemini'
|
|
248
|
-
: pkg.dependencies && pkg.dependencies['@langchain/ollama'] ? 'ollama'
|
|
249
|
-
: 'openai',
|
|
250
244
|
logger: pkg.dependencies && pkg.dependencies.pino ? 'pino' : 'winston',
|
|
251
245
|
};
|
|
252
246
|
};
|
package/lib/generator.js
CHANGED
|
@@ -65,10 +65,6 @@ const createDirectoryStructure = (projectDir, config) => {
|
|
|
65
65
|
dirs.push('src/mcp');
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
if (config.hasAI) {
|
|
69
|
-
dirs.push('src/agents');
|
|
70
|
-
}
|
|
71
|
-
|
|
72
68
|
fs.mkdirSync(projectDir);
|
|
73
69
|
dirs.forEach((dir) => {
|
|
74
70
|
fs.mkdirSync(path.join(projectDir, dir), { recursive: true });
|
|
@@ -152,10 +148,6 @@ const generateFiles = async (config, projectDir) => {
|
|
|
152
148
|
configFiles.push({ template: 'config/queue.js.ejs', output: `src/config/queue.${ext}` });
|
|
153
149
|
}
|
|
154
150
|
|
|
155
|
-
if (config.hasAI) {
|
|
156
|
-
configFiles.push({ template: 'config/ai.js.ejs', output: `src/config/ai.${ext}` });
|
|
157
|
-
}
|
|
158
|
-
|
|
159
151
|
// Route files
|
|
160
152
|
const routeFiles = [
|
|
161
153
|
{ template: 'routes/index.js.ejs', output: `src/routes/index.${ext}` },
|
|
@@ -214,18 +206,6 @@ const generateFiles = async (config, projectDir) => {
|
|
|
214
206
|
);
|
|
215
207
|
}
|
|
216
208
|
|
|
217
|
-
if (config.hasAI) {
|
|
218
|
-
serviceFiles.push(
|
|
219
|
-
{ template: 'services/aiService.js.ejs', output: `src/services/aiService.${ext}` }
|
|
220
|
-
);
|
|
221
|
-
controllerFiles.push(
|
|
222
|
-
{ template: 'controllers/aiController.js.ejs', output: `src/controllers/aiController.${ext}` }
|
|
223
|
-
);
|
|
224
|
-
routeFiles.push(
|
|
225
|
-
{ template: 'routes/aiRoutes.js.ejs', output: `src/routes/aiRoutes.${ext}` }
|
|
226
|
-
);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
209
|
if (config.hasFileUpload) {
|
|
230
210
|
routeFiles.push(
|
|
231
211
|
{ template: 'routes/uploadRoutes.js.ejs', output: `src/routes/uploadRoutes.${ext}` }
|
|
@@ -258,14 +238,7 @@ const generateFiles = async (config, projectDir) => {
|
|
|
258
238
|
);
|
|
259
239
|
}
|
|
260
240
|
|
|
261
|
-
// Agent files
|
|
262
|
-
const agentFiles = [];
|
|
263
|
-
|
|
264
|
-
if (config.hasAI) {
|
|
265
|
-
agentFiles.push(
|
|
266
|
-
{ template: 'agents/graph.js.ejs', output: `src/agents/graph.${ext}` }
|
|
267
|
-
);
|
|
268
|
-
}
|
|
241
|
+
// Agent files — removed (AI endpoints no longer generated)
|
|
269
242
|
|
|
270
243
|
// Middleware files
|
|
271
244
|
const middlewareFiles = [
|
|
@@ -358,7 +331,6 @@ const generateFiles = async (config, projectDir) => {
|
|
|
358
331
|
...testFiles,
|
|
359
332
|
...graphqlFiles,
|
|
360
333
|
...mcpFiles,
|
|
361
|
-
...agentFiles,
|
|
362
334
|
];
|
|
363
335
|
|
|
364
336
|
// GraphQL files (legacy — now handled above)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "express-genix",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.0",
|
|
4
4
|
"description": "Production-grade CLI to generate Express apps with JWT, RBAC, GraphQL, TypeScript, Prisma, MongoDB, PostgreSQL, file uploads, email, background jobs, and more",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
package/templates/core/env.ejs
CHANGED
|
@@ -31,20 +31,7 @@ UPLOAD_MAX_SIZE=5242880
|
|
|
31
31
|
<% } %><% if (hasMCP) { %>
|
|
32
32
|
# MCP Server
|
|
33
33
|
MCP_SERVER_NAME=<%= projectName %>
|
|
34
|
-
<% } %><% if (
|
|
35
|
-
# AI Service (LangChain)
|
|
36
|
-
AI_PROVIDER=<%= aiProvider %>
|
|
37
|
-
<% if (aiProvider === 'openai') { %>AI_MODEL=gpt-4o-mini
|
|
38
|
-
<% } else if (aiProvider === 'anthropic') { %>AI_MODEL=claude-sonnet-4-20250514
|
|
39
|
-
<% } else if (aiProvider === 'gemini') { %>AI_MODEL=gemini-2.0-flash
|
|
40
|
-
<% } else if (aiProvider === 'ollama') { %>AI_MODEL=llama3
|
|
41
|
-
<% } %>AI_TEMPERATURE=0.7
|
|
42
|
-
AI_MAX_TOKENS=2048
|
|
43
|
-
<% if (aiProvider === 'openai') { %>OPENAI_API_KEY=
|
|
44
|
-
<% } else if (aiProvider === 'anthropic') { %>ANTHROPIC_API_KEY=
|
|
45
|
-
<% } else if (aiProvider === 'gemini') { %>GOOGLE_API_KEY=
|
|
46
|
-
<% } else if (aiProvider === 'ollama') { %>OLLAMA_BASE_URL=http://localhost:11434
|
|
47
|
-
<% } %><% } %><% if (db === 'mongodb') { %>
|
|
34
|
+
<% } %><% if (db === 'mongodb') { %>
|
|
48
35
|
# Database
|
|
49
36
|
MONGO_URI=mongodb://localhost:27017/<%= projectName %>
|
|
50
37
|
<% } %><% if (db === 'postgresql' || isPrisma) { %>
|
|
@@ -31,20 +31,7 @@ UPLOAD_MAX_SIZE=5242880
|
|
|
31
31
|
<% } %><% if (hasMCP) { %>
|
|
32
32
|
# MCP Server
|
|
33
33
|
MCP_SERVER_NAME=<%= projectName %>
|
|
34
|
-
<% } %><% if (
|
|
35
|
-
# AI Service (LangChain)
|
|
36
|
-
AI_PROVIDER=<%= aiProvider %>
|
|
37
|
-
<% if (aiProvider === 'openai') { %>AI_MODEL=gpt-4o-mini
|
|
38
|
-
<% } else if (aiProvider === 'anthropic') { %>AI_MODEL=claude-sonnet-4-20250514
|
|
39
|
-
<% } else if (aiProvider === 'gemini') { %>AI_MODEL=gemini-2.0-flash
|
|
40
|
-
<% } else if (aiProvider === 'ollama') { %>AI_MODEL=llama3
|
|
41
|
-
<% } %>AI_TEMPERATURE=0.7
|
|
42
|
-
AI_MAX_TOKENS=2048
|
|
43
|
-
<% if (aiProvider === 'openai') { %>OPENAI_API_KEY=
|
|
44
|
-
<% } else if (aiProvider === 'anthropic') { %>ANTHROPIC_API_KEY=
|
|
45
|
-
<% } else if (aiProvider === 'gemini') { %>GOOGLE_API_KEY=
|
|
46
|
-
<% } else if (aiProvider === 'ollama') { %>OLLAMA_BASE_URL=http://localhost:11434
|
|
47
|
-
<% } %><% } %><% if (db === 'mongodb') { %>
|
|
34
|
+
<% } %><% if (db === 'mongodb') { %>
|
|
48
35
|
# Database
|
|
49
36
|
MONGO_URI=mongodb://localhost:27017/<%= projectName %>
|
|
50
37
|
<% } %><% if (db === 'postgresql' || isPrisma) { %>
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"swagger-ui-express": "^5.0.1"<% } %><% if (hasAuth) { %>,
|
|
33
33
|
"jsonwebtoken": "^9.0.2",
|
|
34
34
|
"bcryptjs": "^2.4.3",
|
|
35
|
-
"validator": "^13.12.0"<% } %><% if (hasAuth || hasMCP
|
|
35
|
+
"validator": "^13.12.0"<% } %><% if (hasAuth || hasMCP) { %>,
|
|
36
36
|
"zod": "^3.23.0"<% } %><% if (db === 'mongodb') { %>,
|
|
37
37
|
"mongoose": "^8.8.0"<% } %><% if (db === 'postgresql') { %>,
|
|
38
38
|
"pg": "^8.13.0",
|
|
@@ -48,13 +48,7 @@
|
|
|
48
48
|
"graphql": "^16.9.0",
|
|
49
49
|
"graphql-tag": "^2.12.6"<% } %><% if (hasBackgroundJobs) { %>,
|
|
50
50
|
"bullmq": "^5.12.0"<% } %><% if (hasMCP) { %>,
|
|
51
|
-
"@modelcontextprotocol/sdk": "^1.12.0"<% } %><% if (
|
|
52
|
-
"@langchain/core": "^0.3.0",
|
|
53
|
-
<% if (aiProvider === 'openai') { %> "@langchain/openai": "^0.5.0",
|
|
54
|
-
<% } else if (aiProvider === 'anthropic') { %> "@langchain/anthropic": "^0.3.0",
|
|
55
|
-
<% } else if (aiProvider === 'gemini') { %> "@langchain/google-genai": "^0.2.0",
|
|
56
|
-
<% } else if (aiProvider === 'ollama') { %> "@langchain/ollama": "^0.1.0",
|
|
57
|
-
<% } %> "@langchain/langgraph": "^0.2.0"<% } %><% if (logger === 'winston') { %>,
|
|
51
|
+
"@modelcontextprotocol/sdk": "^1.12.0"<% } %><% if (logger === 'winston') { %>,
|
|
58
52
|
"winston": "^3.15.0"<% } %><% if (logger === 'pino') { %>,
|
|
59
53
|
"pino": "^9.5.0",
|
|
60
54
|
"pino-pretty": "^13.0.0"<% } %>
|
|
@@ -5,7 +5,6 @@ const adminRoutes = require('./adminRoutes');
|
|
|
5
5
|
<% } else { %>const exampleRoutes = require('./exampleRoutes');
|
|
6
6
|
<% } %><% if (hasFileUpload) { %>const uploadRoutes = require('./uploadRoutes');
|
|
7
7
|
<% } %><% if (hasBackgroundJobs) { %>const jobRoutes = require('./jobRoutes');
|
|
8
|
-
<% } %><% if (hasAI) { %>const aiRoutes = require('./aiRoutes');
|
|
9
8
|
<% } %>
|
|
10
9
|
|
|
11
10
|
const router = express.Router();
|
|
@@ -16,7 +15,6 @@ router.use('/admin', adminRoutes);
|
|
|
16
15
|
<% } else { %>router.use('/examples', exampleRoutes);
|
|
17
16
|
<% } %><% if (hasFileUpload) { %>router.use('/uploads', uploadRoutes);
|
|
18
17
|
<% } %><% if (hasBackgroundJobs) { %>router.use('/jobs', jobRoutes);
|
|
19
|
-
<% } %><% if (hasAI) { %>router.use('/ai', aiRoutes);
|
|
20
18
|
<% } %>
|
|
21
19
|
|
|
22
20
|
/**
|