lapeh 3.0.2 → 3.0.3

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 (2) hide show
  1. package/package.json +127 -126
  2. package/scripts/release.js +284 -0
package/package.json CHANGED
@@ -1,126 +1,127 @@
1
- {
2
- "name": "lapeh",
3
- "version": "3.0.2",
4
- "description": "Framework API Express yang siap pakai (Standardized)",
5
- "engines": {
6
- "node": ">=18.0.0",
7
- "npm": ">=9.0.0"
8
- },
9
- "main": "dist/lib/bootstrap.js",
10
- "bin": {
11
- "lapeh": "bin/index.js"
12
- },
13
- "repository": {
14
- "type": "git",
15
- "url": "git+https://github.com/robyajo/lapeh.git"
16
- },
17
- "homepage": "https://lapeh-doc.vercel.app",
18
- "bugs": {
19
- "url": "https://github.com/robyajo/lapeh/issues"
20
- },
21
- "types": "dist/src/index.d.ts",
22
- "files": [
23
- "bin",
24
- "dist",
25
- "lib",
26
- "scripts",
27
- "src",
28
- "storage",
29
- "doc",
30
- "README.md",
31
- "LICENSE",
32
- "tsconfig.json",
33
- "nodemon.json",
34
- "docker-compose.yml",
35
- ".env.example",
36
- "eslint.config.mjs",
37
- "gitignore.template",
38
- "ecosystem.config.js",
39
- "tsconfig.build.json"
40
- ],
41
- "scripts": {
42
- "dev": "node bin/index.js dev",
43
- "first": "node scripts/init-project.js",
44
- "build": "node bin/index.js build",
45
- "start": "node bin/index.js start",
46
- "start:prod": "node bin/index.js start",
47
- "typecheck": "tsc --noEmit",
48
- "lint": "eslint .",
49
- "lint:fix": "eslint . --fix",
50
- "test": "jest",
51
- "generate:jwt": "node scripts/generate-jwt-secret.js",
52
- "make:module": "node scripts/make-module.js",
53
- "make:modul": "node scripts/make-module.js",
54
- "config:clear": "node scripts/config-clear.js",
55
- "prepublishOnly": "npm run build"
56
- },
57
- "keywords": [
58
- "nodejs-framework",
59
- "typescript-framework",
60
- "express-framework",
61
- "backend-framework",
62
- "rest-api",
63
- "production-ready",
64
- "api-generator",
65
- "boilerplate",
66
- "starter-kit",
67
- "mvc",
68
- "cli",
69
- "lapeh",
70
- "roby-ajo",
71
- "ajo-roby",
72
- "robyajo",
73
- "lapeh"
74
- ],
75
- "author": "robyajo <robyfull.dev@gmail.com>",
76
- "license": "MIT",
77
- "type": "commonjs",
78
- "peerDependencies": {},
79
- "dependencies": {
80
- "@types/bcryptjs": "2.4.6",
81
- "@types/compression": "^1.8.1",
82
- "@types/cors": "2.8.19",
83
- "@types/express": "5.0.6",
84
- "@types/jsonwebtoken": "9.0.10",
85
- "@types/multer": "^2.0.0",
86
- "@types/node": "25.0.3",
87
- "@types/pg": "8.16.0",
88
- "@types/uuid": "10.0.0",
89
- "bcryptjs": "^2.4.3",
90
- "compression": "^1.8.1",
91
- "cors": "2.8.5",
92
- "dotenv": "17.2.3",
93
- "express": "5.2.1",
94
- "express-rate-limit": "8.2.1",
95
- "fast-json-stringify": "^6.1.1",
96
- "helmet": "8.1.0",
97
- "ioredis": "5.8.2",
98
- "ioredis-mock": "^8.13.1",
99
- "jsonwebtoken": "9.0.3",
100
- "module-alias": "^2.2.3",
101
- "multer": "2.0.2",
102
- "pg": "8.16.3",
103
- "slugify": "1.6.6",
104
- "socket.io": "4.8.3",
105
- "ts-node": "^10.9.2",
106
- "tsconfig-paths": "^4.2.0",
107
- "typescript": "^5.9.3",
108
- "uuid": "13.0.0",
109
- "winston": "^3.19.0",
110
- "winston-daily-rotate-file": "^5.0.0",
111
- "zod": "3.23.8"
112
- },
113
- "devDependencies": {
114
- "@eslint/js": "^9.39.2",
115
- "@types/bcrypt": "^5.0.2",
116
- "@types/jest": "^30.0.0",
117
- "@types/module-alias": "^2.0.4",
118
- "@types/supertest": "^6.0.3",
119
- "eslint": "^9.39.2",
120
- "globals": "^16.5.0",
121
- "jest": "^30.2.0",
122
- "supertest": "^7.1.4",
123
- "ts-jest": "^29.4.6",
124
- "typescript-eslint": "^8.50.1"
125
- }
126
- }
1
+ {
2
+ "name": "lapeh",
3
+ "version": "3.0.3",
4
+ "description": "Framework API Express yang siap pakai (Standardized)",
5
+ "engines": {
6
+ "node": ">=18.0.0",
7
+ "npm": ">=9.0.0"
8
+ },
9
+ "main": "dist/lib/bootstrap.js",
10
+ "bin": {
11
+ "lapeh": "bin/index.js"
12
+ },
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/robyajo/lapeh.git"
16
+ },
17
+ "homepage": "https://lapeh-doc.vercel.app",
18
+ "bugs": {
19
+ "url": "https://github.com/robyajo/lapeh/issues"
20
+ },
21
+ "types": "dist/src/index.d.ts",
22
+ "files": [
23
+ "bin",
24
+ "dist",
25
+ "lib",
26
+ "scripts",
27
+ "src",
28
+ "storage",
29
+ "doc",
30
+ "README.md",
31
+ "LICENSE",
32
+ "tsconfig.json",
33
+ "nodemon.json",
34
+ "docker-compose.yml",
35
+ ".env.example",
36
+ "eslint.config.mjs",
37
+ "gitignore.template",
38
+ "ecosystem.config.js",
39
+ "tsconfig.build.json"
40
+ ],
41
+ "scripts": {
42
+ "dev": "node bin/index.js dev",
43
+ "first": "node scripts/init-project.js",
44
+ "build": "node bin/index.js build",
45
+ "start": "node bin/index.js start",
46
+ "start:prod": "node bin/index.js start",
47
+ "typecheck": "tsc --noEmit",
48
+ "lint": "eslint .",
49
+ "lint:fix": "eslint . --fix",
50
+ "test": "jest",
51
+ "generate:jwt": "node scripts/generate-jwt-secret.js",
52
+ "make:module": "node scripts/make-module.js",
53
+ "make:modul": "node scripts/make-module.js",
54
+ "config:clear": "node scripts/config-clear.js",
55
+ "release": "node scripts/release.js",
56
+ "prepublishOnly": "npm run build"
57
+ },
58
+ "keywords": [
59
+ "nodejs-framework",
60
+ "typescript-framework",
61
+ "express-framework",
62
+ "backend-framework",
63
+ "rest-api",
64
+ "production-ready",
65
+ "api-generator",
66
+ "boilerplate",
67
+ "starter-kit",
68
+ "mvc",
69
+ "cli",
70
+ "lapeh",
71
+ "roby-ajo",
72
+ "ajo-roby",
73
+ "robyajo",
74
+ "lapeh"
75
+ ],
76
+ "author": "robyajo <robyfull.dev@gmail.com>",
77
+ "license": "MIT",
78
+ "type": "commonjs",
79
+ "peerDependencies": {},
80
+ "dependencies": {
81
+ "@types/bcryptjs": "2.4.6",
82
+ "@types/compression": "^1.8.1",
83
+ "@types/cors": "2.8.19",
84
+ "@types/express": "5.0.6",
85
+ "@types/jsonwebtoken": "9.0.10",
86
+ "@types/multer": "^2.0.0",
87
+ "@types/node": "25.0.3",
88
+ "@types/pg": "8.16.0",
89
+ "@types/uuid": "10.0.0",
90
+ "bcryptjs": "^2.4.3",
91
+ "compression": "^1.8.1",
92
+ "cors": "2.8.5",
93
+ "dotenv": "17.2.3",
94
+ "express": "5.2.1",
95
+ "express-rate-limit": "8.2.1",
96
+ "fast-json-stringify": "^6.1.1",
97
+ "helmet": "8.1.0",
98
+ "ioredis": "5.8.2",
99
+ "ioredis-mock": "^8.13.1",
100
+ "jsonwebtoken": "9.0.3",
101
+ "module-alias": "^2.2.3",
102
+ "multer": "2.0.2",
103
+ "pg": "8.16.3",
104
+ "slugify": "1.6.6",
105
+ "socket.io": "4.8.3",
106
+ "ts-node": "^10.9.2",
107
+ "tsconfig-paths": "^4.2.0",
108
+ "typescript": "^5.9.3",
109
+ "uuid": "13.0.0",
110
+ "winston": "^3.19.0",
111
+ "winston-daily-rotate-file": "^5.0.0",
112
+ "zod": "3.23.8"
113
+ },
114
+ "devDependencies": {
115
+ "@eslint/js": "^9.39.2",
116
+ "@types/bcrypt": "^5.0.2",
117
+ "@types/jest": "^30.0.0",
118
+ "@types/module-alias": "^2.0.4",
119
+ "@types/supertest": "^6.0.3",
120
+ "eslint": "^9.39.2",
121
+ "globals": "^16.5.0",
122
+ "jest": "^30.2.0",
123
+ "supertest": "^7.1.4",
124
+ "ts-jest": "^29.4.6",
125
+ "typescript-eslint": "^8.50.1"
126
+ }
127
+ }
@@ -0,0 +1,284 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const readline = require('readline');
4
+ const { execSync } = require('child_process');
5
+
6
+ const rl = readline.createInterface({
7
+ input: process.stdin,
8
+ output: process.stdout
9
+ });
10
+
11
+ const question = (query) => new Promise((resolve) => rl.question(query, resolve));
12
+
13
+ // Paths
14
+ const rootDir = path.resolve(__dirname, '..');
15
+ const websiteDir = path.join(rootDir, 'website');
16
+ const packageJsonPath = path.join(rootDir, 'package.json');
17
+ const websitePackageJsonPath = path.join(websiteDir, 'package.json');
18
+
19
+ // Read current version
20
+ const pkg = require(packageJsonPath);
21
+ const currentVersion = pkg.version;
22
+
23
+ console.log(`\nšŸš€ Lapeh Release Automation Script`);
24
+ console.log(`Current Version: ${currentVersion}\n`);
25
+
26
+ // Helper to get git changes
27
+ function getGitChanges() {
28
+ try {
29
+ // Try to find the last tag
30
+ let lastTag = '';
31
+ try {
32
+ lastTag = execSync('git describe --tags --abbrev=0', { stdio: 'pipe' }).toString().trim();
33
+ } catch (e) {
34
+ // No tags found, maybe fetch all commits
35
+ lastTag = '';
36
+ }
37
+
38
+ const range = lastTag ? `${lastTag}..HEAD` : 'HEAD';
39
+ const logs = execSync(`git log ${range} --pretty=format:"%s"`, { stdio: 'pipe' }).toString().trim();
40
+
41
+ if (!logs) return [];
42
+
43
+ // Filter out chores, merges, etc. if desired, or keep everything
44
+ return logs.split('\n')
45
+ .map(l => l.trim())
46
+ .filter(l => l && !l.startsWith('chore:') && !l.startsWith('Merge branch'));
47
+ } catch (e) {
48
+ return [];
49
+ }
50
+ }
51
+
52
+ // Helper to get npm version
53
+ function getNpmVersion() {
54
+ try {
55
+ return execSync('npm view lapeh version', { stdio: 'pipe' }).toString().trim();
56
+ } catch (e) {
57
+ return null;
58
+ }
59
+ }
60
+
61
+ // Helper to increment patch version
62
+ function incrementPatch(version) {
63
+ const parts = version.split('.').map(Number);
64
+ if (parts.length !== 3 || parts.some(isNaN)) return version; // Fallback
65
+ parts[2]++;
66
+ return parts.join('.');
67
+ }
68
+
69
+ async function main() {
70
+ try {
71
+ // 1. Check versions and ask for new one
72
+ console.log('šŸ” Checking npm version...');
73
+ const npmVersion = getNpmVersion();
74
+ const baseVersion = npmVersion || currentVersion;
75
+ const suggestedVersion = incrementPatch(baseVersion);
76
+
77
+ console.log(`Latest npm version: ${npmVersion || 'Not found (using local)'}`);
78
+ console.log(`Current local version: ${currentVersion}`);
79
+
80
+ const newVersionInput = await question(`Enter new version (default: ${suggestedVersion}): `);
81
+ const newVersion = newVersionInput.trim() || suggestedVersion;
82
+
83
+ if (!newVersion) {
84
+ console.log('āŒ Version is required');
85
+ process.exit(1);
86
+ }
87
+
88
+ // Always update package.json locally first
89
+ console.log('\nšŸ“¦ Updating package.json files...');
90
+ updatePackageJson(packageJsonPath, newVersion);
91
+ updatePackageJson(websitePackageJsonPath, newVersion);
92
+
93
+ // 2. Question: Blog
94
+ const createBlog = await question('\n1. Apa Anda akan membuatkan blog untuk fitur baru ini? (y/n): ');
95
+ let blogTitleEN = '';
96
+
97
+ if (createBlog.toLowerCase() === 'y') {
98
+ console.log('\nšŸ¤– Auto-detecting changes from Git...');
99
+ const changes = getGitChanges();
100
+
101
+ // Heuristics for defaults
102
+ const defaultTitle = changes.length > 0 ? changes[0] : 'Maintenance Release';
103
+ const defaultDesc = changes.length > 0 ? `Includes: ${changes.slice(0, 2).join(', ')}` : 'Routine maintenance and updates.';
104
+ const defaultFeatures = changes.join(', ');
105
+
106
+ console.log('\n--- šŸ‡®šŸ‡© Bahasa Indonesia Input ---');
107
+ const titleID = await question(`Judul Rilis (default: "${defaultTitle}"): `) || defaultTitle;
108
+ const descriptionID = await question(`Deskripsi Singkat (default: "${defaultDesc}"): `) || defaultDesc;
109
+ const featuresID = await question(`Fitur Utama (default: "${defaultFeatures}"): `) || defaultFeatures;
110
+
111
+ console.log('\n--- šŸ‡ŗšŸ‡ø English Input ---');
112
+ // Reuse ID inputs as defaults for EN if user just hits enter,
113
+ // but ideally they should type English. We show the same defaults.
114
+ const titleEN = await question(`Release Title (default: "${defaultTitle}"): `) || defaultTitle;
115
+ const descriptionEN = await question(`Short Description (default: "${defaultDesc}"): `) || defaultDesc;
116
+ const featuresEN = await question(`Key Features (default: "${defaultFeatures}"): `) || defaultFeatures;
117
+
118
+ blogTitleEN = titleEN; // Save for commit message
119
+
120
+ console.log('šŸ“ Generating blog posts...');
121
+ const date = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
122
+ const dateString = new Date().toLocaleDateString('id-ID', { day: 'numeric', month: 'long', year: 'numeric' });
123
+ const dateStringEn = new Date().toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' });
124
+
125
+ const blogFileName = `release-v${newVersion}.md`;
126
+
127
+ const featureListID = featuresID.split(',').map(f => `* **${f.trim()}**`).join('\n');
128
+ const featureListEN = featuresEN.split(',').map(f => `* **${f.trim()}**`).join('\n');
129
+
130
+ // Indonesian Blog Content
131
+ const idContent = `---
132
+ title: Rilis v${newVersion} - ${titleID}
133
+ date: ${date}
134
+ author: Tim Lapeh
135
+ description: ${descriptionID}
136
+ ---
137
+
138
+ # Rilis v${newVersion}: ${titleID}
139
+
140
+ Kami dengan senang hati mengumumkan rilis **Lapeh Framework v${newVersion}**!
141
+
142
+ ## Apa yang Baru?
143
+
144
+ ${descriptionID}
145
+
146
+ ### Fitur Utama šŸš€
147
+
148
+ ${featureListID}
149
+
150
+ ## Cara Update
151
+
152
+ \`\`\`bash
153
+ npm install lapeh@latest
154
+ \`\`\`
155
+
156
+ Terima kasih telah menggunakan Lapeh Framework!
157
+ `;
158
+
159
+ // English Blog Content
160
+ const enContent = `---
161
+ title: Release v${newVersion} - ${titleEN}
162
+ date: ${date}
163
+ author: Lapeh Team
164
+ description: ${descriptionEN}
165
+ ---
166
+
167
+ # Release v${newVersion}: ${titleEN}
168
+
169
+ We are excited to announce the release of **Lapeh Framework v${newVersion}**!
170
+
171
+ ## What's New?
172
+
173
+ ${descriptionEN}
174
+
175
+ ### Key Features šŸš€
176
+
177
+ ${featureListEN}
178
+
179
+ ## How to Update
180
+
181
+ \`\`\`bash
182
+ npm install lapeh@latest
183
+ \`\`\`
184
+
185
+ Thank you for using Lapeh Framework!
186
+ `;
187
+
188
+ fs.writeFileSync(path.join(websiteDir, 'blog', blogFileName), idContent);
189
+ fs.writeFileSync(path.join(websiteDir, 'en/blog', blogFileName), enContent);
190
+
191
+ console.log('šŸ“‘ Updating blog indexes...');
192
+ updateBlogIndex(path.join(websiteDir, 'blog/index.md'), newVersion, titleID, dateString, descriptionID, blogFileName, 'id');
193
+ updateBlogIndex(path.join(websiteDir, 'en/blog/index.md'), newVersion, titleEN, dateStringEn, descriptionEN, blogFileName, 'en');
194
+ } else {
195
+ console.log('ā­ļø Skipping blog generation.');
196
+ }
197
+
198
+ // 3. Question: Documentation
199
+ const updateDocs = await question('\n2. Apa Anda ingin update dokumentasi? (y/n): ');
200
+ if (updateDocs.toLowerCase() === 'y') {
201
+ console.log('\nšŸ“š Documentation Reminder:');
202
+ console.log('Jika ada package/method baru, silakan update file berikut secara manual sekarang:');
203
+ console.log(' - website/docs/packages.md');
204
+ console.log(' - website/docs/api.md');
205
+
206
+ await question('Tekan Enter jika Anda sudah selesai update manual (atau jika tidak diperlukan)...');
207
+
208
+ console.log('šŸ”„ Syncing documentation...');
209
+ execSync('node scripts/sync-docs.js', { cwd: websiteDir, stdio: 'inherit' });
210
+ } else {
211
+ console.log('ā­ļø Skipping documentation sync.');
212
+ }
213
+
214
+ // 4. Question: Git
215
+ const pushGit = await question('\n3. Apa ingin publish ke Git? (y/n): ');
216
+ if (pushGit.toLowerCase() === 'y') {
217
+ const commitMsg = blogTitleEN
218
+ ? `chore: release v${newVersion} - ${blogTitleEN}`
219
+ : `chore: release v${newVersion}`;
220
+
221
+ execSync('git add .', { stdio: 'inherit' });
222
+ execSync(`git commit -m "${commitMsg}"`, { stdio: 'inherit' });
223
+ execSync('git push', { stdio: 'inherit' });
224
+ console.log('āœ… Git push complete');
225
+ } else {
226
+ console.log('ā­ļø Skipping Git push.');
227
+ }
228
+
229
+ // 5. Question: NPM
230
+ const publishNpm = await question('\n4. Apa ingin publish ke NPM? (y/n): ');
231
+ if (publishNpm.toLowerCase() === 'y') {
232
+ execSync('npm publish', { stdio: 'inherit' });
233
+ console.log('āœ… NPM publish complete');
234
+ } else {
235
+ console.log('ā­ļø Skipping NPM publish.');
236
+ }
237
+
238
+ console.log('\n✨ Proses selesai!');
239
+
240
+ } catch (error) {
241
+ console.error('āŒ Error:', error.message);
242
+ } finally {
243
+ rl.close();
244
+ }
245
+ }
246
+
247
+ function updatePackageJson(filePath, version) {
248
+ const json = JSON.parse(fs.readFileSync(filePath, 'utf8'));
249
+ json.version = version;
250
+ fs.writeFileSync(filePath, JSON.stringify(json, null, 2) + '\n');
251
+ console.log(`Updated ${path.basename(filePath)} to ${version}`);
252
+ }
253
+
254
+ function updateBlogIndex(filePath, version, title, date, description, fileName, lang) {
255
+ let content = fs.readFileSync(filePath, 'utf8');
256
+
257
+ const readMore = lang === 'id' ? 'Baca selengkapnya' : 'Read more';
258
+ const releaseTag = lang === 'id' ? 'Rilis' : 'Release';
259
+
260
+ // Construct new entry
261
+ const newEntry = `## šŸš€ [${releaseTag} v${version}: ${title}](./${fileName.replace('.md', '')})
262
+
263
+ _${date}_ • šŸ‘¤ Lapeh Team • šŸ·ļø _Release_
264
+
265
+ ${description} [${readMore} →](./${fileName.replace('.md', '')})
266
+
267
+ ---
268
+
269
+ `;
270
+
271
+ const separator = '---';
272
+ const parts = content.split(separator);
273
+
274
+ if (parts.length >= 2) {
275
+ parts.splice(1, 0, '\n\n' + newEntry.trim() + '\n\n');
276
+ content = parts.join(separator);
277
+ } else {
278
+ content = content + '\n\n' + newEntry;
279
+ }
280
+
281
+ fs.writeFileSync(filePath, content);
282
+ }
283
+
284
+ main();