lapeh 2.3.6 → 2.3.8

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 (243) hide show
  1. package/bin/index.js +39 -56
  2. package/dist/generated/prisma/browser.d.ts +80 -0
  3. package/dist/generated/prisma/browser.d.ts.map +1 -0
  4. package/dist/generated/prisma/browser.js +56 -0
  5. package/dist/generated/prisma/client.d.ts +97 -0
  6. package/dist/generated/prisma/client.d.ts.map +1 -0
  7. package/dist/generated/prisma/client.js +68 -0
  8. package/dist/generated/prisma/commonInputTypes.d.ts +486 -0
  9. package/dist/generated/prisma/commonInputTypes.d.ts.map +1 -0
  10. package/dist/generated/prisma/commonInputTypes.js +11 -0
  11. package/dist/generated/prisma/enums.d.ts +2 -0
  12. package/dist/generated/prisma/enums.d.ts.map +1 -0
  13. package/dist/generated/prisma/enums.js +11 -0
  14. package/dist/generated/prisma/internal/class.d.ts +281 -0
  15. package/dist/generated/prisma/internal/class.d.ts.map +1 -0
  16. package/dist/generated/prisma/internal/class.js +76 -0
  17. package/dist/generated/prisma/internal/prismaNamespace.d.ts +1734 -0
  18. package/dist/generated/prisma/internal/prismaNamespace.d.ts.map +1 -0
  19. package/dist/generated/prisma/internal/prismaNamespace.js +260 -0
  20. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts +200 -0
  21. package/dist/generated/prisma/internal/prismaNamespaceBrowser.d.ts.map +1 -0
  22. package/dist/generated/prisma/internal/prismaNamespaceBrowser.js +231 -0
  23. package/dist/generated/prisma/models/cache.d.ts +986 -0
  24. package/dist/generated/prisma/models/cache.d.ts.map +1 -0
  25. package/dist/generated/prisma/models/cache.js +2 -0
  26. package/dist/generated/prisma/models/cache_locks.d.ts +976 -0
  27. package/dist/generated/prisma/models/cache_locks.d.ts.map +1 -0
  28. package/dist/generated/prisma/models/cache_locks.js +2 -0
  29. package/dist/generated/prisma/models/failed_jobs.d.ts +1098 -0
  30. package/dist/generated/prisma/models/failed_jobs.d.ts.map +1 -0
  31. package/dist/generated/prisma/models/failed_jobs.js +2 -0
  32. package/dist/generated/prisma/models/job_batches.d.ts +1212 -0
  33. package/dist/generated/prisma/models/job_batches.d.ts.map +1 -0
  34. package/dist/generated/prisma/models/job_batches.js +2 -0
  35. package/dist/generated/prisma/models/jobs.d.ts +1112 -0
  36. package/dist/generated/prisma/models/jobs.d.ts.map +1 -0
  37. package/dist/generated/prisma/models/jobs.js +2 -0
  38. package/dist/generated/prisma/models/migrations.d.ts +979 -0
  39. package/dist/generated/prisma/models/migrations.d.ts.map +1 -0
  40. package/dist/generated/prisma/models/migrations.js +2 -0
  41. package/dist/generated/prisma/models/password_reset_tokens.d.ts +941 -0
  42. package/dist/generated/prisma/models/password_reset_tokens.d.ts.map +1 -0
  43. package/dist/generated/prisma/models/password_reset_tokens.js +2 -0
  44. package/dist/generated/prisma/models/permissions.d.ts +1333 -0
  45. package/dist/generated/prisma/models/permissions.d.ts.map +1 -0
  46. package/dist/generated/prisma/models/permissions.js +2 -0
  47. package/dist/generated/prisma/models/personal_access_tokens.d.ts +1178 -0
  48. package/dist/generated/prisma/models/personal_access_tokens.d.ts.map +1 -0
  49. package/dist/generated/prisma/models/personal_access_tokens.js +2 -0
  50. package/dist/generated/prisma/models/role_permissions.d.ts +1291 -0
  51. package/dist/generated/prisma/models/role_permissions.d.ts.map +1 -0
  52. package/dist/generated/prisma/models/role_permissions.js +2 -0
  53. package/dist/generated/prisma/models/roles.d.ts +1333 -0
  54. package/dist/generated/prisma/models/roles.d.ts.map +1 -0
  55. package/dist/generated/prisma/models/roles.js +2 -0
  56. package/dist/generated/prisma/models/sessions.d.ts +1073 -0
  57. package/dist/generated/prisma/models/sessions.d.ts.map +1 -0
  58. package/dist/generated/prisma/models/sessions.js +2 -0
  59. package/dist/generated/prisma/models/user_permissions.d.ts +1291 -0
  60. package/dist/generated/prisma/models/user_permissions.d.ts.map +1 -0
  61. package/dist/generated/prisma/models/user_permissions.js +2 -0
  62. package/dist/generated/prisma/models/user_roles.d.ts +1291 -0
  63. package/dist/generated/prisma/models/user_roles.d.ts.map +1 -0
  64. package/dist/generated/prisma/models/user_roles.js +2 -0
  65. package/dist/generated/prisma/models/users.d.ts +1513 -0
  66. package/dist/generated/prisma/models/users.d.ts.map +1 -0
  67. package/dist/generated/prisma/models/users.js +2 -0
  68. package/dist/generated/prisma/models.d.ts +17 -0
  69. package/dist/generated/prisma/models.d.ts.map +1 -0
  70. package/dist/generated/prisma/models.js +2 -0
  71. package/dist/lib/bootstrap.d.ts +2 -0
  72. package/dist/lib/bootstrap.d.ts.map +1 -0
  73. package/dist/lib/bootstrap.js +133 -0
  74. package/dist/lib/core/database.d.ts +3 -0
  75. package/dist/lib/core/database.d.ts.map +1 -0
  76. package/dist/lib/core/database.js +34 -0
  77. package/dist/lib/core/realtime.d.ts +3 -0
  78. package/dist/lib/core/realtime.d.ts.map +1 -0
  79. package/dist/lib/core/realtime.js +36 -0
  80. package/dist/lib/core/redis.d.ts +8 -0
  81. package/dist/lib/core/redis.d.ts.map +1 -0
  82. package/dist/lib/core/redis.js +123 -0
  83. package/dist/lib/core/serializer.d.ts +43 -0
  84. package/dist/lib/core/serializer.d.ts.map +1 -0
  85. package/dist/lib/core/serializer.js +66 -0
  86. package/dist/lib/core/server.d.ts +2 -0
  87. package/dist/lib/core/server.d.ts.map +1 -0
  88. package/dist/lib/core/server.js +60 -0
  89. package/dist/lib/middleware/auth.d.ts +4 -0
  90. package/dist/lib/middleware/auth.d.ts.map +1 -0
  91. package/dist/lib/middleware/auth.js +55 -0
  92. package/dist/lib/middleware/error.d.ts +3 -0
  93. package/dist/lib/middleware/error.d.ts.map +1 -0
  94. package/dist/lib/middleware/error.js +60 -0
  95. package/dist/lib/middleware/multipart.d.ts +4 -0
  96. package/dist/lib/middleware/multipart.d.ts.map +1 -0
  97. package/dist/lib/middleware/multipart.js +17 -0
  98. package/dist/lib/middleware/rateLimit.d.ts +2 -0
  99. package/dist/lib/middleware/rateLimit.d.ts.map +1 -0
  100. package/dist/lib/middleware/rateLimit.js +19 -0
  101. package/dist/lib/middleware/requestLogger.d.ts +3 -0
  102. package/dist/lib/middleware/requestLogger.d.ts.map +1 -0
  103. package/dist/lib/middleware/requestLogger.js +22 -0
  104. package/dist/lib/middleware/visitor.d.ts +3 -0
  105. package/dist/lib/middleware/visitor.d.ts.map +1 -0
  106. package/dist/lib/middleware/visitor.js +144 -0
  107. package/dist/lib/utils/logger.d.ts +11 -0
  108. package/dist/lib/utils/logger.d.ts.map +1 -0
  109. package/dist/lib/utils/logger.js +81 -0
  110. package/dist/lib/utils/pagination.d.ts +19 -0
  111. package/dist/lib/utils/pagination.d.ts.map +1 -0
  112. package/dist/lib/utils/pagination.js +34 -0
  113. package/dist/lib/utils/response.d.ts +11 -0
  114. package/dist/lib/utils/response.d.ts.map +1 -0
  115. package/dist/lib/utils/response.js +57 -0
  116. package/dist/lib/utils/validator.d.ts +38 -0
  117. package/dist/lib/utils/validator.d.ts.map +1 -0
  118. package/dist/lib/utils/validator.js +369 -0
  119. package/dist/prisma/seed.d.ts +2 -0
  120. package/dist/prisma/seed.d.ts.map +1 -0
  121. package/dist/prisma/seed.js +381 -0
  122. package/dist/src/controllers/authController.d.ts +11 -0
  123. package/dist/src/controllers/authController.d.ts.map +1 -0
  124. package/dist/src/controllers/authController.js +414 -0
  125. package/dist/src/controllers/petController.d.ts +7 -0
  126. package/dist/src/controllers/petController.d.ts.map +1 -0
  127. package/dist/src/controllers/petController.js +163 -0
  128. package/dist/src/controllers/rbacController.d.ts +16 -0
  129. package/dist/src/controllers/rbacController.d.ts.map +1 -0
  130. package/dist/src/controllers/rbacController.js +437 -0
  131. package/dist/src/core/database.d.ts +3 -0
  132. package/dist/src/core/database.d.ts.map +1 -0
  133. package/dist/src/core/database.js +34 -0
  134. package/dist/src/core/realtime.d.ts +3 -0
  135. package/dist/src/core/realtime.d.ts.map +1 -0
  136. package/dist/src/core/realtime.js +36 -0
  137. package/dist/src/core/redis.d.ts +8 -0
  138. package/dist/src/core/redis.d.ts.map +1 -0
  139. package/dist/src/core/redis.js +123 -0
  140. package/dist/src/core/serializer.d.ts +43 -0
  141. package/dist/src/core/serializer.d.ts.map +1 -0
  142. package/dist/src/core/serializer.js +66 -0
  143. package/dist/src/core/server.d.ts +2 -0
  144. package/dist/src/core/server.d.ts.map +1 -0
  145. package/dist/src/core/server.js +60 -0
  146. package/dist/src/index.d.ts +2 -0
  147. package/dist/src/index.d.ts.map +1 -0
  148. package/dist/src/index.js +98 -0
  149. package/dist/src/middleware/auth.d.ts +4 -0
  150. package/dist/src/middleware/auth.d.ts.map +1 -0
  151. package/dist/src/middleware/auth.js +48 -0
  152. package/dist/src/middleware/error.d.ts +3 -0
  153. package/dist/src/middleware/error.d.ts.map +1 -0
  154. package/dist/src/middleware/error.js +60 -0
  155. package/dist/src/middleware/multipart.d.ts +4 -0
  156. package/dist/src/middleware/multipart.d.ts.map +1 -0
  157. package/dist/src/middleware/multipart.js +17 -0
  158. package/dist/src/middleware/rateLimit.d.ts +2 -0
  159. package/dist/src/middleware/rateLimit.d.ts.map +1 -0
  160. package/dist/src/middleware/rateLimit.js +19 -0
  161. package/dist/src/middleware/requestLogger.d.ts +3 -0
  162. package/dist/src/middleware/requestLogger.d.ts.map +1 -0
  163. package/dist/src/middleware/requestLogger.js +22 -0
  164. package/dist/src/middleware/visitor.d.ts +3 -0
  165. package/dist/src/middleware/visitor.d.ts.map +1 -0
  166. package/dist/src/middleware/visitor.js +144 -0
  167. package/dist/src/prisma.d.ts +3 -0
  168. package/dist/src/prisma.d.ts.map +1 -0
  169. package/dist/src/prisma.js +34 -0
  170. package/dist/src/realtime.d.ts +3 -0
  171. package/dist/src/realtime.d.ts.map +1 -0
  172. package/dist/src/realtime.js +36 -0
  173. package/dist/src/redis.d.ts +8 -0
  174. package/dist/src/redis.d.ts.map +1 -0
  175. package/dist/src/redis.js +122 -0
  176. package/dist/src/routes/auth.d.ts +2 -0
  177. package/dist/src/routes/auth.d.ts.map +1 -0
  178. package/dist/src/routes/auth.js +45 -0
  179. package/dist/src/routes/index.d.ts +2 -0
  180. package/dist/src/routes/index.d.ts.map +1 -0
  181. package/dist/src/routes/index.js +14 -0
  182. package/dist/src/routes/pets.d.ts +3 -0
  183. package/dist/src/routes/pets.d.ts.map +1 -0
  184. package/dist/src/routes/pets.js +45 -0
  185. package/dist/src/routes/rbac.d.ts +2 -0
  186. package/dist/src/routes/rbac.d.ts.map +1 -0
  187. package/dist/src/routes/rbac.js +23 -0
  188. package/dist/src/schema/auth-schema.d.ts +76 -0
  189. package/dist/src/schema/auth-schema.d.ts.map +1 -0
  190. package/dist/src/schema/auth-schema.js +63 -0
  191. package/dist/src/schema/pet-schema.d.ts +28 -0
  192. package/dist/src/schema/pet-schema.d.ts.map +1 -0
  193. package/dist/src/schema/pet-schema.js +14 -0
  194. package/dist/src/server.d.ts +2 -0
  195. package/dist/src/server.d.ts.map +1 -0
  196. package/dist/src/server.js +31 -0
  197. package/dist/src/utils/logger.d.ts +11 -0
  198. package/dist/src/utils/logger.d.ts.map +1 -0
  199. package/dist/src/utils/logger.js +81 -0
  200. package/dist/src/utils/pagination.d.ts +19 -0
  201. package/dist/src/utils/pagination.d.ts.map +1 -0
  202. package/dist/src/utils/pagination.js +34 -0
  203. package/dist/src/utils/response.d.ts +11 -0
  204. package/dist/src/utils/response.d.ts.map +1 -0
  205. package/dist/src/utils/response.js +57 -0
  206. package/dist/src/utils/validator.d.ts +38 -0
  207. package/dist/src/utils/validator.d.ts.map +1 -0
  208. package/dist/src/utils/validator.js +369 -0
  209. package/lib/bootstrap.ts +6 -0
  210. package/package.json +26 -14
  211. package/.env.example +0 -19
  212. package/doc/ARCHITECTURE_GUIDE.md +0 -73
  213. package/doc/CHANGELOG.md +0 -77
  214. package/doc/CHEATSHEET.md +0 -94
  215. package/doc/CLI.md +0 -139
  216. package/doc/CONTRIBUTING.md +0 -105
  217. package/doc/DEPLOYMENT.md +0 -122
  218. package/doc/FAQ.md +0 -81
  219. package/doc/FEATURES.md +0 -165
  220. package/doc/GETTING_STARTED.md +0 -108
  221. package/doc/INTRODUCTION.md +0 -60
  222. package/doc/PACKAGES.md +0 -66
  223. package/doc/PERFORMANCE.md +0 -91
  224. package/doc/ROADMAP.md +0 -93
  225. package/doc/SECURITY.md +0 -93
  226. package/doc/STRUCTURE.md +0 -90
  227. package/doc/TUTORIAL.md +0 -192
  228. package/docker-compose.yml +0 -24
  229. package/eslint.config.mjs +0 -26
  230. package/framework.md +0 -168
  231. package/nodemon.json +0 -6
  232. package/prisma.config.ts +0 -15
  233. package/src/controllers/authController.ts +0 -469
  234. package/src/controllers/petController.ts +0 -194
  235. package/src/controllers/rbacController.ts +0 -478
  236. package/src/models/core.prisma +0 -163
  237. package/src/models/pets.prisma +0 -9
  238. package/src/routes/auth.ts +0 -74
  239. package/src/routes/index.ts +0 -10
  240. package/src/routes/pets.ts +0 -13
  241. package/src/routes/rbac.ts +0 -42
  242. package/storage/logs/.gitkeep +0 -0
  243. package/tsconfig.json +0 -30
@@ -0,0 +1,414 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ACCESS_TOKEN_EXPIRES_IN_SECONDS = void 0;
7
+ exports.register = register;
8
+ exports.login = login;
9
+ exports.me = me;
10
+ exports.logout = logout;
11
+ exports.refreshToken = refreshToken;
12
+ exports.updateAvatar = updateAvatar;
13
+ exports.updatePassword = updatePassword;
14
+ exports.updateProfile = updateProfile;
15
+ const bcryptjs_1 = __importDefault(require("bcryptjs"));
16
+ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
17
+ const uuid_1 = require("uuid");
18
+ const database_1 = require("../../lib/core/database");
19
+ const response_1 = require("../../lib/utils/response");
20
+ const validator_1 = require("../../lib/utils/validator");
21
+ const serializer_1 = require("../../lib/core/serializer");
22
+ exports.ACCESS_TOKEN_EXPIRES_IN_SECONDS = 7 * 24 * 60 * 60;
23
+ // --- Serializers ---
24
+ const registerSchema = {
25
+ type: "object",
26
+ properties: {
27
+ id: { type: "string" },
28
+ email: { type: "string" },
29
+ name: { type: "string" },
30
+ role: { type: "string" },
31
+ },
32
+ };
33
+ const loginSchema = {
34
+ type: "object",
35
+ properties: {
36
+ token: { type: "string" },
37
+ refreshToken: { type: "string" },
38
+ expiresIn: { type: "integer" },
39
+ expiresAt: { type: "string" },
40
+ name: { type: "string" },
41
+ role: { type: "string" },
42
+ },
43
+ };
44
+ const userProfileSchema = {
45
+ type: "object",
46
+ properties: {
47
+ id: { type: "string" },
48
+ name: { type: "string" },
49
+ email: { type: "string" },
50
+ role: { type: "string" },
51
+ avatar: { type: "string", nullable: true },
52
+ avatar_url: { type: "string", nullable: true },
53
+ email_verified_at: { type: "string", format: "date-time", nullable: true },
54
+ created_at: { type: "string", format: "date-time", nullable: true },
55
+ updated_at: { type: "string", format: "date-time", nullable: true },
56
+ },
57
+ };
58
+ const refreshTokenSchema = {
59
+ type: "object",
60
+ properties: {
61
+ token: { type: "string" },
62
+ expiresIn: { type: "integer" },
63
+ expiresAt: { type: "string" },
64
+ name: { type: "string" },
65
+ role: { type: "string" },
66
+ },
67
+ };
68
+ const registerSerializer = (0, serializer_1.getSerializer)("auth-register", (0, serializer_1.createResponseSchema)(registerSchema));
69
+ const loginSerializer = (0, serializer_1.getSerializer)("auth-login", (0, serializer_1.createResponseSchema)(loginSchema));
70
+ const userProfileSerializer = (0, serializer_1.getSerializer)("auth-profile", (0, serializer_1.createResponseSchema)(userProfileSchema));
71
+ const refreshTokenSerializer = (0, serializer_1.getSerializer)("auth-refresh", (0, serializer_1.createResponseSchema)(refreshTokenSchema));
72
+ const voidSerializer = (0, serializer_1.getSerializer)("void", (0, serializer_1.createResponseSchema)({ type: "null" }));
73
+ // --- Controllers ---
74
+ async function register(req, res) {
75
+ const validator = validator_1.Validator.make(req.body || {}, {
76
+ email: "required|email|unique:users,email",
77
+ name: "required|min:1",
78
+ password: "required|min:4",
79
+ confirmPassword: "required|min:4|same:password",
80
+ });
81
+ if (await validator.fails()) {
82
+ (0, response_1.sendError)(res, 422, "Validation error", validator.errors());
83
+ return;
84
+ }
85
+ const { email, name, password } = await validator.validated();
86
+ // Manual unique check removed as it is handled by validator
87
+ const hash = await bcryptjs_1.default.hash(password, 10);
88
+ const user = await database_1.prisma.users.create({
89
+ data: {
90
+ email,
91
+ name,
92
+ password: hash,
93
+ uuid: (0, uuid_1.v4)(),
94
+ created_at: new Date(),
95
+ updated_at: new Date(),
96
+ },
97
+ });
98
+ const defaultRole = await database_1.prisma.roles.findUnique({
99
+ where: { slug: "user" },
100
+ });
101
+ if (defaultRole) {
102
+ await database_1.prisma.user_roles.create({
103
+ data: {
104
+ user_id: user.id,
105
+ role_id: defaultRole.id,
106
+ created_at: new Date(),
107
+ },
108
+ });
109
+ }
110
+ (0, response_1.sendFastSuccess)(res, 200, registerSerializer, {
111
+ status: "success",
112
+ message: "Registration successful",
113
+ data: {
114
+ id: user.id.toString(),
115
+ email: user.email,
116
+ name: user.name,
117
+ role: defaultRole ? defaultRole.slug : "user",
118
+ },
119
+ });
120
+ }
121
+ async function login(req, res) {
122
+ const validator = validator_1.Validator.make(req.body || {}, {
123
+ email: "required|email",
124
+ password: "required|min:4",
125
+ });
126
+ if (await validator.fails()) {
127
+ (0, response_1.sendError)(res, 422, "Validation error", validator.errors());
128
+ return;
129
+ }
130
+ const { email, password } = await validator.validated();
131
+ const user = await database_1.prisma.users.findUnique({
132
+ where: { email },
133
+ include: {
134
+ user_roles: {
135
+ include: {
136
+ role: true,
137
+ },
138
+ },
139
+ },
140
+ });
141
+ if (!user) {
142
+ (0, response_1.sendError)(res, 401, "Email not registered", {
143
+ field: "email",
144
+ message: "Email is not registered, please register first",
145
+ });
146
+ return;
147
+ }
148
+ const ok = await bcryptjs_1.default.compare(password, user.password);
149
+ if (!ok) {
150
+ (0, response_1.sendError)(res, 401, "Invalid credentials", {
151
+ field: "password",
152
+ message: "The password you entered is incorrect",
153
+ });
154
+ return;
155
+ }
156
+ const secret = process.env.JWT_SECRET;
157
+ if (!secret) {
158
+ (0, response_1.sendError)(res, 500, "Server misconfigured");
159
+ return;
160
+ }
161
+ const primaryUserRole = user.user_roles && user.user_roles.length > 0 && user.user_roles[0].role
162
+ ? user.user_roles[0].role.slug
163
+ : "user";
164
+ const accessExpiresInSeconds = exports.ACCESS_TOKEN_EXPIRES_IN_SECONDS;
165
+ const accessExpiresAt = new Date(Date.now() + accessExpiresInSeconds * 1000).toISOString();
166
+ const token = jsonwebtoken_1.default.sign({ userId: user.id.toString(), role: primaryUserRole }, secret, { expiresIn: accessExpiresInSeconds });
167
+ const refreshExpiresInSeconds = 30 * 24 * 60 * 60;
168
+ const refreshToken = jsonwebtoken_1.default.sign({
169
+ userId: user.id.toString(),
170
+ role: primaryUserRole,
171
+ tokenType: "refresh",
172
+ }, secret, { expiresIn: refreshExpiresInSeconds });
173
+ (0, response_1.sendFastSuccess)(res, 200, loginSerializer, {
174
+ status: "success",
175
+ message: "Login successful",
176
+ data: {
177
+ token,
178
+ refreshToken,
179
+ expiresIn: accessExpiresInSeconds,
180
+ expiresAt: accessExpiresAt,
181
+ name: user.name,
182
+ role: primaryUserRole,
183
+ },
184
+ });
185
+ }
186
+ async function me(req, res) {
187
+ const payload = req.user;
188
+ if (!payload || !payload.userId) {
189
+ (0, response_1.sendError)(res, 401, "Unauthorized");
190
+ return;
191
+ }
192
+ const user = await database_1.prisma.users.findUnique({
193
+ where: { id: BigInt(payload.userId) },
194
+ include: {
195
+ user_roles: {
196
+ include: {
197
+ role: true,
198
+ },
199
+ },
200
+ },
201
+ });
202
+ if (!user) {
203
+ (0, response_1.sendError)(res, 404, "User not found");
204
+ return;
205
+ }
206
+ const { password, remember_token, ...rest } = user;
207
+ (0, response_1.sendFastSuccess)(res, 200, userProfileSerializer, {
208
+ status: "success",
209
+ message: "User profile",
210
+ data: {
211
+ ...rest,
212
+ id: user.id.toString(),
213
+ role: user.user_roles && user.user_roles.length > 0 && user.user_roles[0].role
214
+ ? user.user_roles[0].role.slug
215
+ : "user",
216
+ },
217
+ });
218
+ }
219
+ async function logout(_req, res) {
220
+ // In a stateless JWT setup, logout is client-side (delete token).
221
+ // If using a whitelist/blacklist in Redis, invalidate the token here.
222
+ // For now, just return success.
223
+ (0, response_1.sendFastSuccess)(res, 200, voidSerializer, {
224
+ status: "success",
225
+ message: "Logout successful",
226
+ data: null,
227
+ });
228
+ }
229
+ async function refreshToken(req, res) {
230
+ const validator = validator_1.Validator.make(req.body || {}, {
231
+ refreshToken: "required|min:1",
232
+ });
233
+ if (await validator.fails()) {
234
+ (0, response_1.sendError)(res, 422, "Validation error", validator.errors());
235
+ return;
236
+ }
237
+ const secret = process.env.JWT_SECRET;
238
+ if (!secret) {
239
+ (0, response_1.sendError)(res, 500, "Server misconfigured");
240
+ return;
241
+ }
242
+ try {
243
+ const validatedData = await validator.validated();
244
+ const decoded = jsonwebtoken_1.default.verify(validatedData.refreshToken, secret);
245
+ if (decoded.tokenType !== "refresh") {
246
+ (0, response_1.sendError)(res, 401, "Invalid refresh token");
247
+ return;
248
+ }
249
+ const user = await database_1.prisma.users.findUnique({
250
+ where: { id: BigInt(decoded.userId) },
251
+ include: {
252
+ user_roles: {
253
+ include: {
254
+ role: true,
255
+ },
256
+ },
257
+ },
258
+ });
259
+ if (!user) {
260
+ (0, response_1.sendError)(res, 401, "Invalid refresh token");
261
+ return;
262
+ }
263
+ const primaryUserRole = user.user_roles && user.user_roles.length > 0 && user.user_roles[0].role
264
+ ? user.user_roles[0].role.slug
265
+ : "user";
266
+ const accessExpiresInSeconds = exports.ACCESS_TOKEN_EXPIRES_IN_SECONDS;
267
+ const accessExpiresAt = new Date(Date.now() + accessExpiresInSeconds * 1000).toISOString();
268
+ const token = jsonwebtoken_1.default.sign({ userId: user.id.toString(), role: primaryUserRole }, secret, { expiresIn: accessExpiresInSeconds });
269
+ (0, response_1.sendFastSuccess)(res, 200, refreshTokenSerializer, {
270
+ status: "success",
271
+ message: "Token refreshed",
272
+ data: {
273
+ token,
274
+ expiresIn: accessExpiresInSeconds,
275
+ expiresAt: accessExpiresAt,
276
+ name: user.name,
277
+ role: primaryUserRole,
278
+ },
279
+ });
280
+ }
281
+ catch {
282
+ (0, response_1.sendError)(res, 401, "Invalid refresh token");
283
+ }
284
+ }
285
+ async function updateAvatar(req, res) {
286
+ const payload = req.user;
287
+ if (!payload || !payload.userId) {
288
+ (0, response_1.sendError)(res, 401, "Unauthorized");
289
+ return;
290
+ }
291
+ const data = {
292
+ avatar: req.file,
293
+ };
294
+ const validator = validator_1.Validator.make(data, {
295
+ avatar: "nullable|image|mimes:jpeg,png,jpg,gif|max:2048",
296
+ });
297
+ if (await validator.fails()) {
298
+ (0, response_1.sendError)(res, 422, "Validation error", validator.errors());
299
+ return;
300
+ }
301
+ const { avatar: file } = await validator.validated();
302
+ if (!file) {
303
+ (0, response_1.sendError)(res, 400, "Avatar file is required");
304
+ return;
305
+ }
306
+ const userId = BigInt(payload.userId);
307
+ const avatar = file.filename;
308
+ const avatar_url = process.env.AVATAR_BASE_URL || `/uploads/avatars/${file.filename}`;
309
+ const updated = await database_1.prisma.users.update({
310
+ where: { id: userId },
311
+ data: {
312
+ avatar,
313
+ avatar_url,
314
+ updated_at: new Date(),
315
+ },
316
+ });
317
+ const { password, remember_token, ...rest } = updated;
318
+ // Note: user_roles might not be fetched in update, so role defaults to "user" or fetched if needed.
319
+ // Ideally we should refetch or pass existing role.
320
+ // For now assuming role is preserved or handled by frontend state, but API should return it.
321
+ // Let's rely on nullable role or simple "user" fallback if not present in `updated`.
322
+ // Actually `update` returns what was updated. Relations are not included unless specified.
323
+ // For now we will return it compatible with userProfileSchema.
324
+ (0, response_1.sendFastSuccess)(res, 200, userProfileSerializer, {
325
+ status: "success",
326
+ message: "Avatar updated successfully",
327
+ data: {
328
+ ...rest,
329
+ id: updated.id.toString(),
330
+ role: payload.role, // Use role from JWT payload as it shouldn't change here
331
+ },
332
+ });
333
+ }
334
+ async function updatePassword(req, res) {
335
+ const payload = req.user;
336
+ if (!payload || !payload.userId) {
337
+ (0, response_1.sendError)(res, 401, "Unauthorized");
338
+ return;
339
+ }
340
+ const validator = validator_1.Validator.make(req.body || {}, {
341
+ currentPassword: "required|min:4",
342
+ newPassword: "required|min:4",
343
+ confirmPassword: "required|min:4|same:newPassword",
344
+ });
345
+ if (await validator.fails()) {
346
+ (0, response_1.sendError)(res, 422, "Validation error", validator.errors());
347
+ return;
348
+ }
349
+ const { currentPassword, newPassword } = await validator.validated();
350
+ const user = await database_1.prisma.users.findUnique({
351
+ where: { id: BigInt(payload.userId) },
352
+ });
353
+ if (!user) {
354
+ (0, response_1.sendError)(res, 404, "User not found");
355
+ return;
356
+ }
357
+ const ok = await bcryptjs_1.default.compare(currentPassword, user.password);
358
+ if (!ok) {
359
+ (0, response_1.sendError)(res, 401, "Invalid credentials", {
360
+ field: "currentPassword",
361
+ message: "Current password is incorrect",
362
+ });
363
+ return;
364
+ }
365
+ const hash = await bcryptjs_1.default.hash(newPassword, 10);
366
+ await database_1.prisma.users.update({
367
+ where: { id: user.id },
368
+ data: {
369
+ password: hash,
370
+ updated_at: new Date(),
371
+ },
372
+ });
373
+ (0, response_1.sendFastSuccess)(res, 200, voidSerializer, {
374
+ status: "success",
375
+ message: "Password updated successfully",
376
+ data: null,
377
+ });
378
+ }
379
+ async function updateProfile(req, res) {
380
+ const payload = req.user;
381
+ if (!payload || !payload.userId) {
382
+ (0, response_1.sendError)(res, 401, "Unauthorized");
383
+ return;
384
+ }
385
+ const validator = validator_1.Validator.make(req.body || {}, {
386
+ name: "required|min:1",
387
+ email: `required|email|unique:users,email,${payload.userId}`,
388
+ });
389
+ if (await validator.fails()) {
390
+ (0, response_1.sendError)(res, 422, "Validation error", validator.errors());
391
+ return;
392
+ }
393
+ const { name, email } = await validator.validated();
394
+ const userId = BigInt(payload.userId);
395
+ // Manual unique check removed as it is handled by validator
396
+ const updated = await database_1.prisma.users.update({
397
+ where: { id: userId },
398
+ data: {
399
+ name,
400
+ email,
401
+ updated_at: new Date(),
402
+ },
403
+ });
404
+ const { password, remember_token, ...rest } = updated;
405
+ (0, response_1.sendFastSuccess)(res, 200, userProfileSerializer, {
406
+ status: "success",
407
+ message: "Profile updated successfully",
408
+ data: {
409
+ ...rest,
410
+ id: updated.id.toString(),
411
+ role: payload.role, // Use role from JWT payload
412
+ },
413
+ });
414
+ }
@@ -0,0 +1,7 @@
1
+ import { Request, Response } from "express";
2
+ export declare function index(req: Request, res: Response): Promise<void>;
3
+ export declare function show(req: Request, res: Response): Promise<void>;
4
+ export declare function store(req: Request, res: Response): Promise<void>;
5
+ export declare function update(req: Request, res: Response): Promise<void>;
6
+ export declare function destroy(req: Request, res: Response): Promise<void>;
7
+ //# sourceMappingURL=petController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"petController.d.ts","sourceRoot":"","sources":["../../../src/controllers/petController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAqC5C,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAyCtD;AAED,wBAAsB,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAoBrD;AAED,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBA8BtD;AAED,wBAAsB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAwCvD;AAED,wBAAsB,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAiBxD"}
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.index = index;
4
+ exports.show = show;
5
+ exports.store = store;
6
+ exports.update = update;
7
+ exports.destroy = destroy;
8
+ const database_1 = require("../../lib/core/database");
9
+ const response_1 = require("../../lib/utils/response");
10
+ const pagination_1 = require("../../lib/utils/pagination");
11
+ const validator_1 = require("../../lib/utils/validator");
12
+ const serializer_1 = require("../../lib/core/serializer");
13
+ // 1. Definisikan Schema Output untuk performa tinggi
14
+ const petSchema = {
15
+ type: "object",
16
+ properties: {
17
+ id: { type: "string" }, // BigInt dikonversi ke string
18
+ name: { type: "string" },
19
+ species: { type: "string" },
20
+ age: { type: "integer" },
21
+ created_at: { type: "string", format: "date-time" },
22
+ updated_at: { type: "string", format: "date-time" },
23
+ },
24
+ };
25
+ // 2. Compile Serializer
26
+ // Untuk Single Item
27
+ const petSerializer = (0, serializer_1.getSerializer)("pet-single", (0, serializer_1.createResponseSchema)(petSchema));
28
+ // Untuk List Item (Paginated)
29
+ const petListSerializer = (0, serializer_1.getSerializer)("pet-list", (0, serializer_1.createPaginatedResponseSchema)(petSchema));
30
+ async function index(req, res) {
31
+ const { page, perPage, skip, take } = (0, pagination_1.getPagination)(req.query);
32
+ const search = req.query.search;
33
+ const where = {};
34
+ if (search) {
35
+ where.OR = [
36
+ { name: { contains: search, mode: "insensitive" } },
37
+ { species: { contains: search, mode: "insensitive" } },
38
+ ];
39
+ }
40
+ const [data, total] = await Promise.all([
41
+ database_1.prisma.pets.findMany({
42
+ where,
43
+ skip,
44
+ take,
45
+ orderBy: { created_at: "desc" },
46
+ }),
47
+ database_1.prisma.pets.count({ where }),
48
+ ]);
49
+ // Kita perlu convert BigInt ke string sebelum masuk serializer
50
+ // Karena fast-json-stringify mengharapkan tipe data yang sesuai dengan schema
51
+ const serialized = data.map((item) => ({
52
+ ...item,
53
+ id: item.id.toString(),
54
+ }));
55
+ const meta = (0, pagination_1.buildPaginationMeta)(page, perPage, total);
56
+ // Gunakan sendFastSuccess untuk performa maksimal
57
+ // Struktur data disesuaikan dengan createPaginatedResponseSchema: { data: [], meta: {} }
58
+ (0, response_1.sendFastSuccess)(res, 200, petListSerializer, {
59
+ status: "success",
60
+ message: "Pets retrieved successfully",
61
+ data: {
62
+ data: serialized,
63
+ meta,
64
+ },
65
+ });
66
+ }
67
+ async function show(req, res) {
68
+ const { id } = req.params;
69
+ const pet = await database_1.prisma.pets.findUnique({
70
+ where: { id: BigInt(id) },
71
+ });
72
+ if (!pet) {
73
+ (0, response_1.sendError)(res, 404, "Pet not found");
74
+ return;
75
+ }
76
+ // Gunakan sendFastSuccess
77
+ (0, response_1.sendFastSuccess)(res, 200, petSerializer, {
78
+ status: "success",
79
+ message: "Pet retrieved successfully",
80
+ data: {
81
+ ...pet,
82
+ id: pet.id.toString(),
83
+ },
84
+ });
85
+ }
86
+ async function store(req, res) {
87
+ const validator = validator_1.Validator.make(req.body || {}, {
88
+ name: "required|string",
89
+ species: "required|string",
90
+ age: "required|integer|min:1",
91
+ });
92
+ if (await validator.fails()) {
93
+ (0, response_1.sendError)(res, 422, "Validation error", validator.errors());
94
+ return;
95
+ }
96
+ const validatedData = await validator.validated();
97
+ const pet = await database_1.prisma.pets.create({
98
+ data: {
99
+ ...validatedData,
100
+ created_at: new Date(),
101
+ updated_at: new Date(),
102
+ },
103
+ });
104
+ // Gunakan sendFastSuccess
105
+ (0, response_1.sendFastSuccess)(res, 201, petSerializer, {
106
+ status: "success",
107
+ message: "Pet created successfully",
108
+ data: {
109
+ ...pet,
110
+ id: pet.id.toString(),
111
+ },
112
+ });
113
+ }
114
+ async function update(req, res) {
115
+ const { id } = req.params;
116
+ const validator = validator_1.Validator.make(req.body || {}, {
117
+ name: "string",
118
+ species: "string",
119
+ age: "integer|min:1",
120
+ });
121
+ if (await validator.fails()) {
122
+ (0, response_1.sendError)(res, 422, "Validation error", validator.errors());
123
+ return;
124
+ }
125
+ const existing = await database_1.prisma.pets.findUnique({
126
+ where: { id: BigInt(id) },
127
+ });
128
+ if (!existing) {
129
+ (0, response_1.sendError)(res, 404, "Pet not found");
130
+ return;
131
+ }
132
+ const validatedData = await validator.validated();
133
+ const updated = await database_1.prisma.pets.update({
134
+ where: { id: BigInt(id) },
135
+ data: {
136
+ ...validatedData,
137
+ updated_at: new Date(),
138
+ },
139
+ });
140
+ // Gunakan sendFastSuccess
141
+ (0, response_1.sendFastSuccess)(res, 200, petSerializer, {
142
+ status: "success",
143
+ message: "Pet updated successfully",
144
+ data: {
145
+ ...updated,
146
+ id: updated.id.toString(),
147
+ },
148
+ });
149
+ }
150
+ async function destroy(req, res) {
151
+ const { id } = req.params;
152
+ const existing = await database_1.prisma.pets.findUnique({
153
+ where: { id: BigInt(id) },
154
+ });
155
+ if (!existing) {
156
+ (0, response_1.sendError)(res, 404, "Pet not found");
157
+ return;
158
+ }
159
+ await database_1.prisma.pets.delete({
160
+ where: { id: BigInt(id) },
161
+ });
162
+ (0, response_1.sendSuccess)(res, 200, "Pet deleted successfully", null);
163
+ }
@@ -0,0 +1,16 @@
1
+ import { Request, Response } from "express";
2
+ export declare function createRole(req: Request, res: Response): Promise<void>;
3
+ export declare function listRoles(_req: Request, res: Response): Promise<void>;
4
+ export declare function updateRole(req: Request, res: Response): Promise<void>;
5
+ export declare function deleteRole(req: Request, res: Response): Promise<void>;
6
+ export declare function createPermission(req: Request, res: Response): Promise<void>;
7
+ export declare function listPermissions(_req: Request, res: Response): Promise<void>;
8
+ export declare function updatePermission(req: Request, res: Response): Promise<void>;
9
+ export declare function deletePermission(req: Request, res: Response): Promise<void>;
10
+ export declare function assignRoleToUser(req: Request, res: Response): Promise<void>;
11
+ export declare function removeRoleFromUser(req: Request, res: Response): Promise<void>;
12
+ export declare function assignPermissionToRole(req: Request, res: Response): Promise<void>;
13
+ export declare function removePermissionFromRole(req: Request, res: Response): Promise<void>;
14
+ export declare function assignPermissionToUser(req: Request, res: Response): Promise<void>;
15
+ export declare function removePermissionFromUser(req: Request, res: Response): Promise<void>;
16
+ //# sourceMappingURL=rbacController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rbacController.d.ts","sourceRoot":"","sources":["../../../src/controllers/rbacController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAuD5C,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBA6B3D;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAU3D;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAoC3D;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAgB3D;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBA4BjE;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAajE;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAsCjE;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAsBjE;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBA6CjE;AAED,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAuBnE;AAED,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBA6CvE;AAED,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAuBzE;AAED,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBA6CvE;AAED,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,iBAuBzE"}