nural 0.2.0 → 0.3.2

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 CHANGED
@@ -43,6 +43,22 @@ npm install nural fastify
43
43
 
44
44
  ---
45
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
+
46
62
  ## Quick Start
47
63
 
48
64
  ```typescript
@@ -0,0 +1,209 @@
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.2");
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:",
32
+ choices: ["express", "fastify"],
33
+ default: "express"
34
+ }
35
+ ]);
36
+ console.log(
37
+ chalk__default.default.blue(`
38
+ Initializing new Nural project in ${projectName}...`)
39
+ );
40
+ fs__default.default.ensureDirSync(path__default.default.join(projectPath, "src/config"));
41
+ fs__default.default.ensureDirSync(path__default.default.join(projectPath, "src/routes"));
42
+ fs__default.default.ensureDirSync(path__default.default.join(projectPath, "src/middleware"));
43
+ fs__default.default.ensureDirSync(path__default.default.join(projectPath, "src/services"));
44
+ const packageJson = {
45
+ name: projectName,
46
+ version: "1.0.0",
47
+ main: "dist/index.js",
48
+ scripts: {
49
+ dev: "tsx watch src/index.ts",
50
+ build: "tsup src/index.ts --format cjs,esm --dts",
51
+ start: "node dist/index.js"
52
+ },
53
+ dependencies: {
54
+ nural: "^0.2.0",
55
+ [framework]: framework === "express" ? "^5.0.0" : "^5.0.0",
56
+ // Using explicit versions for peer deps
57
+ zod: "^3.22.4"
58
+ },
59
+ devDependencies: {
60
+ tsx: "^4.7.1",
61
+ tsup: "^8.0.2",
62
+ typescript: "^5.3.3",
63
+ "@types/node": "^20.11.24",
64
+ ...framework === "express" ? { "@types/express": "^5.0.0" } : {}
65
+ }
66
+ };
67
+ fs__default.default.writeJsonSync(path__default.default.join(projectPath, "package.json"), packageJson, {
68
+ spaces: 2
69
+ });
70
+ const tsconfig = {
71
+ compilerOptions: {
72
+ target: "ES2020",
73
+ module: "CommonJS",
74
+ moduleResolution: "node",
75
+ strict: true,
76
+ esModuleInterop: true,
77
+ skipLibCheck: true,
78
+ forceConsistentCasingInFileNames: true,
79
+ outDir: "./dist"
80
+ },
81
+ include: ["src/**/*"],
82
+ exclude: ["node_modules"]
83
+ };
84
+ fs__default.default.writeJsonSync(path__default.default.join(projectPath, "tsconfig.json"), tsconfig, {
85
+ spaces: 2
86
+ });
87
+ const indexContent = `import { Nural } from "nural";
88
+ import { appConfig } from "./config/app.config";
89
+
90
+ const app = new Nural(appConfig);
91
+
92
+ app.start(3000).then(() => {
93
+ console.log("Server is running on http://localhost:3000");
94
+ });
95
+ `;
96
+ fs__default.default.writeFileSync(path__default.default.join(projectPath, "src/index.ts"), indexContent);
97
+ const configContent = `import { NuralConfig } from "nural";
98
+
99
+ export const appConfig: NuralConfig = {
100
+ framework: "${framework}",
101
+ docs: true,
102
+ logger: {
103
+ enabled: true,
104
+ },
105
+ };
106
+ `;
107
+ fs__default.default.writeFileSync(
108
+ path__default.default.join(projectPath, "src/config/app.config.ts"),
109
+ configContent
110
+ );
111
+ console.log(
112
+ chalk__default.default.green(`
113
+ \u2714 Project ${projectName} created successfully!`)
114
+ );
115
+ console.log(chalk__default.default.white(`
116
+ Next steps:`));
117
+ console.log(chalk__default.default.cyan(` cd ${projectName}`));
118
+ console.log(chalk__default.default.cyan(` npm install`));
119
+ console.log(chalk__default.default.cyan(` npm run dev`));
120
+ });
121
+ program.command("generate <type> <name>").alias("g").description("Generate a resource (route, middleware, service)").action((typeArg, nameArg) => {
122
+ const type = typeArg.toLowerCase();
123
+ const name = nameArg.toLowerCase();
124
+ const srcDir = path__default.default.join(process.cwd(), "src");
125
+ if (!fs__default.default.existsSync(srcDir)) {
126
+ console.error(
127
+ chalk__default.default.red(
128
+ "Error: src directory not found. Are you in a Nural project root?"
129
+ )
130
+ );
131
+ process.exit(1);
132
+ }
133
+ const capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1);
134
+ switch (type) {
135
+ case "route": {
136
+ const routeContent = `import { createRoute, z } from "nural";
137
+
138
+ export const ${name}Route = createRoute({
139
+ method: "GET",
140
+ path: "/${name}",
141
+ summary: "${capitalize(name)} route",
142
+ responses: {
143
+ 200: z.object({ message: z.string() }),
144
+ },
145
+ handler: async () => {
146
+ return { message: "Hello from ${name}" };
147
+ },
148
+ });
149
+ `;
150
+ const routesDir = path__default.default.join(srcDir, "routes");
151
+ fs__default.default.ensureDirSync(routesDir);
152
+ fs__default.default.writeFileSync(
153
+ path__default.default.join(routesDir, `${name}.routes.ts`),
154
+ routeContent
155
+ );
156
+ console.log(chalk__default.default.green(`Created src/routes/${name}.routes.ts`));
157
+ break;
158
+ }
159
+ case "middleware": {
160
+ const middlewareContent = `import { defineMiddleware } from "nural";
161
+
162
+ export const ${name}Middleware = defineMiddleware(async (req, res) => {
163
+ // TODO: Implement middleware logic
164
+ return { ${name}: true };
165
+ });
166
+ `;
167
+ const middlewareDir = path__default.default.join(srcDir, "middleware");
168
+ fs__default.default.ensureDirSync(middlewareDir);
169
+ fs__default.default.writeFileSync(
170
+ path__default.default.join(middlewareDir, `${name}.middleware.ts`),
171
+ middlewareContent
172
+ );
173
+ console.log(
174
+ chalk__default.default.green(`Created src/middleware/${name}.middleware.ts`)
175
+ );
176
+ break;
177
+ }
178
+ case "service": {
179
+ const serviceContent = `export class ${capitalize(name)}Service {
180
+ constructor() {}
181
+
182
+ async findAll() {
183
+ return [];
184
+ }
185
+ }
186
+
187
+ export const ${name}Service = new ${capitalize(name)}Service();
188
+ `;
189
+ const servicesDir = path__default.default.join(srcDir, "services");
190
+ fs__default.default.ensureDirSync(servicesDir);
191
+ fs__default.default.writeFileSync(
192
+ path__default.default.join(servicesDir, `${name}.service.ts`),
193
+ serviceContent
194
+ );
195
+ console.log(chalk__default.default.green(`Created src/services/${name}.service.ts`));
196
+ break;
197
+ }
198
+ default:
199
+ console.error(
200
+ chalk__default.default.red(
201
+ `Unknown type: ${type}. Supported: route, middleware, service`
202
+ )
203
+ );
204
+ process.exit(1);
205
+ }
206
+ });
207
+ program.parse(process.argv);
208
+ //# sourceMappingURL=index.cjs.map
209
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/index.ts"],"names":["Command","path","fs","chalk","inquirer"],"mappings":"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","file":"index.cjs","sourcesContent":["#!/usr/bin/env node\n\nimport { 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.2\");\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:\",\n choices: [\"express\", \"fastify\"],\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: \"tsx watch 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.2.0\",\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 \"@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).then(() => {\n console.log(\"Server is running on http://localhost:3000\");\n});\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`;\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"]}
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,200 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import inquirer from 'inquirer';
4
+ import chalk from 'chalk';
5
+ import fs from 'fs-extra';
6
+ import path from 'path';
7
+
8
+ var program = new Command();
9
+ program.name("nural").description("Nural Framework CLI").version("0.3.2");
10
+ program.command("new <project-name>").description("Create a new Nural project").action(async (projectName) => {
11
+ const projectPath = path.join(process.cwd(), projectName);
12
+ if (fs.existsSync(projectPath)) {
13
+ console.error(
14
+ chalk.red(`Error: Directory ${projectName} already exists.`)
15
+ );
16
+ process.exit(1);
17
+ }
18
+ const { framework } = await inquirer.prompt([
19
+ {
20
+ type: "list",
21
+ name: "framework",
22
+ message: "Select a framework:",
23
+ choices: ["express", "fastify"],
24
+ default: "express"
25
+ }
26
+ ]);
27
+ console.log(
28
+ chalk.blue(`
29
+ Initializing new Nural project in ${projectName}...`)
30
+ );
31
+ fs.ensureDirSync(path.join(projectPath, "src/config"));
32
+ fs.ensureDirSync(path.join(projectPath, "src/routes"));
33
+ fs.ensureDirSync(path.join(projectPath, "src/middleware"));
34
+ fs.ensureDirSync(path.join(projectPath, "src/services"));
35
+ const packageJson = {
36
+ name: projectName,
37
+ version: "1.0.0",
38
+ main: "dist/index.js",
39
+ scripts: {
40
+ dev: "tsx watch src/index.ts",
41
+ build: "tsup src/index.ts --format cjs,esm --dts",
42
+ start: "node dist/index.js"
43
+ },
44
+ dependencies: {
45
+ nural: "^0.2.0",
46
+ [framework]: framework === "express" ? "^5.0.0" : "^5.0.0",
47
+ // Using explicit versions for peer deps
48
+ zod: "^3.22.4"
49
+ },
50
+ devDependencies: {
51
+ tsx: "^4.7.1",
52
+ tsup: "^8.0.2",
53
+ typescript: "^5.3.3",
54
+ "@types/node": "^20.11.24",
55
+ ...framework === "express" ? { "@types/express": "^5.0.0" } : {}
56
+ }
57
+ };
58
+ fs.writeJsonSync(path.join(projectPath, "package.json"), packageJson, {
59
+ spaces: 2
60
+ });
61
+ const tsconfig = {
62
+ compilerOptions: {
63
+ target: "ES2020",
64
+ module: "CommonJS",
65
+ moduleResolution: "node",
66
+ strict: true,
67
+ esModuleInterop: true,
68
+ skipLibCheck: true,
69
+ forceConsistentCasingInFileNames: true,
70
+ outDir: "./dist"
71
+ },
72
+ include: ["src/**/*"],
73
+ exclude: ["node_modules"]
74
+ };
75
+ fs.writeJsonSync(path.join(projectPath, "tsconfig.json"), tsconfig, {
76
+ spaces: 2
77
+ });
78
+ const indexContent = `import { Nural } from "nural";
79
+ import { appConfig } from "./config/app.config";
80
+
81
+ const app = new Nural(appConfig);
82
+
83
+ app.start(3000).then(() => {
84
+ console.log("Server is running on http://localhost:3000");
85
+ });
86
+ `;
87
+ fs.writeFileSync(path.join(projectPath, "src/index.ts"), indexContent);
88
+ const configContent = `import { NuralConfig } from "nural";
89
+
90
+ export const appConfig: NuralConfig = {
91
+ framework: "${framework}",
92
+ docs: true,
93
+ logger: {
94
+ enabled: true,
95
+ },
96
+ };
97
+ `;
98
+ fs.writeFileSync(
99
+ path.join(projectPath, "src/config/app.config.ts"),
100
+ configContent
101
+ );
102
+ console.log(
103
+ chalk.green(`
104
+ \u2714 Project ${projectName} created successfully!`)
105
+ );
106
+ console.log(chalk.white(`
107
+ Next steps:`));
108
+ console.log(chalk.cyan(` cd ${projectName}`));
109
+ console.log(chalk.cyan(` npm install`));
110
+ console.log(chalk.cyan(` npm run dev`));
111
+ });
112
+ program.command("generate <type> <name>").alias("g").description("Generate a resource (route, middleware, service)").action((typeArg, nameArg) => {
113
+ const type = typeArg.toLowerCase();
114
+ const name = nameArg.toLowerCase();
115
+ const srcDir = path.join(process.cwd(), "src");
116
+ if (!fs.existsSync(srcDir)) {
117
+ console.error(
118
+ chalk.red(
119
+ "Error: src directory not found. Are you in a Nural project root?"
120
+ )
121
+ );
122
+ process.exit(1);
123
+ }
124
+ const capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1);
125
+ switch (type) {
126
+ case "route": {
127
+ const routeContent = `import { createRoute, z } from "nural";
128
+
129
+ export const ${name}Route = createRoute({
130
+ method: "GET",
131
+ path: "/${name}",
132
+ summary: "${capitalize(name)} route",
133
+ responses: {
134
+ 200: z.object({ message: z.string() }),
135
+ },
136
+ handler: async () => {
137
+ return { message: "Hello from ${name}" };
138
+ },
139
+ });
140
+ `;
141
+ const routesDir = path.join(srcDir, "routes");
142
+ fs.ensureDirSync(routesDir);
143
+ fs.writeFileSync(
144
+ path.join(routesDir, `${name}.routes.ts`),
145
+ routeContent
146
+ );
147
+ console.log(chalk.green(`Created src/routes/${name}.routes.ts`));
148
+ break;
149
+ }
150
+ case "middleware": {
151
+ const middlewareContent = `import { defineMiddleware } from "nural";
152
+
153
+ export const ${name}Middleware = defineMiddleware(async (req, res) => {
154
+ // TODO: Implement middleware logic
155
+ return { ${name}: true };
156
+ });
157
+ `;
158
+ const middlewareDir = path.join(srcDir, "middleware");
159
+ fs.ensureDirSync(middlewareDir);
160
+ fs.writeFileSync(
161
+ path.join(middlewareDir, `${name}.middleware.ts`),
162
+ middlewareContent
163
+ );
164
+ console.log(
165
+ chalk.green(`Created src/middleware/${name}.middleware.ts`)
166
+ );
167
+ break;
168
+ }
169
+ case "service": {
170
+ const serviceContent = `export class ${capitalize(name)}Service {
171
+ constructor() {}
172
+
173
+ async findAll() {
174
+ return [];
175
+ }
176
+ }
177
+
178
+ export const ${name}Service = new ${capitalize(name)}Service();
179
+ `;
180
+ const servicesDir = path.join(srcDir, "services");
181
+ fs.ensureDirSync(servicesDir);
182
+ fs.writeFileSync(
183
+ path.join(servicesDir, `${name}.service.ts`),
184
+ serviceContent
185
+ );
186
+ console.log(chalk.green(`Created src/services/${name}.service.ts`));
187
+ break;
188
+ }
189
+ default:
190
+ console.error(
191
+ chalk.red(
192
+ `Unknown type: ${type}. Supported: route, middleware, service`
193
+ )
194
+ );
195
+ process.exit(1);
196
+ }
197
+ });
198
+ program.parse(process.argv);
199
+ //# sourceMappingURL=index.js.map
200
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["#!/usr/bin/env node\n\nimport { 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.2\");\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:\",\n choices: [\"express\", \"fastify\"],\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: \"tsx watch 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.2.0\",\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 \"@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).then(() => {\n console.log(\"Server is running on http://localhost:3000\");\n});\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`;\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"]}
package/dist/index.cjs CHANGED
@@ -944,10 +944,11 @@ var httpLogger = (options = {}) => {
944
944
  const logger = new Logger(options.context || "Router");
945
945
  return (req, res, next) => {
946
946
  const start = Date.now();
947
- res.on("finish", () => {
947
+ const rawRes = res.raw || res;
948
+ rawRes.on("finish", () => {
948
949
  const { method, url, headers } = req;
949
950
  const duration = Date.now() - start;
950
- const status = res.statusCode;
951
+ const status = rawRes.statusCode;
951
952
  const userAgent = headers ? headers["user-agent"] || "-" : "-";
952
953
  const methodColor = methodColors[method] || resetColor;
953
954
  const coloredMethod = `${methodColor}${method}${resetColor}`;