create-rebe 1.0.0

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 (100) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +54 -0
  3. package/bin/create-rebe.js +310 -0
  4. package/package.json +40 -0
  5. package/template/.env.example +141 -0
  6. package/template/.gitattributes +16 -0
  7. package/template/.nvmrc +1 -0
  8. package/template/.prettierignore +10 -0
  9. package/template/.prettierrc +12 -0
  10. package/template/LICENSE +21 -0
  11. package/template/README.md +150 -0
  12. package/template/SECURITY.md +133 -0
  13. package/template/app/hooks/register.hook.js +22 -0
  14. package/template/app/http/controllers/auth.controller.js +34 -0
  15. package/template/app/http/middlewares/auth.middleware.js +25 -0
  16. package/template/app/http/middlewares/register.middleware.js +18 -0
  17. package/template/app/http/validators/auth.validator.js +8 -0
  18. package/template/app/jobs/register.job.js +17 -0
  19. package/template/app/queue/register.queue.js +11 -0
  20. package/template/app/routes/api.route.js +18 -0
  21. package/template/app/routes/register.route.js +8 -0
  22. package/template/app/routes/web.route.js +7 -0
  23. package/template/app/socket/register.socket.js +15 -0
  24. package/template/config/app.config.js +12 -0
  25. package/template/config/bcrypt.config.js +7 -0
  26. package/template/config/cache.config.js +7 -0
  27. package/template/config/cors.config.js +37 -0
  28. package/template/config/cron.config.js +9 -0
  29. package/template/config/database.config.js +51 -0
  30. package/template/config/express.config.js +37 -0
  31. package/template/config/index.js +19 -0
  32. package/template/config/jwt.config.js +10 -0
  33. package/template/config/logger.config.js +10 -0
  34. package/template/config/mail.config.js +14 -0
  35. package/template/config/queue.config.js +11 -0
  36. package/template/config/redis.config.js +32 -0
  37. package/template/config/runtime.config.js +11 -0
  38. package/template/config/socket.config.js +15 -0
  39. package/template/config/storage.config.js +10 -0
  40. package/template/core/bootstrap.core.js +92 -0
  41. package/template/core/common/array.js +144 -0
  42. package/template/core/common/cache.js +100 -0
  43. package/template/core/common/collection.js +173 -0
  44. package/template/core/common/crypt.js +69 -0
  45. package/template/core/common/date.js +254 -0
  46. package/template/core/common/hash.js +61 -0
  47. package/template/core/common/object.js +155 -0
  48. package/template/core/common/path.js +80 -0
  49. package/template/core/common/storage.js +97 -0
  50. package/template/core/common/string.js +137 -0
  51. package/template/core/common/url.js +81 -0
  52. package/template/core/common.core.js +93 -0
  53. package/template/core/cron.core.js +141 -0
  54. package/template/core/database.core.js +113 -0
  55. package/template/core/error.core.js +83 -0
  56. package/template/core/express.core.js +161 -0
  57. package/template/core/hooks.core.js +47 -0
  58. package/template/core/jwt.core.js +81 -0
  59. package/template/core/logger.core.js +100 -0
  60. package/template/core/mailer.core.js +65 -0
  61. package/template/core/queue.core.js +226 -0
  62. package/template/core/redis.core.js +75 -0
  63. package/template/core/register.core.js +91 -0
  64. package/template/core/runtime.core.js +27 -0
  65. package/template/core/socket.core.js +93 -0
  66. package/template/core/validator.core.js +34 -0
  67. package/template/database/.gitkeep +0 -0
  68. package/template/database/models/post.model.js +26 -0
  69. package/template/database/models/user.model.js +30 -0
  70. package/template/docs/Bootstrap.md +50 -0
  71. package/template/docs/Common.md +48 -0
  72. package/template/docs/Cron.md +47 -0
  73. package/template/docs/Database.md +61 -0
  74. package/template/docs/Express.md +63 -0
  75. package/template/docs/Hooks.md +48 -0
  76. package/template/docs/Jwt.md +63 -0
  77. package/template/docs/Logger.md +60 -0
  78. package/template/docs/Mailer.md +50 -0
  79. package/template/docs/Queue.md +57 -0
  80. package/template/docs/README.md +32 -0
  81. package/template/docs/Redis.md +54 -0
  82. package/template/docs/Register.md +52 -0
  83. package/template/docs/Socket.md +55 -0
  84. package/template/docs/Validator.md +45 -0
  85. package/template/ecosystem.config.js +54 -0
  86. package/template/index.js +6 -0
  87. package/template/jest.config.js +27 -0
  88. package/template/jsconfig.json +37 -0
  89. package/template/logs/.gitkeep +0 -0
  90. package/template/nodemon.json +23 -0
  91. package/template/package-lock.json +7033 -0
  92. package/template/package.json +82 -0
  93. package/template/scripts/cli.js +258 -0
  94. package/template/storage/.gitkeep +0 -0
  95. package/template/tests/common.test.js +45 -0
  96. package/template/tests/crypt-hash-storage.test.js +44 -0
  97. package/template/tests/jwt.test.js +45 -0
  98. package/template/tests/register.test.js +55 -0
  99. package/template/tests/setup.js +11 -0
  100. package/template/tests/validator.test.js +65 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Refkinscallv
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # create-rebe
2
+
3
+ Scaffold a new [rebe](https://www.npmjs.com/package/create-rebe) backend project.
4
+
5
+ ```bash
6
+ npm create rebe@latest my-api
7
+ # or
8
+ npx create-rebe my-api
9
+ ```
10
+
11
+ ## Options
12
+
13
+ | Flag | Description |
14
+ | ---------------------------------- | ------------------------------------------------------------- |
15
+ | `<directory>` | target directory (positional; prompted if omitted) |
16
+ | `--name <name>` | project (package.json) name; defaults to the directory name |
17
+ | `--pm <manager>` | `npm` \| `pnpm` \| `yarn` \| `bun` (auto-detected by default) |
18
+ | `--install` / `--no-install` | install dependencies after scaffolding |
19
+ | `--git` / `--no-git` | initialise a git repository |
20
+ | `--no-env` | do not generate `.env` from `.env.example` |
21
+ | `--force` | scaffold into a non-empty directory |
22
+ | `-y`, `--yes` | accept defaults, never prompt |
23
+ | `-h`, `--help` / `-v`, `--version` | help / version |
24
+
25
+ Examples:
26
+
27
+ ```bash
28
+ npm create rebe@latest my-api --pm pnpm --git --install
29
+ npm create rebe@latest . --name my-api -y
30
+ ```
31
+
32
+ Unless `--no-env` is given, the scaffolder writes a `.env` derived from
33
+ `.env.example` with freshly generated `APP_KEY`, `JWT_SECRET`, and
34
+ `JWT_REFRESH_SECRET`.
35
+
36
+ ## Design
37
+
38
+ - Zero runtime dependencies (Node built-ins only) to keep the supply-chain surface
39
+ minimal.
40
+ - create-rebe lives inside the rebe repo (`app/create-rebe`). The framework template
41
+ is bundled under `template/`, generated from the repo root by `npm run sync` (run
42
+ automatically on `prepublishOnly`), so the framework stays the single source of
43
+ truth.
44
+
45
+ ## Development
46
+
47
+ ```bash
48
+ npm run sync # regenerate template/ from the repo root (excludes create-rebe)
49
+ node bin/create-rebe.js /tmp/demo --no-install -y
50
+ ```
51
+
52
+ ## License
53
+
54
+ MIT
@@ -0,0 +1,310 @@
1
+ #!/usr/bin/env node
2
+
3
+ 'use strict'
4
+
5
+ // Scaffolder for the `rebe` backend framework.
6
+ //
7
+ // npm create rebe@latest [dir] [options]
8
+ //
9
+ // Zero runtime dependencies (Node built-ins only) to keep the supply-chain
10
+ // surface minimal. The framework template is bundled under ./template.
11
+
12
+ const fs = require('fs')
13
+ const path = require('path')
14
+ const crypto = require('crypto')
15
+ const readline = require('readline')
16
+ const { spawnSync } = require('child_process')
17
+
18
+ const COLORS = {
19
+ reset: '\x1b[0m',
20
+ bold: '\x1b[1m',
21
+ dim: '\x1b[2m',
22
+ red: '\x1b[31m',
23
+ green: '\x1b[32m',
24
+ yellow: '\x1b[33m',
25
+ cyan: '\x1b[36m',
26
+ }
27
+
28
+ function c(color, msg) {
29
+ return `${COLORS[color]}${msg}${COLORS.reset}`
30
+ }
31
+
32
+ const log = {
33
+ info: (m) => console.log(`${c('cyan', '-')} ${m}`),
34
+ ok: (m) => console.log(`${c('green', '✓')} ${m}`),
35
+ warn: (m) => console.log(`${c('yellow', '!')} ${m}`),
36
+ err: (m) => console.error(`${c('red', '✗')} ${m}`),
37
+ step: (m) => console.log(`\n${c('bold', m)}`),
38
+ }
39
+
40
+ const PKG = require('../package.json')
41
+
42
+ function resolveTemplateDir() {
43
+ // Published package bundles ./template. During local development fall back to
44
+ // the framework root (create-rebe lives inside the rebe repo at app/create-rebe,
45
+ // so the framework is this package's parent directory).
46
+ const bundled = path.join(__dirname, '..', 'template')
47
+ if (fs.existsSync(path.join(bundled, 'package.json'))) return bundled
48
+
49
+ const repoRoot = path.join(__dirname, '..', '..')
50
+ if (fs.existsSync(path.join(repoRoot, 'package.json'))) return repoRoot
51
+
52
+ return null
53
+ }
54
+
55
+ // ── Argument parsing ────────────────────────────────────────────────────────
56
+ // Tolerant parser: collects positionals, --flag, --flag=value, --no-flag, and
57
+ // short -y. Unknown flags are kept (forward compatible) but ignored.
58
+ function parseArgs(argv) {
59
+ const opts = { _: [] }
60
+ for (let i = 0; i < argv.length; i++) {
61
+ const arg = argv[i]
62
+ if (arg === '-y') {
63
+ opts.yes = true
64
+ } else if (arg === '-h') {
65
+ opts.help = true
66
+ } else if (arg === '-v') {
67
+ opts.version = true
68
+ } else if (arg.startsWith('--')) {
69
+ const body = arg.slice(2)
70
+ if (body.startsWith('no-')) {
71
+ opts[camel(body.slice(3))] = false
72
+ } else if (body.includes('=')) {
73
+ const [k, val] = body.split(/=(.*)/s)
74
+ opts[camel(k)] = val
75
+ } else {
76
+ const next = argv[i + 1]
77
+ if (next !== undefined && !next.startsWith('-')) {
78
+ opts[camel(body)] = next
79
+ i++
80
+ } else {
81
+ opts[camel(body)] = true
82
+ }
83
+ }
84
+ } else {
85
+ opts._.push(arg)
86
+ }
87
+ }
88
+ return opts
89
+ }
90
+
91
+ function camel(s) {
92
+ return s.replace(/-([a-z])/g, (_, ch) => ch.toUpperCase())
93
+ }
94
+
95
+ function printHelp() {
96
+ console.log(`
97
+ ${c('bold', 'create-rebe')} ${c('dim', `v${PKG.version}`)}
98
+
99
+ Scaffold a new rebe backend project.
100
+
101
+ ${c('bold', 'Usage')}
102
+ npm create rebe@latest ${c('dim', '[directory] [options]')}
103
+ npx create-rebe ${c('dim', '[directory] [options]')}
104
+
105
+ ${c('bold', 'Options')}
106
+ --name <name> Project (package.json) name. Default: directory name.
107
+ --pm <manager> Package manager: npm | pnpm | yarn | bun. Default: auto.
108
+ --install Install dependencies after scaffolding.
109
+ --no-install Skip dependency installation.
110
+ --git Initialise a git repository.
111
+ --no-git Skip git initialisation.
112
+ --no-env Do not generate a .env file from .env.example.
113
+ --force Scaffold into a non-empty directory.
114
+ -y, --yes Accept all defaults; never prompt.
115
+ -h, --help Show this help.
116
+ -v, --version Show version.
117
+
118
+ ${c('bold', 'Examples')}
119
+ npm create rebe@latest my-api
120
+ npm create rebe@latest my-api --pm pnpm --git --install
121
+ npm create rebe@latest . --name my-api -y
122
+ `)
123
+ }
124
+
125
+ // ── Validation helpers ──────────────────────────────────────────────────────
126
+ function isValidPackageName(name) {
127
+ // Subset of npm naming rules sufficient for scaffolding.
128
+ return /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(name)
129
+ }
130
+
131
+ function toPackageName(raw) {
132
+ return String(raw)
133
+ .trim()
134
+ .toLowerCase()
135
+ .replace(/[^a-z0-9-._~/@]/g, '-')
136
+ .replace(/^-+|-+$/g, '')
137
+ }
138
+
139
+ function isEmptyDir(dir) {
140
+ if (!fs.existsSync(dir)) return true
141
+ const entries = fs.readdirSync(dir).filter((e) => e !== '.git')
142
+ return entries.length === 0
143
+ }
144
+
145
+ function detectPackageManager() {
146
+ const ua = process.env.npm_config_user_agent || ''
147
+ if (ua.startsWith('pnpm')) return 'pnpm'
148
+ if (ua.startsWith('yarn')) return 'yarn'
149
+ if (ua.startsWith('bun')) return 'bun'
150
+ return 'npm'
151
+ }
152
+
153
+ // ── Prompt (only when interactive and not --yes) ────────────────────────────
154
+ function ask(question, fallback) {
155
+ return new Promise((resolve) => {
156
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
157
+ const suffix = fallback ? c('dim', ` (${fallback})`) : ''
158
+ rl.question(`${c('cyan', '?')} ${question}${suffix} `, (answer) => {
159
+ rl.close()
160
+ resolve(answer.trim() || fallback || '')
161
+ })
162
+ })
163
+ }
164
+
165
+ // ── File operations ─────────────────────────────────────────────────────────
166
+ const COPY_SKIP = new Set(['node_modules', '.git', '.env', 'create-rebe', 'template', 'coverage'])
167
+
168
+ function copyDir(src, dest) {
169
+ fs.mkdirSync(dest, { recursive: true })
170
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
171
+ // Defence in depth: the bundled template is pre-cleaned, but when scaffolding
172
+ // from the repo root (dev fallback) these must never be copied.
173
+ if (COPY_SKIP.has(entry.name)) continue
174
+
175
+ const from = path.join(src, entry.name)
176
+ const to = path.join(dest, entry.name)
177
+ if (entry.isDirectory()) {
178
+ copyDir(from, to)
179
+ } else if (entry.isSymbolicLink()) {
180
+ continue
181
+ } else {
182
+ fs.copyFileSync(from, to)
183
+ }
184
+ }
185
+ }
186
+
187
+ function genKey(bytes) {
188
+ return crypto.randomBytes(bytes).toString('hex')
189
+ }
190
+
191
+ // Generate .env from .env.example with fresh secrets and the project name. Done
192
+ // with plain string replacement so we never execute project code.
193
+ function writeEnv(targetDir, name) {
194
+ const examplePath = path.join(targetDir, '.env.example')
195
+ if (!fs.existsSync(examplePath)) return false
196
+
197
+ let content = fs.readFileSync(examplePath, 'utf8')
198
+ const replacements = {
199
+ APP_NAME: name,
200
+ APP_KEY: genKey(32),
201
+ JWT_SECRET: genKey(64),
202
+ JWT_REFRESH_SECRET: genKey(64),
203
+ }
204
+ for (const [key, value] of Object.entries(replacements)) {
205
+ const re = new RegExp(`^${key}=.*$`, 'm')
206
+ content = re.test(content) ? content.replace(re, `${key}=${value}`) : `${content}\n${key}=${value}`
207
+ }
208
+ fs.writeFileSync(path.join(targetDir, '.env'), content)
209
+ return true
210
+ }
211
+
212
+ function rewritePackageName(targetDir, name) {
213
+ const pkgPath = path.join(targetDir, 'package.json')
214
+ if (!fs.existsSync(pkgPath)) return
215
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'))
216
+ pkg.name = name
217
+ pkg.version = '0.1.0'
218
+ pkg.description = ''
219
+ // Drop framework-specific metadata so a generated project starts clean.
220
+ for (const key of ['author', 'repository', 'bugs', 'homepage', 'keywords']) delete pkg[key]
221
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, '\t') + '\n')
222
+ }
223
+
224
+ function run(cmd, args, cwd) {
225
+ const res = spawnSync(cmd, args, { cwd, stdio: 'inherit', shell: process.platform === 'win32' })
226
+ return res.status === 0
227
+ }
228
+
229
+ // ── Main ────────────────────────────────────────────────────────────────────
230
+ async function main() {
231
+ const opts = parseArgs(process.argv.slice(2))
232
+
233
+ if (opts.version) return console.log(PKG.version)
234
+ if (opts.help) return printHelp()
235
+
236
+ const templateDir = resolveTemplateDir()
237
+ if (!templateDir) {
238
+ log.err('Template not found. The create-rebe package appears to be corrupted.')
239
+ process.exit(1)
240
+ }
241
+
242
+ const interactive = process.stdin.isTTY && !opts.yes
243
+
244
+ // Target directory
245
+ let targetArg = opts._[0]
246
+ if (!targetArg) {
247
+ targetArg = interactive ? await ask('Project directory:', 'rebe-app') : 'rebe-app'
248
+ }
249
+ const targetDir = path.resolve(process.cwd(), targetArg)
250
+ const dirName = path.basename(targetDir)
251
+
252
+ // Project name
253
+ let name = opts.name || (interactive ? await ask('Project name:', toPackageName(dirName)) : toPackageName(dirName))
254
+ name = toPackageName(name)
255
+ if (!isValidPackageName(name)) {
256
+ log.err(`Invalid project name: "${name}"`)
257
+ process.exit(1)
258
+ }
259
+
260
+ // Empty-directory guard
261
+ if (!isEmptyDir(targetDir) && !opts.force) {
262
+ log.err(`Target directory is not empty: ${targetDir}`)
263
+ log.info('Use --force to scaffold anyway, or choose another directory.')
264
+ process.exit(1)
265
+ }
266
+
267
+ // Decisions
268
+ const pm = opts.pm || detectPackageManager()
269
+ if (!['npm', 'pnpm', 'yarn', 'bun'].includes(pm)) {
270
+ log.err(`Unknown package manager: ${pm}`)
271
+ process.exit(1)
272
+ }
273
+ const doGit = opts.git ?? (interactive ? (await ask('Initialise git? (y/N):', 'N')).toLowerCase().startsWith('y') : false)
274
+ const doInstall = opts.install ?? (interactive ? (await ask('Install dependencies? (y/N):', 'N')).toLowerCase().startsWith('y') : false)
275
+ const doEnv = opts.env !== false
276
+
277
+ // Scaffold
278
+ log.step(`Creating ${c('cyan', name)} in ${c('dim', targetDir)}`)
279
+ copyDir(templateDir, targetDir)
280
+ rewritePackageName(targetDir, name)
281
+ log.ok('Project files copied')
282
+
283
+ if (doEnv && writeEnv(targetDir, name)) log.ok('.env created with generated secrets')
284
+
285
+ if (doGit) {
286
+ const ok = run('git', ['init', '-q'], targetDir)
287
+ ok ? log.ok('git repository initialised') : log.warn('git init failed (is git installed?)')
288
+ }
289
+
290
+ if (doInstall) {
291
+ log.step(`Installing dependencies with ${pm}`)
292
+ const ok = run(pm, ['install'], targetDir)
293
+ ok ? log.ok('Dependencies installed') : log.warn('Dependency installation failed; run it manually later')
294
+ }
295
+
296
+ // Next steps
297
+ const rel = path.relative(process.cwd(), targetDir) || '.'
298
+ const runCmd = pm === 'npm' ? 'npm run' : pm
299
+ log.step('Done. Next steps:')
300
+ if (rel !== '.') console.log(` cd ${rel}`)
301
+ if (!doInstall) console.log(` ${pm} install`)
302
+ if (!doEnv) console.log(` cp .env.example .env ${c('dim', '# then set APP_KEY / JWT secrets')}`)
303
+ console.log(` ${runCmd} dev`)
304
+ console.log()
305
+ }
306
+
307
+ main().catch((err) => {
308
+ log.err(err && err.stack ? err.stack : String(err))
309
+ process.exit(1)
310
+ })
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "create-rebe",
3
+ "version": "1.0.0",
4
+ "description": "Scaffold a new rebe backend project: npm create rebe@latest <dir>.",
5
+ "license": "MIT",
6
+ "author": "Refkinscallv <refkinscallv@gmail.com>",
7
+ "type": "commonjs",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/refkinscallv/rebe.git",
11
+ "directory": "create-rebe"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/refkinscallv/rebe/issues"
15
+ },
16
+ "homepage": "https://github.com/refkinscallv/rebe/tree/main/create-rebe#readme",
17
+ "bin": {
18
+ "create-rebe": "bin/create-rebe.js"
19
+ },
20
+ "files": [
21
+ "bin",
22
+ "template",
23
+ "README.md"
24
+ ],
25
+ "engines": {
26
+ "node": ">=20.9.0"
27
+ },
28
+ "scripts": {
29
+ "sync": "node scripts/sync-template.js",
30
+ "prepublishOnly": "node scripts/sync-template.js"
31
+ },
32
+ "keywords": [
33
+ "rebe",
34
+ "create-rebe",
35
+ "scaffold",
36
+ "boilerplate",
37
+ "express",
38
+ "backend"
39
+ ]
40
+ }
@@ -0,0 +1,141 @@
1
+ # ========== Application ==========
2
+ APP_ENV=development
3
+ APP_NAME=rebe
4
+ APP_URL=http://localhost:3000
5
+ APP_PORT=3000
6
+ APP_TIMEZONE=UTC
7
+ # Generate with: npm run cli -- key:generate
8
+ APP_KEY=
9
+
10
+ # ========== HTTP / Express ==========
11
+ # Comma-separated allowlist, or * for any origin. When * is used, credentials are
12
+ # forced off (browsers reject wildcard origin + credentials).
13
+ CORS_ORIGIN=*
14
+ CORS_CREDENTIALS=false
15
+ CORS_MAX_AGE=86400
16
+ EXPRESS_BODY_LIMIT=10mb
17
+ # Number of trusted proxy hops (0 = direct exposure). Set to 1 behind one proxy.
18
+ EXPRESS_TRUST_PROXY=0
19
+ EXPRESS_RATE_LIMIT_ENABLED=true
20
+ EXPRESS_RATE_LIMIT_WINDOW_MS=900000
21
+ EXPRESS_RATE_LIMIT_MAX=100
22
+
23
+ # ========== Database ==========
24
+ DB_ENABLED=false
25
+ DB_DIALECT=mysql
26
+ DB_HOST=localhost
27
+ DB_PORT=3306
28
+ DB_USER=
29
+ DB_PASS=
30
+ DB_NAME=
31
+ DB_TIMEZONE=+00:00
32
+ # Logging
33
+ DB_LOGGING=false
34
+ DB_BENCHMARK=false
35
+ DB_LOG_PARAMS=false
36
+ # Model defaults
37
+ DB_UNDERSCORED=false
38
+ DB_FREEZE_TABLE=false
39
+ DB_TIMESTAMPS=true
40
+ DB_PARANOID=false
41
+ # Schema sync — never enable in production
42
+ DB_FORCE=false
43
+ DB_ALTER=false
44
+ # Pool
45
+ DB_POOL_MAX=10
46
+ DB_POOL_MIN=0
47
+ DB_POOL_ACQUIRE=30000
48
+ DB_POOL_IDLE=10000
49
+ # Retry
50
+ DB_RETRY_MAX=3
51
+ # Dialect specific
52
+ DB_CONNECT_TIMEOUT=10000
53
+ DB_SSL=false
54
+ DB_TRUST_CERT=true
55
+ DB_REQUEST_TIMEOUT=30000
56
+
57
+ # ========== JWT ==========
58
+ # Generate with: npm run cli -- key:jwt (and: npm run cli -- key:jwt --refresh)
59
+ JWT_SECRET=
60
+ JWT_EXPIRES_IN=1d
61
+ JWT_REFRESH_SECRET=
62
+ JWT_REFRESH_EXPIRES_IN=7d
63
+
64
+ # ========== Bcrypt ==========
65
+ BCRYPT_SALT_ROUNDS=10
66
+
67
+ # ========== Storage ==========
68
+ STORAGE_ROOT=storage
69
+ STORAGE_UPLOAD_PATH=storage/uploads
70
+ STORAGE_UPLOAD_MAX_SIZE_MB=50
71
+ STORAGE_UPLOAD_ALLOWED_TYPES=image/jpeg,image/png,image/webp,application/pdf
72
+
73
+ # ========== Logger ==========
74
+ LOG_LEVEL=debug
75
+ LOG_FILE=logs
76
+ LOG_MAX_SIZE=20m
77
+ LOG_MAX_FILES=14d
78
+
79
+ # ========== Runtime ==========
80
+ RUNTIME_MAX_LISTENERS=50
81
+ RUNTIME_STACK_TRACE_LIMIT=50
82
+ RUNTIME_UV_THREADPOOL_SIZE=4
83
+ RUNTIME_BIGINT_JSON=true
84
+ RUNTIME_DEPRECATION_WARNINGS=true
85
+
86
+ # ========== Cache ==========
87
+ CACHE_TTL=3600
88
+
89
+ # ========== Redis (optional, standalone) ==========
90
+ # Disabled by default. Each feature opts in via REDIS_USE_* (only when enabled).
91
+ REDIS_ENABLED=false
92
+ REDIS_HOST=127.0.0.1
93
+ REDIS_PORT=6379
94
+ REDIS_USERNAME=
95
+ REDIS_PASSWORD=
96
+ REDIS_DB=0
97
+ REDIS_KEY_PREFIX=
98
+ REDIS_TLS=false
99
+ REDIS_MAX_RETRIES=3
100
+ REDIS_CONNECT_TIMEOUT=10000
101
+ REDIS_USE_CACHE=false
102
+ REDIS_USE_QUEUE=false
103
+ REDIS_USE_SOCKET=false
104
+ REDIS_USE_SESSION=false
105
+
106
+ # ========== Cron ==========
107
+ CRON_ENABLED=true
108
+ CRON_TIMEZONE=Asia/Jakarta
109
+ # Set CRON_HISTORY=false to disable execution-history recording in the database
110
+ CRON_HISTORY=true
111
+
112
+ # ========== Queue ==========
113
+ QUEUE_ENABLED=true
114
+ QUEUE_CONCURRENCY=5
115
+ QUEUE_MAX_RETRIES=3
116
+ QUEUE_RETRY_DELAY=1000
117
+ # Set QUEUE_PERSIST=false to disable database persistence (jobs lost on restart)
118
+ QUEUE_PERSIST=true
119
+
120
+ # ========== Socket ==========
121
+ SOCKET_ENABLED=true
122
+ SOCKET_PATH=/socket.io/
123
+ SOCKET_CORS_ORIGIN=*
124
+ SOCKET_CORS_CREDENTIALS=false
125
+ SOCKET_SERVE_CLIENT=false
126
+ SOCKET_CONNECT_TIMEOUT=45000
127
+ SOCKET_PING_INTERVAL=25000
128
+ SOCKET_PING_TIMEOUT=20000
129
+ SOCKET_TRANSPORTS=polling,websocket
130
+ SOCKET_ALLOW_UPGRADES=true
131
+ SOCKET_MAX_HTTP_BUFFER_SIZE=1000000
132
+
133
+ # ========== Mail (Nodemailer) ==========
134
+ MAIL_ENABLED=false
135
+ MAIL_HOST=smtp.mailtrap.io
136
+ MAIL_PORT=587
137
+ MAIL_SECURE=false
138
+ MAIL_USERNAME=
139
+ MAIL_PASSWORD=
140
+ MAIL_FROM_ADDRESS=no-reply@example.com
141
+ MAIL_FROM_NAME=
@@ -0,0 +1,16 @@
1
+ # Normalize line endings. The scaffolder bin is executed via its shebang on Unix,
2
+ # so it must stay LF even when committed from Windows.
3
+ * text=auto eol=lf
4
+
5
+ *.js text eol=lf
6
+ *.json text eol=lf
7
+ *.md text eol=lf
8
+ create-rebe/bin/create-rebe.js text eol=lf
9
+
10
+ # Binary assets
11
+ *.png binary
12
+ *.jpg binary
13
+ *.jpeg binary
14
+ *.webp binary
15
+ *.gif binary
16
+ *.ico binary
@@ -0,0 +1 @@
1
+ 20
@@ -0,0 +1,10 @@
1
+ node_modules
2
+ create-rebe/template
3
+ .env
4
+ .env.example
5
+ .prettierrc
6
+ ecosystem.config.js
7
+ jsconfig.json
8
+ nodemon.json
9
+ package.json
10
+ package-lock.json
@@ -0,0 +1,12 @@
1
+ {
2
+ "semi": false,
3
+ "singleQuote": true,
4
+ "trailingComma": "all",
5
+ "printWidth": 500,
6
+ "tabWidth": 4,
7
+ "useTabs": true,
8
+ "bracketSpacing": true,
9
+ "bracketSameLine": false,
10
+ "arrowParens": "always",
11
+ "endOfLine": "lf"
12
+ }
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Refkinscallv
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.