express-modular-monolith 1.0.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.
- package/README.md +14 -0
- package/bin/cli.js +58 -0
- package/package.json +15 -0
- package/templates/javascript/package.json +18 -0
- package/templates/javascript/src/app.js +8 -0
- package/templates/javascript/src/common/config/db.js +1 -0
- package/templates/javascript/src/common/utils/apiError.js +32 -0
- package/templates/javascript/src/common/utils/apiResponse.js +26 -0
- package/templates/javascript/src/server.js +17 -0
- package/templates/typescript/package.json +25 -0
- package/templates/typescript/src/app.ts +7 -0
- package/templates/typescript/src/common/config/db.ts +1 -0
- package/templates/typescript/src/common/utils/apiError.ts +31 -0
- package/templates/typescript/src/common/utils/apiResponse.ts +27 -0
- package/templates/typescript/src/server.ts +17 -0
- package/templates/typescript/tsconfig.json +44 -0
package/README.md
ADDED
package/bin/cli.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { exec } from "node:child_process";
|
|
6
|
+
import fs from "node:fs/promises";
|
|
7
|
+
import { input, select } from "@inquirer/prompts";
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
const projectName = await input({
|
|
11
|
+
message: "Project name:"
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const language = await select({
|
|
15
|
+
message: "Choose a language:",
|
|
16
|
+
choices: [
|
|
17
|
+
{
|
|
18
|
+
name: "JavaScript",
|
|
19
|
+
value: "javascript"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: "TypeScript",
|
|
23
|
+
value: "typescript"
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
30
|
+
const __dirname = path.dirname(__filename);
|
|
31
|
+
|
|
32
|
+
const templatePath = path.join(__dirname, "..", "templates", language);
|
|
33
|
+
|
|
34
|
+
const projectPath = projectName === "." ? process.cwd() : path.join(process.cwd(), projectName);
|
|
35
|
+
await fs.cp( templatePath, projectPath, { recursive: true });
|
|
36
|
+
|
|
37
|
+
const packageJsonPath = path.join(projectPath, "package.json");
|
|
38
|
+
|
|
39
|
+
const packageJson = JSON.parse(
|
|
40
|
+
await fs.readFile(packageJsonPath, "utf-8")
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
if (projectName === ".") {
|
|
44
|
+
packageJson.name = path.basename(process.cwd());
|
|
45
|
+
}else{
|
|
46
|
+
packageJson.name = projectName;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
await fs.writeFile(
|
|
50
|
+
packageJsonPath,
|
|
51
|
+
JSON.stringify(packageJson, null, 2)
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
await exec("npm install", {
|
|
55
|
+
cwd: projectPath
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "express-modular-monolith",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "This is a modular monolith project generator for Express.js",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"express-modular-monolith": "./bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [],
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"author": "Md Khalid Hossain",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@inquirer/prompts": "^8.6.0"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "javascript",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "src/server.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "node src/server.js"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"cors": "^2.8.6",
|
|
11
|
+
"dotenv": "^17.4.2",
|
|
12
|
+
"express": "^5.2.1"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [],
|
|
15
|
+
"author": "",
|
|
16
|
+
"license": "ISC",
|
|
17
|
+
"type": "module"
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// write here your database connection code
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export class ApiError extends Error {
|
|
2
|
+
|
|
3
|
+
constructor(statusCode, message) {
|
|
4
|
+
super(message)
|
|
5
|
+
this.statusCode = statusCode
|
|
6
|
+
Error.captureStackTrace(this, this.constructor)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
static badRequest(message = "Bad request") {
|
|
10
|
+
return new ApiError(400, message);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
static unauthorized(message = "Unauthorized") {
|
|
14
|
+
return new ApiError(401, message);
|
|
15
|
+
}
|
|
16
|
+
static conflict(message = "Conflict") {
|
|
17
|
+
return new ApiError(409, message);
|
|
18
|
+
}
|
|
19
|
+
static forbidden(message = "forbidden") {
|
|
20
|
+
return new ApiError(403, message);
|
|
21
|
+
}
|
|
22
|
+
static notfound(message = "notfound") {
|
|
23
|
+
return new ApiError(404, message);
|
|
24
|
+
}
|
|
25
|
+
static unprocessable(message = "unprocessable"){
|
|
26
|
+
return new ApiError(422, message)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static internal(message = "Internal Server Error") {
|
|
30
|
+
return new ApiError(500, message);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export class ApiResponse {
|
|
2
|
+
|
|
3
|
+
static ok(res, message, data = null)
|
|
4
|
+
{
|
|
5
|
+
return res.status(200).json({
|
|
6
|
+
success: true,
|
|
7
|
+
message,
|
|
8
|
+
data
|
|
9
|
+
})
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
static created(res, message, data = null)
|
|
13
|
+
{
|
|
14
|
+
return res.status(201).json({
|
|
15
|
+
success: true,
|
|
16
|
+
message,
|
|
17
|
+
data
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static noContent(res)
|
|
22
|
+
{
|
|
23
|
+
return res.status(204).send()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import 'dotenv/config'
|
|
2
|
+
import app from './app.js'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
const PORT = process.env.PORT || 8000
|
|
6
|
+
|
|
7
|
+
;(async function start () {
|
|
8
|
+
try {
|
|
9
|
+
// execute database connection function here
|
|
10
|
+
app.listen(PORT, ()=>{
|
|
11
|
+
console.log(`Server is running at port ${PORT}`)
|
|
12
|
+
})
|
|
13
|
+
} catch (error) {
|
|
14
|
+
console.error('Failed to start server', error)
|
|
15
|
+
process.exit(1)
|
|
16
|
+
}
|
|
17
|
+
})()
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "typescript",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "src/server.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "tsc-watch --onSuccess \"node dist/server.js\""
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"cors": "^2.8.6",
|
|
11
|
+
"dotenv": "^17.4.2",
|
|
12
|
+
"express": "^5.2.1"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/cors": "^2.8.19",
|
|
16
|
+
"@types/express": "^5.0.6",
|
|
17
|
+
"@types/node": "^25.6.0",
|
|
18
|
+
"tsc-watch": "^7.2.0",
|
|
19
|
+
"tsx": "^4.21.0"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [],
|
|
22
|
+
"author": "",
|
|
23
|
+
"license": "ISC",
|
|
24
|
+
"type": "module"
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// write here your database connection code
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export class ApiError extends Error {
|
|
2
|
+
constructor(public statusCode: number, message: string) {
|
|
3
|
+
super(message)
|
|
4
|
+
this.statusCode = statusCode
|
|
5
|
+
Error.captureStackTrace(this, this.constructor)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
static badRequest(message = "Bad request") {
|
|
9
|
+
return new ApiError(400, message);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
static unauthorized(message = "Unauthorized") {
|
|
13
|
+
return new ApiError(401, message);
|
|
14
|
+
}
|
|
15
|
+
static conflict(message = "Conflict") {
|
|
16
|
+
return new ApiError(409, message);
|
|
17
|
+
}
|
|
18
|
+
static forbidden(message = "forbidden") {
|
|
19
|
+
return new ApiError(403, message);
|
|
20
|
+
}
|
|
21
|
+
static notfound(message = "notfound") {
|
|
22
|
+
return new ApiError(404, message);
|
|
23
|
+
}
|
|
24
|
+
static unprocessable(message = "unprocessable"){
|
|
25
|
+
return new ApiError(422, message)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static internal(message = "Internal Server Error") {
|
|
29
|
+
return new ApiError(500, message);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Response } from "express"
|
|
2
|
+
|
|
3
|
+
export class ApiResponse {
|
|
4
|
+
static ok(res:Response, message:string, data: unknown = null)
|
|
5
|
+
{
|
|
6
|
+
return res.status(200).json({
|
|
7
|
+
success: true,
|
|
8
|
+
message,
|
|
9
|
+
data
|
|
10
|
+
})
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
static created(res:Response, message:string, data: unknown = null)
|
|
14
|
+
{
|
|
15
|
+
return res.status(201).json({
|
|
16
|
+
success: true,
|
|
17
|
+
message,
|
|
18
|
+
data
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static noContent(res:Response)
|
|
23
|
+
{
|
|
24
|
+
return res.status(204).send()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import 'dotenv/config'
|
|
2
|
+
import app from './app.js'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
const PORT = process.env.PORT || 8000
|
|
6
|
+
|
|
7
|
+
;(async function start () {
|
|
8
|
+
try {
|
|
9
|
+
// execute database connection function here
|
|
10
|
+
app.listen(PORT, ()=>{
|
|
11
|
+
console.log(`Server is running at port ${PORT}`)
|
|
12
|
+
})
|
|
13
|
+
} catch (error) {
|
|
14
|
+
console.error('Failed to start server', error)
|
|
15
|
+
process.exit(1)
|
|
16
|
+
}
|
|
17
|
+
})()
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Visit https://aka.ms/tsconfig to read more about this file
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
// File Layout
|
|
5
|
+
"rootDir": "./src",
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
|
|
8
|
+
// Environment Settings
|
|
9
|
+
// See also https://aka.ms/tsconfig/module
|
|
10
|
+
"module": "nodenext",
|
|
11
|
+
"target": "esnext",
|
|
12
|
+
"types": [],
|
|
13
|
+
// For nodejs:
|
|
14
|
+
// "lib": ["esnext"],
|
|
15
|
+
// "types": ["node"],
|
|
16
|
+
// and npm install -D @types/node
|
|
17
|
+
|
|
18
|
+
// Other Outputs
|
|
19
|
+
"sourceMap": true,
|
|
20
|
+
"declaration": true,
|
|
21
|
+
"declarationMap": true,
|
|
22
|
+
|
|
23
|
+
// Stricter Typechecking Options
|
|
24
|
+
"noUncheckedIndexedAccess": true,
|
|
25
|
+
"exactOptionalPropertyTypes": true,
|
|
26
|
+
|
|
27
|
+
// Style Options
|
|
28
|
+
// "noImplicitReturns": true,
|
|
29
|
+
// "noImplicitOverride": true,
|
|
30
|
+
// "noUnusedLocals": true,
|
|
31
|
+
// "noUnusedParameters": true,
|
|
32
|
+
// "noFallthroughCasesInSwitch": true,
|
|
33
|
+
// "noPropertyAccessFromIndexSignature": true,
|
|
34
|
+
|
|
35
|
+
// Recommended Options
|
|
36
|
+
"strict": true,
|
|
37
|
+
"jsx": "react-jsx",
|
|
38
|
+
"verbatimModuleSyntax": true,
|
|
39
|
+
"isolatedModules": true,
|
|
40
|
+
"noUncheckedSideEffectImports": true,
|
|
41
|
+
"moduleDetection": "force",
|
|
42
|
+
"skipLibCheck": true,
|
|
43
|
+
}
|
|
44
|
+
}
|