nural 0.3.8 → 0.3.10

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/README.md DELETED
@@ -1,446 +0,0 @@
1
- <p align="center">
2
- <picture>
3
- <source media="(prefers-color-scheme: dark)" srcset="assets/logo-dark-mode.png">
4
- <source media="(prefers-color-scheme: light)" srcset="assets/logo-light-mode.png">
5
- <img alt="Nural Logo" src="assets/logo-light-mode.png" width="300">
6
- </picture>
7
- </p>
8
-
9
- # Nural
10
-
11
- <p align="center">
12
- <strong>The intelligent, schema-first REST framework for Node.js</strong>
13
- </p>
14
-
15
- <p align="center">
16
- <a href="https://www.npmjs.com/package/ "><img src="https://img.shields.io/npm/v/nural.svg" alt="npm version"></a>
17
- <a href="https://github.com/ErrorX407/nural/actions/workflows/ci.yml"><img src="https://github.com/ErrorX407/nural/actions/workflows/ci.yml/badge.svg" alt="Build Status"></a>
18
- <img src="https://img.shields.io/npm/l/nural.svg" alt="license">
19
- <a href="https://www.npmjs.com/package/nural"><img src="https://img.shields.io/npm/dm/nural.svg" alt="Downloads"></a>
20
- </p>
21
-
22
- ---
23
-
24
- ## Features
25
-
26
- - ⚡ **Type-Safe** – End-to-end TypeScript inference
27
- - 📝 **Auto Documentation** – OpenAPI spec & Scalar UI out-of-the-box
28
- - 🛡️ **Validation** – Zod-powered input/output validation
29
- - 🔄 **Response Mapping** – Auto-strip unlisted fields (no data leaks!)
30
- - 🔌 **Multi-Framework** – Works with Express & Fastify
31
- - 🎯 **Middleware Context** – Type-safe context injection
32
- - 🔒 **Built-in Security** – CORS & Helmet with zero dependencies
33
-
34
- ---
35
-
36
- ## Installation
37
-
38
- ```bash
39
- npm install nural express
40
- # or
41
- npm install nural fastify
42
- ```
43
-
44
- ---
45
-
46
- ## 🛠️ CLI
47
-
48
- Nural comes with a built-in CLI to help you scaffold projects and generate resources.
49
-
50
- ```bash
51
- # Create a new project
52
- npx nural new my-api
53
-
54
- # Generate resources
55
- npx nural generate route users
56
- npx nural generate middleware auth
57
- npx nural generate service user
58
- ```
59
-
60
- ---
61
-
62
- ## Quick Start
63
-
64
- ```typescript
65
- import { Nural, createRoute, z } from "nural";
66
-
67
- // Create app
68
- const app = new Nural({ framework: "express", docs: true });
69
-
70
- // Define a route
71
- const helloRoute = createRoute({
72
- method: "GET",
73
- path: "/hello",
74
- summary: "Health check",
75
- responses: {
76
- 200: z.object({ message: z.string() }),
77
- },
78
- handler: async () => {
79
- return { message: "Hello from Nural!", secret: "HIDDEN" };
80
- // ↑ 'secret' is auto-stripped from response!
81
- },
82
- });
83
-
84
- // Register and start
85
- app.register([helloRoute]);
86
- app.start(3000);
87
- // 🚀 Server: http://localhost:3000
88
- // 📚 Docs: http://localhost:3000/docs
89
- ```
90
-
91
- ---
92
-
93
- ## Validation
94
-
95
- ```typescript
96
- const userRoute = createRoute({
97
- method: "POST",
98
- path: "/users",
99
- request: {
100
- body: z.object({
101
- name: z.string().min(2),
102
- email: z.string().email(),
103
- }),
104
- },
105
- responses: {
106
- 201: z.object({ id: z.string(), name: z.string() }),
107
- },
108
- handler: async ({ body }) => {
109
- // body is typed as { name: string, email: string }
110
- return { id: "uuid", name: body.name };
111
- },
112
- });
113
- ```
114
-
115
- ---
116
-
117
- ## Middleware
118
-
119
- ```typescript
120
- import { defineMiddleware } from "nural";
121
-
122
- const authMiddleware = defineMiddleware(async (req) => {
123
- const token = req.headers.authorization;
124
- if (!token) throw new Error("Unauthorized");
125
- return { user: { id: "123", role: "admin" } };
126
- });
127
-
128
- const meRoute = createRoute({
129
- method: "GET",
130
- path: "/me",
131
- middleware: [authMiddleware],
132
- responses: { 200: z.object({ id: z.string(), role: z.string() }) },
133
- handler: async ({ user }) => {
134
- // ↑ 'user' is inferred from middleware!
135
- return user;
136
- },
137
- });
138
- ```
139
-
140
- ---
141
-
142
- ## CORS & Helmet (Built-in Security)
143
-
144
- ```typescript
145
- // Enable with defaults
146
- const app = new Nural({
147
- cors: true,
148
- helmet: true,
149
- });
150
-
151
- // Or with full configuration
152
- const app = new Nural({
153
- cors: {
154
- origin: "https://example.com",
155
- methods: ["GET", "POST"],
156
- credentials: true,
157
- },
158
- helmet: {
159
- contentSecurityPolicy: false,
160
- hsts: { maxAge: 31536000, includeSubDomains: true },
161
- },
162
- });
163
- },
164
- });
165
- ```
166
-
167
- ---
168
-
169
- ## Unified Exception System
170
-
171
- Throw standard exceptions anywhere in your code, and Nural automatically formats them into standard JSON error responses.
172
-
173
- ```typescript
174
- import { NotFoundException, UnauthorizedException } from "nural";
175
-
176
- // In your service or handler
177
- if (!user) {
178
- throw new NotFoundException("User not found");
179
- }
180
-
181
- if (!token) {
182
- throw new UnauthorizedException("Missing token");
183
- }
184
- ```
185
-
186
- **Result:**
187
-
188
- ```json
189
- {
190
- "statusCode": 404,
191
- "message": "User not found",
192
- "error": "Not Found",
193
- "timestamp": "2026-02-08T12:00:00.000Z"
194
- }
195
- ```
196
-
197
- ---
198
-
199
- ## Global Error Handler
200
-
201
- ```typescript
202
- // Enable with defaults (smart error mapping)
203
- const app = new Nural({ errorHandler: true });
204
-
205
- // Custom error handler (e.g., Sentry integration)
206
- const app = new Nural({
207
- errorHandler: (ctx) => {
208
- Sentry.captureException(ctx.error);
209
- return {
210
- status: 500,
211
- body: { error: "Something went wrong" },
212
- };
213
- },
214
- });
215
-
216
- // Full configuration
217
- const app = new Nural({
218
- errorHandler: {
219
- handler: customHandler,
220
- includeStack: process.env.NODE_ENV !== "production",
221
- logErrors: true,
222
- logger: (err, ctx) => winston.error(err.message, { path: ctx.path }),
223
- },
224
- });
225
- ```
226
-
227
- **Smart defaults:** Automatically maps `"unauthorized"` → 401, `"not found"` → 404, Zod errors → 400.
228
-
229
- ### Available Exceptions
230
-
231
- | Exception | Status Code |
232
- | :------------------------------ | :---------- |
233
- | `BadRequestException` | 400 |
234
- | `UnauthorizedException` | 401 |
235
- | `ForbiddenException` | 403 |
236
- | `NotFoundException` | 404 |
237
- | `ConflictException` | 409 |
238
- | `GoneException` | 410 |
239
- | `PayloadTooLargeException` | 413 |
240
- | `UnsupportedMediaTypeException` | 415 |
241
- | `UnprocessableEntityException` | 422 |
242
- | `InternalServerErrorException` | 500 |
243
- | `NotImplementedException` | 501 |
244
- | `BadGatewayException` | 502 |
245
- | `ServiceUnavailableException` | 503 |
246
- | `GatewayTimeoutException` | 504 |
247
-
248
- ---
249
-
250
- ## Logger
251
-
252
- Nural comes with a built-in, zero-dependency logger that is lightweight and colorful.
253
-
254
- ```typescript
255
- import { Logger } from "nural";
256
-
257
- const logger = new Logger("MyService");
258
-
259
- logger.log("This is a log message");
260
- logger.warn("Be careful!");
261
- logger.error("Something went wrong");
262
- // Output: [Nural] 1234 - 2026-02-08... [MyService] This is a log message
263
- ```
264
-
265
- ### HTTP Logger
266
-
267
- The HTTP logger middleware is enabled by default and logs all incoming requests with their status and duration.
268
-
269
- ```typescript
270
- const app = new Nural({
271
- logger: {
272
- enabled: true,
273
- showUserAgent: true, // Log User-Agent header
274
- showTime: true, // Log request duration (default: true)
275
- },
276
- });
277
- ```
278
-
279
- ---
280
-
281
- ## Configuration
282
-
283
- ```typescript
284
- const app = new Nural({
285
- framework: "fastify", // or 'express'
286
- cors: true, // Enable CORS with defaults
287
- helmet: true, // Enable security headers with defaults
288
-
289
- // Documentation
290
- docs: {
291
- enabled: true,
292
- path: "/api-docs",
293
- ui: "scalar", // 'scalar' (default) or 'swagger'
294
-
295
- // Full OpenAPI Customization
296
- openApi: {
297
- info: {
298
- title: "My API",
299
- version: "2.0.0",
300
- description: "My awesome API",
301
- },
302
- servers: [{ url: "https://api.example.com" }],
303
- // Add Security Schemes (e.g., API Key, Bearer Token)
304
- components: {
305
- securitySchemes: {
306
- bearerAuth: {
307
- type: "http",
308
- scheme: "bearer",
309
- bearerFormat: "JWT",
310
- },
311
- },
312
- },
313
- // Apply Global Security
314
- security: [{ bearerAuth: [] }],
315
- },
316
-
317
- // Scalar UI Options (fully typed)
318
- scalar: {
319
- theme: "moon", // 'alternate', 'default', 'moon', 'purple', 'solarized', etc.
320
- layout: "modern",
321
- showSidebar: true,
322
- hideModels: true,
323
- darkMode: true,
324
- // Custom Metadata
325
- metaData: { title: "API Docs" },
326
- // Authentication Pre-fill
327
- authentication: {
328
- preferredSecurityScheme: "bearerAuth",
329
- securitySchemes: {
330
- bearerAuth: { token: "EXAMPLE_TOKEN" },
331
- },
332
- },
333
- },
334
-
335
- // Swagger UI Options (fully typed)
336
- swagger: {
337
- theme: "outline", // 'outline', 'classic', or 'no-theme'
338
- options: {
339
- persistAuthorization: true,
340
- docExpansion: "list",
341
- defaultModelsExpandDepth: -1,
342
- filter: true,
343
- syntaxHighlight: { theme: "monokai" },
344
- },
345
- },
346
- },
347
-
348
- // Logger
349
- logger: {
350
- enabled: true,
351
- showUserAgent: false,
352
- showTime: true,
353
- },
354
-
355
- // Error Handling
356
- errorHandler: {
357
- handler: customHandler, // Optional custom handler
358
- includeStack: false, // Hide stack traces in production
359
- logErrors: true, // Log errors to console
360
- },
361
- });
362
- ```
363
-
364
- ---
365
-
366
- ## API Reference
367
-
368
- ### `createRoute(config)`
369
-
370
- | Property | Type | Description |
371
- | ---------------- | --------------------------- | ---------------------------------------------- |
372
- | `method` | `HttpMethod` | GET, POST, PUT, PATCH, DELETE |
373
- | `path` | `string` | Route path (supports `:param`) |
374
- | `summary` | `string?` | Short description for docs |
375
- | `description` | `string?` | Detailed description |
376
- | `tags` | `string[]?` | Grouping for docs |
377
- | `middleware` | `array?` | Middleware functions |
378
- | `request.params` | `ZodSchema?` | Path params validation |
379
- | `request.query` | `ZodSchema?` | Query params validation |
380
- | `request.body` | `ZodSchema?` | Body validation |
381
- | `responses` | `Record<number, ZodSchema>` | Response schemas |
382
- | `security` | `array?` | OpenAPI security (e.g. `[{ bearerAuth: [] }]`) |
383
- | `openapi` | `object?` | OpenAPI operation overrides |
384
- | `handler` | `function` | Route handler |
385
-
386
- ### Per-Route Configuration (Security & Headers)
387
-
388
- You can define security requirements or override OpenAPI properties directly on the route:
389
-
390
- ```typescript
391
- const protectedRoute = createRoute({
392
- method: "GET",
393
- path: "/protected",
394
- // Define security requirements
395
- security: [{ bearerAuth: [] }],
396
- // Override OpenAPI operation (e.g., custom headers)
397
- openapi: {
398
- parameters: [
399
- {
400
- in: "header",
401
- name: "X-Custom-Header",
402
- schema: { type: "string" },
403
- required: true,
404
- },
405
- ],
406
- },
407
- handler: async () => {
408
- return { secret: "data" };
409
- },
410
- });
411
- ```
412
-
413
- ### Route Context (`ctx`)
414
-
415
- The `handler` receives a `ctx` object containing:
416
-
417
- ```typescript
418
- {
419
- params: { id: "123" }, // Validated path params
420
- query: { page: 1 }, // Validated query params
421
- body: { name: "John" }, // Validated body
422
- req: Request, // Native request object
423
- res: Response, // Native response object
424
- ...middlewareProps // Properties injected by middleware
425
- }
426
- ```
427
-
428
- ### `defineMiddleware(fn)`
429
-
430
- Creates a type-safe middleware that injects context into handlers.
431
-
432
- ### `new Nural(config)`
433
-
434
- | Property | Type | Default | Description |
435
- | -------------- | ------------------------------ | ----------- | ------------------------ |
436
- | `framework` | `'express' \| 'fastify'` | `'express'` | Server framework |
437
- | `docs` | `boolean \| DocsConfig` | `true` | Documentation settings |
438
- | `cors` | `boolean \| CorsConfig` | `false` | CORS middleware settings |
439
- | `helmet` | `boolean \| HelmetConfig` | `false` | Security headers |
440
- | `errorHandler` | `boolean \| fn \| ErrorConfig` | `true` | Global error handling |
441
-
442
- ---
443
-
444
- ## License
445
-
446
- MIT © [Chetan Joshi](https://github.com/ErrorX407)
@@ -1,221 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- var commander = require('commander');
5
- var inquirer = require('inquirer');
6
- var chalk = require('chalk');
7
- var fs = require('fs-extra');
8
- var path = require('path');
9
-
10
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
-
12
- var inquirer__default = /*#__PURE__*/_interopDefault(inquirer);
13
- var chalk__default = /*#__PURE__*/_interopDefault(chalk);
14
- var fs__default = /*#__PURE__*/_interopDefault(fs);
15
- var path__default = /*#__PURE__*/_interopDefault(path);
16
-
17
- var program = new commander.Command();
18
- program.name("nural").description("Nural Framework CLI").version("0.3.8");
19
- program.command("new <project-name>").description("Create a new Nural project").action(async (projectName) => {
20
- const projectPath = path__default.default.join(process.cwd(), projectName);
21
- if (fs__default.default.existsSync(projectPath)) {
22
- console.error(
23
- chalk__default.default.red(`Error: Directory ${projectName} already exists.`)
24
- );
25
- process.exit(1);
26
- }
27
- const { framework } = await inquirer__default.default.prompt([
28
- {
29
- type: "list",
30
- name: "framework",
31
- message: "Select a framework (express/fastify):",
32
- choices: [
33
- {
34
- name: "express",
35
- value: "express",
36
- description: "Fast, unopinionated, minimalist web framework"
37
- },
38
- {
39
- name: "fastify",
40
- value: "fastify",
41
- description: "Fast and low overhead web framework"
42
- }
43
- ],
44
- default: "express"
45
- }
46
- ]);
47
- console.log(
48
- chalk__default.default.blue(`
49
- Initializing new Nural project in ${projectName}...`)
50
- );
51
- fs__default.default.ensureDirSync(path__default.default.join(projectPath, "src/config"));
52
- fs__default.default.ensureDirSync(path__default.default.join(projectPath, "src/routes"));
53
- fs__default.default.ensureDirSync(path__default.default.join(projectPath, "src/middleware"));
54
- fs__default.default.ensureDirSync(path__default.default.join(projectPath, "src/services"));
55
- const packageJson = {
56
- name: projectName,
57
- version: "1.0.0",
58
- main: "dist/index.js",
59
- scripts: {
60
- dev: "nodemon --exec tsx src/index.ts",
61
- build: "tsup src/index.ts --format cjs,esm --dts",
62
- start: "node dist/index.js"
63
- },
64
- dependencies: {
65
- nural: "^0.3.8",
66
- [framework]: framework === "express" ? "^5.0.0" : "^5.0.0",
67
- // Using explicit versions for peer deps
68
- zod: "^3.22.4"
69
- },
70
- devDependencies: {
71
- tsx: "^4.7.1",
72
- tsup: "^8.0.2",
73
- typescript: "^5.3.3",
74
- nodemon: "^3.1.11",
75
- "@types/node": "^20.11.24",
76
- ...framework === "express" ? { "@types/express": "^5.0.0" } : {}
77
- }
78
- };
79
- fs__default.default.writeJsonSync(path__default.default.join(projectPath, "package.json"), packageJson, {
80
- spaces: 2
81
- });
82
- const tsconfig = {
83
- compilerOptions: {
84
- target: "ES2020",
85
- module: "CommonJS",
86
- moduleResolution: "node",
87
- strict: true,
88
- esModuleInterop: true,
89
- skipLibCheck: true,
90
- forceConsistentCasingInFileNames: true,
91
- outDir: "./dist"
92
- },
93
- include: ["src/**/*"],
94
- exclude: ["node_modules"]
95
- };
96
- fs__default.default.writeJsonSync(path__default.default.join(projectPath, "tsconfig.json"), tsconfig, {
97
- spaces: 2
98
- });
99
- const indexContent = `import { Nural } from "nural";
100
- import { appConfig } from "./config/app.config";
101
-
102
- const app = new Nural(appConfig);
103
-
104
- app.start(3000)
105
- `;
106
- fs__default.default.writeFileSync(path__default.default.join(projectPath, "src/index.ts"), indexContent);
107
- const configContent = `import { NuralConfig } from "nural";
108
-
109
- export const appConfig: NuralConfig = {
110
- framework: "${framework}",
111
- docs: true,
112
- logger: {
113
- enabled: true,
114
- },
115
- };
116
- `;
117
- fs__default.default.writeFileSync(
118
- path__default.default.join(projectPath, "src/config/app.config.ts"),
119
- configContent
120
- );
121
- console.log(
122
- chalk__default.default.green(`
123
- \u2714 Project ${projectName} created successfully!`)
124
- );
125
- console.log(chalk__default.default.white(`
126
- Next steps:`));
127
- console.log(chalk__default.default.cyan(` cd ${projectName}`));
128
- console.log(chalk__default.default.cyan(` npm install`));
129
- console.log(chalk__default.default.cyan(` npm run dev`));
130
- });
131
- program.command("generate <type> <name>").alias("g").description("Generate a resource (route, middleware, service)").action((typeArg, nameArg) => {
132
- const type = typeArg.toLowerCase();
133
- const name = nameArg.toLowerCase();
134
- const srcDir = path__default.default.join(process.cwd(), "src");
135
- if (!fs__default.default.existsSync(srcDir)) {
136
- console.error(
137
- chalk__default.default.red(
138
- "Error: src directory not found. Are you in a Nural project root?"
139
- )
140
- );
141
- process.exit(1);
142
- }
143
- const capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1);
144
- switch (type) {
145
- case "route": {
146
- const routeContent = `import { createRoute, z } from "nural";
147
-
148
- export const ${name}Route = createRoute({
149
- method: "GET",
150
- path: "/${name}",
151
- summary: "${capitalize(name)} route",
152
- responses: {
153
- 200: z.object({ message: z.string() }),
154
- },
155
- handler: async () => {
156
- return { message: "Hello from ${name}" };
157
- },
158
-
159
- export const ${name}Routes = [${name}Route]
160
- });
161
- `;
162
- const routesDir = path__default.default.join(srcDir, "routes");
163
- fs__default.default.ensureDirSync(routesDir);
164
- fs__default.default.writeFileSync(
165
- path__default.default.join(routesDir, `${name}.routes.ts`),
166
- routeContent
167
- );
168
- console.log(chalk__default.default.green(`Created src/routes/${name}.routes.ts`));
169
- break;
170
- }
171
- case "middleware": {
172
- const middlewareContent = `import { defineMiddleware } from "nural";
173
-
174
- export const ${name}Middleware = defineMiddleware(async (req, res) => {
175
- // TODO: Implement middleware logic
176
- return { ${name}: true };
177
- });
178
- `;
179
- const middlewareDir = path__default.default.join(srcDir, "middleware");
180
- fs__default.default.ensureDirSync(middlewareDir);
181
- fs__default.default.writeFileSync(
182
- path__default.default.join(middlewareDir, `${name}.middleware.ts`),
183
- middlewareContent
184
- );
185
- console.log(
186
- chalk__default.default.green(`Created src/middleware/${name}.middleware.ts`)
187
- );
188
- break;
189
- }
190
- case "service": {
191
- const serviceContent = `export class ${capitalize(name)}Service {
192
- constructor() {}
193
-
194
- async findAll() {
195
- return [];
196
- }
197
- }
198
-
199
- export const ${name}Service = new ${capitalize(name)}Service();
200
- `;
201
- const servicesDir = path__default.default.join(srcDir, "services");
202
- fs__default.default.ensureDirSync(servicesDir);
203
- fs__default.default.writeFileSync(
204
- path__default.default.join(servicesDir, `${name}.service.ts`),
205
- serviceContent
206
- );
207
- console.log(chalk__default.default.green(`Created src/services/${name}.service.ts`));
208
- break;
209
- }
210
- default:
211
- console.error(
212
- chalk__default.default.red(
213
- `Unknown type: ${type}. Supported: route, middleware, service`
214
- )
215
- );
216
- process.exit(1);
217
- }
218
- });
219
- program.parse(process.argv);
220
- //# sourceMappingURL=index.cjs.map
221
- //# sourceMappingURL=index.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/cli/index.ts"],"names":["Command","path","fs","chalk","inquirer"],"mappings":"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","file":"index.cjs","sourcesContent":["import { Command } from \"commander\";\nimport inquirer from \"inquirer\";\nimport chalk from \"chalk\";\nimport fs from \"fs-extra\";\nimport path from \"path\";\n\nconst program = new Command();\n\nprogram.name(\"nural\").description(\"Nural Framework CLI\").version(\"0.3.8\");\n\nprogram\n .command(\"new <project-name>\")\n .description(\"Create a new Nural project\")\n .action(async (projectName) => {\n const projectPath = path.join(process.cwd(), projectName);\n\n if (fs.existsSync(projectPath)) {\n console.error(\n chalk.red(`Error: Directory ${projectName} already exists.`),\n );\n process.exit(1);\n }\n\n const { framework } = await inquirer.prompt([\n {\n type: \"list\",\n name: \"framework\",\n message: \"Select a framework (express/fastify):\",\n choices: [\n {\n name: \"express\",\n value: \"express\",\n description: \"Fast, unopinionated, minimalist web framework\",\n },\n {\n name: \"fastify\",\n value: \"fastify\",\n description: \"Fast and low overhead web framework\",\n },\n ],\n default: \"express\",\n },\n ]);\n\n console.log(\n chalk.blue(`\\nInitializing new Nural project in ${projectName}...`),\n );\n\n // Create directories\n fs.ensureDirSync(path.join(projectPath, \"src/config\"));\n fs.ensureDirSync(path.join(projectPath, \"src/routes\"));\n fs.ensureDirSync(path.join(projectPath, \"src/middleware\"));\n fs.ensureDirSync(path.join(projectPath, \"src/services\"));\n\n // Create package.json\n const packageJson = {\n name: projectName,\n version: \"1.0.0\",\n main: \"dist/index.js\",\n scripts: {\n dev: \"nodemon --exec tsx src/index.ts\",\n build: \"tsup src/index.ts --format cjs,esm --dts\",\n start: \"node dist/index.js\",\n },\n dependencies: {\n nural: \"^0.3.8\",\n [framework]: framework === \"express\" ? \"^5.0.0\" : \"^5.0.0\", // Using explicit versions for peer deps\n zod: \"^3.22.4\",\n },\n devDependencies: {\n tsx: \"^4.7.1\",\n tsup: \"^8.0.2\",\n typescript: \"^5.3.3\",\n nodemon: \"^3.1.11\",\n \"@types/node\": \"^20.11.24\",\n ...(framework === \"express\" ? { \"@types/express\": \"^5.0.0\" } : {}),\n },\n };\n\n fs.writeJsonSync(path.join(projectPath, \"package.json\"), packageJson, {\n spaces: 2,\n });\n\n // Create tsconfig.json\n const tsconfig = {\n compilerOptions: {\n target: \"ES2020\",\n module: \"CommonJS\",\n moduleResolution: \"node\",\n strict: true,\n esModuleInterop: true,\n skipLibCheck: true,\n forceConsistentCasingInFileNames: true,\n outDir: \"./dist\",\n },\n include: [\"src/**/*\"],\n exclude: [\"node_modules\"],\n };\n\n fs.writeJsonSync(path.join(projectPath, \"tsconfig.json\"), tsconfig, {\n spaces: 2,\n });\n\n // Create src/index.ts\n const indexContent = `import { Nural } from \"nural\";\nimport { appConfig } from \"./config/app.config\";\n\nconst app = new Nural(appConfig);\n\napp.start(3000)\n`;\n fs.writeFileSync(path.join(projectPath, \"src/index.ts\"), indexContent);\n\n // Create src/config/app.config.ts\n const configContent = `import { NuralConfig } from \"nural\";\n\nexport const appConfig: NuralConfig = {\n framework: \"${framework}\",\n docs: true,\n logger: {\n enabled: true,\n },\n};\n`;\n fs.writeFileSync(\n path.join(projectPath, \"src/config/app.config.ts\"),\n configContent,\n );\n\n console.log(\n chalk.green(`\\n✔ Project ${projectName} created successfully!`),\n );\n console.log(chalk.white(`\\nNext steps:`));\n console.log(chalk.cyan(` cd ${projectName}`));\n console.log(chalk.cyan(` npm install`));\n console.log(chalk.cyan(` npm run dev`));\n });\n\nprogram\n .command(\"generate <type> <name>\")\n .alias(\"g\")\n .description(\"Generate a resource (route, middleware, service)\")\n .action((typeArg, nameArg) => {\n const type = typeArg.toLowerCase();\n const name = nameArg.toLowerCase();\n const srcDir = path.join(process.cwd(), \"src\");\n\n if (!fs.existsSync(srcDir)) {\n console.error(\n chalk.red(\n \"Error: src directory not found. Are you in a Nural project root?\",\n ),\n );\n process.exit(1);\n }\n\n const capitalize = (s: string) => s.charAt(0).toUpperCase() + s.slice(1);\n\n switch (type) {\n case \"route\": {\n const routeContent = `import { createRoute, z } from \"nural\";\n\nexport const ${name}Route = createRoute({\n method: \"GET\",\n path: \"/${name}\",\n summary: \"${capitalize(name)} route\",\n responses: {\n 200: z.object({ message: z.string() }),\n },\n handler: async () => {\n return { message: \"Hello from ${name}\" };\n },\n\n export const ${name}Routes = [${name}Route]\n});\n`;\n const routesDir = path.join(srcDir, \"routes\");\n fs.ensureDirSync(routesDir);\n fs.writeFileSync(\n path.join(routesDir, `${name}.routes.ts`),\n routeContent,\n );\n console.log(chalk.green(`Created src/routes/${name}.routes.ts`));\n break;\n }\n case \"middleware\": {\n const middlewareContent = `import { defineMiddleware } from \"nural\";\n\nexport const ${name}Middleware = defineMiddleware(async (req, res) => {\n // TODO: Implement middleware logic\n return { ${name}: true };\n});\n`;\n const middlewareDir = path.join(srcDir, \"middleware\");\n fs.ensureDirSync(middlewareDir);\n fs.writeFileSync(\n path.join(middlewareDir, `${name}.middleware.ts`),\n middlewareContent,\n );\n console.log(\n chalk.green(`Created src/middleware/${name}.middleware.ts`),\n );\n break;\n }\n case \"service\": {\n const serviceContent = `export class ${capitalize(name)}Service {\n constructor() {}\n\n async findAll() {\n return [];\n }\n}\n\nexport const ${name}Service = new ${capitalize(name)}Service();\n`;\n const servicesDir = path.join(srcDir, \"services\");\n fs.ensureDirSync(servicesDir);\n fs.writeFileSync(\n path.join(servicesDir, `${name}.service.ts`),\n serviceContent,\n );\n console.log(chalk.green(`Created src/services/${name}.service.ts`));\n break;\n }\n default:\n console.error(\n chalk.red(\n `Unknown type: ${type}. Supported: route, middleware, service`,\n ),\n );\n process.exit(1);\n }\n });\n\nprogram.parse(process.argv);\n"]}
@@ -1,2 +0,0 @@
1
-
2
- export { }
@@ -1,2 +0,0 @@
1
-
2
- export { }