lapeh 2.0.0 ā 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +5 -6
- package/docker-compose.yml +8 -1
- package/package.json +1 -1
- package/readme.md +38 -0
- package/scripts/init-project.js +16 -1
- package/src/redis.ts +14 -6
package/.env.example
CHANGED
|
@@ -3,12 +3,11 @@ DATABASE_PROVIDER="postgresql"
|
|
|
3
3
|
DATABASE_URL="postgresql://sianu:12341234@localhost:5432/db_example_test?schema=public"
|
|
4
4
|
JWT_SECRET="replace_this_with_a_secure_random_string"
|
|
5
5
|
|
|
6
|
-
# Redis Configuration (Optional)
|
|
7
|
-
# If REDIS_URL is not set or connection fails, the framework will automatically
|
|
8
|
-
# switch to an in-memory Redis mock (bundled). No installation required for development.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
# REDIS_URL="redis://localhost:6379"
|
|
6
|
+
# Redis Configuration (Optional)
|
|
7
|
+
# If REDIS_URL is not set or connection fails, the framework will automatically
|
|
8
|
+
# switch to an in-memory Redis mock (bundled). No installation required for development.
|
|
9
|
+
# REDIS_URL="redis://lapeh:12341234@localhost:6379"
|
|
10
|
+
# NO_REDIS="true"
|
|
12
11
|
|
|
13
12
|
# To force disable Redis and use in-memory mock even if Redis is available:
|
|
14
13
|
# NO_REDIS="true"
|
package/docker-compose.yml
CHANGED
|
@@ -2,7 +2,14 @@ version: "3.9"
|
|
|
2
2
|
services:
|
|
3
3
|
redis:
|
|
4
4
|
image: redis:7-alpine
|
|
5
|
-
command:
|
|
5
|
+
command:
|
|
6
|
+
- "redis-server"
|
|
7
|
+
- "--appendonly"
|
|
8
|
+
- "yes"
|
|
9
|
+
- "--user"
|
|
10
|
+
- "default on >12341234 ~* +@all"
|
|
11
|
+
- "--user"
|
|
12
|
+
- "lapeh on >12341234 ~* +@all"
|
|
6
13
|
ports:
|
|
7
14
|
- "6379:6379"
|
|
8
15
|
volumes:
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -75,6 +75,44 @@ Jika Anda melakukan setup dengan flag `--full`, database akan terisi dengan akun
|
|
|
75
75
|
|
|
76
76
|
---
|
|
77
77
|
|
|
78
|
+
## š§ Zero-Config Redis
|
|
79
|
+
|
|
80
|
+
Lapeh otomatis mendeteksi ketersediaan Redis.
|
|
81
|
+
|
|
82
|
+
1. **Auto-Discovery**: Mencoba terhubung ke Redis URL di `.env` (`REDIS_URL`).
|
|
83
|
+
2. **Smart Fallback**: Jika Redis tidak tersedia atau koneksi gagal, otomatis beralih ke **In-Memory Mock**.
|
|
84
|
+
- Tidak perlu install Redis di local development.
|
|
85
|
+
- Fitur rate-limiting dan caching tetap berjalan (namun data hilang saat restart).
|
|
86
|
+
3. **Production Safety**: Memberikan peringatan log jika berjalan di Production menggunakan Mock.
|
|
87
|
+
|
|
88
|
+
**Force Mock Mode:**
|
|
89
|
+
Anda bisa memaksa menggunakan mock (misal untuk testing) dengan menambahkan env variable:
|
|
90
|
+
|
|
91
|
+
```env
|
|
92
|
+
NO_REDIS=true
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Optional: Menggunakan Real Redis dengan Docker
|
|
96
|
+
|
|
97
|
+
Jika Anda ingin menggunakan Redis yang sebenarnya di local environment, kami telah menyertakan konfigurasi `docker-compose.yml` yang aman (menggunakan ACL).
|
|
98
|
+
|
|
99
|
+
1. Jalankan Redis container:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
docker-compose up -d
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
2. Uncomment konfigurasi Redis di file `.env` Anda:
|
|
106
|
+
|
|
107
|
+
```env
|
|
108
|
+
REDIS_URL="redis://lapeh:12341234@localhost:6379"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
> **Credential Default:**
|
|
112
|
+
>
|
|
113
|
+
> - User: `lapeh`
|
|
114
|
+
> - Password: `12341234`
|
|
115
|
+
|
|
78
116
|
## š Development Tools
|
|
79
117
|
|
|
80
118
|
API Lapeh menyediakan tools untuk mempercepat development, mirip dengan `artisan` di Laravel.
|
package/scripts/init-project.js
CHANGED
|
@@ -122,7 +122,22 @@ const selectOption = async (query, options) => {
|
|
|
122
122
|
console.log("\nš¦ Installing dependencies...");
|
|
123
123
|
execSync("npm install", { stdio: "inherit", cwd: rootDir });
|
|
124
124
|
|
|
125
|
-
// 4.
|
|
125
|
+
// 4. Create .vscode/settings.json
|
|
126
|
+
console.log("\nš ļø Configuring VS Code...");
|
|
127
|
+
const vscodeDir = path.join(rootDir, ".vscode");
|
|
128
|
+
if (!fs.existsSync(vscodeDir)) {
|
|
129
|
+
fs.mkdirSync(vscodeDir, { recursive: true });
|
|
130
|
+
}
|
|
131
|
+
const settingsFile = path.join(vscodeDir, "settings.json");
|
|
132
|
+
const settingsContent = {
|
|
133
|
+
"files.associations": {
|
|
134
|
+
"*.model": "prisma"
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
fs.writeFileSync(settingsFile, JSON.stringify(settingsContent, null, 2));
|
|
138
|
+
console.log("ā
VS Code configured (.model support added).");
|
|
139
|
+
|
|
140
|
+
// 5. Generate JWT Secret
|
|
126
141
|
console.log("\nš Generating JWT Secret...");
|
|
127
142
|
try {
|
|
128
143
|
execSync("node scripts/generate-jwt-secret.js", {
|
package/src/redis.ts
CHANGED
|
@@ -38,12 +38,10 @@ redis.on("error", (err) => {
|
|
|
38
38
|
// Replace the global redis instance with mock
|
|
39
39
|
// Note: This is a runtime switch. Existing listeners might be lost if we don't handle carefully.
|
|
40
40
|
// However, for a simple fallback, we can just use the mock for future calls.
|
|
41
|
-
|
|
42
|
-
// Better approach: Since we exported 'redis' as a const (reference), we can't reassign it easily
|
|
41
|
+
// Better approach: Since we exported 'redis' as a const (reference), we can't reassign it easily
|
|
43
42
|
// if other modules already imported it.
|
|
44
43
|
// BUT, ioredis instance itself is an EventEmitter.
|
|
45
|
-
|
|
46
|
-
// Strategy: We keep 'redis' as the main interface.
|
|
44
|
+
// Strategy: We keep 'redis' as the main interface.
|
|
47
45
|
// If real redis fails, we just don't set isRedisConnected to true for the *real* one.
|
|
48
46
|
// But wait, the user wants 'bundle redis'.
|
|
49
47
|
// The best way is to detect failure during init and SWAP the implementation.
|
|
@@ -63,6 +61,7 @@ let activeRedis = redis; // Start with real redis attempt
|
|
|
63
61
|
export async function initRedis() {
|
|
64
62
|
if (process.env.NO_REDIS === "true") {
|
|
65
63
|
activeRedis = mockRedis;
|
|
64
|
+
console.log("ā
Redis: Active (Source: Zero-Config Redis [NO_REDIS=true])");
|
|
66
65
|
if (process.env.NODE_ENV === "production") {
|
|
67
66
|
console.warn(
|
|
68
67
|
"ā ļø WARNING: Running in PRODUCTION with in-memory Redis mock. Data will be lost on restart and not shared between instances."
|
|
@@ -75,9 +74,18 @@ export async function initRedis() {
|
|
|
75
74
|
await redis.connect();
|
|
76
75
|
activeRedis = redis; // Keep using real redis
|
|
77
76
|
isRedisConnected = true;
|
|
77
|
+
|
|
78
|
+
// Determine source label
|
|
79
|
+
const sourceLabel = process.env.REDIS_URL
|
|
80
|
+
? redisUrl
|
|
81
|
+
: "Zero-Config Redis (Localhost)";
|
|
82
|
+
|
|
83
|
+
console.log(`ā
Redis: Active (Source: ${sourceLabel})`);
|
|
78
84
|
} catch (err) {
|
|
79
85
|
// Connection failed, switch to mock
|
|
80
|
-
|
|
86
|
+
console.log(
|
|
87
|
+
`ā ļø Redis: Connection failed to ${redisUrl}, switching to fallback (Source: Zero-Config Redis [Mock])`
|
|
88
|
+
);
|
|
81
89
|
activeRedis = mockRedis;
|
|
82
90
|
isRedisConnected = true; // Mock is always "connected"
|
|
83
91
|
if (process.env.NODE_ENV === "production") {
|
|
@@ -118,4 +126,4 @@ export async function delCache(key: string) {
|
|
|
118
126
|
}
|
|
119
127
|
|
|
120
128
|
// Export the proxy as 'redis' so consumers use it transparently
|
|
121
|
-
export { redisProxy as redis };
|
|
129
|
+
export { redisProxy as redis };
|