lapeh 3.0.4 → 3.0.5
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) {
|
package/doc/en/STRUCTURE.md
CHANGED
|
@@ -1,84 +1,103 @@
|
|
|
1
|
-
# Project Structure
|
|
1
|
+
# Project Structure
|
|
2
|
+
|
|
3
|
+
Understanding the folder structure is the first step to mastering Lapeh Framework. This project is designed to be **easy to navigate**, separating your application logic (*User Space*) from the framework engine (*Core Framework*).
|
|
4
|
+
|
|
5
|
+
## Directory Map
|
|
6
|
+
|
|
7
|
+
Here is the big picture of the Lapeh project directory structure:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
lapeh/
|
|
11
|
+
├── bin/ # CLI entry point (npx lapeh)
|
|
12
|
+
├── lib/ # ⚙️ Framework Core (Lapeh Engine)
|
|
13
|
+
├── scripts/ # Automation scripts (Build, Release, Generators)
|
|
14
|
+
├── src/ # 🏠 Your Application Source Code (Where you work)
|
|
15
|
+
│ ├── config/ # Application configuration
|
|
16
|
+
│ ├── modules/ # Business logic per feature (Controllers)
|
|
17
|
+
│ └── routes/ # API route definitions
|
|
18
|
+
├── storage/ # Temporary files, logs, and uploads
|
|
19
|
+
├── tests/ # Unit & Integration Tests
|
|
20
|
+
├── website/ # Documentation source code
|
|
21
|
+
├── .env # Environment variables (Secrets!)
|
|
22
|
+
├── ecosystem.config.js # PM2 Configuration
|
|
23
|
+
├── jest.config.js # Testing Configuration
|
|
24
|
+
├── package.json # Project dependencies
|
|
25
|
+
└── tsconfig.json # TypeScript Configuration
|
|
26
|
+
```
|
|
2
27
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Root Directory
|
|
6
|
-
|
|
7
|
-
| File/Folder | Description |
|
|
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. |
|
|
28
|
+
---
|
|
19
29
|
|
|
20
|
-
## `src/` Folder (
|
|
30
|
+
## 🏠 `src/` Folder (User Space)
|
|
21
31
|
|
|
22
|
-
This is
|
|
32
|
+
This is the most important folder. 99% of your coding time will be spent here.
|
|
23
33
|
|
|
24
34
|
### `src/modules/` (Modular Architecture)
|
|
35
|
+
Lapeh uses a **Modular** approach. Each feature is grouped into a single folder to keep code organized as the application grows.
|
|
25
36
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
Example `Auth` module structure:
|
|
29
|
-
|
|
30
|
-
- `Auth/auth.controller.ts`: Application logic (Controller).
|
|
37
|
+
* **Example**: If you build a "Product" feature, you will have a `src/modules/Product/` folder.
|
|
38
|
+
* **Contents**: Usually contains the `controller` (logic) and supporting files for that feature.
|
|
31
39
|
|
|
32
40
|
### `src/routes/`
|
|
41
|
+
Where you define your API URLs.
|
|
33
42
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
- Connects URLs (e.g., `/api/login`) to functions in Controllers.
|
|
37
|
-
- Attaches Middleware (e.g., `requireAuth`).
|
|
43
|
+
* **`index.ts`**: The main gateway for all routes.
|
|
44
|
+
* **Other route files**: Connect URLs (e.g., `/api/users`) to functions in Controllers and attach middleware.
|
|
38
45
|
|
|
39
46
|
### `src/config/`
|
|
40
|
-
|
|
41
47
|
Static application configuration.
|
|
42
48
|
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
* **`app.ts`**: General settings.
|
|
50
|
+
* **`cors.ts`**: Domain access security settings (CORS).
|
|
45
51
|
|
|
46
|
-
|
|
52
|
+
---
|
|
47
53
|
|
|
48
|
-
|
|
54
|
+
## ⚙️ `lib/` Folder (Framework Core)
|
|
49
55
|
|
|
50
|
-
|
|
56
|
+
This folder is the "engine" behind the scenes. It contains the core code that runs the server, database connections, and built-in utilities.
|
|
51
57
|
|
|
52
|
-
|
|
58
|
+
> **Note**: You rarely need to touch this folder unless you want to modify the framework's basic behavior.
|
|
53
59
|
|
|
54
|
-
|
|
55
|
-
- `
|
|
56
|
-
|
|
60
|
+
* **`lib/core/`**: Express server setup, Redis connection, and Serializer.
|
|
61
|
+
* **`lib/middleware/`**: Built-in middleware like `auth` (JWT), `rateLimit`, and `requestLogger`.
|
|
62
|
+
* **`lib/utils/`**: Helper functions like `validator` (input validation), `logger` (logging), and `response` (standard response format).
|
|
57
63
|
|
|
58
|
-
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 🧪 `tests/` Folder
|
|
59
67
|
|
|
60
|
-
|
|
68
|
+
Where you write automated tests to ensure your application runs smoothly.
|
|
61
69
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
70
|
+
* **`unit/`**: Tests for small functions in isolation.
|
|
71
|
+
* **`integration/`**: Tests for complete API flows (e.g., hit login endpoint and verify token receipt).
|
|
72
|
+
* **`setup.ts`**: Initial configuration before tests run.
|
|
65
73
|
|
|
66
|
-
|
|
74
|
+
---
|
|
67
75
|
|
|
68
|
-
|
|
76
|
+
## 📦 `storage/` Folder
|
|
69
77
|
|
|
70
|
-
|
|
71
|
-
- `response.ts`: Standard JSON response format (`sendFastSuccess`, `sendError`).
|
|
72
|
-
- `logger.ts`: Logging system (Winston).
|
|
78
|
+
Folder for storing files generated by the application at runtime.
|
|
73
79
|
|
|
74
|
-
|
|
80
|
+
* **`logs/`**: Application log files (error log, access log).
|
|
81
|
+
* **`uploads/`** (Optional): Storage for user-uploaded files (if using local storage).
|
|
75
82
|
|
|
76
|
-
|
|
83
|
+
---
|
|
77
84
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
85
|
+
## 🛠️ Important Configuration Files
|
|
86
|
+
|
|
87
|
+
| File | Description |
|
|
88
|
+
| :--- | :--- |
|
|
89
|
+
| **`.env`** | Stores application **secrets** (Database URL, API Keys). **Do not commit this file to Git!** |
|
|
90
|
+
| **`package.json`** | List of libraries used and script commands (`npm run ...`). |
|
|
91
|
+
| **`ecosystem.config.js`** | Configuration for **PM2**. Used when deploying to production servers (VPS) for auto-restart. |
|
|
92
|
+
| **`jest.config.js`** | Settings for the testing framework (Jest). |
|
|
93
|
+
| **`nodemon.json`** | Server auto-restart settings while you are coding (Development mode). |
|
|
81
94
|
|
|
82
95
|
---
|
|
83
96
|
|
|
84
|
-
|
|
97
|
+
## 🤖 `scripts/` Folder
|
|
98
|
+
|
|
99
|
+
Contains "magic" scripts that make your life easier. These scripts are usually called via `npm run`.
|
|
100
|
+
|
|
101
|
+
* **`release.js`**: Automates version release, changelog, and blog.
|
|
102
|
+
* **`make-module.js`**: Generator to quickly create new modules/controllers.
|
|
103
|
+
* **`sync-docs.js`**: Synchronizes documentation across languages.
|
package/doc/id/STRUCTURE.md
CHANGED
|
@@ -1,84 +1,103 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Struktur Proyek
|
|
2
|
+
|
|
3
|
+
Memahami struktur folder adalah langkah pertama untuk menguasai Lapeh Framework. Proyek ini didesain agar **mudah dinavigasi**, memisahkan logika aplikasi Anda (*User Space*) dengan mesin framework (*Core Framework*).
|
|
4
|
+
|
|
5
|
+
## Peta Direktori
|
|
6
|
+
|
|
7
|
+
Berikut adalah gambaran besar struktur direktori proyek Lapeh:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
lapeh/
|
|
11
|
+
├── bin/ # Entry point untuk CLI (npx lapeh)
|
|
12
|
+
├── lib/ # ⚙️ Framework Core (Mesin Lapeh)
|
|
13
|
+
├── scripts/ # Script otomatisasi (Build, Release, Generator)
|
|
14
|
+
├── src/ # 🏠 Source Code Aplikasi Anda (Tempat Anda bekerja)
|
|
15
|
+
│ ├── config/ # Konfigurasi aplikasi
|
|
16
|
+
│ ├── modules/ # Logika bisnis per fitur (Controller)
|
|
17
|
+
│ └── routes/ # Definisi rute API
|
|
18
|
+
├── storage/ # File sementara, log, dan upload
|
|
19
|
+
├── tests/ # Unit & Integration Tests
|
|
20
|
+
├── website/ # Source code dokumentasi ini
|
|
21
|
+
├── .env # Environment variables (Rahasia!)
|
|
22
|
+
├── ecosystem.config.js # Konfigurasi PM2
|
|
23
|
+
├── jest.config.js # Konfigurasi Testing
|
|
24
|
+
├── package.json # Dependensi proyek
|
|
25
|
+
└── tsconfig.json # Konfigurasi TypeScript
|
|
26
|
+
```
|
|
2
27
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Root Directory
|
|
6
|
-
|
|
7
|
-
| File/Folder | Deskripsi |
|
|
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. |
|
|
28
|
+
---
|
|
19
29
|
|
|
20
|
-
## Folder `src/` (
|
|
30
|
+
## 🏠 Folder `src/` (User Space)
|
|
21
31
|
|
|
22
|
-
Ini adalah
|
|
32
|
+
Ini adalah folder terpenting. 99% waktu coding Anda akan dihabiskan di sini.
|
|
23
33
|
|
|
24
34
|
### `src/modules/` (Modular Architecture)
|
|
35
|
+
Lapeh menggunakan pendekatan **Modular**. Setiap fitur dikelompokkan dalam satu folder agar kode tetap rapi seiring berkembangnya aplikasi.
|
|
25
36
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
Contoh struktur modul `Auth`:
|
|
29
|
-
|
|
30
|
-
- `Auth/auth.controller.ts`: Logika aplikasi (Controller).
|
|
37
|
+
* **Contoh**: Jika Anda membuat fitur "Produk", Anda akan memiliki folder `src/modules/Product/`.
|
|
38
|
+
* **Isi**: Biasanya berisi `controller` (logika) dan file pendukung fitur tersebut.
|
|
31
39
|
|
|
32
40
|
### `src/routes/`
|
|
41
|
+
Tempat mendefinisikan URL API Anda.
|
|
33
42
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
- Menghubungkan URL (misal `/api/login`) ke fungsi di Controller.
|
|
37
|
-
- Menempelkan Middleware (misal `requireAuth`).
|
|
43
|
+
* **`index.ts`**: Pintu gerbang utama semua rute.
|
|
44
|
+
* **File route lainnya**: Menghubungkan URL (misal `/api/users`) ke fungsi di Controller dan memasang middleware.
|
|
38
45
|
|
|
39
46
|
### `src/config/`
|
|
47
|
+
Konfigurasi statis aplikasi Anda.
|
|
40
48
|
|
|
41
|
-
|
|
49
|
+
* **`app.ts`**: Pengaturan umum.
|
|
50
|
+
* **`cors.ts`**: Pengaturan keamanan akses domain (CORS).
|
|
42
51
|
|
|
43
|
-
|
|
44
|
-
- `cors.ts`: Konfigurasi CORS (Cross-Origin Resource Sharing).
|
|
52
|
+
---
|
|
45
53
|
|
|
46
|
-
## Folder `lib/` (Framework
|
|
54
|
+
## ⚙️ Folder `lib/` (Framework Core)
|
|
47
55
|
|
|
48
|
-
|
|
56
|
+
Folder ini adalah "mesin" di balik layar. Isinya adalah kode inti yang menjalankan server, koneksi database, dan utilitas bawaan.
|
|
49
57
|
|
|
50
|
-
|
|
58
|
+
> **Catatan**: Anda jarang perlu menyentuh folder ini kecuali Anda ingin memodifikasi perilaku dasar framework.
|
|
51
59
|
|
|
52
|
-
|
|
60
|
+
* **`lib/core/`**: Setup server Express, koneksi Redis, dan Serializer.
|
|
61
|
+
* **`lib/middleware/`**: Middleware bawaan seperti `auth` (JWT), `rateLimit`, dan `requestLogger`.
|
|
62
|
+
* **`lib/utils/`**: Fungsi bantuan seperti `validator` (validasi input), `logger` (pencatatan log), dan `response` (format respon standar).
|
|
53
63
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 🧪 Folder `tests/`
|
|
57
67
|
|
|
58
|
-
|
|
68
|
+
Tempat Anda menulis pengujian otomatis untuk memastikan aplikasi berjalan lancar.
|
|
59
69
|
|
|
60
|
-
|
|
70
|
+
* **`unit/`**: Tes untuk fungsi-fungsi kecil secara terisolasi.
|
|
71
|
+
* **`integration/`**: Tes untuk alur API secara menyeluruh (misal: hit endpoint login dan pastikan dapat token).
|
|
72
|
+
* **`setup.ts`**: Konfigurasi awal sebelum tes dijalankan.
|
|
61
73
|
|
|
62
|
-
|
|
63
|
-
- `rateLimit.ts`: Batasi jumlah request.
|
|
64
|
-
- `requestLogger.ts`: Log setiap request yang masuk.
|
|
74
|
+
---
|
|
65
75
|
|
|
66
|
-
|
|
76
|
+
## 📦 Folder `storage/`
|
|
67
77
|
|
|
68
|
-
|
|
78
|
+
Folder untuk menyimpan file yang dihasilkan oleh aplikasi saat berjalan (runtime).
|
|
69
79
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
- `logger.ts`: Sistem logging (Winston).
|
|
80
|
+
* **`logs/`**: File log aplikasi (error log, access log).
|
|
81
|
+
* **`uploads/`** (Opsional): Tempat penyimpanan file yang diunggah user (jika menggunakan penyimpanan lokal).
|
|
73
82
|
|
|
74
|
-
|
|
83
|
+
---
|
|
75
84
|
|
|
76
|
-
|
|
85
|
+
## 🛠️ File Konfigurasi Penting
|
|
77
86
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
87
|
+
| File | Deskripsi |
|
|
88
|
+
| :--- | :--- |
|
|
89
|
+
| **`.env`** | Menyimpan **rahasia** aplikasi (Database URL, API Keys). **Jangan commit file ini ke Git!** |
|
|
90
|
+
| **`package.json`** | Daftar pustaka (library) yang dipakai dan perintah script (`npm run ...`). |
|
|
91
|
+
| **`ecosystem.config.js`** | Konfigurasi untuk **PM2**. Digunakan saat deploy ke server production (VPS) agar aplikasi auto-restart. |
|
|
92
|
+
| **`jest.config.js`** | Pengaturan untuk framework testing (Jest). |
|
|
93
|
+
| **`nodemon.json`** | Pengaturan auto-restart server saat Anda sedang coding (Development mode). |
|
|
81
94
|
|
|
82
95
|
---
|
|
83
96
|
|
|
84
|
-
|
|
97
|
+
## 🤖 Folder `scripts/`
|
|
98
|
+
|
|
99
|
+
Berisi script "ajaib" yang memudahkan hidup Anda. Script ini biasanya dipanggil lewat perintah `npm run`.
|
|
100
|
+
|
|
101
|
+
* **`release.js`**: Otomatisasi rilis versi, changelog, dan blog.
|
|
102
|
+
* **`make-module.js`**: Generator untuk membuat modul/controller baru dengan cepat.
|
|
103
|
+
* **`sync-docs.js`**: Sinkronisasi dokumentasi antar bahasa.
|
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();
|
|
@@ -142,7 +198,7 @@ async function main() {
|
|
|
142
198
|
title: Rilis v${newVersion} - ${titleID}
|
|
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}
|
|
@@ -171,7 +227,7 @@ Terima kasih telah menggunakan Lapeh Framework!
|
|
|
171
227
|
title: Release v${newVersion} - ${titleEN}
|
|
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}
|
|
@@ -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
|