lapeeh 1.0.10 → 1.0.12

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 (77) hide show
  1. package/dist/lib/bootstrap.d.ts +3 -0
  2. package/dist/lib/bootstrap.d.ts.map +1 -0
  3. package/dist/lib/bootstrap.js +184 -0
  4. package/dist/lib/core/realtime.d.ts +3 -0
  5. package/dist/lib/core/realtime.d.ts.map +1 -0
  6. package/dist/lib/core/realtime.js +36 -0
  7. package/dist/lib/core/redis.d.ts +9 -0
  8. package/dist/lib/core/redis.d.ts.map +1 -0
  9. package/dist/lib/core/redis.js +133 -0
  10. package/dist/lib/core/serializer.d.ts +43 -0
  11. package/dist/lib/core/serializer.d.ts.map +1 -0
  12. package/dist/lib/core/serializer.js +66 -0
  13. package/dist/lib/core/server.d.ts +2 -0
  14. package/dist/lib/core/server.d.ts.map +1 -0
  15. package/dist/lib/core/server.js +60 -0
  16. package/dist/lib/core/store.d.ts +55 -0
  17. package/dist/lib/core/store.d.ts.map +1 -0
  18. package/dist/lib/core/store.js +66 -0
  19. package/dist/lib/middleware/auth.d.ts +4 -0
  20. package/dist/lib/middleware/auth.d.ts.map +1 -0
  21. package/dist/lib/middleware/auth.js +55 -0
  22. package/dist/lib/middleware/error.d.ts +3 -0
  23. package/dist/lib/middleware/error.d.ts.map +1 -0
  24. package/dist/lib/middleware/error.js +41 -0
  25. package/dist/lib/middleware/multipart.d.ts +4 -0
  26. package/dist/lib/middleware/multipart.d.ts.map +1 -0
  27. package/dist/lib/middleware/multipart.js +17 -0
  28. package/dist/lib/middleware/rateLimit.d.ts +2 -0
  29. package/dist/lib/middleware/rateLimit.d.ts.map +1 -0
  30. package/dist/lib/middleware/rateLimit.js +19 -0
  31. package/dist/lib/middleware/requestLogger.d.ts +3 -0
  32. package/dist/lib/middleware/requestLogger.d.ts.map +1 -0
  33. package/dist/lib/middleware/requestLogger.js +22 -0
  34. package/dist/lib/middleware/visitor.d.ts +3 -0
  35. package/dist/lib/middleware/visitor.d.ts.map +1 -0
  36. package/dist/lib/middleware/visitor.js +144 -0
  37. package/dist/lib/utils/logger.d.ts +11 -0
  38. package/dist/lib/utils/logger.d.ts.map +1 -0
  39. package/dist/lib/utils/logger.js +81 -0
  40. package/dist/lib/utils/pagination.d.ts +19 -0
  41. package/dist/lib/utils/pagination.d.ts.map +1 -0
  42. package/dist/lib/utils/pagination.js +34 -0
  43. package/dist/lib/utils/response.d.ts +11 -0
  44. package/dist/lib/utils/response.d.ts.map +1 -0
  45. package/dist/lib/utils/response.js +57 -0
  46. package/dist/lib/utils/validator.d.ts +38 -0
  47. package/dist/lib/utils/validator.d.ts.map +1 -0
  48. package/dist/lib/utils/validator.js +346 -0
  49. package/dist/src/config/app.d.ts +10 -0
  50. package/dist/src/config/app.d.ts.map +1 -0
  51. package/dist/src/config/app.js +12 -0
  52. package/dist/src/config/cors.d.ts +6 -0
  53. package/dist/src/config/cors.d.ts.map +1 -0
  54. package/dist/src/config/cors.js +8 -0
  55. package/dist/src/modules/Auth/auth.controller.d.ts +11 -0
  56. package/dist/src/modules/Auth/auth.controller.d.ts.map +1 -0
  57. package/dist/src/modules/Auth/auth.controller.js +427 -0
  58. package/dist/src/modules/Auth/auth.routes.d.ts +2 -0
  59. package/dist/src/modules/Auth/auth.routes.d.ts.map +1 -0
  60. package/dist/src/modules/Auth/auth.routes.js +45 -0
  61. package/dist/src/modules/Auth/auth.service.d.ts +3 -0
  62. package/dist/src/modules/Auth/auth.service.d.ts.map +1 -0
  63. package/dist/src/modules/Auth/auth.service.js +8 -0
  64. package/dist/src/modules/Rbac/rbac.controller.d.ts +16 -0
  65. package/dist/src/modules/Rbac/rbac.controller.d.ts.map +1 -0
  66. package/dist/src/modules/Rbac/rbac.controller.js +438 -0
  67. package/dist/src/modules/Rbac/rbac.routes.d.ts +2 -0
  68. package/dist/src/modules/Rbac/rbac.routes.d.ts.map +1 -0
  69. package/dist/src/modules/Rbac/rbac.routes.js +23 -0
  70. package/dist/src/modules/Rbac/rbac.service.d.ts +3 -0
  71. package/dist/src/modules/Rbac/rbac.service.d.ts.map +1 -0
  72. package/dist/src/modules/Rbac/rbac.service.js +8 -0
  73. package/dist/src/routes/index.d.ts +2 -0
  74. package/dist/src/routes/index.d.ts.map +1 -0
  75. package/dist/src/routes/index.js +9 -0
  76. package/package.json +23 -1
  77. package/tsconfig.json +1 -0
@@ -0,0 +1,3 @@
1
+ export declare function createApp(): Promise<import("express-serve-static-core").Express>;
2
+ export declare function bootstrap(): Promise<void>;
3
+ //# sourceMappingURL=bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../lib/bootstrap.ts"],"names":[],"mappings":"AAkBA,wBAAsB,SAAS,yDAiI9B;AAED,wBAAsB,SAAS,kBAuD9B"}
@@ -0,0 +1,184 @@
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.createApp = createApp;
7
+ exports.bootstrap = bootstrap;
8
+ const dotenv_1 = __importDefault(require("dotenv"));
9
+ dotenv_1.default.config();
10
+ const moduleAlias = require("module-alias");
11
+ const express_1 = __importDefault(require("express"));
12
+ const cors_1 = __importDefault(require("cors"));
13
+ const helmet_1 = __importDefault(require("helmet"));
14
+ const compression_1 = __importDefault(require("compression"));
15
+ const http_1 = __importDefault(require("http"));
16
+ const path_1 = __importDefault(require("path"));
17
+ const realtime_1 = require("./core/realtime");
18
+ const redis_1 = require("./core/redis");
19
+ const visitor_1 = require("./middleware/visitor");
20
+ const error_1 = require("./middleware/error");
21
+ const rateLimit_1 = require("./middleware/rateLimit");
22
+ const requestLogger_1 = require("./middleware/requestLogger");
23
+ const response_1 = require("./utils/response");
24
+ async function createApp() {
25
+ // Register aliases for production runtime
26
+ // Since user code (compiled JS) uses require('lapeeh/...')
27
+ // We map 'lapeeh' to the directory containing this file (lib/ or dist/lib/)
28
+ moduleAlias.addAlias("lapeeh", __dirname);
29
+ // Register alias for src directory (@/) to support imports in controllers/routes
30
+ const isProduction = process.env.NODE_ENV === "production";
31
+ moduleAlias.addAlias("@", isProduction
32
+ ? path_1.default.join(process.cwd(), "dist", "src")
33
+ : path_1.default.join(process.cwd(), "src"));
34
+ // LOAD USER CONFIG
35
+ const configPath = isProduction
36
+ ? path_1.default.join(process.cwd(), "dist", "src", "config")
37
+ : path_1.default.join(process.cwd(), "src", "config");
38
+ let appConfig = { timeout: 30000, jsonLimit: "10mb" };
39
+ let corsConfig = {
40
+ origin: process.env.CORS_ORIGIN || "*",
41
+ credentials: true,
42
+ exposedHeaders: ["x-access-token", "x-access-expires-at"],
43
+ };
44
+ try {
45
+ const appConfModule = require(path_1.default.join(configPath, "app"));
46
+ if (appConfModule.appConfig)
47
+ appConfig = { ...appConfig, ...appConfModule.appConfig };
48
+ }
49
+ catch (e) {
50
+ // ignore
51
+ }
52
+ try {
53
+ const corsConfModule = require(path_1.default.join(configPath, "cors"));
54
+ if (corsConfModule.corsConfig)
55
+ corsConfig = { ...corsConfig, ...corsConfModule.corsConfig };
56
+ }
57
+ catch (e) {
58
+ // ignore
59
+ }
60
+ const app = (0, express_1.default)();
61
+ app.disable("x-powered-by");
62
+ app.use((0, compression_1.default)());
63
+ // Request Timeout Middleware
64
+ app.use((_req, res, next) => {
65
+ const timeout = appConfig.timeout || 30000;
66
+ res.setTimeout(timeout, () => {
67
+ res.status(408).send({
68
+ status: "error",
69
+ message: `Request Timeout (${timeout / 1000}s limit)`,
70
+ });
71
+ });
72
+ next();
73
+ });
74
+ app.use((0, helmet_1.default)({
75
+ contentSecurityPolicy: false,
76
+ crossOriginResourcePolicy: { policy: "cross-origin" },
77
+ }));
78
+ app.use((0, cors_1.default)(corsConfig));
79
+ app.use(requestLogger_1.requestLogger);
80
+ app.use(express_1.default.json({ limit: appConfig.jsonLimit || "10mb" }));
81
+ app.use(express_1.default.urlencoded({ extended: true, limit: appConfig.jsonLimit || "10mb" }));
82
+ app.use(rateLimit_1.apiLimiter);
83
+ app.use(visitor_1.visitorCounter);
84
+ // Health Check
85
+ app.get("/", (_req, res) => {
86
+ (0, response_1.sendSuccess)(res, 200, "lapeeh API is running", {
87
+ status: "active",
88
+ timestamp: new Date(),
89
+ version: process.env.npm_package_version || "unknown",
90
+ });
91
+ });
92
+ // DYNAMIC ROUTE LOADING
93
+ try {
94
+ console.log("BOOTSTRAP: Loading routes. NODE_ENV=", process.env.NODE_ENV);
95
+ const isProduction = process.env.NODE_ENV === "production";
96
+ let userRoutesPath = isProduction
97
+ ? path_1.default.join(process.cwd(), "dist", "src", "routes")
98
+ : path_1.default.join(process.cwd(), "src", "routes");
99
+ // In test environment, explicitly point to index to ensure resolution
100
+ if (process.env.NODE_ENV === "test") {
101
+ // In test environment (ts-jest), we need to point to the TS file
102
+ // And we might need to use the full path with extension
103
+ userRoutesPath = path_1.default.join(process.cwd(), "src", "routes", "index.ts");
104
+ }
105
+ // Gunakan require agar sinkron dan mudah dicatch
106
+ // Check if file exists before requiring to avoid crash in tests/clean env
107
+ try {
108
+ const { apiRouter } = require(userRoutesPath);
109
+ app.use("/api", apiRouter);
110
+ }
111
+ catch (e) {
112
+ // If it's just missing module, maybe we are in test mode or fresh install
113
+ if (process.env.NODE_ENV !== "test") {
114
+ console.warn(`⚠️ Could not load user routes from ${userRoutesPath}. (This is expected during initial setup or if src/routes is missing)`);
115
+ }
116
+ else {
117
+ // In test mode, we really want to know if it failed to load
118
+ console.error(`Error loading routes in test mode from ${userRoutesPath}:`, e);
119
+ throw e;
120
+ }
121
+ }
122
+ }
123
+ catch (error) {
124
+ console.error(error);
125
+ if (process.env.NODE_ENV === "test")
126
+ throw error;
127
+ }
128
+ app.use(error_1.errorHandler);
129
+ return app;
130
+ }
131
+ async function bootstrap() {
132
+ // Validasi Environment Variables
133
+ const requiredEnvs = ["JWT_SECRET"];
134
+ const missingEnvs = requiredEnvs.filter((key) => !process.env[key]);
135
+ if (missingEnvs.length > 0) {
136
+ console.error(`❌ Missing required environment variables: ${missingEnvs.join(", ")}`);
137
+ process.exit(1);
138
+ }
139
+ const app = await createApp();
140
+ const port = process.env.PORT ? Number(process.env.PORT) : 8000;
141
+ const server = http_1.default.createServer(app);
142
+ (0, realtime_1.initRealtime)(server);
143
+ try {
144
+ await (0, redis_1.initRedis)();
145
+ server.on("error", (e) => {
146
+ if (e.code === "EADDRINUSE") {
147
+ console.log(`\n❌ Error: Port ${port} is already in use.`);
148
+ process.exit(1);
149
+ }
150
+ });
151
+ server.listen(port, () => {
152
+ console.log(`✅ API running at http://localhost:${port}`);
153
+ console.log(`🛡️ Environment: ${process.env.NODE_ENV || "development"}`);
154
+ });
155
+ }
156
+ catch (error) {
157
+ console.error("❌ Failed to start server:", error);
158
+ process.exit(1);
159
+ }
160
+ // Graceful Shutdown
161
+ const shutdown = async (signal) => {
162
+ console.log(`\n🛑 ${signal} received. Closing resources...`);
163
+ server.close(() => console.log("Http server closed."));
164
+ try {
165
+ if (redis_1.redis && redis_1.redis.status === "ready")
166
+ await redis_1.redis.quit();
167
+ process.exit(0);
168
+ }
169
+ catch (err) {
170
+ console.error("Error during shutdown:", err);
171
+ process.exit(1);
172
+ }
173
+ };
174
+ process.on("SIGTERM", () => shutdown("SIGTERM"));
175
+ process.on("SIGINT", () => shutdown("SIGINT"));
176
+ process.on("uncaughtException", (error) => {
177
+ console.error("❌ Uncaught Exception:", error);
178
+ shutdown("uncaughtException");
179
+ });
180
+ }
181
+ // Self-executing if run directly
182
+ if (require.main === module) {
183
+ bootstrap();
184
+ }
@@ -0,0 +1,3 @@
1
+ export declare function initRealtime(server: import("http").Server): void;
2
+ export declare function notifyUser(userId: string, event: string, payload: any): void;
3
+ //# sourceMappingURL=realtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../../../lib/core/realtime.ts"],"names":[],"mappings":"AAKA,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,MAAM,EAAE,MAAM,QAuBzD;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,QAGrE"}
@@ -0,0 +1,36 @@
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.initRealtime = initRealtime;
7
+ exports.notifyUser = notifyUser;
8
+ const socket_io_1 = require("socket.io");
9
+ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
10
+ let io = null;
11
+ function initRealtime(server) {
12
+ io = new socket_io_1.Server(server, {
13
+ cors: { origin: "*", methods: ["GET", "POST", "PUT", "DELETE"] },
14
+ });
15
+ io.on("connection", (socket) => {
16
+ const token = socket.handshake.query?.token ||
17
+ socket.handshake.headers["authorization"]
18
+ ?.toString()
19
+ ?.replace("Bearer ", "") ||
20
+ "";
21
+ const secret = process.env.JWT_SECRET;
22
+ if (secret && token) {
23
+ try {
24
+ const payload = jsonwebtoken_1.default.verify(token, secret);
25
+ const room = `user:${payload.userId}`;
26
+ socket.join(room);
27
+ }
28
+ catch { }
29
+ }
30
+ });
31
+ }
32
+ function notifyUser(userId, event, payload) {
33
+ if (!io)
34
+ return;
35
+ io.to(`user:${userId}`).emit(event, payload);
36
+ }
@@ -0,0 +1,9 @@
1
+ import Redis from "ioredis";
2
+ export declare function initRedis(): Promise<void>;
3
+ declare const redisProxy: Redis;
4
+ export declare function getCache(key: string): Promise<any>;
5
+ export declare function setCache(key: string, value: any, ttlSeconds?: number): Promise<void>;
6
+ export declare function delCache(key: string): Promise<void>;
7
+ export declare function delCachePattern(pattern: string): Promise<void>;
8
+ export { redisProxy as redis };
9
+ //# sourceMappingURL=redis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../../lib/core/redis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,SAAS,CAAC;AA4D5B,wBAAsB,SAAS,kBAoC9B;AAGD,QAAA,MAAM,UAAU,OAMd,CAAC;AAEH,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,gBAOzC;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,SAAK,iBAItE;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,MAAM,iBAIzC;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,iBAOpD;AAGD,OAAO,EAAE,UAAU,IAAI,KAAK,EAAE,CAAC"}
@@ -0,0 +1,133 @@
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.redis = void 0;
7
+ exports.initRedis = initRedis;
8
+ exports.getCache = getCache;
9
+ exports.setCache = setCache;
10
+ exports.delCache = delCache;
11
+ exports.delCachePattern = delCachePattern;
12
+ const ioredis_1 = __importDefault(require("ioredis"));
13
+ // @ts-ignore
14
+ const ioredis_mock_1 = __importDefault(require("ioredis-mock"));
15
+ const redisUrl = process.env.REDIS_URL || "redis://localhost:6379";
16
+ // Create a wrapper to handle connection attempts
17
+ let redis;
18
+ let isRedisConnected = false;
19
+ // If explicitly disabled via env
20
+ if (process.env.NO_REDIS === "true") {
21
+ console.log("Redis disabled via NO_REDIS, using in-memory mock.");
22
+ redis = new ioredis_mock_1.default();
23
+ isRedisConnected = true;
24
+ }
25
+ else {
26
+ // Try to connect to real Redis
27
+ redis = new ioredis_1.default(redisUrl, {
28
+ lazyConnect: true,
29
+ maxRetriesPerRequest: 1,
30
+ retryStrategy: (times) => {
31
+ // Retry 3 times then give up
32
+ if (times > 3)
33
+ return null;
34
+ return 200;
35
+ },
36
+ });
37
+ }
38
+ redis.on("ready", () => {
39
+ isRedisConnected = true;
40
+ // console.log("Redis connected!");
41
+ });
42
+ redis.on("error", (_err) => {
43
+ // If connection fails and we haven't switched to mock yet
44
+ if (!isRedisConnected && !(redis instanceof ioredis_mock_1.default)) {
45
+ // console.log("Redis connection failed, switching to in-memory mock...");
46
+ // Replace the global redis instance with mock
47
+ // Note: This is a runtime switch. Existing listeners might be lost if we don't handle carefully.
48
+ // However, for a simple fallback, we can just use the mock for future calls.
49
+ // Better approach: Since we exported 'redis' as a const (reference), we can't reassign it easily
50
+ // if other modules already imported it.
51
+ // BUT, ioredis instance itself is an EventEmitter.
52
+ // Strategy: We keep 'redis' as the main interface.
53
+ // If real redis fails, we just don't set isRedisConnected to true for the *real* one.
54
+ // But wait, the user wants 'bundle redis'.
55
+ // The best way is to detect failure during init and SWAP the implementation.
56
+ }
57
+ isRedisConnected = false;
58
+ });
59
+ // We need a way to seamlessly switch or just default to Mock if connect fails.
60
+ // Since 'redis' is exported immediately, we can't easily swap the object reference for importers.
61
+ // PROXY APPROACH:
62
+ // We export a Proxy that forwards to real redis OR mock redis.
63
+ const mockRedis = new ioredis_mock_1.default();
64
+ let activeRedis = redis; // Start with real redis attempt
65
+ // Custom init function to determine which one to use
66
+ async function initRedis() {
67
+ if (process.env.NO_REDIS === "true") {
68
+ activeRedis = mockRedis;
69
+ console.log("✅ Redis: Active (Source: Zero-Config Redis [NO_REDIS=true])");
70
+ if (process.env.NODE_ENV === "production") {
71
+ console.warn("⚠️ WARNING: Running in PRODUCTION with in-memory Redis mock. Data will be lost on restart and not shared between instances.");
72
+ }
73
+ return;
74
+ }
75
+ try {
76
+ await redis.connect();
77
+ activeRedis = redis; // Keep using real redis
78
+ isRedisConnected = true;
79
+ // Determine source label
80
+ const sourceLabel = process.env.REDIS_URL
81
+ ? redisUrl
82
+ : "Zero-Config Redis (Localhost)";
83
+ console.log(`✅ Redis: Active (Source: ${sourceLabel})`);
84
+ }
85
+ catch (err) {
86
+ // Connection failed, switch to mock
87
+ console.log(`⚠️ Redis: Connection failed to ${redisUrl}, switching to fallback (Source: Zero-Config Redis [Mock])`);
88
+ activeRedis = mockRedis;
89
+ isRedisConnected = true; // Mock is always "connected"
90
+ if (process.env.NODE_ENV === "production") {
91
+ console.warn("⚠️ WARNING: Redis connection failed in PRODUCTION. Switched to in-memory mock. Data will be lost on restart.");
92
+ }
93
+ }
94
+ }
95
+ // Proxy handler to forward all calls to activeRedis
96
+ const redisProxy = new Proxy({}, {
97
+ get: (_target, prop) => {
98
+ // If accessing a property on the proxy, forward it to activeRedis
99
+ const value = activeRedis[prop];
100
+ return value;
101
+ },
102
+ });
103
+ exports.redis = redisProxy;
104
+ async function getCache(key) {
105
+ try {
106
+ const v = await activeRedis.get(key);
107
+ return v ? JSON.parse(v) : null;
108
+ }
109
+ catch {
110
+ return null;
111
+ }
112
+ }
113
+ async function setCache(key, value, ttlSeconds = 60) {
114
+ try {
115
+ await activeRedis.set(key, JSON.stringify(value), "EX", ttlSeconds);
116
+ }
117
+ catch { }
118
+ }
119
+ async function delCache(key) {
120
+ try {
121
+ await activeRedis.del(key);
122
+ }
123
+ catch { }
124
+ }
125
+ async function delCachePattern(pattern) {
126
+ try {
127
+ const keys = await activeRedis.keys(pattern);
128
+ if (keys.length > 0) {
129
+ await activeRedis.del(...keys);
130
+ }
131
+ }
132
+ catch { }
133
+ }
@@ -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 lapeeh
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":["../../../lib/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 lapeeh
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":["../../../lib/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
+ // import { apiRouter } from "../../src/routes"; // Routes are now loaded dynamically in bootstrap.ts
12
+ const visitor_1 = require("../middleware/visitor");
13
+ // import { errorHandler } from "../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, "lapeeh API is running", {
52
+ status: "active",
53
+ timestamp: new Date(),
54
+ version: process.env.npm_package_version || "2.1.6",
55
+ });
56
+ });
57
+ // Routes are loaded in bootstrap.ts via app.use('/api', userApiRouter)
58
+ // Global Error Handler
59
+ // Note: We don't attach error handler here because we want to attach it AFTER routes are loaded in bootstrap
60
+ // app.use(errorHandler);
@@ -0,0 +1,55 @@
1
+ export interface User {
2
+ id: string;
3
+ email: string;
4
+ name: string;
5
+ password?: string;
6
+ uuid: string;
7
+ avatar?: string | null;
8
+ avatar_url?: string | null;
9
+ email_verified_at?: string | Date | null;
10
+ created_at: string | Date;
11
+ updated_at: string | Date;
12
+ }
13
+ export interface Role {
14
+ id: string;
15
+ name: string;
16
+ slug: string;
17
+ description?: string | null;
18
+ created_at: string | Date;
19
+ updated_at: string | Date;
20
+ }
21
+ export interface Permission {
22
+ id: string;
23
+ name: string;
24
+ slug: string;
25
+ description?: string | null;
26
+ created_at: string | Date;
27
+ updated_at: string | Date;
28
+ }
29
+ export interface UserRole {
30
+ id: string;
31
+ user_id: string;
32
+ role_id: string;
33
+ created_at: string | Date;
34
+ }
35
+ export interface RolePermission {
36
+ id: string;
37
+ role_id: string;
38
+ permission_id: string;
39
+ created_at: string | Date;
40
+ }
41
+ export interface UserPermission {
42
+ id: string;
43
+ user_id: string;
44
+ permission_id: string;
45
+ created_at: string | Date;
46
+ }
47
+ export declare const users: User[];
48
+ export declare const roles: Role[];
49
+ export declare const permissions: Permission[];
50
+ export declare const user_roles: UserRole[];
51
+ export declare const role_permissions: RolePermission[];
52
+ export declare const user_permissions: UserPermission[];
53
+ export declare function saveStore(): void;
54
+ export declare const generateId: () => string;
55
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../lib/core/store.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IACzC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AA4CD,eAAO,MAAM,KAAK,EAAE,IAAI,EAAe,CAAC;AACxC,eAAO,MAAM,KAAK,EAAE,IAAI,EAAe,CAAC;AACxC,eAAO,MAAM,WAAW,EAAE,UAAU,EAAqB,CAAC;AAC1D,eAAO,MAAM,UAAU,EAAE,QAAQ,EAAoB,CAAC;AACtD,eAAO,MAAM,gBAAgB,EAAE,cAAc,EAA0B,CAAC;AACxE,eAAO,MAAM,gBAAgB,EAAE,cAAc,EAA0B,CAAC;AAGxE,wBAAgB,SAAS,SAUxB;AAGD,eAAO,MAAM,UAAU,cAAgD,CAAC"}