lapeh 3.0.4 → 3.0.6
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/bin/index.js
CHANGED
|
@@ -133,7 +133,7 @@ sendTelemetry(command || 'init');
|
|
|
133
133
|
|
|
134
134
|
switch (command) {
|
|
135
135
|
case 'dev':
|
|
136
|
-
runDev();
|
|
136
|
+
(async () => { await runDev(); })();
|
|
137
137
|
break;
|
|
138
138
|
case 'start':
|
|
139
139
|
(async () => { await runStart(); })();
|
|
@@ -155,8 +155,69 @@ switch (command) {
|
|
|
155
155
|
break;
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
function
|
|
158
|
+
async function checkUpdate() {
|
|
159
|
+
try {
|
|
160
|
+
const pkg = require(path.join(__dirname, '../package.json'));
|
|
161
|
+
const currentVersion = pkg.version;
|
|
162
|
+
|
|
163
|
+
// Fetch latest version from npm registry
|
|
164
|
+
const latestVersion = await new Promise((resolve) => {
|
|
165
|
+
const https = require('https');
|
|
166
|
+
const req = https.get('https://registry.npmjs.org/lapeh/latest', {
|
|
167
|
+
headers: { 'User-Agent': 'Lapeh-CLI' },
|
|
168
|
+
timeout: 1500 // 1.5s timeout
|
|
169
|
+
}, (res) => {
|
|
170
|
+
let data = '';
|
|
171
|
+
res.on('data', chunk => data += chunk);
|
|
172
|
+
res.on('end', () => {
|
|
173
|
+
try {
|
|
174
|
+
const json = JSON.parse(data);
|
|
175
|
+
resolve(json.version);
|
|
176
|
+
} catch (e) {
|
|
177
|
+
resolve(null);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
req.on('error', () => resolve(null));
|
|
183
|
+
req.on('timeout', () => {
|
|
184
|
+
req.destroy();
|
|
185
|
+
resolve(null);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
if (latestVersion && latestVersion !== currentVersion) {
|
|
190
|
+
const currentParts = currentVersion.split('.').map(Number);
|
|
191
|
+
const latestParts = latestVersion.split('.').map(Number);
|
|
192
|
+
|
|
193
|
+
let isOutdated = false;
|
|
194
|
+
for(let i=0; i<3; i++) {
|
|
195
|
+
if (latestParts[i] > currentParts[i]) {
|
|
196
|
+
isOutdated = true;
|
|
197
|
+
break;
|
|
198
|
+
} else if (latestParts[i] < currentParts[i]) {
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (isOutdated) {
|
|
204
|
+
console.log('\n');
|
|
205
|
+
console.log('\x1b[33m┌────────────────────────────────────────────────────────────┐\x1b[0m');
|
|
206
|
+
console.log(`\x1b[33m│\x1b[0m \x1b[1mUpdate available!\x1b[0m \x1b[31m${currentVersion}\x1b[0m → \x1b[32m${latestVersion}\x1b[0m \x1b[33m│\x1b[0m`);
|
|
207
|
+
console.log(`\x1b[33m│\x1b[0m Run \x1b[36mnpm install lapeh@latest\x1b[0m to update \x1b[33m│\x1b[0m`);
|
|
208
|
+
console.log(`\x1b[33m│\x1b[0m Then run \x1b[36mnpx lapeh upgrade\x1b[0m to sync files \x1b[33m│\x1b[0m`);
|
|
209
|
+
console.log('\x1b[33m└────────────────────────────────────────────────────────────┘\x1b[0m');
|
|
210
|
+
console.log('\n');
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
} catch (e) {
|
|
214
|
+
// Ignore errors during update check
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async function runDev() {
|
|
159
219
|
console.log('🚀 Starting Lapeh in development mode...');
|
|
220
|
+
await checkUpdate();
|
|
160
221
|
try {
|
|
161
222
|
const tsNodePath = require.resolve('ts-node/register');
|
|
162
223
|
const tsConfigPathsPath = require.resolve('tsconfig-paths/register');
|
|
@@ -305,6 +366,12 @@ async function upgradeProject() {
|
|
|
305
366
|
'src/redis.ts'
|
|
306
367
|
];
|
|
307
368
|
|
|
369
|
+
const updateStats = {
|
|
370
|
+
updated: [],
|
|
371
|
+
created: [],
|
|
372
|
+
removed: []
|
|
373
|
+
};
|
|
374
|
+
|
|
308
375
|
function syncDirectory(src, dest, clean = false) {
|
|
309
376
|
if (!fs.existsSync(src)) return;
|
|
310
377
|
if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
|
|
@@ -316,11 +383,28 @@ async function upgradeProject() {
|
|
|
316
383
|
srcEntryNames.add(entry.name);
|
|
317
384
|
const srcPath = path.join(src, entry.name);
|
|
318
385
|
const destPath = path.join(dest, entry.name);
|
|
386
|
+
const relativePath = path.relative(currentDir, destPath);
|
|
319
387
|
|
|
320
388
|
if (entry.isDirectory()) {
|
|
321
389
|
syncDirectory(srcPath, destPath, clean);
|
|
322
390
|
} else {
|
|
323
|
-
|
|
391
|
+
let shouldCopy = true;
|
|
392
|
+
|
|
393
|
+
if (fs.existsSync(destPath)) {
|
|
394
|
+
const srcContent = fs.readFileSync(srcPath);
|
|
395
|
+
const destContent = fs.readFileSync(destPath);
|
|
396
|
+
if (srcContent.equals(destContent)) {
|
|
397
|
+
shouldCopy = false;
|
|
398
|
+
} else {
|
|
399
|
+
updateStats.updated.push(relativePath);
|
|
400
|
+
}
|
|
401
|
+
} else {
|
|
402
|
+
updateStats.created.push(relativePath);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (shouldCopy) {
|
|
406
|
+
fs.copyFileSync(srcPath, destPath);
|
|
407
|
+
}
|
|
324
408
|
}
|
|
325
409
|
}
|
|
326
410
|
|
|
@@ -329,7 +413,11 @@ async function upgradeProject() {
|
|
|
329
413
|
for (const entry of destEntries) {
|
|
330
414
|
if (!srcEntryNames.has(entry.name)) {
|
|
331
415
|
const destPath = path.join(dest, entry.name);
|
|
416
|
+
const relativePath = path.relative(currentDir, destPath);
|
|
417
|
+
|
|
332
418
|
console.log(`🗑️ Removing obsolete file/directory: ${destPath}`);
|
|
419
|
+
updateStats.removed.push(relativePath);
|
|
420
|
+
|
|
333
421
|
if (entry.isDirectory()) {
|
|
334
422
|
fs.rmSync(destPath, { recursive: true, force: true });
|
|
335
423
|
} else {
|
|
@@ -343,6 +431,7 @@ async function upgradeProject() {
|
|
|
343
431
|
for (const item of filesToSync) {
|
|
344
432
|
const srcPath = path.join(templateDir, item);
|
|
345
433
|
const destPath = path.join(currentDir, item);
|
|
434
|
+
const relativePath = item; // Since item is relative to templateDir/currentDir
|
|
346
435
|
|
|
347
436
|
if (fs.existsSync(srcPath)) {
|
|
348
437
|
const stats = fs.statSync(srcPath);
|
|
@@ -350,10 +439,26 @@ async function upgradeProject() {
|
|
|
350
439
|
console.log(`🔄 Syncing directory ${item}...`);
|
|
351
440
|
syncDirectory(srcPath, destPath, item === 'lib');
|
|
352
441
|
} else {
|
|
353
|
-
console.log(`🔄
|
|
442
|
+
console.log(`🔄 Checking file ${item}...`);
|
|
354
443
|
const destDir = path.dirname(destPath);
|
|
355
444
|
if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
|
|
356
|
-
|
|
445
|
+
|
|
446
|
+
let shouldCopy = true;
|
|
447
|
+
if (fs.existsSync(destPath)) {
|
|
448
|
+
const srcContent = fs.readFileSync(srcPath);
|
|
449
|
+
const destContent = fs.readFileSync(destPath);
|
|
450
|
+
if (srcContent.equals(destContent)) {
|
|
451
|
+
shouldCopy = false;
|
|
452
|
+
} else {
|
|
453
|
+
updateStats.updated.push(relativePath);
|
|
454
|
+
}
|
|
455
|
+
} else {
|
|
456
|
+
updateStats.created.push(relativePath);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
if (shouldCopy) {
|
|
460
|
+
fs.copyFileSync(srcPath, destPath);
|
|
461
|
+
}
|
|
357
462
|
}
|
|
358
463
|
}
|
|
359
464
|
}
|
|
@@ -430,7 +535,27 @@ async function upgradeProject() {
|
|
|
430
535
|
}
|
|
431
536
|
|
|
432
537
|
console.log('\n✅ Upgrade completed successfully!');
|
|
433
|
-
|
|
538
|
+
|
|
539
|
+
if (updateStats.created.length > 0) {
|
|
540
|
+
console.log('\n✨ Created files:');
|
|
541
|
+
updateStats.created.forEach(f => console.log(` \x1b[32m+ ${f}\x1b[0m`));
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
if (updateStats.updated.length > 0) {
|
|
545
|
+
console.log('\n📝 Updated files:');
|
|
546
|
+
updateStats.updated.forEach(f => console.log(` \x1b[33m~ ${f}\x1b[0m`));
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
if (updateStats.removed.length > 0) {
|
|
550
|
+
console.log('\n🗑️ Removed files:');
|
|
551
|
+
updateStats.removed.forEach(f => console.log(` \x1b[31m- ${f}\x1b[0m`));
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if (updateStats.created.length === 0 && updateStats.updated.length === 0 && updateStats.removed.length === 0) {
|
|
555
|
+
console.log(' No files were changed.');
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
console.log('\n Please check your .env file against .env.example for any new required variables.');
|
|
434
559
|
}
|
|
435
560
|
|
|
436
561
|
function createProject(skipFirstArg = false) {
|
|
@@ -520,7 +645,15 @@ function createProject(skipFirstArg = false) {
|
|
|
520
645
|
if (ignoreList.includes(entry.name)) continue;
|
|
521
646
|
const srcPath = path.join(src, entry.name);
|
|
522
647
|
const destPath = path.join(dest, entry.name);
|
|
523
|
-
|
|
648
|
+
|
|
649
|
+
// Clean storage/logs: skip everything except .gitkeep
|
|
650
|
+
// Check if we are inside storage/logs
|
|
651
|
+
const relPath = path.relative(templateDir, srcPath);
|
|
652
|
+
const isInLogs = relPath.includes(path.join('storage', 'logs')) || relPath.includes('storage/logs') || relPath.includes('storage\\logs');
|
|
653
|
+
|
|
654
|
+
if (isInLogs && !entry.isDirectory() && entry.name !== '.gitkeep') {
|
|
655
|
+
continue;
|
|
656
|
+
}
|
|
524
657
|
|
|
525
658
|
if (entry.isDirectory()) {
|
|
526
659
|
fs.mkdirSync(destPath);
|
package/doc/en/STRUCTURE.md
CHANGED
|
@@ -1,84 +1,79 @@
|
|
|
1
|
-
# Project Structure
|
|
1
|
+
# 🏗️ Project Structure
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Lapeh Framework is designed to be **intuitive**. We separate your application code (_User Space_) from the framework engine (_Core_), so you can focus on building features without being distracted by system complexity.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 🗺️ Navigation Map
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
| :------------------- | :----------------------------------------------------------------------------- |
|
|
9
|
-
| `bin/` | Contains execution scripts for CLI (`npx lapeh`). You rarely touch this. |
|
|
10
|
-
| `doc/` | Project documentation resides here. |
|
|
11
|
-
| `lib/` | **Framework Core**. Internal parts of the framework you rarely touch. |
|
|
12
|
-
| `scripts/` | Collection of Node.js utility scripts (generators, schema compilers, etc). |
|
|
13
|
-
| `src/` | **Main Source Code**. 99% of your coding happens here. |
|
|
14
|
-
| `.env` | Secret variables (Database URL, API Keys). **Do not commit this file to Git!** |
|
|
15
|
-
| `docker-compose.yml` | Docker configuration for running local Database & Redis. |
|
|
16
|
-
| `nodemon.json` | Auto-restart configuration during development. |
|
|
17
|
-
| `package.json` | List of libraries (dependencies) and commands (`npm run ...`). |
|
|
18
|
-
| `tsconfig.json` | TypeScript configuration. |
|
|
7
|
+
Here is a mental map to understand Lapeh folders:
|
|
19
8
|
|
|
20
|
-
|
|
9
|
+
| Folder | Icon | Function | Status |
|
|
10
|
+
| :------------- | :--: | :---------------------------------------------------------------------- | :-------------- |
|
|
11
|
+
| **`src/`** | 🏠 | **YOUR APP CODE**. You work here every day. | **Must Edit** |
|
|
12
|
+
| **`scripts/`** | 🤖 | **Automation Assistants**. Scripts for release, module generation, etc. | **Can Edit** |
|
|
13
|
+
| **`bin/`** | 🚀 | **CLI Tools**. Entry point for `npx lapeh` commands. | **Rarely Edit** |
|
|
14
|
+
| **`lib/`** | ⚙️ | **Framework Engine**. Core server & database logic. | **DO NOT Edit** |
|
|
21
15
|
|
|
22
|
-
|
|
16
|
+
---
|
|
23
17
|
|
|
24
|
-
|
|
18
|
+
## 1. 🏠 Folder `src/` (User Space)
|
|
25
19
|
|
|
26
|
-
|
|
20
|
+
This is your "home". 99% of new feature code will be written here.
|
|
27
21
|
|
|
28
|
-
|
|
22
|
+
### `src/modules/` (Modular Architecture)
|
|
29
23
|
|
|
30
|
-
|
|
24
|
+
Lapeh uses a **Modular** approach. One feature = One folder.
|
|
25
|
+
|
|
26
|
+
- **Example**: `src/modules/Auth/` folder contains all login/register logic.
|
|
27
|
+
- **Benefit**: Code is neat, easy to find, and easy to delete if the feature is no longer used.
|
|
31
28
|
|
|
32
29
|
### `src/routes/`
|
|
33
30
|
|
|
34
|
-
|
|
31
|
+
Your API gateway.
|
|
35
32
|
|
|
36
|
-
-
|
|
37
|
-
-
|
|
33
|
+
- Defines URLs (e.g., `/api/users`).
|
|
34
|
+
- Connects URLs to **Controllers**.
|
|
38
35
|
|
|
39
36
|
### `src/config/`
|
|
40
37
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
- `app.ts`: General application configuration.
|
|
44
|
-
- `cors.ts`: CORS (Cross-Origin Resource Sharing) configuration.
|
|
38
|
+
Application settings center.
|
|
45
39
|
|
|
46
|
-
|
|
40
|
+
- `app.ts`: Global configuration.
|
|
41
|
+
- `cors.ts`: Domain access security.
|
|
47
42
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
### `lib/core/`
|
|
43
|
+
---
|
|
51
44
|
|
|
52
|
-
|
|
45
|
+
## 2. 🤖 Folder `scripts/` (Robot Assistants)
|
|
53
46
|
|
|
54
|
-
|
|
55
|
-
- `redis.ts`: Redis connection.
|
|
56
|
-
- `serializer.ts`: JSON Schema caching logic.
|
|
47
|
+
Don't do boring things manually! Lapeh provides robots here:
|
|
57
48
|
|
|
58
|
-
|
|
49
|
+
- **`release.js`**: **Super Script** for releasing new versions.
|
|
50
|
+
- ✨ Automatic version bump (package.json).
|
|
51
|
+
- 📝 **Auto-Blog**: Automatically creates release articles from Git Commit history.
|
|
52
|
+
- 🔄 **Auto-Sync**: Synchronizes documentation to the website.
|
|
53
|
+
- 🚀 Push to Git & Publish to NPM in one command.
|
|
54
|
+
- **`make-module.js`**: Generator to create new module folder structures instantly.
|
|
59
55
|
|
|
60
|
-
|
|
56
|
+
---
|
|
61
57
|
|
|
62
|
-
|
|
63
|
-
- `rateLimit.ts`: Limit request count.
|
|
64
|
-
- `requestLogger.ts`: Log every incoming request.
|
|
58
|
+
## 3. 🚀 Folder `bin/` (CLI & Update)
|
|
65
59
|
|
|
66
|
-
|
|
60
|
+
This folder handles `npx lapeh` terminal commands.
|
|
67
61
|
|
|
68
|
-
|
|
62
|
+
- Provides **Auto-Update Check** feature when you run `npm run dev`.
|
|
63
|
+
- Handles `upgrade` command to sync your project with the latest Lapeh version without breaking your code.
|
|
69
64
|
|
|
70
|
-
|
|
71
|
-
- `response.ts`: Standard JSON response format (`sendFastSuccess`, `sendError`).
|
|
72
|
-
- `logger.ts`: Logging system (Winston).
|
|
65
|
+
---
|
|
73
66
|
|
|
74
|
-
## `
|
|
67
|
+
## 4. ⚙️ Folder `lib/` (The Core)
|
|
75
68
|
|
|
76
|
-
"
|
|
69
|
+
Lapeh's "Engine Room". Contains Express setup, Database connection, Logger, and basic Middleware.
|
|
77
70
|
|
|
78
|
-
|
|
79
|
-
- `init-project.js`: Initial setup wizard.
|
|
80
|
-
- `generate-jwt-secret.js`: Automatic JWT secret key generator.
|
|
71
|
+
> ⚠️ **Warning**: Changing the contents of this folder can make the application difficult to update to the next Lapeh version.
|
|
81
72
|
|
|
82
73
|
---
|
|
83
74
|
|
|
84
|
-
|
|
75
|
+
## 📄 Other Important Files
|
|
76
|
+
|
|
77
|
+
- **`.env`**: **Secret Keys**. Store DB passwords and API Keys here. (Do not upload to Git!)
|
|
78
|
+
- **`package.json`**: List of your project's library "shopping list".
|
|
79
|
+
- **`ecosystem.config.js`**: Ready to deploy? This file configures how the application runs on a production server (VPS) using PM2.
|
package/doc/id/STRUCTURE.md
CHANGED
|
@@ -1,84 +1,79 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 🏗️ Struktur Proyek
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Lapeh Framework didesain agar **intuitif**. Kami memisahkan kode aplikasi Anda (_User Space_) dari mesin framework (_Core_), sehingga Anda bisa fokus membangun fitur tanpa terganggu kompleksitas sistem.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 🗺️ Peta Navigasi
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
| :------------------- | :---------------------------------------------------------------------------- |
|
|
9
|
-
| `bin/` | Berisi script eksekusi untuk CLI (`npx lapeh`). Anda jarang menyentuh ini. |
|
|
10
|
-
| `doc/` | Dokumentasi proyek ini berada. |
|
|
11
|
-
| `lib/` | **Framework Core**. Bagian internal framework yang jarang Anda sentuh. |
|
|
12
|
-
| `scripts/` | Kumpulan script Node.js untuk utility (generator, compiler schema, dll). |
|
|
13
|
-
| `src/` | **Source Code Utama**. 99% kodingan Anda ada di sini. |
|
|
14
|
-
| `.env` | Variabel rahasia (Database URL, API Keys). **Jangan commit file ini ke Git!** |
|
|
15
|
-
| `docker-compose.yml` | Konfigurasi Docker untuk menjalankan Database & Redis lokal. |
|
|
16
|
-
| `nodemon.json` | Konfigurasi auto-restart saat development. |
|
|
17
|
-
| `package.json` | Daftar library (dependencies) dan perintah (`npm run ...`). |
|
|
18
|
-
| `tsconfig.json` | Konfigurasi TypeScript. |
|
|
7
|
+
Berikut adalah peta mental untuk memahami folder Lapeh:
|
|
19
8
|
|
|
20
|
-
|
|
9
|
+
| Folder | Ikon | Fungsi | Status |
|
|
10
|
+
| :------------- | :--: | :------------------------------------------------------------- | :---------------- |
|
|
11
|
+
| **`src/`** | 🏠 | **KODE APLIKASI ANDA**. Disini Anda bekerja setiap hari. | **Wajib Edit** |
|
|
12
|
+
| **`scripts/`** | 🤖 | **Asisten Otomatis**. Script untuk rilis, generate modul, dll. | **Boleh Edit** |
|
|
13
|
+
| **`bin/`** | 🚀 | **CLI Tools**. Entry point untuk perintah `npx lapeh`. | **Jarang Edit** |
|
|
14
|
+
| **`lib/`** | ⚙️ | **Mesin Framework**. Core logic server & database. | **DILARANG Edit** |
|
|
21
15
|
|
|
22
|
-
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 1. 🏠 Folder `src/` (User Space)
|
|
23
19
|
|
|
24
|
-
|
|
20
|
+
Ini adalah "kandang" Anda. 99% kode fitur baru akan ditulis di sini.
|
|
25
21
|
|
|
26
|
-
|
|
22
|
+
### `src/modules/` (Arsitektur Modular)
|
|
27
23
|
|
|
28
|
-
|
|
24
|
+
Lapeh menggunakan pendekatan **Modular**. Satu fitur = Satu folder.
|
|
29
25
|
|
|
30
|
-
- `Auth
|
|
26
|
+
- **Contoh**: Folder `src/modules/Auth/` berisi semua logika login/register.
|
|
27
|
+
- **Keuntungan**: Kode rapi, mudah dicari, dan mudah dihapus jika fitur tidak dipakai lagi.
|
|
31
28
|
|
|
32
29
|
### `src/routes/`
|
|
33
30
|
|
|
34
|
-
|
|
31
|
+
Pintu gerbang API Anda.
|
|
35
32
|
|
|
36
|
-
-
|
|
37
|
-
-
|
|
33
|
+
- Mendefinisikan URL (misal: `/api/users`).
|
|
34
|
+
- Menghubungkan URL ke **Controller**.
|
|
38
35
|
|
|
39
36
|
### `src/config/`
|
|
40
37
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
- `app.ts`: Konfigurasi umum aplikasi.
|
|
44
|
-
- `cors.ts`: Konfigurasi CORS (Cross-Origin Resource Sharing).
|
|
45
|
-
|
|
46
|
-
## Folder `lib/` (Framework Internals)
|
|
38
|
+
Pusat pengaturan aplikasi.
|
|
47
39
|
|
|
48
|
-
|
|
40
|
+
- `app.ts`: Konfigurasi global.
|
|
41
|
+
- `cors.ts`: Keamanan akses domain.
|
|
49
42
|
|
|
50
|
-
|
|
43
|
+
---
|
|
51
44
|
|
|
52
|
-
|
|
45
|
+
## 2. 🤖 Folder `scripts/` (Asisten Robot)
|
|
53
46
|
|
|
54
|
-
|
|
55
|
-
- `redis.ts`: Koneksi Redis.
|
|
56
|
-
- `serializer.ts`: Logic caching JSON Schema.
|
|
47
|
+
Jangan lakukan hal membosankan secara manual! Lapeh menyediakan robot di sini:
|
|
57
48
|
|
|
58
|
-
|
|
49
|
+
- **`release.js`**: **Super Script** untuk merilis versi baru.
|
|
50
|
+
- ✨ Otomatis bump versi (package.json).
|
|
51
|
+
- 📝 **Auto-Blog**: Membuat artikel rilis otomatis dari history Git Commit.
|
|
52
|
+
- 🔄 **Auto-Sync**: Sinkronisasi dokumentasi ke website.
|
|
53
|
+
- 🚀 Push ke Git & Publish ke NPM dalam satu perintah.
|
|
54
|
+
- **`make-module.js`**: Generator untuk membuat struktur folder module baru dalam sekejap.
|
|
59
55
|
|
|
60
|
-
|
|
56
|
+
---
|
|
61
57
|
|
|
62
|
-
|
|
63
|
-
- `rateLimit.ts`: Batasi jumlah request.
|
|
64
|
-
- `requestLogger.ts`: Log setiap request yang masuk.
|
|
58
|
+
## 3. 🚀 Folder `bin/` (CLI & Update)
|
|
65
59
|
|
|
66
|
-
|
|
60
|
+
Folder ini menangani perintah terminal `npx lapeh`.
|
|
67
61
|
|
|
68
|
-
|
|
62
|
+
- Menyediakan fitur **Auto-Update Check** saat Anda menjalankan `npm run dev`.
|
|
63
|
+
- Menangani perintah `upgrade` untuk menyinkronkan proyek Anda dengan versi Lapeh terbaru tanpa merusak kode Anda.
|
|
69
64
|
|
|
70
|
-
|
|
71
|
-
- `response.ts`: Standar format JSON response (`sendFastSuccess`, `sendError`).
|
|
72
|
-
- `logger.ts`: Sistem logging (Winston).
|
|
65
|
+
---
|
|
73
66
|
|
|
74
|
-
## Folder `
|
|
67
|
+
## 4. ⚙️ Folder `lib/` (The Core)
|
|
75
68
|
|
|
76
|
-
|
|
69
|
+
"Ruang Mesin" Lapeh. Berisi setup Express, koneksi Database, Logger, dan Middleware dasar.
|
|
77
70
|
|
|
78
|
-
|
|
79
|
-
- `init-project.js`: Wizard setup awal.
|
|
80
|
-
- `generate-jwt-secret.js`: Generator kunci rahasia JWT otomatis.
|
|
71
|
+
> ⚠️ **Peringatan**: Mengubah isi folder ini bisa membuat aplikasi sulit di-update ke versi Lapeh selanjutnya.
|
|
81
72
|
|
|
82
73
|
---
|
|
83
74
|
|
|
84
|
-
|
|
75
|
+
## 📄 File Penting Lainnya
|
|
76
|
+
|
|
77
|
+
- **`.env`**: **Kunci Rahasia**. Simpan password DB dan API Key disini. (Jangan di-upload ke Git!)
|
|
78
|
+
- **`package.json`**: Daftar "belanjaan" library proyek Anda.
|
|
79
|
+
- **`ecosystem.config.js`**: Siap deploy? File ini mengatur cara aplikasi berjalan di server production (VPS) menggunakan PM2.
|
package/package.json
CHANGED
package/scripts/release.js
CHANGED
|
@@ -73,8 +73,64 @@ function incrementPatch(version) {
|
|
|
73
73
|
return parts.join('.');
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
// Helper to generate auto commit message
|
|
77
|
+
function generateAutoCommitMessage() {
|
|
78
|
+
try {
|
|
79
|
+
const status = execSync('git status --porcelain', { stdio: 'pipe' }).toString().trim();
|
|
80
|
+
if (!status) return 'chore: no changes detected';
|
|
81
|
+
|
|
82
|
+
const files = status.split('\n').map(line => line.substring(3).trim());
|
|
83
|
+
|
|
84
|
+
const hasDocs = files.some(f => f.startsWith('website/') || f.startsWith('doc/') || f.endsWith('.md'));
|
|
85
|
+
const hasScripts = files.some(f => f.startsWith('scripts/'));
|
|
86
|
+
const hasPackage = files.some(f => f.includes('package.json'));
|
|
87
|
+
const hasSrc = files.some(f => !f.startsWith('website/') && !f.startsWith('doc/') && !f.startsWith('scripts/') && !f.includes('package.json') && !f.startsWith('.'));
|
|
88
|
+
|
|
89
|
+
let types = [];
|
|
90
|
+
if (hasDocs) types.push('docs');
|
|
91
|
+
if (hasScripts) types.push('scripts');
|
|
92
|
+
if (hasPackage) types.push('deps');
|
|
93
|
+
if (hasSrc) types.push('feat/fix');
|
|
94
|
+
|
|
95
|
+
if (types.length === 0) return 'chore: update project files';
|
|
96
|
+
|
|
97
|
+
if (hasDocs && !hasSrc && !hasScripts) return 'docs: update documentation';
|
|
98
|
+
if (hasScripts && !hasSrc) return 'chore: update build scripts';
|
|
99
|
+
|
|
100
|
+
return `chore: update ${types.join(', ')}`;
|
|
101
|
+
} catch (e) {
|
|
102
|
+
return 'chore: update project files';
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
76
106
|
async function main() {
|
|
77
107
|
try {
|
|
108
|
+
// 0. Quick Git Update Check
|
|
109
|
+
const quickGit = await question('\n⚡ Apakah ini hanya Quick Git Update (tanpa rilis versi)? (y/n): ');
|
|
110
|
+
if (quickGit.toLowerCase() === 'y') {
|
|
111
|
+
console.log('\n🤖 Auto-generating commit message...');
|
|
112
|
+
const commitMsg = generateAutoCommitMessage();
|
|
113
|
+
console.log(`📝 Commit Message: "${commitMsg}"`);
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
console.log('🔄 Syncing documentation (just in case)...');
|
|
117
|
+
try {
|
|
118
|
+
execSync('node scripts/sync-docs.js', { cwd: websiteDir, stdio: 'inherit' });
|
|
119
|
+
} catch (e) {
|
|
120
|
+
console.log('⚠️ Warning: Doc sync failed, continuing...');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
execSync('git add .', { stdio: 'inherit' });
|
|
124
|
+
execSync(`git commit -m "${commitMsg}"`, { stdio: 'inherit' });
|
|
125
|
+
execSync('git push origin HEAD', { stdio: 'inherit' });
|
|
126
|
+
console.log('✅ Quick Git Update selesai!');
|
|
127
|
+
process.exit(0);
|
|
128
|
+
} catch (e) {
|
|
129
|
+
console.error('❌ Error during git operations:', e.message);
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
78
134
|
// 1. Check versions and ask for new one
|
|
79
135
|
console.log('🔍 Checking npm version...');
|
|
80
136
|
const npmVersion = getNpmVersion();
|
|
@@ -139,10 +195,10 @@ async function main() {
|
|
|
139
195
|
|
|
140
196
|
// Indonesian Blog Content
|
|
141
197
|
const idContent = `---
|
|
142
|
-
title: Rilis v${newVersion} - ${titleID}
|
|
198
|
+
title: "Rilis v${newVersion} - ${titleID.replace(/"/g, '\\"')}"
|
|
143
199
|
date: ${date}
|
|
144
200
|
author: Tim Lapeh
|
|
145
|
-
description: ${descriptionID}
|
|
201
|
+
description: "${descriptionID.replace(/"/g, '\\"')}"
|
|
146
202
|
---
|
|
147
203
|
|
|
148
204
|
# Rilis v${newVersion}: ${titleID}
|
|
@@ -168,10 +224,10 @@ Terima kasih telah menggunakan Lapeh Framework!
|
|
|
168
224
|
|
|
169
225
|
// English Blog Content
|
|
170
226
|
const enContent = `---
|
|
171
|
-
title: Release v${newVersion} - ${titleEN}
|
|
227
|
+
title: "Release v${newVersion} - ${titleEN.replace(/"/g, '\\"')}"
|
|
172
228
|
date: ${date}
|
|
173
229
|
author: Lapeh Team
|
|
174
|
-
description: ${descriptionEN}
|
|
230
|
+
description: "${descriptionEN.replace(/"/g, '\\"')}"
|
|
175
231
|
---
|
|
176
232
|
|
|
177
233
|
# Release v${newVersion}: ${titleEN}
|
|
@@ -208,12 +264,18 @@ Thank you for using Lapeh Framework!
|
|
|
208
264
|
// 3. Question: Documentation
|
|
209
265
|
const updateDocs = await question('\n2. Apa Anda ingin update dokumentasi? (y/n): ');
|
|
210
266
|
if (updateDocs.toLowerCase() === 'y') {
|
|
211
|
-
console.log('\n📚 Documentation
|
|
267
|
+
console.log('\n📚 Documentation Update:');
|
|
268
|
+
console.log('Sistem akan menjalankan sinkronisasi otomatis:');
|
|
269
|
+
console.log(' - Menyalin file dari `doc/id` ke `website/docs`');
|
|
270
|
+
console.log(' - Menyalin file dari `doc/en` ke `website/en/docs`');
|
|
271
|
+
console.log(' - Mengubah nama file menjadi format URL-friendly (contoh: GETTING_STARTED.md -> getting-started.md)');
|
|
272
|
+
|
|
273
|
+
console.log('\n⚠️ Manual Action Required (If applicable):');
|
|
212
274
|
console.log('Jika ada package/method baru, silakan update file berikut secara manual sekarang:');
|
|
213
275
|
console.log(' - website/docs/packages.md');
|
|
214
276
|
console.log(' - website/docs/api.md');
|
|
215
277
|
|
|
216
|
-
await question('Tekan Enter
|
|
278
|
+
await question('Tekan Enter untuk menjalankan sinkronisasi otomatis (setelah Anda selesai update manual)...');
|
|
217
279
|
|
|
218
280
|
console.log('🔄 Syncing documentation...');
|
|
219
281
|
execSync('node scripts/sync-docs.js', { cwd: websiteDir, stdio: 'inherit' });
|
|
@@ -228,10 +290,30 @@ Thank you for using Lapeh Framework!
|
|
|
228
290
|
? `chore: release v${newVersion} - ${blogTitleEN}`
|
|
229
291
|
: `chore: release v${newVersion}`;
|
|
230
292
|
|
|
231
|
-
|
|
232
|
-
|
|
293
|
+
try {
|
|
294
|
+
execSync('git add .', { stdio: 'inherit' });
|
|
295
|
+
execSync(`git commit -m "${commitMsg}"`, { stdio: 'inherit' });
|
|
296
|
+
} catch (e) {
|
|
297
|
+
console.log('⚠️ No changes to commit or commit failed. Continuing...');
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
try {
|
|
301
|
+
// Delete tag if it exists locally to avoid "already exists" error
|
|
302
|
+
execSync(`git tag -d v${newVersion}`, { stdio: 'ignore' });
|
|
303
|
+
} catch (e) {
|
|
304
|
+
// Ignore if tag doesn't exist
|
|
305
|
+
}
|
|
306
|
+
|
|
233
307
|
execSync(`git tag v${newVersion}`, { stdio: 'inherit' });
|
|
234
|
-
execSync(`git push origin HEAD
|
|
308
|
+
execSync(`git push origin HEAD`, { stdio: 'inherit' });
|
|
309
|
+
|
|
310
|
+
try {
|
|
311
|
+
execSync(`git push origin v${newVersion}`, { stdio: 'inherit' });
|
|
312
|
+
} catch (e) {
|
|
313
|
+
console.log('⚠️ Tag push failed. Trying force push (updating existing tag)...');
|
|
314
|
+
execSync(`git push origin v${newVersion} --force`, { stdio: 'inherit' });
|
|
315
|
+
}
|
|
316
|
+
|
|
235
317
|
console.log('✅ Git push & tag complete');
|
|
236
318
|
} else {
|
|
237
319
|
console.log('⏭️ Skipping Git push.');
|
|
@@ -240,8 +322,20 @@ Thank you for using Lapeh Framework!
|
|
|
240
322
|
// 5. Question: NPM
|
|
241
323
|
const publishNpm = await question('\n4. Apa ingin publish ke NPM? (y/n): ');
|
|
242
324
|
if (publishNpm.toLowerCase() === 'y') {
|
|
243
|
-
|
|
244
|
-
|
|
325
|
+
try {
|
|
326
|
+
execSync('npm publish', { stdio: 'inherit' });
|
|
327
|
+
console.log('✅ NPM publish complete');
|
|
328
|
+
} catch (error) {
|
|
329
|
+
console.log('\n⚠️ NPM Publish failed. This might be due to 2FA.');
|
|
330
|
+
const otp = await question('🔐 Masukkan kode OTP (Authenticator App) Anda: ');
|
|
331
|
+
if (otp && otp.trim() !== '') {
|
|
332
|
+
execSync(`npm publish --otp=${otp.trim()}`, { stdio: 'inherit' });
|
|
333
|
+
console.log('✅ NPM publish complete');
|
|
334
|
+
} else {
|
|
335
|
+
console.log('❌ NPM publish aborted.');
|
|
336
|
+
throw error;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
245
339
|
} else {
|
|
246
340
|
console.log('⏭️ Skipping NPM publish.');
|
|
247
341
|
}
|
|
@@ -19,6 +19,11 @@
|
|
|
19
19
|
"date": 1767106155460,
|
|
20
20
|
"name": "E:\\PROJECT\\ANY\\2026\\lapeh\\storage\\logs\\lapeh-2025-12-30.log",
|
|
21
21
|
"hash": "f090b6426f3343ed97dadce1dfe5cf1b15b0e4f173b3a0b4fbfe19d9f86dec03"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"date": 1767116159016,
|
|
25
|
+
"name": "E:\\PROJECT\\ANY\\2026\\lapeh\\storage\\logs\\lapeh-2025-12-31.log",
|
|
26
|
+
"hash": "d0e8ef584ec2262b3b615e4747e50c0f7f2bf687c8d4264b6881edbe00f039e0"
|
|
22
27
|
}
|
|
23
28
|
],
|
|
24
29
|
"hashType": "sha256"
|
|
File without changes
|