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,43 @@
1
+ /**
2
+ * Membuat atau mengambil serializer yang sudah dicompile.
3
+ *
4
+ * @param key Identifier unik untuk schema (misal: 'UserResponse', 'ProductList')
5
+ * @param schema JSON Schema definition (Standard JSON Schema)
6
+ * @returns Fungsi yang mengubah object menjadi JSON string dengan sangat cepat
7
+ */
8
+ export declare function getSerializer(key: string, schema: any): <TDoc = any>(doc: TDoc) => any;
9
+ /**
10
+ * Helper untuk mendefinisikan schema standar response Lapeh
11
+ * { status: "success", message: string, data: T }
12
+ */
13
+ export declare function createResponseSchema(dataSchema: any): {
14
+ title: string;
15
+ type: string;
16
+ properties: {
17
+ status: {
18
+ type: string;
19
+ };
20
+ message: {
21
+ type: string;
22
+ };
23
+ data: any;
24
+ };
25
+ };
26
+ /**
27
+ * Helper khusus untuk response paginasi
28
+ * { status: "success", message: string, data: { data: T[], meta: ... } }
29
+ */
30
+ export declare function createPaginatedResponseSchema(itemSchema: any): {
31
+ title: string;
32
+ type: string;
33
+ properties: {
34
+ status: {
35
+ type: string;
36
+ };
37
+ message: {
38
+ type: string;
39
+ };
40
+ data: any;
41
+ };
42
+ };
43
+ //# sourceMappingURL=serializer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../../../src/core/serializer.ts"],"names":[],"mappings":"AAMA;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,kCAQrD;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,GAAG;;;;;;;;;;;;EAUnD;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,GAAG;;;;;;;;;;;;EAmB5D"}
@@ -0,0 +1,66 @@
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.getSerializer = getSerializer;
7
+ exports.createResponseSchema = createResponseSchema;
8
+ exports.createPaginatedResponseSchema = createPaginatedResponseSchema;
9
+ const fast_json_stringify_1 = __importDefault(require("fast-json-stringify"));
10
+ // Cache untuk menyimpan fungsi stringify yang sudah dicompile
11
+ // Key: Nama schema/Identifier, Value: Fungsi stringify
12
+ const serializerCache = new Map();
13
+ /**
14
+ * Membuat atau mengambil serializer yang sudah dicompile.
15
+ *
16
+ * @param key Identifier unik untuk schema (misal: 'UserResponse', 'ProductList')
17
+ * @param schema JSON Schema definition (Standard JSON Schema)
18
+ * @returns Fungsi yang mengubah object menjadi JSON string dengan sangat cepat
19
+ */
20
+ function getSerializer(key, schema) {
21
+ if (serializerCache.has(key)) {
22
+ return serializerCache.get(key);
23
+ }
24
+ const stringify = (0, fast_json_stringify_1.default)(schema);
25
+ serializerCache.set(key, stringify);
26
+ return stringify;
27
+ }
28
+ /**
29
+ * Helper untuk mendefinisikan schema standar response Lapeh
30
+ * { status: "success", message: string, data: T }
31
+ */
32
+ function createResponseSchema(dataSchema) {
33
+ return {
34
+ title: "StandardResponse",
35
+ type: "object",
36
+ properties: {
37
+ status: { type: "string" },
38
+ message: { type: "string" },
39
+ data: dataSchema,
40
+ },
41
+ };
42
+ }
43
+ /**
44
+ * Helper khusus untuk response paginasi
45
+ * { status: "success", message: string, data: { data: T[], meta: ... } }
46
+ */
47
+ function createPaginatedResponseSchema(itemSchema) {
48
+ return createResponseSchema({
49
+ type: "object",
50
+ properties: {
51
+ data: {
52
+ type: "array",
53
+ items: itemSchema,
54
+ },
55
+ meta: {
56
+ type: "object",
57
+ properties: {
58
+ page: { type: "integer" },
59
+ perPage: { type: "integer" },
60
+ total: { type: "integer" },
61
+ lastPage: { type: "integer" },
62
+ },
63
+ },
64
+ },
65
+ });
66
+ }
@@ -0,0 +1,2 @@
1
+ export declare const app: import("express-serve-static-core").Express;
2
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/core/server.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,GAAG,6CAAY,CAAC"}
@@ -0,0 +1,60 @@
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.app = void 0;
7
+ const express_1 = __importDefault(require("express"));
8
+ const cors_1 = __importDefault(require("cors"));
9
+ const helmet_1 = __importDefault(require("helmet"));
10
+ const compression_1 = __importDefault(require("compression"));
11
+ const routes_1 = require("../routes"); // Import unified routes
12
+ const visitor_1 = require("../middleware/visitor");
13
+ const error_1 = require("../middleware/error");
14
+ const rateLimit_1 = require("../middleware/rateLimit");
15
+ const requestLogger_1 = require("../middleware/requestLogger");
16
+ const response_1 = require("../utils/response");
17
+ exports.app = (0, express_1.default)();
18
+ exports.app.disable("x-powered-by");
19
+ // Compression (Gzip)
20
+ exports.app.use((0, compression_1.default)());
21
+ // Request Timeout Middleware (30s)
22
+ exports.app.use((_req, res, next) => {
23
+ res.setTimeout(30000, () => {
24
+ res.status(408).send({
25
+ status: "error",
26
+ message: "Request Timeout (30s limit)",
27
+ });
28
+ });
29
+ next();
30
+ });
31
+ // Security Headers
32
+ exports.app.use((0, helmet_1.default)({
33
+ contentSecurityPolicy: false, // Disarankan true jika menggunakan frontend di domain yang sama
34
+ crossOriginResourcePolicy: { policy: "cross-origin" },
35
+ }));
36
+ const corsOrigin = process.env.CORS_ORIGIN || "*";
37
+ exports.app.use((0, cors_1.default)({
38
+ origin: corsOrigin,
39
+ credentials: true,
40
+ exposedHeaders: ["x-access-token", "x-access-expires-at"],
41
+ }));
42
+ // Logging & Parsing
43
+ exports.app.use(requestLogger_1.requestLogger);
44
+ exports.app.use(express_1.default.json({ limit: "10mb" })); // Limit dinaikkan untuk upload file base64/besar
45
+ exports.app.use(express_1.default.urlencoded({ extended: true, limit: "10mb" }));
46
+ // Rate Limiting (Global)
47
+ exports.app.use(rateLimit_1.apiLimiter);
48
+ exports.app.use(visitor_1.visitorCounter);
49
+ // Health Check Endpoint
50
+ exports.app.get("/", (_req, res) => {
51
+ (0, response_1.sendSuccess)(res, 200, "Lapeh API is running", {
52
+ status: "active",
53
+ timestamp: new Date(),
54
+ version: process.env.npm_package_version || "2.1.6",
55
+ });
56
+ });
57
+ // Routes
58
+ exports.app.use("/api", routes_1.apiRouter);
59
+ // Global Error Handler
60
+ exports.app.use(error_1.errorHandler);
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,98 @@
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
+ const dotenv_1 = __importDefault(require("dotenv"));
7
+ dotenv_1.default.config();
8
+ // Validasi Environment Variables
9
+ const requiredEnvs = ["DATABASE_URL", "JWT_SECRET"];
10
+ const missingEnvs = requiredEnvs.filter((key) => !process.env[key]);
11
+ if (missingEnvs.length > 0) {
12
+ console.error(`❌ Missing required environment variables: ${missingEnvs.join(", ")}`);
13
+ process.exit(1);
14
+ }
15
+ const server_1 = require("./core/server");
16
+ const http_1 = __importDefault(require("http"));
17
+ const realtime_1 = require("./core/realtime");
18
+ const redis_1 = require("./core/redis"); // Pastikan redis diexport di redis.ts
19
+ const database_1 = require("./core/database");
20
+ const port = process.env.PORT ? Number(process.env.PORT) : 4000;
21
+ const server = http_1.default.createServer(server_1.app);
22
+ (0, realtime_1.initRealtime)(server);
23
+ const startServer = async () => {
24
+ try {
25
+ // Initialize Redis transparently (no logs if missing)
26
+ await (0, redis_1.initRedis)();
27
+ // Handle specific listen errors
28
+ server.on("error", (e) => {
29
+ if (e.code === "EADDRINUSE") {
30
+ console.log(`\n❌ Error: Port ${port} is already in use.`);
31
+ console.log(`💡 Suggestion: Run this command to kill the conflicting process:\n`);
32
+ if (process.platform === "win32") {
33
+ console.log(` npx kill-port ${port}`);
34
+ console.log(` (PowerShell): Stop-Process -Id (Get-NetTCPConnection -LocalPort ${port}).OwningProcess -Force`);
35
+ }
36
+ else if (process.platform === "darwin") {
37
+ console.log(` npx kill-port ${port}`);
38
+ console.log(` (Terminal): kill -9 $(lsof -t -i:${port})`);
39
+ }
40
+ else {
41
+ // Linux
42
+ console.log(` npx kill-port ${port}`);
43
+ console.log(` (Terminal): fuser -k ${port}/tcp`);
44
+ }
45
+ process.exit(1);
46
+ }
47
+ });
48
+ server.listen(port, () => {
49
+ console.log(`✅ API running at http://localhost:${port}`);
50
+ console.log(`🛡️ Environment: ${process.env.NODE_ENV || "development"}`);
51
+ });
52
+ }
53
+ catch (error) {
54
+ console.error("❌ Failed to start server:", error);
55
+ process.exit(1);
56
+ }
57
+ };
58
+ startServer();
59
+ // Graceful Shutdown
60
+ const shutdown = async (signal) => {
61
+ console.log(`\n🛑 ${signal} received. Closing resources...`);
62
+ server.close(() => {
63
+ console.log("Http server closed.");
64
+ });
65
+ try {
66
+ await database_1.prisma.$disconnect();
67
+ console.log("Prisma disconnected.");
68
+ // Jika redis object available, disconnect
69
+ if (redis_1.redis && redis_1.redis.status === "ready") {
70
+ await redis_1.redis.quit();
71
+ console.log("Redis disconnected.");
72
+ }
73
+ process.exit(0);
74
+ }
75
+ catch (err) {
76
+ console.error("Error during shutdown:", err);
77
+ process.exit(1);
78
+ }
79
+ };
80
+ process.on("SIGTERM", () => shutdown("SIGTERM"));
81
+ process.on("SIGINT", () => shutdown("SIGINT"));
82
+ // Menangani Uncaught Exceptions (Error sinkron yang tidak tertangkap)
83
+ process.on("uncaughtException", (error) => {
84
+ console.error("❌ Uncaught Exception:", error);
85
+ // Disarankan untuk restart process di production (gunakan PM2 atau Docker)
86
+ shutdown("uncaughtException");
87
+ });
88
+ // Menangani Unhandled Rejection (Promise yang error tapi tidak di-catch)
89
+ process.on("unhandledRejection", (reason) => {
90
+ console.error("❌ Unhandled Rejection:", reason);
91
+ // Tidak perlu langsung exit, tapi harus dicatat
92
+ // shutdown("unhandledRejection");
93
+ });
94
+ // Menangani Unhandled Rejection (Promise yang reject tapi tidak di-catch)
95
+ process.on("unhandledRejection", (reason, promise) => {
96
+ console.error("❌ Unhandled Rejection at:", promise, "reason:", reason);
97
+ // Log error tapi jangan matikan server jika tidak kritikal, atau shutdown jika perlu
98
+ });
@@ -0,0 +1,4 @@
1
+ import { Request, Response, NextFunction } from "express";
2
+ export declare function requireAuth(req: Request, res: Response, next: NextFunction): void;
3
+ export declare function requireAdmin(req: Request, res: Response, next: NextFunction): void;
4
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/middleware/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAK1D,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,QAmC1E;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,QAa3E"}
@@ -0,0 +1,48 @@
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.requireAuth = requireAuth;
7
+ exports.requireAdmin = requireAdmin;
8
+ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
9
+ const response_1 = require("../utils/response");
10
+ const authController_1 = require("../controllers/authController");
11
+ function requireAuth(req, res, next) {
12
+ const header = req.headers.authorization;
13
+ if (!header || !header.startsWith("Bearer ")) {
14
+ (0, response_1.sendError)(res, 401, "Unauthorized");
15
+ return;
16
+ }
17
+ const token = header.slice(7);
18
+ const secret = process.env.JWT_SECRET;
19
+ if (!secret) {
20
+ (0, response_1.sendError)(res, 500, "Server misconfigured");
21
+ return;
22
+ }
23
+ try {
24
+ const payload = jsonwebtoken_1.default.verify(token, secret);
25
+ req.user = { userId: payload.userId, role: payload.role };
26
+ const accessExpiresInSeconds = authController_1.ACCESS_TOKEN_EXPIRES_IN_SECONDS;
27
+ const accessExpiresAt = new Date(Date.now() + accessExpiresInSeconds * 1000).toISOString();
28
+ const newToken = jsonwebtoken_1.default.sign({ userId: payload.userId, role: payload.role }, secret, { expiresIn: accessExpiresInSeconds });
29
+ res.setHeader("x-access-token", newToken);
30
+ res.setHeader("x-access-expires-at", accessExpiresAt);
31
+ next();
32
+ }
33
+ catch {
34
+ (0, response_1.sendError)(res, 401, "Invalid token");
35
+ }
36
+ }
37
+ function requireAdmin(req, res, next) {
38
+ const user = req.user;
39
+ if (!user) {
40
+ (0, response_1.sendError)(res, 401, "Unauthorized");
41
+ return;
42
+ }
43
+ if (user.role !== "admin" && user.role !== "super_admin") {
44
+ (0, response_1.sendError)(res, 403, "Forbidden");
45
+ return;
46
+ }
47
+ next();
48
+ }
@@ -0,0 +1,3 @@
1
+ import { Request, Response, NextFunction } from "express";
2
+ export declare function errorHandler(err: any, req: Request, res: Response, _next: NextFunction): Response<any, Record<string, any>>;
3
+ //# sourceMappingURL=error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../../src/middleware/error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAM1D,wBAAgB,YAAY,CAC1B,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,KAAK,EAAE,YAAY,sCA2DpB"}
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.errorHandler = errorHandler;
4
+ const zod_1 = require("zod");
5
+ const client_1 = require("@prisma/client");
6
+ const response_1 = require("../utils/response");
7
+ const logger_1 = require("../utils/logger");
8
+ function errorHandler(err, req, res, _next) {
9
+ // 1. Zod Validation Error
10
+ if (err instanceof zod_1.ZodError) {
11
+ const formattedErrors = err.errors.map((e) => ({
12
+ field: e.path.join("."),
13
+ message: e.message,
14
+ }));
15
+ return (0, response_1.sendError)(res, 400, "Validation Error", formattedErrors);
16
+ }
17
+ // 2. Prisma Errors
18
+ if (err instanceof client_1.Prisma.PrismaClientKnownRequestError) {
19
+ // P2002: Unique constraint failed
20
+ if (err.code === "P2002") {
21
+ const target = err.meta?.target || [];
22
+ const fields = target.length > 0 ? target.join(", ") : "field";
23
+ return (0, response_1.sendError)(res, 409, `Unique constraint failed on: ${fields}`);
24
+ }
25
+ // P2003: Foreign key constraint failed
26
+ if (err.code === "P2003") {
27
+ const field = err.meta?.field_name || "unknown field";
28
+ return (0, response_1.sendError)(res, 400, `Foreign key constraint failed on: ${field}`);
29
+ }
30
+ // P2025: Record not found
31
+ if (err.code === "P2025") {
32
+ return (0, response_1.sendError)(res, 404, "Record not found");
33
+ }
34
+ }
35
+ // 3. JWT Errors
36
+ if (err.name === "JsonWebTokenError") {
37
+ return (0, response_1.sendError)(res, 401, "Invalid token");
38
+ }
39
+ if (err.name === "TokenExpiredError") {
40
+ return (0, response_1.sendError)(res, 401, "Token expired");
41
+ }
42
+ // 4. Syntax Error (JSON body parsing)
43
+ if (err instanceof SyntaxError && "body" in err) {
44
+ return (0, response_1.sendError)(res, 400, "Invalid JSON format");
45
+ }
46
+ // 5. Default / Custom Error
47
+ const code = err.statusCode || 500;
48
+ const msg = err.message || "Internal Server Error";
49
+ // Log error (file log for production, console for dev)
50
+ if (code === 500) {
51
+ logger_1.Log.error(msg, {
52
+ error: err,
53
+ path: req.path,
54
+ method: req.method,
55
+ ip: req.ip,
56
+ stack: err.stack,
57
+ });
58
+ }
59
+ return (0, response_1.sendError)(res, code, msg);
60
+ }
@@ -0,0 +1,4 @@
1
+ import multer from "multer";
2
+ export declare const parseMultipart: import("express").RequestHandler<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
3
+ export declare const upload: multer.Multer;
4
+ //# sourceMappingURL=multipart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multipart.d.ts","sourceRoot":"","sources":["../../../src/middleware/multipart.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,eAAO,MAAM,cAAc,8IAAkB,CAAC;AAI9C,eAAO,MAAM,MAAM,eAKjB,CAAC"}
@@ -0,0 +1,17 @@
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.upload = exports.parseMultipart = void 0;
7
+ const multer_1 = __importDefault(require("multer"));
8
+ // Middleware for parsing multipart/form-data (text fields only)
9
+ exports.parseMultipart = (0, multer_1.default)().none();
10
+ // Middleware for parsing multipart/form-data with files
11
+ // You can configure storage/limits here as needed
12
+ exports.upload = (0, multer_1.default)({
13
+ dest: "storage/uploads/",
14
+ limits: {
15
+ fileSize: 5 * 1024 * 1024, // 5MB
16
+ },
17
+ });
@@ -0,0 +1,2 @@
1
+ export declare const apiLimiter: import("express-rate-limit").RateLimitRequestHandler;
2
+ //# sourceMappingURL=rateLimit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rateLimit.d.ts","sourceRoot":"","sources":["../../../src/middleware/rateLimit.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,UAAU,sDASrB,CAAC"}
@@ -0,0 +1,19 @@
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.apiLimiter = void 0;
7
+ const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
8
+ // import { redis } from "../core/redis"; // Optional: Use Redis for distributed rate limiting
9
+ // Rate limiting untuk mencegah brute force dan DDoS ringan
10
+ exports.apiLimiter = (0, express_rate_limit_1.default)({
11
+ windowMs: 15 * 60 * 1000, // 15 menit
12
+ max: 100, // Batas 100 request per window per IP
13
+ standardHeaders: true, // Return rate limit info di `RateLimit-*` headers
14
+ legacyHeaders: false, // Disable `X-RateLimit-*` headers
15
+ message: {
16
+ success: false,
17
+ message: "Terlalu banyak permintaan, silakan coba lagi nanti.",
18
+ },
19
+ });
@@ -0,0 +1,3 @@
1
+ import { Request, Response, NextFunction } from "express";
2
+ export declare const requestLogger: (req: Request, res: Response, next: NextFunction) => void;
3
+ //# sourceMappingURL=requestLogger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requestLogger.d.ts","sourceRoot":"","sources":["../../../src/middleware/requestLogger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG1D,eAAO,MAAM,aAAa,GACxB,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,MAAM,YAAY,SAoBnB,CAAC"}
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.requestLogger = void 0;
4
+ const logger_1 = require("../utils/logger");
5
+ const requestLogger = (req, res, next) => {
6
+ const start = Date.now();
7
+ const { method, url, ip } = req;
8
+ // Log saat response selesai
9
+ res.on("finish", () => {
10
+ const duration = Date.now() - start;
11
+ const { statusCode } = res;
12
+ const message = `${method} ${url} ${statusCode} - ${duration}ms - ${ip}`;
13
+ if (statusCode >= 400) {
14
+ logger_1.Log.warn(message);
15
+ }
16
+ else {
17
+ logger_1.Log.info(message);
18
+ }
19
+ });
20
+ next();
21
+ };
22
+ exports.requestLogger = requestLogger;
@@ -0,0 +1,3 @@
1
+ import { Request, Response, NextFunction } from "express";
2
+ export declare function visitorCounter(req: Request, res: Response, next: NextFunction): Promise<void>;
3
+ //# sourceMappingURL=visitor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visitor.d.ts","sourceRoot":"","sources":["../../../src/middleware/visitor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AA0C1D,wBAAsB,cAAc,CAClC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,YAAY,iBAoInB"}
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.visitorCounter = visitorCounter;
4
+ const uuid_1 = require("uuid");
5
+ const redis_1 = require("../core/redis");
6
+ const memoryStats = new Map();
7
+ const globalVisitors = new Set();
8
+ function formatDateKey(d) {
9
+ const dd = String(d.getDate()).padStart(2, "0");
10
+ const mm = String(d.getMonth() + 1).padStart(2, "0");
11
+ const yyyy = d.getFullYear();
12
+ return `${dd}-${mm}-${yyyy}`;
13
+ }
14
+ function parseCookies(header) {
15
+ const cookies = {};
16
+ if (!header)
17
+ return cookies;
18
+ const parts = header.split(";");
19
+ for (const part of parts) {
20
+ const [k, v] = part.split("=").map((s) => s.trim());
21
+ if (k && v)
22
+ cookies[k] = decodeURIComponent(v);
23
+ }
24
+ return cookies;
25
+ }
26
+ function isMobileUserAgent(ua) {
27
+ if (!ua)
28
+ return false;
29
+ return /Mobile|Android|iPhone|iPad|iPod/i.test(ua);
30
+ }
31
+ async function visitorCounter(req, res, next) {
32
+ const now = new Date();
33
+ const dateKey = formatDateKey(now);
34
+ const ip = req.ip ||
35
+ req.headers["x-forwarded-for"] ||
36
+ req.socket.remoteAddress ||
37
+ "";
38
+ const userAgent = req.headers["user-agent"];
39
+ const mobile = isMobileUserAgent(userAgent);
40
+ const cookies = parseCookies(req.headers.cookie);
41
+ let visitorId = cookies["visitor_id"];
42
+ if (!visitorId) {
43
+ visitorId = (0, uuid_1.v4)();
44
+ res.cookie("visitor_id", visitorId, {
45
+ httpOnly: true,
46
+ sameSite: "lax",
47
+ maxAge: 365 * 24 * 60 * 60 * 1000,
48
+ });
49
+ }
50
+ let sessionId = cookies["visitor_session_id"];
51
+ if (!sessionId) {
52
+ sessionId = (0, uuid_1.v4)();
53
+ res.cookie("visitor_session_id", sessionId, {
54
+ httpOnly: true,
55
+ sameSite: "lax",
56
+ });
57
+ }
58
+ if (redis_1.redis && redis_1.redis.status === "ready") {
59
+ const base = dateKey;
60
+ const kRequests = `requests-${base}`;
61
+ const kNewVisitors = `new-visitors-${base}`;
62
+ const kVisitors = `visitors-${base}`;
63
+ const kNewVisitorsMobile = `new-visitors-from-mobile-${base}`;
64
+ const kVisitorsMobile = `visitors-from-mobile-${base}`;
65
+ const kIpAddresses = `ip-addresses-${base}`;
66
+ const kSessions = `sessions-${base}`;
67
+ const kVisitorsSet = `visitors-set-${base}`;
68
+ const kVisitorsMobileSet = `visitors-from-mobile-set-${base}`;
69
+ const kIpSet = `ip-addresses-set-${base}`;
70
+ const kSessionsSet = `sessions-set-${base}`;
71
+ const kVisitorsAll = `visitors-all`;
72
+ try {
73
+ await redis_1.redis.incr(kRequests);
74
+ const isNewEver = await redis_1.redis.sadd(kVisitorsAll, visitorId);
75
+ if (isNewEver === 1) {
76
+ await redis_1.redis.incr(kNewVisitors);
77
+ }
78
+ const addedVisitor = await redis_1.redis.sadd(kVisitorsSet, visitorId);
79
+ if (addedVisitor === 1) {
80
+ await redis_1.redis.incr(kVisitors);
81
+ }
82
+ if (mobile) {
83
+ const addedMobileVisitor = await redis_1.redis.sadd(kVisitorsMobileSet, visitorId);
84
+ if (addedMobileVisitor === 1) {
85
+ await redis_1.redis.incr(kVisitorsMobile);
86
+ }
87
+ if (isNewEver === 1) {
88
+ await redis_1.redis.incr(kNewVisitorsMobile);
89
+ }
90
+ }
91
+ if (ip) {
92
+ const addedIp = await redis_1.redis.sadd(kIpSet, ip);
93
+ if (addedIp === 1) {
94
+ await redis_1.redis.incr(kIpAddresses);
95
+ }
96
+ }
97
+ const addedSession = await redis_1.redis.sadd(kSessionsSet, sessionId);
98
+ if (addedSession === 1) {
99
+ await redis_1.redis.incr(kSessions);
100
+ }
101
+ }
102
+ catch { }
103
+ }
104
+ else {
105
+ let stats = memoryStats.get(dateKey);
106
+ if (!stats) {
107
+ stats = {
108
+ requests: 0,
109
+ newVisitors: 0,
110
+ visitors: new Set(),
111
+ newVisitorsMobile: 0,
112
+ visitorsMobile: new Set(),
113
+ ipAddresses: 0,
114
+ ipSet: new Set(),
115
+ sessions: 0,
116
+ sessionSet: new Set(),
117
+ };
118
+ memoryStats.set(dateKey, stats);
119
+ }
120
+ stats.requests += 1;
121
+ if (!globalVisitors.has(visitorId)) {
122
+ globalVisitors.add(visitorId);
123
+ stats.newVisitors += 1;
124
+ if (mobile) {
125
+ stats.newVisitorsMobile += 1;
126
+ }
127
+ }
128
+ if (!stats.visitors.has(visitorId)) {
129
+ stats.visitors.add(visitorId);
130
+ }
131
+ if (mobile && !stats.visitorsMobile.has(visitorId)) {
132
+ stats.visitorsMobile.add(visitorId);
133
+ }
134
+ if (ip && !stats.ipSet.has(ip)) {
135
+ stats.ipSet.add(ip);
136
+ stats.ipAddresses += 1;
137
+ }
138
+ if (!stats.sessionSet.has(sessionId)) {
139
+ stats.sessionSet.add(sessionId);
140
+ stats.sessions += 1;
141
+ }
142
+ }
143
+ next();
144
+ }
@@ -0,0 +1,3 @@
1
+ declare let prisma: any;
2
+ export { prisma };
3
+ //# sourceMappingURL=prisma.d.ts.map