projects-init-cli 1.1.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,427 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateExpress = generateExpress;
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const path_1 = __importDefault(require("path"));
9
+ async function generateExpress(backendPath, config) {
10
+ const dependencies = {
11
+ express: '^4.21.1',
12
+ cors: '^2.8.5',
13
+ dotenv: '^16.4.5'
14
+ };
15
+ const devDependencies = {
16
+ '@types/express': '^5.0.0',
17
+ '@types/cors': '^2.8.17',
18
+ '@types/node': '^22.7.5',
19
+ typescript: '^5.6.3',
20
+ 'ts-node': '^10.9.2',
21
+ nodemon: '^3.1.7',
22
+ 'vitest': '^2.1.3',
23
+ '@vitest/ui': '^2.1.3',
24
+ 'supertest': '^7.0.0',
25
+ '@types/supertest': '^6.0.2',
26
+ '@vitest/coverage-v8': '^2.1.3'
27
+ };
28
+ // Add database dependencies
29
+ if (config.storage === 'local-json') {
30
+ // No additional dependencies needed for JSON file storage
31
+ }
32
+ else if (config.storage === 'local-sqlite') {
33
+ if (config.databaseType === 'sql' && config.sqlOption === 'prisma') {
34
+ dependencies['@prisma/client'] = '^6.0.1';
35
+ devDependencies['prisma'] = '^6.0.1';
36
+ }
37
+ else if (config.databaseType === 'sql') {
38
+ dependencies['better-sqlite3'] = '^11.7.0';
39
+ devDependencies['@types/better-sqlite3'] = '^7.6.9';
40
+ }
41
+ else if (config.databaseType === 'nosql' && config.nosqlOption === 'mongodb') {
42
+ dependencies['mongoose'] = '^8.8.4';
43
+ }
44
+ else if (config.databaseType === 'nosql' && config.nosqlOption === 'dynamodb') {
45
+ dependencies['@aws-sdk/client-dynamodb'] = '^3.699.0';
46
+ dependencies['@aws-sdk/lib-dynamodb'] = '^3.699.0';
47
+ }
48
+ }
49
+ else if (config.storage === 'external-url') {
50
+ if (config.databaseType === 'sql' && config.sqlOption === 'prisma') {
51
+ dependencies['@prisma/client'] = '^6.0.1';
52
+ devDependencies['prisma'] = '^6.0.1';
53
+ }
54
+ else if (config.databaseType === 'sql') {
55
+ dependencies['pg'] = '^8.13.1';
56
+ devDependencies['@types/pg'] = '^8.11.10';
57
+ }
58
+ else if (config.databaseType === 'nosql' && config.nosqlOption === 'mongodb') {
59
+ dependencies['mongoose'] = '^8.8.4';
60
+ }
61
+ else if (config.databaseType === 'nosql' && config.nosqlOption === 'dynamodb') {
62
+ dependencies['@aws-sdk/client-dynamodb'] = '^3.699.0';
63
+ dependencies['@aws-sdk/lib-dynamodb'] = '^3.699.0';
64
+ }
65
+ }
66
+ // Add API type dependencies
67
+ if (config.apiType === 'graphql') {
68
+ dependencies['graphql'] = '^16.9.0';
69
+ dependencies['express-graphql'] = '^0.12.0';
70
+ devDependencies['@types/express-graphql'] = '^0.12.0';
71
+ }
72
+ const packageJson = {
73
+ name: `${config.projectName}-backend`,
74
+ version: '1.0.0',
75
+ main: 'dist/index.js',
76
+ scripts: {
77
+ dev: 'nodemon --exec ts-node src/index.ts',
78
+ build: 'tsc',
79
+ start: 'node dist/index.js',
80
+ test: 'vitest',
81
+ 'test:ui': 'vitest --ui',
82
+ 'test:coverage': 'vitest --coverage'
83
+ },
84
+ dependencies,
85
+ devDependencies
86
+ };
87
+ await fs_extra_1.default.writeJSON(path_1.default.join(backendPath, 'package.json'), packageJson, { spaces: 2 });
88
+ // Create TypeScript config
89
+ const tsconfig = {
90
+ compilerOptions: {
91
+ target: 'ES2020',
92
+ module: 'commonjs',
93
+ lib: ['ES2020'],
94
+ outDir: './dist',
95
+ rootDir: './src',
96
+ strict: true,
97
+ esModuleInterop: true,
98
+ skipLibCheck: true,
99
+ forceConsistentCasingInFileNames: true,
100
+ resolveJsonModule: true,
101
+ moduleResolution: 'node'
102
+ },
103
+ include: ['src/**/*'],
104
+ exclude: ['node_modules', 'dist']
105
+ };
106
+ await fs_extra_1.default.writeJSON(path_1.default.join(backendPath, 'tsconfig.json'), tsconfig, { spaces: 2 });
107
+ // Create Vitest config
108
+ const vitestConfig = `import { defineConfig } from 'vitest/config'
109
+
110
+ export default defineConfig({
111
+ test: {
112
+ globals: true,
113
+ environment: 'node',
114
+ coverage: {
115
+ provider: 'v8',
116
+ reporter: ['text', 'json', 'html'],
117
+ },
118
+ },
119
+ })
120
+ `;
121
+ await fs_extra_1.default.writeFile(path_1.default.join(backendPath, 'vitest.config.ts'), vitestConfig);
122
+ // Create src directory
123
+ const srcPath = path_1.default.join(backendPath, 'src');
124
+ await fs_extra_1.default.ensureDir(srcPath);
125
+ // Create index.ts
126
+ let indexContent = `import express from 'express';
127
+ import cors from 'cors';
128
+ import dotenv from 'dotenv';
129
+
130
+ dotenv.config();
131
+
132
+ const app = express();
133
+ const PORT = process.env.PORT || 3001;
134
+
135
+ app.use(cors());
136
+ app.use(express.json());
137
+
138
+ // Health check endpoint
139
+ app.get('/health', (req, res) => {
140
+ res.json({ status: 'ok', message: 'Server is running' });
141
+ });
142
+
143
+ `;
144
+ if (config.apiType === 'graphql') {
145
+ indexContent += `import { graphqlHTTP } from 'express-graphql';
146
+ import { buildSchema } from 'graphql';
147
+
148
+ // GraphQL schema
149
+ const schema = buildSchema(\`
150
+ type Query {
151
+ hello: String
152
+ }
153
+ \`);
154
+
155
+ // Root resolver
156
+ const root = {
157
+ hello: () => 'Hello from GraphQL!',
158
+ };
159
+
160
+ app.use('/graphql', graphqlHTTP({
161
+ schema: schema,
162
+ rootValue: root,
163
+ graphiql: true,
164
+ }));
165
+
166
+ `;
167
+ }
168
+ else {
169
+ indexContent += `// REST API routes
170
+ app.get('/api', (req, res) => {
171
+ res.json({ message: 'Welcome to the REST API' });
172
+ });
173
+
174
+ `;
175
+ }
176
+ indexContent += `const server = app.listen(PORT, () => {
177
+ console.log(\`Server is running on http://localhost:\${PORT}\`);
178
+ });
179
+
180
+ export default app;
181
+ `;
182
+ await fs_extra_1.default.writeFile(path_1.default.join(srcPath, 'index.ts'), indexContent);
183
+ // Create .env.example
184
+ let envExample = `PORT=3001
185
+ `;
186
+ if (config.storage === 'external-url' && config.databaseUrl) {
187
+ envExample += `DATABASE_URL=${config.databaseUrl}\n`;
188
+ }
189
+ await fs_extra_1.default.writeFile(path_1.default.join(backendPath, '.env.example'), envExample);
190
+ // Create database setup if needed
191
+ if (config.storage === 'local-json') {
192
+ await generateJSONFileSetup(srcPath, config);
193
+ }
194
+ else if (config.databaseType === 'sql' && config.sqlOption === 'prisma') {
195
+ await generatePrismaConfig(backendPath, config);
196
+ }
197
+ else if (config.databaseType === 'sql' && config.storage === 'local-sqlite') {
198
+ await generateSQLiteSetup(srcPath, config);
199
+ }
200
+ else if (config.databaseType === 'nosql' && config.nosqlOption === 'mongodb') {
201
+ await generateMongoDBSetup(srcPath, config);
202
+ }
203
+ else if (config.databaseType === 'nosql' && config.nosqlOption === 'dynamodb') {
204
+ await generateDynamoDBSetup(srcPath, config);
205
+ }
206
+ // Create test files
207
+ const testPath = path_1.default.join(srcPath, '__tests__');
208
+ await fs_extra_1.default.ensureDir(testPath);
209
+ const testFile = `import { describe, it, expect, beforeAll, afterAll } from 'vitest'
210
+ import request from 'supertest'
211
+ import app from '../index'
212
+
213
+ describe('API Tests', () => {
214
+ it('should return health check', async () => {
215
+ const res = await request(app).get('/health')
216
+ expect(res.status).toBe(200)
217
+ expect(res.body.status).toBe('ok')
218
+ })
219
+
220
+ ${config.apiType === 'rest' ? ` it('should return API welcome message', async () => {
221
+ const res = await request(app).get('/api')
222
+ expect(res.status).toBe(200)
223
+ expect(res.body.message).toContain('REST API')
224
+ })` : ` it('should handle GraphQL query', async () => {
225
+ const res = await request(app)
226
+ .post('/graphql')
227
+ .send({ query: '{ hello }' })
228
+ expect(res.status).toBe(200)
229
+ expect(res.body.data.hello).toBe('Hello from GraphQL!')
230
+ })`}
231
+ })
232
+ `;
233
+ await fs_extra_1.default.writeFile(path_1.default.join(testPath, 'api.test.ts'), testFile);
234
+ // Create deployment files
235
+ await generateBackendDeployment(backendPath, config);
236
+ }
237
+ async function generateBackendDeployment(backendPath, config) {
238
+ // Render configuration
239
+ const renderYaml = `services:
240
+ - type: web
241
+ name: ${config.projectName}-backend
242
+ env: node
243
+ buildCommand: npm install && npm run build
244
+ startCommand: npm start
245
+ envVars:
246
+ - key: NODE_ENV
247
+ value: production
248
+ - key: PORT
249
+ value: 3001
250
+ `;
251
+ await fs_extra_1.default.writeFile(path_1.default.join(backendPath, 'render.yaml'), renderYaml);
252
+ }
253
+ async function generatePrismaConfig(backendPath, config) {
254
+ const prismaPath = path_1.default.join(backendPath, 'prisma');
255
+ await fs_extra_1.default.ensureDir(prismaPath);
256
+ let datasource = '';
257
+ if (config.storage === 'local-sqlite') {
258
+ datasource = `datasource db {
259
+ provider = "sqlite"
260
+ url = "file:./dev.db"
261
+ }`;
262
+ }
263
+ else if (config.storage === 'external-url') {
264
+ datasource = `datasource db {
265
+ provider = "postgresql"
266
+ url = env("DATABASE_URL")
267
+ }`;
268
+ }
269
+ const schema = `${datasource}
270
+
271
+ generator client {
272
+ provider = "prisma-client-js"
273
+ }
274
+
275
+ model User {
276
+ id Int @id @default(autoincrement())
277
+ email String @unique
278
+ name String?
279
+ createdAt DateTime @default(now())
280
+ updatedAt DateTime @updatedAt
281
+ }
282
+ `;
283
+ await fs_extra_1.default.writeFile(path_1.default.join(prismaPath, 'schema.prisma'), schema);
284
+ }
285
+ async function generateSQLiteSetup(srcPath, config) {
286
+ const dbContent = `import Database from 'better-sqlite3';
287
+ import path from 'path';
288
+
289
+ const dbPath = path.join(process.cwd(), 'database.db');
290
+ const db = new Database(dbPath);
291
+
292
+ // Initialize database
293
+ db.exec(\`
294
+ CREATE TABLE IF NOT EXISTS users (
295
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
296
+ email TEXT UNIQUE NOT NULL,
297
+ name TEXT,
298
+ createdAt DATETIME DEFAULT CURRENT_TIMESTAMP
299
+ )
300
+ \`);
301
+
302
+ export default db;
303
+ `;
304
+ await fs_extra_1.default.writeFile(path_1.default.join(srcPath, 'db.ts'), dbContent);
305
+ }
306
+ async function generateMongoDBSetup(srcPath, config) {
307
+ const dbContent = `import mongoose from 'mongoose';
308
+
309
+ const connectDB = async () => {
310
+ try {
311
+ const mongoURI = process.env.DATABASE_URL || 'mongodb://localhost:27017/${config.projectName}';
312
+ await mongoose.connect(mongoURI);
313
+ console.log('MongoDB connected');
314
+ } catch (error) {
315
+ console.error('MongoDB connection error:', error);
316
+ process.exit(1);
317
+ }
318
+ };
319
+
320
+ // User schema example
321
+ const userSchema = new mongoose.Schema({
322
+ email: { type: String, required: true, unique: true },
323
+ name: String,
324
+ createdAt: { type: Date, default: Date.now }
325
+ });
326
+
327
+ export const User = mongoose.model('User', userSchema);
328
+ export default connectDB;
329
+ `;
330
+ await fs_extra_1.default.writeFile(path_1.default.join(srcPath, 'db.ts'), dbContent);
331
+ }
332
+ async function generateDynamoDBSetup(srcPath, config) {
333
+ const dbContent = `import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
334
+ import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
335
+
336
+ const client = new DynamoDBClient({
337
+ region: process.env.AWS_REGION || 'us-east-1',
338
+ });
339
+
340
+ export const docClient = DynamoDBDocumentClient.from(client);
341
+
342
+ export default docClient;
343
+ `;
344
+ await fs_extra_1.default.writeFile(path_1.default.join(srcPath, 'db.ts'), dbContent);
345
+ }
346
+ async function generateJSONFileSetup(srcPath, config) {
347
+ const backendPath = path_1.default.dirname(path_1.default.dirname(srcPath));
348
+ const dbContent = `import fs from 'fs-extra';
349
+ import path from 'path';
350
+
351
+ const DB_FILE = path.join(process.cwd(), 'data', 'database.json');
352
+
353
+ // Ensure data directory exists
354
+ const dataDir = path.dirname(DB_FILE);
355
+ fs.ensureDirSync(dataDir);
356
+
357
+ // Initialize database file if it doesn't exist
358
+ if (!fs.existsSync(DB_FILE)) {
359
+ fs.writeJSONSync(DB_FILE, { users: [] }, { spaces: 2 });
360
+ }
361
+
362
+ // Read database
363
+ export const readDB = (): any => {
364
+ try {
365
+ return fs.readJSONSync(DB_FILE);
366
+ } catch (error) {
367
+ console.error('Error reading database:', error);
368
+ return { users: [] };
369
+ }
370
+ };
371
+
372
+ // Write database
373
+ export const writeDB = (data: any): void => {
374
+ try {
375
+ fs.writeJSONSync(DB_FILE, data, { spaces: 2 });
376
+ } catch (error) {
377
+ console.error('Error writing database:', error);
378
+ throw error;
379
+ }
380
+ };
381
+
382
+ // Helper functions
383
+ export const getUsers = () => {
384
+ const db = readDB();
385
+ return db.users || [];
386
+ };
387
+
388
+ export const addUser = (user: any) => {
389
+ const db = readDB();
390
+ if (!db.users) db.users = [];
391
+ const newUser = { ...user, id: db.users.length + 1, createdAt: new Date().toISOString() };
392
+ db.users.push(newUser);
393
+ writeDB(db);
394
+ return newUser;
395
+ };
396
+
397
+ export const getUserById = (id: number) => {
398
+ const db = readDB();
399
+ return db.users?.find((u: any) => u.id === id);
400
+ };
401
+
402
+ export const updateUser = (id: number, updates: any) => {
403
+ const db = readDB();
404
+ const userIndex = db.users?.findIndex((u: any) => u.id === id);
405
+ if (userIndex !== -1 && userIndex !== undefined) {
406
+ db.users[userIndex] = { ...db.users[userIndex], ...updates, updatedAt: new Date().toISOString() };
407
+ writeDB(db);
408
+ return db.users[userIndex];
409
+ }
410
+ return null;
411
+ };
412
+
413
+ export const deleteUser = (id: number) => {
414
+ const db = readDB();
415
+ db.users = db.users?.filter((u: any) => u.id !== id) || [];
416
+ writeDB(db);
417
+ return true;
418
+ };
419
+
420
+ export default { readDB, writeDB, getUsers, addUser, getUserById, updateUser, deleteUser };
421
+ `;
422
+ await fs_extra_1.default.writeFile(path_1.default.join(srcPath, 'db.ts'), dbContent);
423
+ // Create initial data directory and file
424
+ const dataPath = path_1.default.join(backendPath, 'data');
425
+ await fs_extra_1.default.ensureDir(dataPath);
426
+ await fs_extra_1.default.writeJSON(path_1.default.join(dataPath, 'database.json'), { users: [] }, { spaces: 2 });
427
+ }
@@ -0,0 +1,259 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateFastAPI = generateFastAPI;
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const path_1 = __importDefault(require("path"));
9
+ async function generateFastAPI(backendPath, config) {
10
+ const dependencies = [
11
+ 'fastapi==0.115.6',
12
+ 'uvicorn[standard]==0.32.1',
13
+ 'python-dotenv==1.0.1',
14
+ 'pydantic==2.10.3',
15
+ 'pydantic-settings==2.6.1'
16
+ ];
17
+ // Add database dependencies
18
+ if (config.storage === 'local-json') {
19
+ // No additional dependencies needed for JSON file storage (uses built-in json module)
20
+ }
21
+ else if (config.storage === 'local-sqlite') {
22
+ if (config.databaseType === 'sql') {
23
+ dependencies.push('sqlalchemy==2.0.36');
24
+ }
25
+ else if (config.databaseType === 'nosql' && config.nosqlOption === 'mongodb') {
26
+ dependencies.push('motor==3.6.0');
27
+ dependencies.push('pymongo==4.10.1');
28
+ }
29
+ }
30
+ else if (config.storage === 'external-url') {
31
+ if (config.databaseType === 'sql') {
32
+ dependencies.push('sqlalchemy==2.0.36');
33
+ dependencies.push('psycopg2-binary==2.9.10');
34
+ }
35
+ else if (config.databaseType === 'nosql' && config.nosqlOption === 'mongodb') {
36
+ dependencies.push('motor==3.6.0');
37
+ dependencies.push('pymongo==4.10.1');
38
+ }
39
+ else if (config.databaseType === 'nosql' && config.nosqlOption === 'dynamodb') {
40
+ dependencies.push('boto3==1.35.47');
41
+ }
42
+ }
43
+ // Create requirements.txt
44
+ await fs_extra_1.default.writeFile(path_1.default.join(backendPath, 'requirements.txt'), dependencies.join('\n'));
45
+ // Create main.py
46
+ const srcPath = path_1.default.join(backendPath, 'src');
47
+ await fs_extra_1.default.ensureDir(srcPath);
48
+ let mainContent = `from fastapi import FastAPI
49
+ from fastapi.middleware.cors import CORSMiddleware
50
+ from dotenv import load_dotenv
51
+ import os
52
+
53
+ load_dotenv()
54
+
55
+ app = FastAPI(title="${config.projectName} API")
56
+
57
+ app.add_middleware(
58
+ CORSMiddleware,
59
+ allow_origins=["*"],
60
+ allow_credentials=True,
61
+ allow_methods=["*"],
62
+ allow_headers=["*"],
63
+ )
64
+
65
+ @app.get("/")
66
+ def read_root():
67
+ return {"message": "Welcome to ${config.projectName} API"}
68
+
69
+ @app.get("/health")
70
+ def health_check():
71
+ return {"status": "ok", "message": "Server is running"}
72
+
73
+ if __name__ == "__main__":
74
+ import uvicorn
75
+ port = int(os.getenv("PORT", 3001))
76
+ uvicorn.run(app, host="0.0.0.0", port=port)
77
+ `;
78
+ await fs_extra_1.default.writeFile(path_1.default.join(srcPath, 'main.py'), mainContent);
79
+ // Create .env.example
80
+ let envExample = `PORT=3001
81
+ `;
82
+ if (config.storage === 'external-url' && config.databaseUrl) {
83
+ envExample += `DATABASE_URL=${config.databaseUrl}\n`;
84
+ }
85
+ await fs_extra_1.default.writeFile(path_1.default.join(backendPath, '.env.example'), envExample);
86
+ // Create database setup if needed
87
+ if (config.storage === 'local-json') {
88
+ await generateJSONFileSetup(srcPath, config);
89
+ }
90
+ else if (config.databaseType === 'sql') {
91
+ await generateSQLAlchemySetup(srcPath, config);
92
+ }
93
+ else if (config.databaseType === 'nosql' && config.nosqlOption === 'mongodb') {
94
+ await generateMongoDBSetup(srcPath, config);
95
+ }
96
+ else if (config.databaseType === 'nosql' && config.nosqlOption === 'dynamodb') {
97
+ await generateDynamoDBSetup(srcPath, config);
98
+ }
99
+ // Create deployment files
100
+ await generateBackendDeployment(backendPath, config);
101
+ }
102
+ async function generateBackendDeployment(backendPath, config) {
103
+ // Render configuration
104
+ const renderYaml = `services:
105
+ - type: web
106
+ name: ${config.projectName}-backend
107
+ env: python
108
+ buildCommand: pip install -r requirements.txt
109
+ startCommand: uvicorn src.main:app --host 0.0.0.0 --port \$PORT
110
+ envVars:
111
+ - key: PORT
112
+ value: 3001
113
+ `;
114
+ await fs_extra_1.default.writeFile(path_1.default.join(backendPath, 'render.yaml'), renderYaml);
115
+ }
116
+ async function generateSQLAlchemySetup(srcPath, config) {
117
+ const dbUrlLine = config.storage === 'local-sqlite'
118
+ ? 'DATABASE_URL = "sqlite:///./database.db"'
119
+ : 'DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://user:password@localhost/dbname")';
120
+ const dbContent = `from sqlalchemy import create_engine, Column, Integer, String, DateTime
121
+ from sqlalchemy.ext.declarative import declarative_base
122
+ from sqlalchemy.orm import sessionmaker
123
+ import os
124
+ from datetime import datetime
125
+
126
+ ${dbUrlLine}
127
+
128
+ engine = create_engine(DATABASE_URL)
129
+ SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
130
+ Base = declarative_base()
131
+
132
+ class User(Base):
133
+ __tablename__ = "users"
134
+
135
+ id = Column(Integer, primary_key=True, index=True)
136
+ email = Column(String, unique=True, index=True)
137
+ name = Column(String, nullable=True)
138
+ created_at = Column(DateTime, default=datetime.utcnow)
139
+
140
+ Base.metadata.create_all(bind=engine)
141
+
142
+ def get_db():
143
+ db = SessionLocal()
144
+ try:
145
+ yield db
146
+ finally:
147
+ db.close()
148
+ `;
149
+ await fs_extra_1.default.writeFile(path_1.default.join(srcPath, 'database.py'), dbContent);
150
+ }
151
+ async function generateMongoDBSetup(srcPath, config) {
152
+ const dbContent = `from motor.motor_asyncio import AsyncIOMotorClient
153
+ import os
154
+
155
+ DATABASE_URL = os.getenv("DATABASE_URL", "mongodb://localhost:27017")
156
+ DATABASE_NAME = "${config.projectName}"
157
+
158
+ client = AsyncIOMotorClient(DATABASE_URL)
159
+ db = client[DATABASE_NAME]
160
+
161
+ # Collections
162
+ users_collection = db["users"]
163
+ `;
164
+ await fs_extra_1.default.writeFile(path_1.default.join(srcPath, 'database.py'), dbContent);
165
+ }
166
+ async function generateDynamoDBSetup(srcPath, config) {
167
+ const dbContent = `import boto3
168
+ import os
169
+
170
+ dynamodb = boto3.resource(
171
+ 'dynamodb',
172
+ region_name=os.getenv('AWS_REGION', 'us-east-1')
173
+ )
174
+
175
+ # Table references
176
+ users_table = dynamodb.Table('users')
177
+ `;
178
+ await fs_extra_1.default.writeFile(path_1.default.join(srcPath, 'database.py'), dbContent);
179
+ }
180
+ async function generateJSONFileSetup(srcPath, config) {
181
+ const backendPath = path_1.default.dirname(path_1.default.dirname(srcPath));
182
+ const dbContent = `import json
183
+ import os
184
+ from pathlib import Path
185
+ from typing import Dict, List, Any, Optional
186
+
187
+ DB_FILE = Path(__file__).parent.parent / 'data' / 'database.json'
188
+
189
+ # Ensure data directory exists
190
+ DB_FILE.parent.mkdir(parents=True, exist_ok=True)
191
+
192
+ # Initialize database file if it doesn't exist
193
+ if not DB_FILE.exists():
194
+ with open(DB_FILE, 'w') as f:
195
+ json.dump({'users': []}, f, indent=2)
196
+
197
+ def read_db() -> Dict[str, Any]:
198
+ """Read the database from JSON file."""
199
+ try:
200
+ with open(DB_FILE, 'r') as f:
201
+ return json.load(f)
202
+ except (FileNotFoundError, json.JSONDecodeError):
203
+ return {'users': []}
204
+
205
+ def write_db(data: Dict[str, Any]) -> None:
206
+ """Write data to the database JSON file."""
207
+ with open(DB_FILE, 'w') as f:
208
+ json.dump(data, f, indent=2)
209
+
210
+ def get_users() -> List[Dict[str, Any]]:
211
+ """Get all users from the database."""
212
+ db = read_db()
213
+ return db.get('users', [])
214
+
215
+ def add_user(user: Dict[str, Any]) -> Dict[str, Any]:
216
+ """Add a new user to the database."""
217
+ db = read_db()
218
+ users = db.get('users', [])
219
+ new_user = {
220
+ **user,
221
+ 'id': len(users) + 1,
222
+ 'created_at': str(Path(__file__).stat().st_mtime)
223
+ }
224
+ users.append(new_user)
225
+ db['users'] = users
226
+ write_db(db)
227
+ return new_user
228
+
229
+ def get_user_by_id(user_id: int) -> Optional[Dict[str, Any]]:
230
+ """Get a user by ID."""
231
+ users = get_users()
232
+ return next((u for u in users if u.get('id') == user_id), None)
233
+
234
+ def update_user(user_id: int, updates: Dict[str, Any]) -> Optional[Dict[str, Any]]:
235
+ """Update a user by ID."""
236
+ db = read_db()
237
+ users = db.get('users', [])
238
+ for i, user in enumerate(users):
239
+ if user.get('id') == user_id:
240
+ users[i] = {**user, **updates, 'updated_at': str(Path(__file__).stat().st_mtime)}
241
+ db['users'] = users
242
+ write_db(db)
243
+ return users[i]
244
+ return None
245
+
246
+ def delete_user(user_id: int) -> bool:
247
+ """Delete a user by ID."""
248
+ db = read_db()
249
+ users = db.get('users', [])
250
+ db['users'] = [u for u in users if u.get('id') != user_id]
251
+ write_db(db)
252
+ return True
253
+ `;
254
+ await fs_extra_1.default.writeFile(path_1.default.join(srcPath, 'database.py'), dbContent);
255
+ // Create initial data directory and file
256
+ const dataPath = path_1.default.join(backendPath, 'data');
257
+ await fs_extra_1.default.ensureDir(dataPath);
258
+ await fs_extra_1.default.writeJSON(path_1.default.join(dataPath, 'database.json'), { users: [] }, { spaces: 2 });
259
+ }