nurjs-cli 0.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.
Files changed (101) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +114 -0
  3. package/dist/cli.d.ts +4 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +48 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/doctor.command.d.ts +2 -0
  8. package/dist/commands/doctor.command.d.ts.map +1 -0
  9. package/dist/commands/doctor.command.js +32 -0
  10. package/dist/commands/doctor.command.js.map +1 -0
  11. package/dist/commands/init.command.d.ts +6 -0
  12. package/dist/commands/init.command.d.ts.map +1 -0
  13. package/dist/commands/init.command.js +117 -0
  14. package/dist/commands/init.command.js.map +1 -0
  15. package/dist/commands/install.command.d.ts +8 -0
  16. package/dist/commands/install.command.d.ts.map +1 -0
  17. package/dist/commands/install.command.js +86 -0
  18. package/dist/commands/install.command.js.map +1 -0
  19. package/dist/commands/list.command.d.ts +2 -0
  20. package/dist/commands/list.command.d.ts.map +1 -0
  21. package/dist/commands/list.command.js +14 -0
  22. package/dist/commands/list.command.js.map +1 -0
  23. package/dist/commands/start.command.d.ts +6 -0
  24. package/dist/commands/start.command.d.ts.map +1 -0
  25. package/dist/commands/start.command.js +64 -0
  26. package/dist/commands/start.command.js.map +1 -0
  27. package/dist/config/loadNurConfig.d.ts +3 -0
  28. package/dist/config/loadNurConfig.d.ts.map +1 -0
  29. package/dist/config/loadNurConfig.js +38 -0
  30. package/dist/config/loadNurConfig.js.map +1 -0
  31. package/dist/config/projectDetector.d.ts +3 -0
  32. package/dist/config/projectDetector.d.ts.map +1 -0
  33. package/dist/config/projectDetector.js +11 -0
  34. package/dist/config/projectDetector.js.map +1 -0
  35. package/dist/index.d.ts +2 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +2 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/utils/envFile.d.ts +2 -0
  40. package/dist/utils/envFile.d.ts.map +1 -0
  41. package/dist/utils/envFile.js +21 -0
  42. package/dist/utils/envFile.js.map +1 -0
  43. package/dist/utils/fileSystem.d.ts +11 -0
  44. package/dist/utils/fileSystem.d.ts.map +1 -0
  45. package/dist/utils/fileSystem.js +45 -0
  46. package/dist/utils/fileSystem.js.map +1 -0
  47. package/dist/utils/markers.d.ts +7 -0
  48. package/dist/utils/markers.d.ts.map +1 -0
  49. package/dist/utils/markers.js +22 -0
  50. package/dist/utils/markers.js.map +1 -0
  51. package/dist/utils/packageJson.d.ts +9 -0
  52. package/dist/utils/packageJson.d.ts.map +1 -0
  53. package/dist/utils/packageJson.js +21 -0
  54. package/dist/utils/packageJson.js.map +1 -0
  55. package/dist/utils/packageMetadata.d.ts +2 -0
  56. package/dist/utils/packageMetadata.d.ts.map +1 -0
  57. package/dist/utils/packageMetadata.js +8 -0
  58. package/dist/utils/packageMetadata.js.map +1 -0
  59. package/dist/utils/paths.d.ts +3 -0
  60. package/dist/utils/paths.d.ts.map +1 -0
  61. package/dist/utils/paths.js +10 -0
  62. package/dist/utils/paths.js.map +1 -0
  63. package/dist/utils/runCommand.d.ts +2 -0
  64. package/dist/utils/runCommand.d.ts.map +1 -0
  65. package/dist/utils/runCommand.js +19 -0
  66. package/dist/utils/runCommand.js.map +1 -0
  67. package/package.json +49 -0
  68. package/templates/app/.env.example.tpl +11 -0
  69. package/templates/app/.env.tpl +11 -0
  70. package/templates/app/.gitignore.tpl +5 -0
  71. package/templates/app/README.md.tpl +43 -0
  72. package/templates/app/nur.config.ts.tpl +29 -0
  73. package/templates/app/package.json.tpl +33 -0
  74. package/templates/app/pnpm-workspace.yaml.tpl +2 -0
  75. package/templates/app/src/app.ts.tpl +23 -0
  76. package/templates/app/src/config/app.config.ts.tpl +17 -0
  77. package/templates/app/src/config/env.ts.tpl +22 -0
  78. package/templates/app/src/main.ts.tpl +6 -0
  79. package/templates/app/src/middlewares/errorHandler.middleware.ts.tpl +23 -0
  80. package/templates/app/src/middlewares/notFound.middleware.ts.tpl +6 -0
  81. package/templates/app/src/middlewares/requestLogger.middleware.ts.tpl +17 -0
  82. package/templates/app/src/modules/health/health.controller.ts.tpl +12 -0
  83. package/templates/app/src/modules/health/health.module.ts.tpl +12 -0
  84. package/templates/app/src/modules/health/health.routes.ts.tpl +10 -0
  85. package/templates/app/src/modules/index.ts.tpl +12 -0
  86. package/templates/app/src/shared/errors/.gitkeep.tpl +0 -0
  87. package/templates/app/src/shared/logger/logger.ts.tpl +43 -0
  88. package/templates/app/src/shared/response/.gitkeep.tpl +0 -0
  89. package/templates/app/src/shared/validation/.gitkeep.tpl +0 -0
  90. package/templates/app/tsconfig.json.tpl +24 -0
  91. package/templates/modules/auth/files/src/modules/auth/auth.controller.ts.tpl +60 -0
  92. package/templates/modules/auth/files/src/modules/auth/auth.module.ts.tpl +22 -0
  93. package/templates/modules/auth/files/src/modules/auth/auth.repository.ts.tpl +22 -0
  94. package/templates/modules/auth/files/src/modules/auth/auth.routes.ts.tpl +21 -0
  95. package/templates/modules/auth/files/src/modules/auth/auth.schema.ts.tpl +19 -0
  96. package/templates/modules/auth/files/src/modules/auth/auth.service.ts.tpl +92 -0
  97. package/templates/modules/auth/files/src/modules/auth/auth.types.ts.tpl +14 -0
  98. package/templates/modules/auth/files/src/modules/auth/index.ts.tpl +1 -0
  99. package/templates/modules/auth/files/src/shared/security/jwt.ts.tpl +49 -0
  100. package/templates/modules/auth/files/src/shared/security/password.ts.tpl +11 -0
  101. package/templates/modules/auth/manifest.json +29 -0
@@ -0,0 +1,38 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { resolve } from "node:path";
3
+ function matchString(content, key, fallback) {
4
+ const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5
+ const match = content.match(new RegExp(`${escaped}\\s*:\\s*[\"']([^\"']+)[\"']`));
6
+ return match?.[1] ?? fallback;
7
+ }
8
+ function matchNumber(content, key, fallback) {
9
+ const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
10
+ const match = content.match(new RegExp(`${escaped}\\s*:\\s*(\\d+)`));
11
+ return match?.[1] ? Number(match[1]) : fallback;
12
+ }
13
+ export async function loadNurConfig(cwd = process.cwd()) {
14
+ const configPath = resolve(cwd, "nur.config.ts");
15
+ const content = await readFile(configPath, "utf8");
16
+ return {
17
+ projectName: matchString(content, "projectName", "nur-api"),
18
+ runtime: {
19
+ entry: matchString(content, "entry", "src/main.ts"),
20
+ distEntry: matchString(content, "distEntry", "dist/main.js"),
21
+ tsconfig: matchString(content, "tsconfig", "tsconfig.json"),
22
+ },
23
+ server: {
24
+ host: matchString(content, "host", "127.0.0.1"),
25
+ port: matchNumber(content, "port", 5000),
26
+ apiPrefix: matchString(content, "apiPrefix", "/api/v1"),
27
+ },
28
+ paths: {
29
+ srcDir: matchString(content, "srcDir", "src"),
30
+ modulesDir: matchString(content, "modulesDir", "src/modules"),
31
+ moduleRegistryFile: matchString(content, "moduleRegistryFile", "src/modules/index.ts"),
32
+ envFile: matchString(content, "envFile", ".env"),
33
+ envExampleFile: matchString(content, "envExampleFile", ".env.example"),
34
+ },
35
+ packageManager: matchString(content, "packageManager", "pnpm"),
36
+ };
37
+ }
38
+ //# sourceMappingURL=loadNurConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadNurConfig.js","sourceRoot":"","sources":["../../src/config/loadNurConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,SAAS,WAAW,CAAC,OAAe,EAAE,GAAW,EAAE,QAAgB;IACjE,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;IAC3D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,GAAG,OAAO,8BAA8B,CAAC,CAAC,CAAC;IAClF,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC;AAChC,CAAC;AAED,SAAS,WAAW,CAAC,OAAe,EAAE,GAAW,EAAE,QAAgB;IACjE,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;IAC3D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,GAAG,OAAO,iBAAiB,CAAC,CAAC,CAAC;IACrE,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AAClD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IACrD,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAEnD,OAAO;QACL,WAAW,EAAE,WAAW,CAAC,OAAO,EAAE,aAAa,EAAE,SAAS,CAAC;QAC3D,OAAO,EAAE;YACP,KAAK,EAAE,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,aAAa,CAAC;YACnD,SAAS,EAAE,WAAW,CAAC,OAAO,EAAE,WAAW,EAAE,cAAc,CAAC;YAC5D,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,eAAe,CAAC;SAC5D;QACD,MAAM,EAAE;YACN,IAAI,EAAE,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC;YAC/C,IAAI,EAAE,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC;YACxC,SAAS,EAAE,WAAW,CAAC,OAAO,EAAE,WAAW,EAAE,SAAS,CAAC;SACxD;QACD,KAAK,EAAE;YACL,MAAM,EAAE,WAAW,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC;YAC7C,UAAU,EAAE,WAAW,CAAC,OAAO,EAAE,YAAY,EAAE,aAAa,CAAC;YAC7D,kBAAkB,EAAE,WAAW,CAAC,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,CAAC;YACtF,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC;YAChD,cAAc,EAAE,WAAW,CAAC,OAAO,EAAE,gBAAgB,EAAE,cAAc,CAAC;SACvE;QACD,cAAc,EAAE,WAAW,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAuC;KACrG,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function isNurProject(cwd?: string): boolean;
2
+ export declare function assertNurProject(cwd?: string): void;
3
+ //# sourceMappingURL=projectDetector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectDetector.d.ts","sourceRoot":"","sources":["../../src/config/projectDetector.ts"],"names":[],"mappings":"AAGA,wBAAgB,YAAY,CAAC,GAAG,SAAgB,GAAG,OAAO,CAEzD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,SAAgB,GAAG,IAAI,CAI1D"}
@@ -0,0 +1,11 @@
1
+ import { existsSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ export function isNurProject(cwd = process.cwd()) {
4
+ return existsSync(resolve(cwd, "nur.config.ts")) && existsSync(resolve(cwd, "package.json"));
5
+ }
6
+ export function assertNurProject(cwd = process.cwd()) {
7
+ if (!isNurProject(cwd)) {
8
+ throw new Error("This directory does not look like a NurJS project. Missing nur.config.ts or package.json.");
9
+ }
10
+ }
11
+ //# sourceMappingURL=projectDetector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectDetector.js","sourceRoot":"","sources":["../../src/config/projectDetector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,UAAU,YAAY,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IAC9C,OAAO,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC,IAAI,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC;AAC/F,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IAClD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,2FAA2F,CAAC,CAAC;IAC/G,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { createCliProgram } from "./cli.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { createCliProgram } from "./cli.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function appendEnvEntries(path: string, entries: string[]): Promise<void>;
2
+ //# sourceMappingURL=envFile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envFile.d.ts","sourceRoot":"","sources":["../../src/utils/envFile.ts"],"names":[],"mappings":"AAGA,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBrF"}
@@ -0,0 +1,21 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
2
+ import { existsSync } from "node:fs";
3
+ export async function appendEnvEntries(path, entries) {
4
+ const current = existsSync(path) ? await readFile(path, "utf8") : "";
5
+ const lines = current.split(/\r?\n/);
6
+ const existingKeys = new Set(lines
7
+ .map((line) => line.trim())
8
+ .filter((line) => line && !line.startsWith("#"))
9
+ .map((line) => line.split("=")[0])
10
+ .filter(Boolean));
11
+ const missing = entries.filter((entry) => {
12
+ const key = entry.split("=")[0];
13
+ return key && !existingKeys.has(key);
14
+ });
15
+ if (missing.length === 0) {
16
+ return;
17
+ }
18
+ const prefix = current.endsWith("\n") || current.length === 0 ? "" : "\n";
19
+ await writeFile(path, `${current}${prefix}\n# NurJS module env\n${missing.join("\n")}\n`, "utf8");
20
+ }
21
+ //# sourceMappingURL=envFile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envFile.js","sourceRoot":"","sources":["../../src/utils/envFile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAY,EAAE,OAAiB;IACpE,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACrE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACrC,MAAM,YAAY,GAAG,IAAI,GAAG,CAC1B,KAAK;SACF,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;SAC/C,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;SACjC,MAAM,CAAC,OAAO,CAAC,CACnB,CAAC;IAEF,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;QACvC,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAChC,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1E,MAAM,SAAS,CAAC,IAAI,EAAE,GAAG,OAAO,GAAG,MAAM,yBAAyB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACpG,CAAC"}
@@ -0,0 +1,11 @@
1
+ export type TemplateVariables = Record<string, string | number | boolean>;
2
+ export declare function interpolate(content: string, variables: TemplateVariables): string;
3
+ export declare function copyTemplateDirectory(options: {
4
+ from: string;
5
+ to: string;
6
+ variables: TemplateVariables;
7
+ dryRun?: boolean;
8
+ force?: boolean;
9
+ }): Promise<string[]>;
10
+ export declare function pathExists(path: string): boolean;
11
+ //# sourceMappingURL=fileSystem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileSystem.d.ts","sourceRoot":"","sources":["../../src/utils/fileSystem.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;AAE1E,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,iBAAiB,GAAG,MAAM,CAQjF;AAED,wBAAsB,qBAAqB,CAAC,OAAO,EAAE;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,iBAAiB,CAAC;IAC7B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAuCpB;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEhD"}
@@ -0,0 +1,45 @@
1
+ import { mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
2
+ import { existsSync } from "node:fs";
3
+ import { basename, join } from "node:path";
4
+ export function interpolate(content, variables) {
5
+ let next = content;
6
+ for (const [key, value] of Object.entries(variables)) {
7
+ next = next.replaceAll(`__${key}__`, String(value));
8
+ }
9
+ return next;
10
+ }
11
+ export async function copyTemplateDirectory(options) {
12
+ const created = [];
13
+ async function walk(sourceDir, targetDir) {
14
+ const entries = await readdir(sourceDir);
15
+ for (const entry of entries) {
16
+ const sourcePath = join(sourceDir, entry);
17
+ const sourceStat = await stat(sourcePath);
18
+ const cleanEntry = entry.endsWith(".tpl") ? entry.slice(0, -4) : entry;
19
+ const targetPath = join(targetDir, cleanEntry);
20
+ if (sourceStat.isDirectory()) {
21
+ if (!options.dryRun) {
22
+ await mkdir(targetPath, { recursive: true });
23
+ }
24
+ await walk(sourcePath, targetPath);
25
+ continue;
26
+ }
27
+ if (existsSync(targetPath) && !options.force) {
28
+ throw new Error(`File already exists: ${targetPath}. Use --force to overwrite generated files.`);
29
+ }
30
+ const raw = await readFile(sourcePath, "utf8");
31
+ const rendered = interpolate(raw, options.variables);
32
+ if (!options.dryRun) {
33
+ await mkdir(targetDir, { recursive: true });
34
+ await writeFile(targetPath, rendered, "utf8");
35
+ }
36
+ created.push(targetPath);
37
+ }
38
+ }
39
+ await walk(options.from, options.to);
40
+ return created.map((file) => basename(file) === file ? file : file);
41
+ }
42
+ export function pathExists(path) {
43
+ return existsSync(path);
44
+ }
45
+ //# sourceMappingURL=fileSystem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileSystem.js","sourceRoot":"","sources":["../../src/utils/fileSystem.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAI3C,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,SAA4B;IACvE,IAAI,IAAI,GAAG,OAAO,CAAC;IAEnB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACrD,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,GAAG,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACtD,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,OAM3C;IACC,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,UAAU,IAAI,CAAC,SAAiB,EAAE,SAAiB;QACtD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,CAAC;QAEzC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;YAC1C,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC;YAC1C,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;YACvE,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;YAE/C,IAAI,UAAU,CAAC,WAAW,EAAE,EAAE,CAAC;gBAC7B,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;oBACpB,MAAM,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC/C,CAAC;gBACD,MAAM,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;gBACnC,SAAS;YACX,CAAC;YAED,IAAI,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;gBAC7C,MAAM,IAAI,KAAK,CAAC,wBAAwB,UAAU,6CAA6C,CAAC,CAAC;YACnG,CAAC;YAED,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;YAC/C,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;YAErD,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;gBACpB,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC5C,MAAM,SAAS,CAAC,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;YAChD,CAAC;YAED,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;IAErC,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,7 @@
1
+ export declare function insertBetweenMarkers(content: string, startMarker: string, endMarker: string, lineToInsert: string): string;
2
+ export declare function updateModuleRegistry(options: {
3
+ filePath: string;
4
+ moduleImport: string;
5
+ moduleExportName: string;
6
+ }): Promise<void>;
7
+ //# sourceMappingURL=markers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markers.d.ts","sourceRoot":"","sources":["../../src/utils/markers.ts"],"names":[],"mappings":"AAEA,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAiB1H;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE;IAClD,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBhB"}
@@ -0,0 +1,22 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
2
+ export function insertBetweenMarkers(content, startMarker, endMarker, lineToInsert) {
3
+ if (content.includes(lineToInsert)) {
4
+ return content;
5
+ }
6
+ const startIndex = content.indexOf(startMarker);
7
+ const endIndex = content.indexOf(endMarker);
8
+ if (startIndex === -1 || endIndex === -1 || endIndex < startIndex) {
9
+ throw new Error(`Could not find marker zone: ${startMarker} ... ${endMarker}`);
10
+ }
11
+ const beforeEndMarker = content.slice(0, endIndex);
12
+ const afterEndMarker = content.slice(endIndex);
13
+ const linePrefix = beforeEndMarker.endsWith("\n") ? "" : "\n";
14
+ return `${beforeEndMarker}${linePrefix}${lineToInsert}\n${afterEndMarker}`;
15
+ }
16
+ export async function updateModuleRegistry(options) {
17
+ const current = await readFile(options.filePath, "utf8");
18
+ const withImport = insertBetweenMarkers(current, "// nur:imports:start", "// nur:imports:end", options.moduleImport);
19
+ const withModule = insertBetweenMarkers(withImport, "// nur:modules:start", "// nur:modules:end", ` ${options.moduleExportName},`);
20
+ await writeFile(options.filePath, withModule, "utf8");
21
+ }
22
+ //# sourceMappingURL=markers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markers.js","sourceRoot":"","sources":["../../src/utils/markers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEvD,MAAM,UAAU,oBAAoB,CAAC,OAAe,EAAE,WAAmB,EAAE,SAAiB,EAAE,YAAoB;IAChH,IAAI,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QACnC,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAE5C,IAAI,UAAU,KAAK,CAAC,CAAC,IAAI,QAAQ,KAAK,CAAC,CAAC,IAAI,QAAQ,GAAG,UAAU,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,+BAA+B,WAAW,QAAQ,SAAS,EAAE,CAAC,CAAC;IACjF,CAAC;IAED,MAAM,eAAe,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IACnD,MAAM,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC/C,MAAM,UAAU,GAAG,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAE9D,OAAO,GAAG,eAAe,GAAG,UAAU,GAAG,YAAY,KAAK,cAAc,EAAE,CAAC;AAC7E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,OAI1C;IACC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAEzD,MAAM,UAAU,GAAG,oBAAoB,CACrC,OAAO,EACP,sBAAsB,EACtB,oBAAoB,EACpB,OAAO,CAAC,YAAY,CACrB,CAAC;IAEF,MAAM,UAAU,GAAG,oBAAoB,CACrC,UAAU,EACV,sBAAsB,EACtB,oBAAoB,EACpB,KAAK,OAAO,CAAC,gBAAgB,GAAG,CACjC,CAAC;IAEF,MAAM,SAAS,CAAC,OAAO,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;AACxD,CAAC"}
@@ -0,0 +1,9 @@
1
+ export type PackageJson = {
2
+ dependencies?: Record<string, string>;
3
+ devDependencies?: Record<string, string>;
4
+ [key: string]: unknown;
5
+ };
6
+ export declare function readPackageJson(path: string): Promise<PackageJson>;
7
+ export declare function writePackageJson(path: string, pkg: PackageJson): Promise<void>;
8
+ export declare function mergeDependencies(pkg: PackageJson, dependencies?: Record<string, string>, devDependencies?: Record<string, string>): PackageJson;
9
+ //# sourceMappingURL=packageJson.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"packageJson.d.ts","sourceRoot":"","sources":["../../src/utils/packageJson.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,GAAG;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAExE;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAEpF;AAED,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,WAAW,EAChB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACrC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACvC,WAAW,CAYb"}
@@ -0,0 +1,21 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
2
+ export async function readPackageJson(path) {
3
+ return JSON.parse(await readFile(path, "utf8"));
4
+ }
5
+ export async function writePackageJson(path, pkg) {
6
+ await writeFile(path, `${JSON.stringify(pkg, null, 2)}\n`, "utf8");
7
+ }
8
+ export function mergeDependencies(pkg, dependencies, devDependencies) {
9
+ return {
10
+ ...pkg,
11
+ dependencies: {
12
+ ...(pkg.dependencies ?? {}),
13
+ ...(dependencies ?? {}),
14
+ },
15
+ devDependencies: {
16
+ ...(pkg.devDependencies ?? {}),
17
+ ...(devDependencies ?? {}),
18
+ },
19
+ };
20
+ }
21
+ //# sourceMappingURL=packageJson.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"packageJson.js","sourceRoot":"","sources":["../../src/utils/packageJson.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAQvD,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY;IAChD,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAgB,CAAC;AACjE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAY,EAAE,GAAgB;IACnE,MAAM,SAAS,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,GAAgB,EAChB,YAAqC,EACrC,eAAwC;IAExC,OAAO;QACL,GAAG,GAAG;QACN,YAAY,EAAE;YACZ,GAAG,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC;YAC3B,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC;SACxB;QACD,eAAe,EAAE;YACf,GAAG,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC;YAC9B,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC;SAC3B;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function getCliPackageVersion(): string;
2
+ //# sourceMappingURL=packageMetadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"packageMetadata.d.ts","sourceRoot":"","sources":["../../src/utils/packageMetadata.ts"],"names":[],"mappings":"AAOA,wBAAgB,oBAAoB,IAAI,MAAM,CAK7C"}
@@ -0,0 +1,8 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { fileURLToPath } from "node:url";
3
+ export function getCliPackageVersion() {
4
+ const packageJsonPath = fileURLToPath(new URL("../../package.json", import.meta.url));
5
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
6
+ return packageJson.version;
7
+ }
8
+ //# sourceMappingURL=packageMetadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"packageMetadata.js","sourceRoot":"","sources":["../../src/utils/packageMetadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAMzC,MAAM,UAAU,oBAAoB;IAClC,MAAM,eAAe,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,oBAAoB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACtF,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAmB,CAAC;IAExF,OAAO,WAAW,CAAC,OAAO,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function getPackageRoot(): string;
2
+ export declare function getTemplatesDir(): string;
3
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAGA,wBAAgB,cAAc,IAAI,MAAM,CAGvC;AAED,wBAAgB,eAAe,IAAI,MAAM,CAExC"}
@@ -0,0 +1,10 @@
1
+ import { dirname, resolve } from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ export function getPackageRoot() {
4
+ const currentFile = fileURLToPath(import.meta.url);
5
+ return resolve(dirname(currentFile), "../..");
6
+ }
7
+ export function getTemplatesDir() {
8
+ return resolve(getPackageRoot(), "templates");
9
+ }
10
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,cAAc;IAC5B,MAAM,WAAW,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IACnD,OAAO,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,OAAO,CAAC,cAAc,EAAE,EAAE,WAAW,CAAC,CAAC;AAChD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function runCommand(command: string, args: string[], cwd: string): Promise<void>;
2
+ //# sourceMappingURL=runCommand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runCommand.d.ts","sourceRoot":"","sources":["../../src/utils/runCommand.ts"],"names":[],"mappings":"AAEA,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBtF"}
@@ -0,0 +1,19 @@
1
+ import { spawn } from "node:child_process";
2
+ export function runCommand(command, args, cwd) {
3
+ return new Promise((resolve, reject) => {
4
+ const child = spawn(command, args, {
5
+ cwd,
6
+ stdio: "inherit",
7
+ shell: process.platform === "win32",
8
+ });
9
+ child.on("error", reject);
10
+ child.on("close", (code) => {
11
+ if (code === 0) {
12
+ resolve();
13
+ return;
14
+ }
15
+ reject(new Error(`${command} ${args.join(" ")} exited with code ${code}`));
16
+ });
17
+ });
18
+ }
19
+ //# sourceMappingURL=runCommand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runCommand.js","sourceRoot":"","sources":["../../src/utils/runCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,IAAc,EAAE,GAAW;IACrE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;YACjC,GAAG;YACH,KAAK,EAAE,SAAS;YAChB,KAAK,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO;SACpC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAE1B,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACf,OAAO,EAAE,CAAC;gBACV,OAAO;YACT,CAAC;YAED,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,qBAAqB,IAAI,EAAE,CAAC,CAAC,CAAC;QAC7E,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "nurjs-cli",
3
+ "version": "0.1.0",
4
+ "description": "CLI for NurJS backend projects.",
5
+ "type": "module",
6
+ "bin": {
7
+ "nur": "dist/cli.js"
8
+ },
9
+ "main": "dist/index.js",
10
+ "types": "dist/index.d.ts",
11
+ "files": [
12
+ "dist",
13
+ "templates",
14
+ "README.md"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsc -p tsconfig.json",
18
+ "check": "tsc --noEmit -p tsconfig.json",
19
+ "dev": "tsx src/cli.ts",
20
+ "prepack": "npm run build"
21
+ },
22
+ "dependencies": {
23
+ "@inquirer/prompts": "^8.7.2",
24
+ "commander": "^15.0.0"
25
+ },
26
+ "devDependencies": {
27
+ "@types/node": "^24.13.4",
28
+ "nurjs-core": "workspace:*",
29
+ "tsx": "^4.23.13",
30
+ "typescript": "^7.0.2"
31
+ },
32
+ "license": "MIT",
33
+ "author": "WebDigiTech",
34
+ "keywords": [
35
+ "nurjs",
36
+ "cli",
37
+ "express",
38
+ "typescript",
39
+ "backend",
40
+ "scaffold",
41
+ "generator"
42
+ ],
43
+ "engines": {
44
+ "node": ">=24.0.0"
45
+ },
46
+ "publishConfig": {
47
+ "access": "public"
48
+ }
49
+ }
@@ -0,0 +1,11 @@
1
+ NODE_ENV=development
2
+
3
+ APP_NAME=__PROJECT_NAME__
4
+ APP_HOST=__APP_HOST__
5
+ APP_PORT=__APP_PORT__
6
+ API_PREFIX=__API_PREFIX__
7
+
8
+ CORS_ENABLED=true
9
+ CORS_ORIGIN=__CORS_ORIGIN__
10
+
11
+ LOG_LEVEL=info
@@ -0,0 +1,11 @@
1
+ NODE_ENV=development
2
+
3
+ APP_NAME=__PROJECT_NAME__
4
+ APP_HOST=__APP_HOST__
5
+ APP_PORT=__APP_PORT__
6
+ API_PREFIX=__API_PREFIX__
7
+
8
+ CORS_ENABLED=true
9
+ CORS_ORIGIN=__CORS_ORIGIN__
10
+
11
+ LOG_LEVEL=info
@@ -0,0 +1,5 @@
1
+ node_modules
2
+ dist
3
+ .env.local
4
+ .DS_Store
5
+ *.log
@@ -0,0 +1,43 @@
1
+ # __PROJECT_NAME__
2
+
3
+ Generated with NurJS.
4
+
5
+ ## Requirements
6
+
7
+ Node.js 24 LTS or newer.
8
+
9
+ ## Development
10
+
11
+ ```bash
12
+ __PACKAGE_MANAGER__ install
13
+ nur start
14
+ ```
15
+
16
+ Default health endpoint:
17
+
18
+ ```txt
19
+ GET __API_PREFIX__/health
20
+ ```
21
+
22
+ ## Project checks
23
+
24
+ ```bash
25
+ __PACKAGE_MANAGER__ run check
26
+ __PACKAGE_MANAGER__ run build
27
+ nur doctor
28
+ ```
29
+
30
+ ## Add the auth starter module
31
+
32
+ ```bash
33
+ nur install auth
34
+ ```
35
+
36
+ The v0.1.0 auth repository is in-memory. Before production use, replace it with persistent storage and set a strong `JWT_SECRET`.
37
+
38
+ ## Production build
39
+
40
+ ```bash
41
+ __PACKAGE_MANAGER__ run build
42
+ __PACKAGE_MANAGER__ run start:prod
43
+ ```
@@ -0,0 +1,29 @@
1
+ import type { NurProjectConfig } from "nurjs-core";
2
+
3
+ const config: NurProjectConfig = {
4
+ projectName: "__PROJECT_NAME__",
5
+
6
+ runtime: {
7
+ entry: "src/main.ts",
8
+ distEntry: "dist/main.js",
9
+ tsconfig: "tsconfig.json",
10
+ },
11
+
12
+ server: {
13
+ host: "__APP_HOST__",
14
+ port: __APP_PORT__,
15
+ apiPrefix: "__API_PREFIX__",
16
+ },
17
+
18
+ paths: {
19
+ srcDir: "src",
20
+ modulesDir: "src/modules",
21
+ moduleRegistryFile: "src/modules/index.ts",
22
+ envFile: ".env",
23
+ envExampleFile: ".env.example",
24
+ },
25
+
26
+ packageManager: "__PACKAGE_MANAGER__",
27
+ };
28
+
29
+ export default config;
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "__PROJECT_NAME__",
3
+ "version": "0.1.0",
4
+ "description": "__DESCRIPTION__",
5
+ "private": true,
6
+ "type": "module",
7
+ "scripts": {
8
+ "dev": "tsx watch src/main.ts",
9
+ "start": "tsx watch src/main.ts",
10
+ "build": "tsc",
11
+ "start:prod": "node dist/main.js",
12
+ "check": "tsc --noEmit"
13
+ },
14
+ "dependencies": {
15
+ "nurjs-core": "__NUR_CORE_DEP__",
16
+ "cors": "^2.8.6",
17
+ "dotenv": "^17.4.2",
18
+ "express": "^5.2.1",
19
+ "helmet": "^8.3.0",
20
+ "pino": "^10.3.1",
21
+ "zod": "^4.6.5"
22
+ },
23
+ "devDependencies": {
24
+ "@types/cors": "^2.8.19",
25
+ "@types/express": "^5.0.6",
26
+ "@types/node": "^24.13.4",
27
+ "tsx": "^4.23.13",
28
+ "typescript": "^7.0.2"
29
+ },
30
+ "engines": {
31
+ "node": ">=24.0.0"
32
+ }
33
+ }
@@ -0,0 +1,2 @@
1
+ allowBuilds:
2
+ esbuild: true
@@ -0,0 +1,23 @@
1
+ import { createNurApp, registerNurModules, startNurServer } from "nurjs-core";
2
+ import { appConfig } from "./config/app.config.js";
3
+ import { modules } from "./modules/index.js";
4
+ import { logger } from "./shared/logger/logger.js";
5
+ import { requestLoggerMiddleware } from "./middlewares/requestLogger.middleware.js";
6
+ import { notFoundMiddleware } from "./middlewares/notFound.middleware.js";
7
+ import { errorHandlerMiddleware } from "./middlewares/errorHandler.middleware.js";
8
+
9
+ export async function bootstrap(): Promise<void> {
10
+ const ctx = createNurApp({
11
+ config: appConfig,
12
+ logger,
13
+ });
14
+
15
+ ctx.app.use(requestLoggerMiddleware);
16
+
17
+ await registerNurModules(ctx, modules);
18
+
19
+ ctx.app.use(notFoundMiddleware);
20
+ ctx.app.use(errorHandlerMiddleware);
21
+
22
+ await startNurServer(ctx);
23
+ }
@@ -0,0 +1,17 @@
1
+ import type { NurAppConfig } from "nurjs-core";
2
+ import { env } from "./env.js";
3
+
4
+ export const appConfig: NurAppConfig = {
5
+ appName: env.APP_NAME,
6
+ nodeEnv: env.NODE_ENV,
7
+ host: env.APP_HOST,
8
+ port: env.APP_PORT,
9
+ apiPrefix: env.API_PREFIX,
10
+ cors: {
11
+ enabled: env.CORS_ENABLED,
12
+ origin: env.CORS_ORIGIN,
13
+ },
14
+ logger: {
15
+ level: env.LOG_LEVEL,
16
+ },
17
+ };
@@ -0,0 +1,22 @@
1
+ import { config as loadEnv } from "dotenv";
2
+ import { z } from "zod";
3
+
4
+ loadEnv({ quiet: true });
5
+
6
+ const envSchema = z.object({
7
+ NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
8
+ APP_NAME: z.string().default("nur-api"),
9
+ APP_HOST: z.string().default("127.0.0.1"),
10
+ APP_PORT: z.coerce.number().int().positive().default(5000),
11
+ API_PREFIX: z.string().default("/api/v1"),
12
+ CORS_ENABLED: z
13
+ .enum(["true", "false"])
14
+ .default("true")
15
+ .transform((value) => value === "true"),
16
+ CORS_ORIGIN: z.string().default("http://localhost:3000"),
17
+ LOG_LEVEL: z
18
+ .enum(["trace", "debug", "info", "warn", "error", "fatal"])
19
+ .default("info"),
20
+ });
21
+
22
+ export const env = envSchema.parse(process.env);
@@ -0,0 +1,6 @@
1
+ import { bootstrap } from "./app.js";
2
+
3
+ bootstrap().catch((error: unknown) => {
4
+ console.error("Failed to start NurJS application", error);
5
+ process.exit(1);
6
+ });