@paralect/hive 0.1.48 → 0.1.50-alpha.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.
Files changed (165) hide show
  1. package/.cursor/commands/deslop.md +12 -0
  2. package/.hive/.babelrc +3 -0
  3. package/.hive/.cursor/commands/add-endpoint.md +262 -0
  4. package/.hive/.cursor/commands/add-handler.md +137 -0
  5. package/.hive/.cursor/commands/add-middleware.md +95 -0
  6. package/.hive/.cursor/commands/add-resource.md +71 -0
  7. package/.hive/.cursor/commands/add-scheduler.md +138 -0
  8. package/.hive/.cursor/commands/add-service.md +188 -0
  9. package/.hive/.cursor/skills/hive-auth/SKILL.md +134 -0
  10. package/.hive/.cursor/skills/hive-database/SKILL.md +103 -0
  11. package/.hive/.cursor/skills/hive-endpoint/SKILL.md +103 -0
  12. package/.hive/.cursor/skills/hive-handler/SKILL.md +88 -0
  13. package/.hive/.cursor/skills/hive-mapping/SKILL.md +85 -0
  14. package/.hive/.cursor/skills/hive-middleware/SKILL.md +104 -0
  15. package/.hive/.cursor/skills/hive-overview/SKILL.md +50 -0
  16. package/.hive/.cursor/skills/hive-scheduler/SKILL.md +94 -0
  17. package/.hive/.cursor/skills/hive-schema/SKILL.md +73 -0
  18. package/.hive/.cursor/skills/hive-service/SKILL.md +90 -0
  19. package/.hive/.dockerignore +1 -0
  20. package/.hive/Dockerfile +22 -0
  21. package/.hive/Dockerfile.dev +33 -0
  22. package/.hive/Dockerfile.prod +29 -0
  23. package/.hive/README.md +11 -0
  24. package/.hive/bin/deploy.sh +5 -0
  25. package/.hive/bin/start.sh +2 -0
  26. package/.hive/bootstrap-hive.js +118 -0
  27. package/.hive/deploy/api/Chart.yaml +6 -0
  28. package/.hive/deploy/api/staging.yaml +3 -0
  29. package/.hive/deploy/api/templates/deployment.yaml +44 -0
  30. package/.hive/deploy/api/templates/ingress.yaml +26 -0
  31. package/.hive/deploy/api/templates/service.yaml +14 -0
  32. package/.hive/deploy/script/Dockerfile +39 -0
  33. package/.hive/deploy/script/package-lock.json +1499 -0
  34. package/.hive/deploy/script/package.json +12 -0
  35. package/.hive/deploy/script/src/config.js +48 -0
  36. package/.hive/deploy/script/src/index.js +108 -0
  37. package/.hive/deploy/script/src/util.js +19 -0
  38. package/.hive/initial-data.json +176 -0
  39. package/.hive/package-lock.json +10242 -0
  40. package/.hive/package.json +98 -0
  41. package/.hive/ship_logo.png +0 -0
  42. package/.hive/src/app-config/app.js +3 -0
  43. package/.hive/src/app-config/assertEnv.js +15 -0
  44. package/.hive/src/app-config/index.js +62 -0
  45. package/.hive/src/app.js +69 -0
  46. package/.hive/src/assets/emails/components/header.mjml +13 -0
  47. package/.hive/src/assets/emails/dist/.gitkeep +0 -0
  48. package/.hive/src/assets/emails/signup-welcome.mjml +34 -0
  49. package/.hive/src/assets/emails/styles/index.mjml +77 -0
  50. package/.hive/src/autoMap/addHandlers.js +142 -0
  51. package/.hive/src/autoMap/getDependentFields.js +37 -0
  52. package/.hive/src/autoMap/mapSchema.js +99 -0
  53. package/.hive/src/autoMap/schemaMappings.js +13 -0
  54. package/.hive/src/autoMap/schemaMappings.json +3 -0
  55. package/.hive/src/bullMqBus.js +21 -0
  56. package/.hive/src/bullMqWrapper.js +23 -0
  57. package/.hive/src/db.js +52 -0
  58. package/.hive/src/emails/MyEmailComponent.jsx +14 -0
  59. package/.hive/src/emails/compiled/MyEmailComponent.js +18 -0
  60. package/.hive/src/emails/compiled/compiled/MyEmailComponent.js +18 -0
  61. package/.hive/src/helpers/db/ifUpdated.js +22 -0
  62. package/.hive/src/helpers/getMiddlewares.js +38 -0
  63. package/.hive/src/helpers/getResourceEndpoints.js +28 -0
  64. package/.hive/src/helpers/getResources.js +32 -0
  65. package/.hive/src/helpers/getSchemas.js +50 -0
  66. package/.hive/src/helpers/importHandlers.js +29 -0
  67. package/.hive/src/helpers/isZodArray.js +13 -0
  68. package/.hive/src/helpers/prettierFormat.js +8 -0
  69. package/.hive/src/helpers/schema/db.schema.js +9 -0
  70. package/.hive/src/helpers/schema/pagination.schema.js +14 -0
  71. package/.hive/src/ioEmitter.js +9 -0
  72. package/.hive/src/jsconfig.json +5 -0
  73. package/.hive/src/lib/node-mongo/.github/workflows/npm-publish.yml +32 -0
  74. package/.hive/src/lib/node-mongo/API.md +654 -0
  75. package/.hive/src/lib/node-mongo/CHANGELOG.md +98 -0
  76. package/.hive/src/lib/node-mongo/README.md +97 -0
  77. package/.hive/src/lib/node-mongo/package-lock.json +3682 -0
  78. package/.hive/src/lib/node-mongo/package.json +74 -0
  79. package/.hive/src/lib/node-mongo/src/index.js +64 -0
  80. package/.hive/src/lib/node-mongo/src/mongo-query-service.js +78 -0
  81. package/.hive/src/lib/node-mongo/src/mongo-service-error.js +15 -0
  82. package/.hive/src/lib/node-mongo/src/mongo-service.js +303 -0
  83. package/.hive/src/logger.js +43 -0
  84. package/.hive/src/middlewares/allowNoAuth.js +9 -0
  85. package/.hive/src/middlewares/attachUser.js +41 -0
  86. package/.hive/src/middlewares/global/extractUserTokens.js +15 -0
  87. package/.hive/src/middlewares/global/tryToAttachUser.js +33 -0
  88. package/.hive/src/middlewares/isAuthorized.js +18 -0
  89. package/.hive/src/middlewares/shouldExist.js +37 -0
  90. package/.hive/src/middlewares/shouldNotExist.js +19 -0
  91. package/.hive/src/middlewares/uploadFile.js +5 -0
  92. package/.hive/src/middlewares/validate.js +32 -0
  93. package/.hive/src/migrations/migration.js +8 -0
  94. package/.hive/src/migrations/migration.service.js +73 -0
  95. package/.hive/src/migrations/migrations/1.js +22 -0
  96. package/.hive/src/migrations/migrations-log/migration-log.schema.js +13 -0
  97. package/.hive/src/migrations/migrations-log/migration-log.service.js +50 -0
  98. package/.hive/src/migrations/migrations.schema.js +6 -0
  99. package/.hive/src/migrations/migrator.js +75 -0
  100. package/.hive/src/migrator.js +4 -0
  101. package/.hive/src/resources/_dev/endpoints/triggerSchedulerHandler.js +32 -0
  102. package/.hive/src/resources/health/endpoints/get.js +19 -0
  103. package/.hive/src/resources/schemaMappings/schemaMappings.schema.js +6 -0
  104. package/.hive/src/resources/tokens/methods/generateSecureToken.js +9 -0
  105. package/.hive/src/resources/tokens/methods/setToken.js +8 -0
  106. package/.hive/src/resources/tokens/methods/storeToken.js +35 -0
  107. package/.hive/src/resources/tokens/tokens.schema.js +11 -0
  108. package/.hive/src/resources/users/endpoints/getCurrentUser.js +14 -0
  109. package/.hive/src/resources/users/endpoints/getUserProfile.js +19 -0
  110. package/.hive/src/resources/users/handlers/test.js +1 -0
  111. package/.hive/src/resources/users/methods/ensureUserCreated.js +68 -0
  112. package/.hive/src/resources/users/users.schema.js +16 -0
  113. package/.hive/src/routes/index.js +172 -0
  114. package/.hive/src/routes/middlewares/attachCustomErrors.js +28 -0
  115. package/.hive/src/routes/middlewares/routeErrorHandler.js +27 -0
  116. package/.hive/src/scheduler/handlers/sendDailyReport.example.js +7 -0
  117. package/.hive/src/scheduler.js +32 -0
  118. package/.hive/src/security.util.js +38 -0
  119. package/.hive/src/services/emailService.js +15 -0
  120. package/.hive/src/services/globalTest.js +0 -0
  121. package/.hive/src/services/setCookie.js +21 -0
  122. package/.hive/src/socketIo.js +99 -0
  123. package/.hive/tsconfig.json +31 -0
  124. package/AGENTS.md +96 -0
  125. package/README.md +271 -0
  126. package/cli/helpers/docker.js +59 -0
  127. package/cli/helpers/envCheck.js +123 -0
  128. package/cli/helpers/findPort.js +32 -0
  129. package/cli/hive.js +155 -15
  130. package/package.json +1 -1
  131. package/starter/.cursor/commands/add-endpoint.md +262 -0
  132. package/starter/.cursor/commands/add-handler.md +137 -0
  133. package/starter/.cursor/commands/add-middleware.md +95 -0
  134. package/starter/.cursor/commands/add-resource.md +71 -0
  135. package/starter/.cursor/commands/add-scheduler.md +138 -0
  136. package/starter/.cursor/commands/add-service.md +188 -0
  137. package/starter/.cursor/skills/hive-auth/SKILL.md +134 -0
  138. package/starter/.cursor/skills/hive-database/SKILL.md +103 -0
  139. package/starter/.cursor/skills/hive-endpoint/SKILL.md +103 -0
  140. package/starter/.cursor/skills/hive-handler/SKILL.md +88 -0
  141. package/starter/.cursor/skills/hive-mapping/SKILL.md +85 -0
  142. package/starter/.cursor/skills/hive-middleware/SKILL.md +104 -0
  143. package/starter/.cursor/skills/hive-overview/SKILL.md +50 -0
  144. package/starter/.cursor/skills/hive-scheduler/SKILL.md +94 -0
  145. package/starter/.cursor/skills/hive-schema/SKILL.md +73 -0
  146. package/starter/.cursor/skills/hive-service/SKILL.md +90 -0
  147. package/starter/src/app.js +4 -3
  148. package/test-app/.cursor/commands/add-endpoint.md +262 -0
  149. package/test-app/.cursor/commands/add-handler.md +137 -0
  150. package/test-app/.cursor/commands/add-middleware.md +95 -0
  151. package/test-app/.cursor/commands/add-resource.md +71 -0
  152. package/test-app/.cursor/commands/add-scheduler.md +138 -0
  153. package/test-app/.cursor/commands/add-service.md +188 -0
  154. package/test-app/.cursor/skills/hive-auth/SKILL.md +134 -0
  155. package/test-app/.cursor/skills/hive-database/SKILL.md +103 -0
  156. package/test-app/.cursor/skills/hive-endpoint/SKILL.md +103 -0
  157. package/test-app/.cursor/skills/hive-handler/SKILL.md +88 -0
  158. package/test-app/.cursor/skills/hive-mapping/SKILL.md +85 -0
  159. package/test-app/.cursor/skills/hive-middleware/SKILL.md +104 -0
  160. package/test-app/.cursor/skills/hive-overview/SKILL.md +50 -0
  161. package/test-app/.cursor/skills/hive-scheduler/SKILL.md +94 -0
  162. package/test-app/.cursor/skills/hive-schema/SKILL.md +73 -0
  163. package/test-app/.cursor/skills/hive-service/SKILL.md +90 -0
  164. package/test-app/package-lock.json +8684 -0
  165. package/test-app/package.json +21 -0
package/README.md ADDED
@@ -0,0 +1,271 @@
1
+ # 🐝 Hive
2
+
3
+ **An AI-native backend framework for engineers who are *pissed off* about the complexity of modern technology.**
4
+
5
+ Hive preconfigures the entire backend stack: database, cache, queues, event handlers, auth, real-time — so you don't duct-tape different pieces yourself. It dictates a clean architecture that's easy to understand, easy to read, and scales to millions of users.
6
+
7
+ ```bash
8
+ npm install -g @paralect/hive
9
+
10
+ hive init my-app
11
+ cd my-app
12
+ hive run ./src
13
+ ```
14
+
15
+ Your API is live. MongoDB, validation, auth infrastructure, real-time events — all preconfigured.
16
+
17
+ ---
18
+
19
+ ## 🤖 AI-Native Development
20
+
21
+ Hive is designed for AI coding assistants. Open your project in Cursor and build with natural language:
22
+
23
+ ```
24
+ add-resource tasks
25
+ add-endpoint tasks post title, status, assignee: { _id }
26
+ add-endpoint tasks get page, perPage
27
+ add-handler tasks
28
+ ```
29
+
30
+ ### Commands
31
+
32
+ | Command | What it does |
33
+ |---------|--------------|
34
+ | `add-resource tasks` | Create resource with schema + folders |
35
+ | `add-endpoint tasks post title, dueOn` | Create POST endpoint with inferred types |
36
+ | `add-endpoint tasks get page, perPage` | Create GET list endpoint |
37
+ | `add-endpoint tasks update /:id title` | Create PUT endpoint |
38
+ | `add-handler tasks` | Create event handlers for DB changes |
39
+ | `add-middleware isAdmin` | Create custom middleware |
40
+ | `add-service slack sendMessage` | Create service with go-to library |
41
+ | `add-scheduler sendReport daily at 9am` | Create cron job |
42
+
43
+ The AI understands Hive conventions and generates production-ready code.
44
+
45
+ ---
46
+
47
+ ## What's Preconfigured
48
+
49
+ | Concern | Solution |
50
+ |---------|----------|
51
+ | Database | MongoDB with auto-generated services per schema |
52
+ | Validation | Zod schemas, auto-applied to all endpoints |
53
+ | Auth | Token-based auth infrastructure, ready to extend |
54
+ | Events | Persistent handlers that react to DB changes |
55
+ | Real-time | Socket.io with Redis adapter for scaling |
56
+ | Queues | BullMQ for background jobs |
57
+ | Scheduler | Cron-based jobs, no external service needed |
58
+ | Auto-sync | Embedded documents stay fresh automatically |
59
+
60
+ You focus on your product. Hive handles the plumbing.
61
+
62
+ ---
63
+
64
+ ## Architecture
65
+
66
+ Every feature is a **resource** — a folder with predictable structure:
67
+
68
+ ```
69
+ src/resources/{name}/
70
+ ├── {name}.schema.js # Data shape (required)
71
+ ├── endpoints/ # API routes
72
+ ├── handlers/ # React to DB events
73
+ └── methods/ # Shared logic
74
+ ```
75
+
76
+ This scales. New developers understand it in minutes. Your codebase stays clean at 10 endpoints or 1000.
77
+
78
+ ---
79
+
80
+ ## 📦 Schemas
81
+
82
+ Define your data once. Hive creates the collection and service.
83
+
84
+ ```javascript
85
+ import { z } from 'zod';
86
+ import dbSchema from 'helpers/schema/db.schema.js';
87
+
88
+ const schema = dbSchema.extend({
89
+ title: z.coerce.string().nullable().optional(),
90
+ status: z.coerce.string().default('pending'),
91
+ assignee: z.object({
92
+ _id: z.string(),
93
+ fullName: z.coerce.string().nullable().optional(),
94
+ }).nullable().optional(),
95
+ });
96
+
97
+ export default schema;
98
+ export const secureFields = ['internalNotes'];
99
+ ```
100
+
101
+ Every schema gets `_id`, `createdOn`, `updatedOn` automatically.
102
+
103
+ ---
104
+
105
+ ## 🔌 Endpoints
106
+
107
+ Four exports. No router config.
108
+
109
+ ```javascript
110
+ import { z } from 'zod';
111
+ import db from 'db';
112
+
113
+ const tasksService = db.services.tasks;
114
+
115
+ export const middlewares = [];
116
+
117
+ export const requestSchema = z.object({
118
+ page: z.coerce.number().default(1),
119
+ perPage: z.coerce.number().default(20),
120
+ });
121
+
122
+ export const handler = async (ctx) => {
123
+ const { page, perPage } = ctx.validatedData;
124
+ return tasksService.find({}, { page, perPage, sort: '-createdOn' });
125
+ };
126
+
127
+ export const endpoint = {
128
+ url: '/',
129
+ method: 'get',
130
+ };
131
+ ```
132
+
133
+ Route auto-generated as `GET /tasks`.
134
+
135
+ ---
136
+
137
+ ## 🗄️ Database
138
+
139
+ Auto-generated services for every schema:
140
+
141
+ ```javascript
142
+ import db from 'db';
143
+
144
+ const tasksService = db.services.tasks;
145
+
146
+ // Find
147
+ const { results, count } = await tasksService.find({ status: 'active' }, { page: 1, perPage: 20 });
148
+ const task = await tasksService.findOne({ _id: id });
149
+
150
+ // Create
151
+ const task = await tasksService.create({ title: 'New', user: ctx.state.user });
152
+
153
+ // Update
154
+ await tasksService.updateOne({ _id: id }, (doc) => ({ ...doc, status: 'done' }));
155
+
156
+ // Delete
157
+ await tasksService.remove({ _id: id });
158
+ ```
159
+
160
+ ---
161
+
162
+ ## ⚡ Handlers
163
+
164
+ React to database changes. Perfect for side effects, notifications, syncing data.
165
+
166
+ ```javascript
167
+ import db from 'db';
168
+ import ifUpdated from 'helpers/db/ifUpdated';
169
+
170
+ const tasksService = db.services.tasks;
171
+
172
+ tasksService.on('created', async ({ doc }) => {
173
+ // Send notification, create activity log, etc.
174
+ });
175
+
176
+ tasksService.on('updated', ifUpdated(['status'], async ({ doc, prevDoc }) => {
177
+ // Only runs when status changed
178
+ }));
179
+
180
+ tasksService.on('removed', async ({ doc }) => {
181
+ // Cleanup related data
182
+ });
183
+ ```
184
+
185
+ ---
186
+
187
+ ## 🛡️ Middlewares
188
+
189
+ Built-in: `allowNoAuth`, `isAuthorized`, `shouldExist`, `attachUser`
190
+
191
+ Custom:
192
+
193
+ ```javascript
194
+ export default async (ctx, next) => {
195
+ if (!ctx.state.user?.isAdmin) ctx.throw(403, 'Admin only');
196
+ return next();
197
+ };
198
+ ```
199
+
200
+ ---
201
+
202
+ ## ⏰ Scheduler
203
+
204
+ Background jobs with cron:
205
+
206
+ ```javascript
207
+ import db from 'db';
208
+
209
+ export const handler = async () => {
210
+ await db.services.invoices.updateMany(
211
+ { isPaid: { $ne: true }, dueOn: { $lt: new Date() } },
212
+ (doc) => ({ ...doc, isOverdue: true })
213
+ );
214
+ };
215
+
216
+ export const cron = '0 9 * * *';
217
+ ```
218
+
219
+ ---
220
+
221
+ ## 🔄 Auto-Sync
222
+
223
+ Embedded documents stay fresh. When a user updates their name, all tasks with that user update automatically.
224
+
225
+ ```json
226
+ {
227
+ "tasks": {
228
+ "assignee": { "schema": "users" }
229
+ }
230
+ }
231
+ ```
232
+
233
+ ---
234
+
235
+ ## CLI
236
+
237
+ ```bash
238
+ hive init [name] # Create new project
239
+ hive run [path] # Start dev server
240
+ hive prepare [path] # Build for production
241
+ hive deploy # Deploy to Hive Cloud
242
+ hive install <plugin> # Install plugin
243
+ hive login # Login to Hive Cloud
244
+ ```
245
+
246
+ ---
247
+
248
+ ## Project Structure
249
+
250
+ ```
251
+ my-app/
252
+ ├── src/
253
+ │ ├── resources/ # Your features
254
+ │ ├── middlewares/ # Custom middlewares
255
+ │ ├── services/ # External APIs
256
+ │ └── scheduler/handlers/
257
+ └── .hive/ # Framework (don't edit)
258
+ ```
259
+
260
+ ---
261
+
262
+ ## Tech Stack
263
+
264
+ Proven, boring technology:
265
+
266
+ - **Koa** — Node.js framework
267
+ - **MongoDB** — Document database
268
+ - **Zod** — Schema validation
269
+ - **Socket.io** — Real-time
270
+ - **BullMQ** — Job queues
271
+ - **Redis** — Cache & pub/sub
@@ -0,0 +1,59 @@
1
+ const { execSync } = require('child_process');
2
+
3
+ const isDockerInstalled = () => {
4
+ try {
5
+ execSync('docker --version', { stdio: 'ignore' });
6
+ return true;
7
+ } catch {
8
+ return false;
9
+ }
10
+ };
11
+
12
+ const getContainerStatus = (name) => {
13
+ try {
14
+ const result = execSync(`docker inspect --format='{{.State.Status}}' ${name}`, {
15
+ encoding: 'utf8',
16
+ stdio: ['pipe', 'pipe', 'ignore']
17
+ });
18
+ return result.trim();
19
+ } catch {
20
+ return null; // Container doesn't exist
21
+ }
22
+ };
23
+
24
+ const startContainer = async (name, image, port, extraArgs = '') => {
25
+ const status = getContainerStatus(name);
26
+
27
+ if (status === 'running') {
28
+ console.log(` ${name} already running`);
29
+ return true;
30
+ }
31
+
32
+ if (status === 'exited' || status === 'created') {
33
+ console.log(` Starting ${name}...`);
34
+ execSync(`docker start ${name}`, { stdio: 'inherit' });
35
+ return true;
36
+ }
37
+
38
+ // Container doesn't exist, create it
39
+ console.log(` Creating ${name}...`);
40
+ const cmd = `docker run -d --name ${name} -p ${port}:${port} ${extraArgs} ${image}`;
41
+ execSync(cmd, { stdio: 'inherit' });
42
+ return true;
43
+ };
44
+
45
+ const startMongo = async () => {
46
+ return startContainer('hive-mongo', 'mongo:7', 27017);
47
+ };
48
+
49
+ const startRedis = async () => {
50
+ return startContainer('hive-redis', 'redis:7-alpine', 6379);
51
+ };
52
+
53
+ module.exports = {
54
+ isDockerInstalled,
55
+ getContainerStatus,
56
+ startContainer,
57
+ startMongo,
58
+ startRedis,
59
+ };
@@ -0,0 +1,123 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const inquirer = require('inquirer');
4
+
5
+ const hashCode = (str) => {
6
+ let hash = 0;
7
+ for (let i = 0; i < str.length; i++) {
8
+ const char = str.charCodeAt(i);
9
+ hash = ((hash << 5) - hash) + char;
10
+ hash = hash & hash;
11
+ }
12
+ return Math.abs(hash);
13
+ };
14
+
15
+ const readEnvFile = (envPath) => {
16
+ if (!fs.existsSync(envPath)) {
17
+ return {};
18
+ }
19
+
20
+ const content = fs.readFileSync(envPath, 'utf8');
21
+ const env = {};
22
+
23
+ content.split('\n').forEach(line => {
24
+ const trimmed = line.trim();
25
+ if (trimmed && !trimmed.startsWith('#')) {
26
+ const [key, ...valueParts] = trimmed.split('=');
27
+ if (key) {
28
+ env[key.trim()] = valueParts.join('=').trim();
29
+ }
30
+ }
31
+ });
32
+
33
+ return env;
34
+ };
35
+
36
+ const writeEnvFile = (envPath, env) => {
37
+ const content = Object.entries(env)
38
+ .map(([key, value]) => `${key}=${value}`)
39
+ .join('\n') + '\n';
40
+
41
+ fs.writeFileSync(envPath, content);
42
+ };
43
+
44
+ const updateEnvFile = (envPath, updates) => {
45
+ const env = readEnvFile(envPath);
46
+ Object.assign(env, updates);
47
+ writeEnvFile(envPath, env);
48
+ };
49
+
50
+ const ensureEnvConfig = async (projectDir) => {
51
+ const envPath = path.join(projectDir, '.env');
52
+ const env = readEnvFile(envPath);
53
+ const projectName = path.basename(projectDir);
54
+ const updates = {};
55
+
56
+ // Check MONGODB_URI
57
+ if (!env.MONGODB_URI) {
58
+ const { mongoChoice } = await inquirer.prompt([{
59
+ type: 'list',
60
+ name: 'mongoChoice',
61
+ message: 'MONGODB_URI not set. How would you like to configure MongoDB?',
62
+ choices: [
63
+ { name: 'Use local Docker (localhost:27017)', value: 'local' },
64
+ { name: 'Enter custom URI', value: 'custom' },
65
+ ]
66
+ }]);
67
+
68
+ if (mongoChoice === 'local') {
69
+ updates.MONGODB_URI = `mongodb://localhost:27017/${projectName}`;
70
+ } else {
71
+ const { mongoUri } = await inquirer.prompt([{
72
+ type: 'input',
73
+ name: 'mongoUri',
74
+ message: 'Enter MongoDB URI:',
75
+ default: `mongodb://localhost:27017/${projectName}`
76
+ }]);
77
+ updates.MONGODB_URI = mongoUri;
78
+ }
79
+ }
80
+
81
+ // Check REDIS_URI
82
+ if (!env.REDIS_URI) {
83
+ const { redisChoice } = await inquirer.prompt([{
84
+ type: 'list',
85
+ name: 'redisChoice',
86
+ message: 'REDIS_URI not set. How would you like to configure Redis?',
87
+ choices: [
88
+ { name: 'Use local Docker (localhost:6379)', value: 'local' },
89
+ { name: 'Enter custom URI', value: 'custom' },
90
+ { name: 'Skip (Redis optional)', value: 'skip' },
91
+ ]
92
+ }]);
93
+
94
+ if (redisChoice === 'local') {
95
+ const redisDb = hashCode(projectName) % 16;
96
+ updates.REDIS_URI = `redis://localhost:6379/${redisDb}`;
97
+ } else if (redisChoice === 'custom') {
98
+ const { redisUri } = await inquirer.prompt([{
99
+ type: 'input',
100
+ name: 'redisUri',
101
+ message: 'Enter Redis URI:',
102
+ default: `redis://localhost:6379/0`
103
+ }]);
104
+ updates.REDIS_URI = redisUri;
105
+ }
106
+ }
107
+
108
+ // Write updates if any
109
+ if (Object.keys(updates).length > 0) {
110
+ updateEnvFile(envPath, updates);
111
+ console.log(`\n Updated .env with: ${Object.keys(updates).join(', ')}\n`);
112
+ }
113
+
114
+ return { ...env, ...updates };
115
+ };
116
+
117
+ module.exports = {
118
+ readEnvFile,
119
+ writeEnvFile,
120
+ updateEnvFile,
121
+ ensureEnvConfig,
122
+ hashCode,
123
+ };
@@ -0,0 +1,32 @@
1
+ const net = require('net');
2
+
3
+ const isPortAvailable = (port) => {
4
+ return new Promise((resolve) => {
5
+ const server = net.createServer();
6
+
7
+ server.once('error', () => {
8
+ resolve(false);
9
+ });
10
+
11
+ server.once('listening', () => {
12
+ server.close();
13
+ resolve(true);
14
+ });
15
+
16
+ server.listen(port, '127.0.0.1');
17
+ });
18
+ };
19
+
20
+ const findAvailablePort = async (startPort = 3001, maxAttempts = 100) => {
21
+ for (let port = startPort; port < startPort + maxAttempts; port++) {
22
+ if (await isPortAvailable(port)) {
23
+ return port;
24
+ }
25
+ }
26
+ throw new Error(`No available port found between ${startPort} and ${startPort + maxAttempts - 1}`);
27
+ };
28
+
29
+ module.exports = {
30
+ isPortAvailable,
31
+ findAvailablePort,
32
+ };