lapeh 2.2.6 → 2.2.7
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/api-testing-sepuluh/.env.example +19 -0
- package/api-testing-sepuluh/doc/ARCHITECTURE_GUIDE.md +73 -0
- package/api-testing-sepuluh/doc/CHANGELOG.md +77 -0
- package/api-testing-sepuluh/doc/CHEATSHEET.md +94 -0
- package/api-testing-sepuluh/doc/CLI.md +106 -0
- package/api-testing-sepuluh/doc/CONTRIBUTING.md +105 -0
- package/api-testing-sepuluh/doc/DEPLOYMENT.md +122 -0
- package/api-testing-sepuluh/doc/FAQ.md +81 -0
- package/api-testing-sepuluh/doc/FEATURES.md +165 -0
- package/api-testing-sepuluh/doc/GETTING_STARTED.md +108 -0
- package/api-testing-sepuluh/doc/INTRODUCTION.md +60 -0
- package/api-testing-sepuluh/doc/PACKAGES.md +66 -0
- package/api-testing-sepuluh/doc/PERFORMANCE.md +91 -0
- package/api-testing-sepuluh/doc/ROADMAP.md +93 -0
- package/api-testing-sepuluh/doc/SECURITY.md +93 -0
- package/api-testing-sepuluh/doc/STRUCTURE.md +90 -0
- package/api-testing-sepuluh/doc/TUTORIAL.md +192 -0
- package/api-testing-sepuluh/docker-compose.yml +24 -0
- package/api-testing-sepuluh/eslint.config.mjs +26 -0
- package/api-testing-sepuluh/framework.md +168 -0
- package/api-testing-sepuluh/nodemon.json +6 -0
- package/api-testing-sepuluh/package-lock.json +5539 -0
- package/api-testing-sepuluh/package.json +103 -0
- package/api-testing-sepuluh/prisma/base.prisma.template +7 -0
- package/api-testing-sepuluh/prisma/migrations/20251227034737_init_setup/migration.sql +248 -0
- package/api-testing-sepuluh/prisma/migrations/migration_lock.toml +3 -0
- package/api-testing-sepuluh/prisma/schema.prisma +183 -0
- package/api-testing-sepuluh/prisma/seed.ts +411 -0
- package/api-testing-sepuluh/prisma.config.ts +15 -0
- package/api-testing-sepuluh/readme.md +414 -0
- package/api-testing-sepuluh/scripts/check-update.js +92 -0
- package/api-testing-sepuluh/scripts/compile-schema.js +29 -0
- package/api-testing-sepuluh/scripts/config-clear.js +45 -0
- package/api-testing-sepuluh/scripts/generate-jwt-secret.js +38 -0
- package/api-testing-sepuluh/scripts/init-project.js +178 -0
- package/api-testing-sepuluh/scripts/make-controller.js +205 -0
- package/api-testing-sepuluh/scripts/make-model.js +42 -0
- package/api-testing-sepuluh/scripts/make-module.js +158 -0
- package/api-testing-sepuluh/scripts/verify-rbac-functional.js +187 -0
- package/api-testing-sepuluh/src/controllers/authController.ts +469 -0
- package/api-testing-sepuluh/src/controllers/petController.ts +194 -0
- package/api-testing-sepuluh/src/controllers/rbacController.ts +478 -0
- package/api-testing-sepuluh/src/models/core.prisma +163 -0
- package/api-testing-sepuluh/src/models/pets.prisma +9 -0
- package/api-testing-sepuluh/src/routes/auth.ts +74 -0
- package/api-testing-sepuluh/src/routes/index.ts +10 -0
- package/api-testing-sepuluh/src/routes/pets.ts +13 -0
- package/api-testing-sepuluh/src/routes/rbac.ts +42 -0
- package/api-testing-sepuluh/storage/logs/.gitkeep +0 -0
- package/api-testing-sepuluh/tsconfig.json +39 -0
- package/bin/index.js +68 -13
- package/package.json +1 -1
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
model cache {
|
|
2
|
+
key String @id
|
|
3
|
+
value String
|
|
4
|
+
expiration Int
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
model cache_locks {
|
|
8
|
+
key String @id
|
|
9
|
+
owner String
|
|
10
|
+
expiration Int
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
model failed_jobs {
|
|
14
|
+
id BigInt @id @default(autoincrement())
|
|
15
|
+
uuid String @unique
|
|
16
|
+
connection String
|
|
17
|
+
queue String
|
|
18
|
+
payload String
|
|
19
|
+
exception String
|
|
20
|
+
failed_at DateTime @default(now())
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
model job_batches {
|
|
24
|
+
id String @id
|
|
25
|
+
name String
|
|
26
|
+
total_jobs Int
|
|
27
|
+
pending_jobs Int
|
|
28
|
+
failed_jobs Int
|
|
29
|
+
failed_job_ids String
|
|
30
|
+
options String?
|
|
31
|
+
cancelled_at Int?
|
|
32
|
+
created_at Int
|
|
33
|
+
finished_at Int?
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
model jobs {
|
|
37
|
+
id BigInt @id @default(autoincrement())
|
|
38
|
+
queue String
|
|
39
|
+
payload String
|
|
40
|
+
attempts Int
|
|
41
|
+
reserved_at Int?
|
|
42
|
+
available_at Int
|
|
43
|
+
created_at Int
|
|
44
|
+
|
|
45
|
+
@@index([queue])
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
model migrations {
|
|
49
|
+
id Int @id @default(autoincrement())
|
|
50
|
+
migration String
|
|
51
|
+
batch Int
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
model password_reset_tokens {
|
|
55
|
+
email String @id
|
|
56
|
+
token String
|
|
57
|
+
created_at DateTime?
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
model personal_access_tokens {
|
|
61
|
+
id BigInt @id @default(autoincrement())
|
|
62
|
+
tokenable_type String
|
|
63
|
+
tokenable_id BigInt
|
|
64
|
+
name String
|
|
65
|
+
token String @unique
|
|
66
|
+
abilities String?
|
|
67
|
+
last_used_at DateTime?
|
|
68
|
+
expires_at DateTime?
|
|
69
|
+
created_at DateTime?
|
|
70
|
+
updated_at DateTime?
|
|
71
|
+
|
|
72
|
+
@@index([expires_at])
|
|
73
|
+
@@index([tokenable_type, tokenable_id])
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
model sessions {
|
|
77
|
+
id String @id
|
|
78
|
+
user_id BigInt?
|
|
79
|
+
ip_address String?
|
|
80
|
+
user_agent String?
|
|
81
|
+
payload String
|
|
82
|
+
last_activity Int
|
|
83
|
+
|
|
84
|
+
@@index([last_activity])
|
|
85
|
+
@@index([user_id])
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
model users {
|
|
89
|
+
id BigInt @id @default(autoincrement())
|
|
90
|
+
uuid String @unique
|
|
91
|
+
name String
|
|
92
|
+
email String @unique
|
|
93
|
+
avatar String?
|
|
94
|
+
avatar_url String?
|
|
95
|
+
email_verified_at DateTime?
|
|
96
|
+
password String
|
|
97
|
+
remember_token String?
|
|
98
|
+
created_at DateTime?
|
|
99
|
+
updated_at DateTime?
|
|
100
|
+
|
|
101
|
+
user_roles user_roles[]
|
|
102
|
+
user_permissions user_permissions[]
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
model roles {
|
|
106
|
+
id BigInt @id @default(autoincrement())
|
|
107
|
+
name String
|
|
108
|
+
slug String @unique
|
|
109
|
+
description String?
|
|
110
|
+
created_at DateTime?
|
|
111
|
+
updated_at DateTime?
|
|
112
|
+
|
|
113
|
+
user_roles user_roles[]
|
|
114
|
+
role_permissions role_permissions[]
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
model permissions {
|
|
118
|
+
id BigInt @id @default(autoincrement())
|
|
119
|
+
name String
|
|
120
|
+
slug String @unique
|
|
121
|
+
description String?
|
|
122
|
+
created_at DateTime?
|
|
123
|
+
updated_at DateTime?
|
|
124
|
+
|
|
125
|
+
role_permissions role_permissions[]
|
|
126
|
+
user_permissions user_permissions[]
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
model user_roles {
|
|
130
|
+
id BigInt @id @default(autoincrement())
|
|
131
|
+
user_id BigInt
|
|
132
|
+
role_id BigInt
|
|
133
|
+
created_at DateTime?
|
|
134
|
+
|
|
135
|
+
user users @relation(fields: [user_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
|
|
136
|
+
role roles @relation(fields: [role_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
|
|
137
|
+
|
|
138
|
+
@@unique([user_id, role_id])
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
model role_permissions {
|
|
142
|
+
id BigInt @id @default(autoincrement())
|
|
143
|
+
role_id BigInt
|
|
144
|
+
permission_id BigInt
|
|
145
|
+
created_at DateTime?
|
|
146
|
+
|
|
147
|
+
role roles @relation(fields: [role_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
|
|
148
|
+
permission permissions @relation(fields: [permission_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
|
|
149
|
+
|
|
150
|
+
@@unique([role_id, permission_id])
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
model user_permissions {
|
|
154
|
+
id BigInt @id @default(autoincrement())
|
|
155
|
+
user_id BigInt
|
|
156
|
+
permission_id BigInt
|
|
157
|
+
created_at DateTime?
|
|
158
|
+
|
|
159
|
+
user users @relation(fields: [user_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
|
|
160
|
+
permission permissions @relation(fields: [permission_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
|
|
161
|
+
|
|
162
|
+
@@unique([user_id, permission_id])
|
|
163
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import rateLimit from "express-rate-limit";
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
4
|
+
const multer = require("multer");
|
|
5
|
+
import path from "path";
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
import {
|
|
8
|
+
register,
|
|
9
|
+
login,
|
|
10
|
+
me,
|
|
11
|
+
logout,
|
|
12
|
+
refreshToken,
|
|
13
|
+
updatePassword,
|
|
14
|
+
updateProfile,
|
|
15
|
+
updateAvatar,
|
|
16
|
+
} from "@/controllers/authController";
|
|
17
|
+
import { requireAuth } from "@lapeh/middleware/auth";
|
|
18
|
+
|
|
19
|
+
const authLimiter = rateLimit({
|
|
20
|
+
windowMs: 15 * 60 * 1000,
|
|
21
|
+
max: 50,
|
|
22
|
+
standardHeaders: true,
|
|
23
|
+
legacyHeaders: false,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const avatarUploadDir = process.env.AVATAR_UPLOAD_DIR || "uploads/avatars";
|
|
27
|
+
if (!fs.existsSync(avatarUploadDir)) {
|
|
28
|
+
fs.mkdirSync(avatarUploadDir, { recursive: true });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const storage = (multer as any).diskStorage({
|
|
32
|
+
destination(
|
|
33
|
+
_req: any,
|
|
34
|
+
_file: any,
|
|
35
|
+
cb: (error: Error | null, destination: string) => void
|
|
36
|
+
) {
|
|
37
|
+
cb(null, avatarUploadDir);
|
|
38
|
+
},
|
|
39
|
+
filename(
|
|
40
|
+
_req: any,
|
|
41
|
+
file: any,
|
|
42
|
+
cb: (error: Error | null, filename: string) => void
|
|
43
|
+
) {
|
|
44
|
+
const ext = path.extname(file.originalname);
|
|
45
|
+
const base = path.basename(file.originalname, ext);
|
|
46
|
+
const unique = Date.now() + "-" + Math.round(Math.random() * 1e9);
|
|
47
|
+
cb(null, base + "-" + unique + ext);
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const uploadAvatar = multer({ storage });
|
|
52
|
+
|
|
53
|
+
export const authRouter = Router();
|
|
54
|
+
|
|
55
|
+
authRouter.post("/register", authLimiter, register);
|
|
56
|
+
|
|
57
|
+
authRouter.post("/login", authLimiter, login);
|
|
58
|
+
|
|
59
|
+
authRouter.get("/me", requireAuth, me);
|
|
60
|
+
|
|
61
|
+
authRouter.post("/logout", requireAuth, logout);
|
|
62
|
+
|
|
63
|
+
authRouter.post("/refresh", authLimiter, refreshToken);
|
|
64
|
+
|
|
65
|
+
authRouter.put("/password", requireAuth, updatePassword);
|
|
66
|
+
|
|
67
|
+
authRouter.put("/profile", requireAuth, updateProfile);
|
|
68
|
+
|
|
69
|
+
authRouter.post(
|
|
70
|
+
"/avatar",
|
|
71
|
+
requireAuth,
|
|
72
|
+
uploadAvatar.single("avatar"),
|
|
73
|
+
updateAvatar
|
|
74
|
+
);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import { authRouter } from "@/routes/auth";
|
|
3
|
+
import { rbacRouter } from "@/routes/rbac";
|
|
4
|
+
import petRouter from "@/routes/pets";
|
|
5
|
+
|
|
6
|
+
export const apiRouter = Router();
|
|
7
|
+
|
|
8
|
+
apiRouter.use("/auth", authRouter);
|
|
9
|
+
apiRouter.use("/rbac", rbacRouter);
|
|
10
|
+
apiRouter.use("/pets", petRouter);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import * as PetController from "@/controllers/petController";
|
|
3
|
+
import { parseMultipart } from "@lapeh/middleware/multipart";
|
|
4
|
+
|
|
5
|
+
const router = Router();
|
|
6
|
+
|
|
7
|
+
router.get("/", PetController.index);
|
|
8
|
+
router.get("/:id", PetController.show);
|
|
9
|
+
router.post("/", parseMultipart, PetController.store);
|
|
10
|
+
router.put("/:id", parseMultipart, PetController.update);
|
|
11
|
+
router.delete("/:id", PetController.destroy);
|
|
12
|
+
|
|
13
|
+
export default router;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import { requireAdmin, requireAuth } from "@lapeh/middleware/auth";
|
|
3
|
+
import {
|
|
4
|
+
createRole,
|
|
5
|
+
listRoles,
|
|
6
|
+
updateRole,
|
|
7
|
+
deleteRole,
|
|
8
|
+
createPermission,
|
|
9
|
+
listPermissions,
|
|
10
|
+
updatePermission,
|
|
11
|
+
deletePermission,
|
|
12
|
+
assignRoleToUser,
|
|
13
|
+
removeRoleFromUser,
|
|
14
|
+
assignPermissionToRole,
|
|
15
|
+
removePermissionFromRole,
|
|
16
|
+
assignPermissionToUser,
|
|
17
|
+
removePermissionFromUser,
|
|
18
|
+
} from "@/controllers/rbacController";
|
|
19
|
+
|
|
20
|
+
export const rbacRouter = Router();
|
|
21
|
+
|
|
22
|
+
rbacRouter.use(requireAuth);
|
|
23
|
+
rbacRouter.use(requireAdmin);
|
|
24
|
+
|
|
25
|
+
rbacRouter.post("/roles", createRole);
|
|
26
|
+
rbacRouter.get("/roles", listRoles);
|
|
27
|
+
rbacRouter.put("/roles/:id", updateRole);
|
|
28
|
+
rbacRouter.delete("/roles/:id", deleteRole);
|
|
29
|
+
|
|
30
|
+
rbacRouter.post("/permissions", createPermission);
|
|
31
|
+
rbacRouter.get("/permissions", listPermissions);
|
|
32
|
+
rbacRouter.put("/permissions/:id", updatePermission);
|
|
33
|
+
rbacRouter.delete("/permissions/:id", deletePermission);
|
|
34
|
+
|
|
35
|
+
rbacRouter.post("/users/assign-role", assignRoleToUser);
|
|
36
|
+
rbacRouter.post("/users/remove-role", removeRoleFromUser);
|
|
37
|
+
|
|
38
|
+
rbacRouter.post("/roles/assign-permission", assignPermissionToRole);
|
|
39
|
+
rbacRouter.post("/roles/remove-permission", removePermissionFromRole);
|
|
40
|
+
|
|
41
|
+
rbacRouter.post("/users/assign-permission", assignPermissionToUser);
|
|
42
|
+
rbacRouter.post("/users/remove-permission", removePermissionFromUser);
|
|
File without changes
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "CommonJS",
|
|
5
|
+
"outDir": "dist",
|
|
6
|
+
"rootDir": ".",
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"declarationMap": true,
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"noUnusedLocals": true,
|
|
14
|
+
"noUnusedParameters": true,
|
|
15
|
+
"paths": {
|
|
16
|
+
"@lapeh/*": [
|
|
17
|
+
"./node_modules/lapeh/lib/*"
|
|
18
|
+
],
|
|
19
|
+
"@/*": [
|
|
20
|
+
"./src/*"
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"include": [
|
|
25
|
+
"lib",
|
|
26
|
+
"src",
|
|
27
|
+
"prisma",
|
|
28
|
+
"generated"
|
|
29
|
+
],
|
|
30
|
+
"exclude": [
|
|
31
|
+
"node_modules",
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"ts-node": {
|
|
35
|
+
"ignore": [
|
|
36
|
+
"node_modules/(?!lapeh)"
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
}
|
package/bin/index.js
CHANGED
|
@@ -183,7 +183,7 @@ async function upgradeProject() {
|
|
|
183
183
|
|
|
184
184
|
// Update paths
|
|
185
185
|
if (tsconfig.compilerOptions && tsconfig.compilerOptions.paths) {
|
|
186
|
-
tsconfig.compilerOptions.paths["@lapeh/*"] = ["node_modules/lapeh/lib/*"];
|
|
186
|
+
tsconfig.compilerOptions.paths["@lapeh/*"] = ["./node_modules/lapeh/lib/*"];
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
// Add ts-node ignore configuration
|
|
@@ -210,6 +210,7 @@ async function upgradeProject() {
|
|
|
210
210
|
function createProject() {
|
|
211
211
|
const projectName = args.find(arg => !arg.startsWith('-'));
|
|
212
212
|
const isFull = args.includes('--full');
|
|
213
|
+
const useDefaults = args.includes('--defaults');
|
|
213
214
|
|
|
214
215
|
if (!projectName) {
|
|
215
216
|
console.error('❌ Please specify the project name:');
|
|
@@ -266,27 +267,45 @@ function createProject() {
|
|
|
266
267
|
|
|
267
268
|
// --- DATABASE SELECTION ---
|
|
268
269
|
console.log("\n--- Database Configuration ---");
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
270
|
+
let dbType, host, port, user, password, dbName;
|
|
271
|
+
|
|
272
|
+
if (useDefaults) {
|
|
273
|
+
console.log("ℹ️ Using default configuration (--defaults)...");
|
|
274
|
+
dbType = { key: "pgsql", label: "PostgreSQL", provider: "postgresql", defaultPort: "5432" };
|
|
275
|
+
host = "localhost";
|
|
276
|
+
port = "5432";
|
|
277
|
+
user = "postgres"; // Default postgres user is usually postgres, not root
|
|
278
|
+
password = "password"; // Default password
|
|
279
|
+
dbName = projectName.replace(/-/g, '_');
|
|
280
|
+
} else {
|
|
281
|
+
dbType = await selectOption("Database apa yang akan digunakan?", [
|
|
282
|
+
{ key: "pgsql", label: "PostgreSQL", provider: "postgresql", defaultPort: "5432" },
|
|
283
|
+
{ key: "mysql", label: "MySQL", provider: "mysql", defaultPort: "3306" },
|
|
284
|
+
]);
|
|
285
|
+
|
|
286
|
+
host = await ask("Database Host", "localhost");
|
|
287
|
+
port = await ask("Database Port", dbType.defaultPort);
|
|
288
|
+
user = await ask("Database User", "root");
|
|
289
|
+
password = await ask("Database Password", "");
|
|
290
|
+
dbName = await ask("Database Name", projectName.replace(/-/g, '_')); // Default db name based on project name
|
|
291
|
+
}
|
|
273
292
|
|
|
274
293
|
let dbUrl = "";
|
|
275
294
|
let dbProvider = dbType.provider;
|
|
276
295
|
|
|
277
|
-
const host = await ask("Database Host", "localhost");
|
|
278
|
-
const port = await ask("Database Port", dbType.defaultPort);
|
|
279
|
-
const user = await ask("Database User", "root");
|
|
280
|
-
const password = await ask("Database Password", "");
|
|
281
|
-
const dbName = await ask("Database Name", projectName.replace(/-/g, '_')); // Default db name based on project name
|
|
282
|
-
|
|
283
296
|
if (dbType.key === "pgsql") {
|
|
284
297
|
dbUrl = `postgresql://${user}:${password}@${host}:${port}/${dbName}?schema=public`;
|
|
285
298
|
} else {
|
|
286
299
|
dbUrl = `mysql://${user}:${password}@${host}:${port}/${dbName}`;
|
|
287
300
|
}
|
|
288
301
|
|
|
289
|
-
|
|
302
|
+
if (!useDefaults) {
|
|
303
|
+
rl.close();
|
|
304
|
+
} else {
|
|
305
|
+
// If we didn't use rl, we might not need to close it if we didn't open it?
|
|
306
|
+
// Actually rl is created at the top. We should close it.
|
|
307
|
+
rl.close();
|
|
308
|
+
}
|
|
290
309
|
|
|
291
310
|
// List of files/folders to exclude
|
|
292
311
|
const ignoreList = [
|
|
@@ -346,6 +365,10 @@ function createProject() {
|
|
|
346
365
|
// Ensure prisma CLI is available in devDependencies for the new project
|
|
347
366
|
packageJson.devDependencies = packageJson.devDependencies || {};
|
|
348
367
|
packageJson.devDependencies["prisma"] = "7.2.0";
|
|
368
|
+
|
|
369
|
+
// Add missing types for dev
|
|
370
|
+
packageJson.devDependencies["@types/express"] = "^5.0.0";
|
|
371
|
+
packageJson.devDependencies["@types/compression"] = "^1.7.5";
|
|
349
372
|
|
|
350
373
|
packageJson.version = '1.0.0';
|
|
351
374
|
packageJson.description = 'Generated by lapeh';
|
|
@@ -373,7 +396,7 @@ function createProject() {
|
|
|
373
396
|
|
|
374
397
|
// Update paths
|
|
375
398
|
if (tsconfig.compilerOptions && tsconfig.compilerOptions.paths) {
|
|
376
|
-
tsconfig.compilerOptions.paths["@lapeh/*"] = ["node_modules/lapeh/lib/*"];
|
|
399
|
+
tsconfig.compilerOptions.paths["@lapeh/*"] = ["./node_modules/lapeh/lib/*"];
|
|
377
400
|
}
|
|
378
401
|
|
|
379
402
|
// Add ts-node ignore configuration
|
|
@@ -384,6 +407,38 @@ function createProject() {
|
|
|
384
407
|
fs.writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2));
|
|
385
408
|
}
|
|
386
409
|
|
|
410
|
+
// Configure prisma.config.ts to use tsconfig-paths
|
|
411
|
+
const prismaConfigPath = path.join(projectDir, 'prisma.config.ts');
|
|
412
|
+
if (fs.existsSync(prismaConfigPath)) {
|
|
413
|
+
console.log('🔧 Configuring prisma.config.ts...');
|
|
414
|
+
let prismaConfigContent = fs.readFileSync(prismaConfigPath, 'utf8');
|
|
415
|
+
prismaConfigContent = prismaConfigContent.replace(
|
|
416
|
+
/seed:\s*"ts-node\s+prisma\/seed\.ts"/g,
|
|
417
|
+
'seed: "ts-node -r tsconfig-paths/register prisma/seed.ts"'
|
|
418
|
+
);
|
|
419
|
+
fs.writeFileSync(prismaConfigPath, prismaConfigContent);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Configure prisma/seed.ts imports
|
|
423
|
+
const prismaSeedPath = path.join(projectDir, 'prisma', 'seed.ts');
|
|
424
|
+
if (fs.existsSync(prismaSeedPath)) {
|
|
425
|
+
console.log('🔧 Configuring prisma/seed.ts...');
|
|
426
|
+
let seedContent = fs.readFileSync(prismaSeedPath, 'utf8');
|
|
427
|
+
|
|
428
|
+
// Add dotenv config if missing
|
|
429
|
+
if (!seedContent.includes('dotenv.config()')) {
|
|
430
|
+
seedContent = 'import dotenv from "dotenv";\ndotenv.config();\n\n' + seedContent;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Update import path
|
|
434
|
+
seedContent = seedContent.replace(
|
|
435
|
+
/import\s+{\s*prisma\s*}\s+from\s+["']@lapeh\/core\/database["']/,
|
|
436
|
+
'import { prisma } from "@lapeh/core/database"'
|
|
437
|
+
);
|
|
438
|
+
|
|
439
|
+
fs.writeFileSync(prismaSeedPath, seedContent);
|
|
440
|
+
}
|
|
441
|
+
|
|
387
442
|
// Create .env from .env.example with correct DB config
|
|
388
443
|
console.log('⚙️ Configuring environment...');
|
|
389
444
|
const envExamplePath = path.join(projectDir, '.env.example');
|