express-project-init 0.0.0-stage → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +140 -2
  2. package/dist/features.js +17 -0
  3. package/dist/features.js.map +1 -0
  4. package/dist/index.js +50 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/services/file.service.js +73 -0
  7. package/dist/services/file.service.js.map +1 -0
  8. package/dist/services/project.service.js +44 -0
  9. package/dist/services/project.service.js.map +1 -0
  10. package/dist/services/prompts.service.js +92 -0
  11. package/dist/services/prompts.service.js.map +1 -0
  12. package/dist/services/template.service.js +200 -0
  13. package/dist/services/template.service.js.map +1 -0
  14. package/dist/types.js +2 -0
  15. package/dist/types.js.map +1 -0
  16. package/package.json +57 -4
  17. package/templates/format/biome/both/biome.json +17 -0
  18. package/templates/format/biome/both/package.json +12 -0
  19. package/templates/format/biome/format/biome.json +14 -0
  20. package/templates/format/biome/format/package.json +9 -0
  21. package/templates/format/prettier/.prettierignore +3 -0
  22. package/templates/format/prettier/.prettierrc +6 -0
  23. package/templates/format/prettier/package.json +9 -0
  24. package/templates/javascript/base/package.json +13 -0
  25. package/templates/javascript/base/src/app.js +22 -0
  26. package/templates/javascript/base/src/server.js +8 -0
  27. package/templates/javascript/base/src/utils/helpers.js +3 -0
  28. package/templates/javascript/base/src/utils/responseHelpers.js +19 -0
  29. package/templates/javascript/error-handler/src/app.js +28 -0
  30. package/templates/javascript/error-handler/src/middleware/error.middleware.js +36 -0
  31. package/templates/javascript/error-handler/src/middleware/notFound.middleware.js +5 -0
  32. package/templates/javascript/error-handler/src/utils/AppError.js +30 -0
  33. package/templates/lint/biome/biome.json +15 -0
  34. package/templates/lint/biome/package.json +9 -0
  35. package/templates/lint/eslint/eslint.config.js +36 -0
  36. package/templates/lint/eslint/package.json +12 -0
  37. package/templates/lint/oxlint/.oxlintrc.json +13 -0
  38. package/templates/lint/oxlint/package.json +9 -0
  39. package/templates/typescript/base/package.json +20 -0
  40. package/templates/typescript/base/src/app.ts +22 -0
  41. package/templates/typescript/base/src/server.ts +8 -0
  42. package/templates/typescript/base/src/utils/helpers.ts +3 -0
  43. package/templates/typescript/base/src/utils/responseHelpers.ts +42 -0
  44. package/templates/typescript/base/tsconfig.json +30 -0
  45. package/templates/typescript/error-handler/src/app.ts +28 -0
  46. package/templates/typescript/error-handler/src/middleware/error.middleware.ts +42 -0
  47. package/templates/typescript/error-handler/src/middleware/notFound.middleware.ts +10 -0
  48. package/templates/typescript/error-handler/src/utils/AppError.ts +44 -0
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,59 @@
1
1
  {
2
2
  "name": "express-project-init",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.1.0",
4
+ "description": "Create production-ready Express.js API projects with JavaScript or TypeScript using clean, reusable starter templates.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "bin": {
8
+ "express-project-init": "./dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "templates",
13
+ "README.md",
14
+ "LICENSE"
15
+ ],
16
+ "engines": {
17
+ "node": ">=20"
18
+ },
19
+ "scripts": {
20
+ "dev": "tsx src/index.ts",
21
+ "clean": "node -e \"const fs=require('node:fs'); for (const p of ['dist','tsconfig.tsbuildinfo']) fs.rmSync(p,{recursive:true,force:true})\"",
22
+ "build": "tsc",
23
+ "typecheck": "tsc --noEmit",
24
+ "prepack": "npm run clean && npm run build",
25
+ "start": "node dist/index.js"
26
+ },
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+https://github.com/raunak-ray/ExpressKit.git"
30
+ },
31
+ "homepage": "https://github.com/raunak-ray/ExpressKit#readme",
32
+ "bugs": {
33
+ "url": "https://github.com/raunak-ray/ExpressKit/issues"
34
+ },
35
+ "keywords": [
36
+ "express",
37
+ "expressjs",
38
+ "express-generator",
39
+ "express-cli",
40
+ "nodejs",
41
+ "api-generator",
42
+ "backend",
43
+ "project-scaffolding",
44
+ "boilerplate",
45
+ "starter-template",
46
+ "typescript",
47
+ "javascript"
48
+ ],
49
+ "author": "Raunak Ray",
50
+ "license": "MIT",
51
+ "dependencies": {
52
+ "@clack/prompts": "^1.8.1"
53
+ },
54
+ "devDependencies": {
55
+ "@types/node": "^26.6.5",
56
+ "tsx": "^4.23.15",
57
+ "typescript": "^7.0.2"
58
+ }
59
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.6.4/schema.json",
3
+ "files": {
4
+ "ignoreUnknown": false
5
+ },
6
+ "formatter": {
7
+ "enabled": true,
8
+ "indentStyle": "space",
9
+ "indentWidth": 2
10
+ },
11
+ "linter": {
12
+ "enabled": true,
13
+ "rules": {
14
+ "preset": "recommended"
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "scripts": {
3
+ "lint": "biome lint",
4
+ "lint:fix": "biome lint --write",
5
+ "format": "biome format --write",
6
+ "format:check": "biome format",
7
+ "check": "biome check"
8
+ },
9
+ "devDependencies": {
10
+ "@biomejs/biome": "^2.6.4"
11
+ }
12
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.6.4/schema.json",
3
+ "files": {
4
+ "ignoreUnknown": false
5
+ },
6
+ "formatter": {
7
+ "enabled": true,
8
+ "indentStyle": "space",
9
+ "indentWidth": 2
10
+ },
11
+ "linter": {
12
+ "enabled": false
13
+ }
14
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "scripts": {
3
+ "format": "biome format --write",
4
+ "format:check": "biome format"
5
+ },
6
+ "devDependencies": {
7
+ "@biomejs/biome": "^2.6.4"
8
+ }
9
+ }
@@ -0,0 +1,3 @@
1
+ node_modules
2
+ dist
3
+ coverage
@@ -0,0 +1,6 @@
1
+ {
2
+ "semi": true,
3
+ "singleQuote": false,
4
+ "trailingComma": "all",
5
+ "tabWidth": 2
6
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "scripts": {
3
+ "format": "prettier --write .",
4
+ "format:check": "prettier --check ."
5
+ },
6
+ "devDependencies": {
7
+ "prettier": "^3.9.10"
8
+ }
9
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "my-api",
3
+ "version": "1.0.0",
4
+ "description": "Express API generated by ExpressKit",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "node --watch src/server.js",
8
+ "start": "node src/server.js"
9
+ },
10
+ "dependencies": {
11
+ "express": "^5.1.0"
12
+ }
13
+ }
@@ -0,0 +1,22 @@
1
+ import express from "express";
2
+ import { getTimeStamp } from "./utils/helpers.js";
3
+ import { successResponse } from "./utils/responseHelpers.js";
4
+
5
+ const app = express();
6
+
7
+ app.use(express.json());
8
+
9
+ // Health check
10
+ app.get("/health", (_req, res) =>
11
+ successResponse(res, {
12
+ statusCode: 200,
13
+ message: "API is up and running",
14
+ data: {
15
+ status: "ok",
16
+ uptime: Math.round(process.uptime()),
17
+ timestamp: getTimeStamp(),
18
+ },
19
+ }),
20
+ );
21
+
22
+ export default app;
@@ -0,0 +1,8 @@
1
+ import app from "./app.js";
2
+
3
+ const PORT = process.env.PORT || 3000;
4
+
5
+ app.listen(PORT, () => {
6
+ console.log(`API running on http://localhost:${PORT}`);
7
+ console.log(`Health check: http://localhost:${PORT}/health`);
8
+ });
@@ -0,0 +1,3 @@
1
+ export function getTimeStamp() {
2
+ return new Date().toISOString();
3
+ }
@@ -0,0 +1,19 @@
1
+ export function successResponse(res, { statusCode = 200, message, data }) {
2
+ return res.status(statusCode).json({
3
+ success: true,
4
+ message,
5
+ data,
6
+ });
7
+ }
8
+
9
+ export function errorResponse(
10
+ res,
11
+ { statusCode = 500, message, code = "INTERNAL_ERROR", fields },
12
+ ) {
13
+ return res.status(statusCode).json({
14
+ success: false,
15
+ message,
16
+ code,
17
+ fields,
18
+ });
19
+ }
@@ -0,0 +1,28 @@
1
+ import express from "express";
2
+ import errorMiddleware from "./middleware/error.middleware.js";
3
+ import notFoundMiddleware from "./middleware/notFound.middleware.js";
4
+ import { getTimeStamp } from "./utils/helpers.js";
5
+ import { successResponse } from "./utils/responseHelpers.js";
6
+
7
+ const app = express();
8
+
9
+ app.use(express.json());
10
+
11
+ // Health check
12
+ app.get("/health", (_req, res) =>
13
+ successResponse(res, {
14
+ statusCode: 200,
15
+ message: "API is up and running",
16
+ data: {
17
+ status: "ok",
18
+ uptime: Math.round(process.uptime()),
19
+ timestamp: getTimeStamp(),
20
+ },
21
+ }),
22
+ );
23
+
24
+ // Unknown routes → 404, then every error gets formatted in one place.
25
+ app.use(notFoundMiddleware);
26
+ app.use(errorMiddleware);
27
+
28
+ export default app;
@@ -0,0 +1,36 @@
1
+ import { AppError, BadRequestError } from "../utils/AppError.js";
2
+ import { getTimeStamp } from "../utils/helpers.js";
3
+ import { errorResponse } from "../utils/responseHelpers.js";
4
+
5
+ // Express error handler — needs all 4 params, that's how Express recognizes it.
6
+ export default function errorMiddleware(error, req, res, _next) {
7
+ const timeStamp = getTimeStamp();
8
+
9
+ // Expected errors — log them and send their details
10
+ if (error instanceof AppError) {
11
+ console.log(
12
+ `[${timeStamp}] [ERROR] ${req.method} ${req.originalUrl} - ${error.message}`,
13
+ );
14
+
15
+ return errorResponse(res, {
16
+ statusCode: error.statusCode,
17
+ message: error.message,
18
+ code: error.code,
19
+ fields: error instanceof BadRequestError ? error.fields : undefined, // fields only for bad requests
20
+ });
21
+ }
22
+
23
+ // Not an AppError — build a message if it's an Error, otherwise fall back
24
+ const message =
25
+ error instanceof Error ? error.message : "Internal server error";
26
+
27
+ console.error(
28
+ `[${timeStamp}] [ERROR] ${req.method} ${req.originalUrl} - ${message}`,
29
+ error,
30
+ );
31
+
32
+ return errorResponse(res, {
33
+ statusCode: 500,
34
+ message,
35
+ });
36
+ }
@@ -0,0 +1,5 @@
1
+ import { NotFoundError } from "../utils/AppError.js";
2
+
3
+ export default function notFoundMiddleware(_req, _res, next) {
4
+ next(new NotFoundError("Route not found"));
5
+ }
@@ -0,0 +1,30 @@
1
+ export class AppError extends Error {
2
+ constructor(message, { code = "INTERNAL_ERROR", statusCode = 500 } = {}) {
3
+ super(message);
4
+
5
+ this.name = this.constructor.name;
6
+ this.code = code; // machine-readable code, e.g. "BAD_REQUEST"
7
+ this.statusCode = statusCode; // HTTP status to send back
8
+ }
9
+ }
10
+
11
+ export class BadRequestError extends AppError {
12
+ // fields: validation errors, e.g. [{ field: "email", message: "required" }]
13
+ constructor(message = "Bad request", fields = []) {
14
+ super(message, { code: "BAD_REQUEST", statusCode: 400 });
15
+
16
+ this.fields = fields;
17
+ }
18
+ }
19
+
20
+ export class UnauthorizedError extends AppError {
21
+ constructor(message = "Unauthorized") {
22
+ super(message, { code: "UNAUTHORIZED", statusCode: 401 });
23
+ }
24
+ }
25
+
26
+ export class NotFoundError extends AppError {
27
+ constructor(message = "Not found") {
28
+ super(message, { code: "NOT_FOUND", statusCode: 404 });
29
+ }
30
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.6.4/schema.json",
3
+ "files": {
4
+ "ignoreUnknown": false
5
+ },
6
+ "formatter": {
7
+ "enabled": false
8
+ },
9
+ "linter": {
10
+ "enabled": true,
11
+ "rules": {
12
+ "preset": "recommended"
13
+ }
14
+ }
15
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "scripts": {
3
+ "lint": "biome lint",
4
+ "lint:fix": "biome lint --write"
5
+ },
6
+ "devDependencies": {
7
+ "@biomejs/biome": "^2.6.4"
8
+ }
9
+ }
@@ -0,0 +1,36 @@
1
+ import js from "@eslint/js";
2
+ import globals from "globals";
3
+ import tseslint from "typescript-eslint";
4
+
5
+ let prettier = [];
6
+ try {
7
+ const prettierConfig = await import("eslint-config-prettier");
8
+ prettier = [prettierConfig.default];
9
+ } catch (error) {
10
+ // eslint-config-prettier is optional, used when Prettier is also configured
11
+ void error;
12
+ }
13
+
14
+ export default tseslint.config(
15
+ {
16
+ languageOptions: {
17
+ globals: {
18
+ ...globals.node,
19
+ },
20
+ },
21
+ },
22
+ js.configs.recommended,
23
+ ...tseslint.configs.recommended,
24
+ {
25
+ rules: {
26
+ "@typescript-eslint/no-unused-vars": [
27
+ "error",
28
+ {
29
+ argsIgnorePattern: "^_",
30
+ varsIgnorePattern: "^_",
31
+ },
32
+ ],
33
+ },
34
+ },
35
+ ...prettier,
36
+ );
@@ -0,0 +1,12 @@
1
+ {
2
+ "scripts": {
3
+ "lint": "eslint .",
4
+ "lint:fix": "eslint . --fix"
5
+ },
6
+ "devDependencies": {
7
+ "@eslint/js": "^9.20.0",
8
+ "eslint": "^9.20.0",
9
+ "globals": "^16.0.0",
10
+ "typescript-eslint": "^8.24.0"
11
+ }
12
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "$schema": "./node_modules/oxlint/configuration_schema.json",
3
+ "plugins": ["typescript", "unicorn", "oxc"],
4
+ "categories": {
5
+ "correctness": "error"
6
+ },
7
+ "rules": {},
8
+ "env": {
9
+ "builtin": true,
10
+ "node": true
11
+ },
12
+ "ignorePatterns": ["node_modules", "dist"]
13
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "scripts": {
3
+ "lint": "oxlint",
4
+ "lint:fix": "oxlint --fix"
5
+ },
6
+ "devDependencies": {
7
+ "oxlint": "^1.90.0"
8
+ }
9
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "my-api",
3
+ "version": "1.0.0",
4
+ "description": "Express API generated by ExpressKit",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "tsx watch src/server.ts",
8
+ "start": "tsx src/server.ts",
9
+ "typecheck": "tsc --noEmit"
10
+ },
11
+ "dependencies": {
12
+ "express": "^5.1.0"
13
+ },
14
+ "devDependencies": {
15
+ "@types/express": "^5.0.0",
16
+ "@types/node": "^26.6.5",
17
+ "tsx": "^4.23.15",
18
+ "typescript": "^5.9.0"
19
+ }
20
+ }
@@ -0,0 +1,22 @@
1
+ import express, { type Request, type Response } from "express";
2
+ import { getTimeStamp } from "./utils/helpers";
3
+ import { successResponse } from "./utils/responseHelpers";
4
+
5
+ const app = express();
6
+
7
+ app.use(express.json());
8
+
9
+ // Health check
10
+ app.get("/health", (_req: Request, res: Response) =>
11
+ successResponse(res, {
12
+ statusCode: 200,
13
+ message: "API is up and running",
14
+ data: {
15
+ status: "ok",
16
+ uptime: Math.round(process.uptime()),
17
+ timestamp: getTimeStamp(),
18
+ },
19
+ }),
20
+ );
21
+
22
+ export default app;
@@ -0,0 +1,8 @@
1
+ import app from "./app";
2
+
3
+ const PORT = Number(process.env.PORT) || 3000;
4
+
5
+ app.listen(PORT, () => {
6
+ console.log(`API running on http://localhost:${PORT}`);
7
+ console.log(`Health check: http://localhost:${PORT}/health`);
8
+ });
@@ -0,0 +1,3 @@
1
+ export function getTimeStamp(): string {
2
+ return new Date().toISOString();
3
+ }
@@ -0,0 +1,42 @@
1
+ import type { Response } from "express";
2
+
3
+ export type FieldError = {
4
+ field: string;
5
+ message: string;
6
+ };
7
+
8
+ type SuccessOptions<T> = {
9
+ statusCode?: number;
10
+ message: string;
11
+ data?: T;
12
+ };
13
+
14
+ export function successResponse<T>(
15
+ res: Response,
16
+ { statusCode = 200, message, data }: SuccessOptions<T>,
17
+ ): Response {
18
+ return res.status(statusCode).json({
19
+ success: true,
20
+ message,
21
+ data,
22
+ });
23
+ }
24
+
25
+ type ErrorOptions = {
26
+ statusCode?: number;
27
+ message: string;
28
+ code?: string;
29
+ fields?: FieldError[];
30
+ };
31
+
32
+ export function errorResponse(
33
+ res: Response,
34
+ { statusCode = 500, message, code = "INTERNAL_ERROR", fields }: ErrorOptions,
35
+ ): Response {
36
+ return res.status(statusCode).json({
37
+ success: false,
38
+ message,
39
+ code,
40
+ fields,
41
+ });
42
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "compilerOptions": {
3
+ // Imports / modules
4
+ // "bundler" is THE setting that lets you import WITHOUT extensions:
5
+ // import app from "./app" (not "./app.ts")
6
+ "module": "esnext", // emit modern ES module syntax
7
+ "moduleResolution": "bundler", // resolve imports without ".ts" extensions
8
+ "moduleDetection": "force", // treat every file as an ES module (no CommonJS guessing)
9
+ "esModuleInterop": true, // allow normal default imports from CJS packages (express)
10
+ "verbatimModuleSyntax": true, // keep imports exactly as written; type-only imports must use "import type"
11
+
12
+ // Language level
13
+ "target": "esnext", // allow the newest JS features, no downleveling
14
+
15
+ // Type checking
16
+ "strict": true, // turn on all strict type checks
17
+ "noUnusedLocals": true, // error on declared-but-unused variables
18
+ "noUnusedParameters": true, // error on unused function parameters
19
+ "skipLibCheck": true, // don't type-check ".d.ts" files inside node_modules (faster)
20
+
21
+ // Runtime types
22
+ "types": ["node"], // auto-include ONLY Node types (no stray umbrella types)
23
+
24
+ // Output
25
+ "noEmit": true // tsx runs the code directly, so tsc only type-checks, never writes files
26
+ },
27
+ // Files in scope
28
+ "include": ["src"], // the compiler only looks at src/
29
+ "exclude": ["node_modules"] // never scan dependencies
30
+ }
@@ -0,0 +1,28 @@
1
+ import express, { type Request, type Response } from "express";
2
+ import errorMiddleware from "./middleware/error.middleware";
3
+ import notFoundMiddleware from "./middleware/notFound.middleware";
4
+ import { getTimeStamp } from "./utils/helpers";
5
+ import { successResponse } from "./utils/responseHelpers";
6
+
7
+ const app = express();
8
+
9
+ app.use(express.json());
10
+
11
+ // Health check
12
+ app.get("/health", (_req: Request, res: Response) =>
13
+ successResponse(res, {
14
+ statusCode: 200,
15
+ message: "API is up and running",
16
+ data: {
17
+ status: "ok",
18
+ uptime: Math.round(process.uptime()),
19
+ timestamp: getTimeStamp(),
20
+ },
21
+ }),
22
+ );
23
+
24
+ // Unknown routes → 404, then every error gets formatted in one place.
25
+ app.use(notFoundMiddleware);
26
+ app.use(errorMiddleware);
27
+
28
+ export default app;
@@ -0,0 +1,42 @@
1
+ import type { NextFunction, Request, Response } from "express";
2
+ import { AppError, BadRequestError } from "../utils/AppError";
3
+ import { getTimeStamp } from "../utils/helpers";
4
+ import { errorResponse } from "../utils/responseHelpers";
5
+
6
+ // Express error handler — needs all 4 params, that's how Express recognizes it.
7
+ export default function errorMiddleware(
8
+ error: unknown,
9
+ req: Request,
10
+ res: Response,
11
+ _next: NextFunction,
12
+ ): Response {
13
+ const timeStamp = getTimeStamp();
14
+
15
+ // Expected errors — log them and send their details
16
+ if (error instanceof AppError) {
17
+ console.log(
18
+ `[${timeStamp}] [ERROR] ${req.method} ${req.originalUrl} - ${error.message}`,
19
+ );
20
+
21
+ return errorResponse(res, {
22
+ statusCode: error.statusCode,
23
+ message: error.message,
24
+ code: error.code,
25
+ fields: error instanceof BadRequestError ? error.fields : undefined, // fields only for bad requests
26
+ });
27
+ }
28
+
29
+ // Not an AppError — build a message if it's an Error, otherwise fall back
30
+ const message =
31
+ error instanceof Error ? error.message : "Internal server error";
32
+
33
+ console.error(
34
+ `[${timeStamp}] [ERROR] ${req.method} ${req.originalUrl} - ${message}`,
35
+ error,
36
+ );
37
+
38
+ return errorResponse(res, {
39
+ statusCode: 500,
40
+ message,
41
+ });
42
+ }
@@ -0,0 +1,10 @@
1
+ import type { NextFunction, Request, Response } from "express";
2
+ import { NotFoundError } from "../utils/AppError";
3
+
4
+ export default function notFoundMiddleware(
5
+ _req: Request,
6
+ _res: Response,
7
+ next: NextFunction,
8
+ ): void {
9
+ next(new NotFoundError("Route not found"));
10
+ }