@basicbenframework/core 0.1.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 (186) hide show
  1. package/.github/workflows/publish.yml +35 -0
  2. package/README.md +588 -0
  3. package/bin/cli.js +8 -0
  4. package/create-basicben-app/index.js +205 -0
  5. package/create-basicben-app/package.json +30 -0
  6. package/create-basicben-app/template/.env.example +24 -0
  7. package/create-basicben-app/template/README.md +59 -0
  8. package/create-basicben-app/template/basicben.config.js +33 -0
  9. package/create-basicben-app/template/index.html +54 -0
  10. package/create-basicben-app/template/migrations/001_create_users.js +15 -0
  11. package/create-basicben-app/template/migrations/002_create_posts.js +18 -0
  12. package/create-basicben-app/template/public/.gitkeep +0 -0
  13. package/create-basicben-app/template/seeds/01_users.js +29 -0
  14. package/create-basicben-app/template/seeds/02_posts.js +43 -0
  15. package/create-basicben-app/template/src/client/components/Alert.jsx +11 -0
  16. package/create-basicben-app/template/src/client/components/Avatar.jsx +11 -0
  17. package/create-basicben-app/template/src/client/components/BackLink.jsx +10 -0
  18. package/create-basicben-app/template/src/client/components/Button.jsx +19 -0
  19. package/create-basicben-app/template/src/client/components/Card.jsx +10 -0
  20. package/create-basicben-app/template/src/client/components/Empty.jsx +6 -0
  21. package/create-basicben-app/template/src/client/components/Input.jsx +12 -0
  22. package/create-basicben-app/template/src/client/components/Loading.jsx +6 -0
  23. package/create-basicben-app/template/src/client/components/Logo.jsx +40 -0
  24. package/create-basicben-app/template/src/client/components/Nav/DarkModeToggle.jsx +23 -0
  25. package/create-basicben-app/template/src/client/components/Nav/DesktopNav.jsx +32 -0
  26. package/create-basicben-app/template/src/client/components/Nav/MobileNav.jsx +107 -0
  27. package/create-basicben-app/template/src/client/components/NavLink.jsx +10 -0
  28. package/create-basicben-app/template/src/client/components/PageHeader.jsx +8 -0
  29. package/create-basicben-app/template/src/client/components/PostCard.jsx +19 -0
  30. package/create-basicben-app/template/src/client/components/Textarea.jsx +12 -0
  31. package/create-basicben-app/template/src/client/components/ThemeContext.jsx +5 -0
  32. package/create-basicben-app/template/src/client/contexts/ToastContext.jsx +94 -0
  33. package/create-basicben-app/template/src/client/layouts/AppLayout.jsx +60 -0
  34. package/create-basicben-app/template/src/client/layouts/AuthLayout.jsx +33 -0
  35. package/create-basicben-app/template/src/client/layouts/DocsLayout.jsx +60 -0
  36. package/create-basicben-app/template/src/client/layouts/RootLayout.jsx +25 -0
  37. package/create-basicben-app/template/src/client/pages/Auth.jsx +55 -0
  38. package/create-basicben-app/template/src/client/pages/Authentication.jsx +236 -0
  39. package/create-basicben-app/template/src/client/pages/Database.jsx +426 -0
  40. package/create-basicben-app/template/src/client/pages/Feed.jsx +34 -0
  41. package/create-basicben-app/template/src/client/pages/FeedPost.jsx +37 -0
  42. package/create-basicben-app/template/src/client/pages/GettingStarted.jsx +136 -0
  43. package/create-basicben-app/template/src/client/pages/Home.jsx +206 -0
  44. package/create-basicben-app/template/src/client/pages/PostForm.jsx +69 -0
  45. package/create-basicben-app/template/src/client/pages/Posts.jsx +59 -0
  46. package/create-basicben-app/template/src/client/pages/Profile.jsx +68 -0
  47. package/create-basicben-app/template/src/client/pages/Routing.jsx +207 -0
  48. package/create-basicben-app/template/src/client/pages/Testing.jsx +251 -0
  49. package/create-basicben-app/template/src/client/pages/Validation.jsx +210 -0
  50. package/create-basicben-app/template/src/controllers/AuthController.js +81 -0
  51. package/create-basicben-app/template/src/controllers/HomeController.js +17 -0
  52. package/create-basicben-app/template/src/controllers/PostController.js +86 -0
  53. package/create-basicben-app/template/src/controllers/ProfileController.js +66 -0
  54. package/create-basicben-app/template/src/helpers/api.js +24 -0
  55. package/create-basicben-app/template/src/main.jsx +9 -0
  56. package/create-basicben-app/template/src/middleware/auth.js +16 -0
  57. package/create-basicben-app/template/src/models/Post.js +63 -0
  58. package/create-basicben-app/template/src/models/User.js +42 -0
  59. package/create-basicben-app/template/src/routes/App.jsx +38 -0
  60. package/create-basicben-app/template/src/routes/api/auth.js +7 -0
  61. package/create-basicben-app/template/src/routes/api/posts.js +15 -0
  62. package/create-basicben-app/template/src/routes/api/profile.js +8 -0
  63. package/create-basicben-app/template/src/server/index.js +16 -0
  64. package/create-basicben-app/template/vite.config.js +18 -0
  65. package/database.sqlite +0 -0
  66. package/my-test-app/.env.example +24 -0
  67. package/my-test-app/README.md +59 -0
  68. package/my-test-app/basicben.config.js +33 -0
  69. package/my-test-app/database.sqlite-shm +0 -0
  70. package/my-test-app/database.sqlite-wal +0 -0
  71. package/my-test-app/index.html +54 -0
  72. package/my-test-app/migrations/001_create_users.js +15 -0
  73. package/my-test-app/migrations/002_create_posts.js +18 -0
  74. package/my-test-app/package-lock.json +2160 -0
  75. package/my-test-app/package.json +29 -0
  76. package/my-test-app/public/.gitkeep +0 -0
  77. package/my-test-app/seeds/01_users.js +29 -0
  78. package/my-test-app/seeds/02_posts.js +43 -0
  79. package/my-test-app/src/client/components/Alert.jsx +11 -0
  80. package/my-test-app/src/client/components/Avatar.jsx +11 -0
  81. package/my-test-app/src/client/components/BackLink.jsx +10 -0
  82. package/my-test-app/src/client/components/Button.jsx +19 -0
  83. package/my-test-app/src/client/components/Card.jsx +10 -0
  84. package/my-test-app/src/client/components/Empty.jsx +6 -0
  85. package/my-test-app/src/client/components/Input.jsx +12 -0
  86. package/my-test-app/src/client/components/Loading.jsx +6 -0
  87. package/my-test-app/src/client/components/Logo.jsx +40 -0
  88. package/my-test-app/src/client/components/Nav/DarkModeToggle.jsx +23 -0
  89. package/my-test-app/src/client/components/Nav/DesktopNav.jsx +32 -0
  90. package/my-test-app/src/client/components/Nav/MobileNav.jsx +107 -0
  91. package/my-test-app/src/client/components/NavLink.jsx +10 -0
  92. package/my-test-app/src/client/components/PageHeader.jsx +8 -0
  93. package/my-test-app/src/client/components/PostCard.jsx +19 -0
  94. package/my-test-app/src/client/components/Textarea.jsx +12 -0
  95. package/my-test-app/src/client/components/ThemeContext.jsx +5 -0
  96. package/my-test-app/src/client/contexts/AppContext.jsx +13 -0
  97. package/my-test-app/src/client/contexts/ToastContext.jsx +94 -0
  98. package/my-test-app/src/client/layouts/AppLayout.jsx +60 -0
  99. package/my-test-app/src/client/layouts/AuthLayout.jsx +33 -0
  100. package/my-test-app/src/client/layouts/DocsLayout.jsx +60 -0
  101. package/my-test-app/src/client/layouts/RootLayout.jsx +25 -0
  102. package/my-test-app/src/client/pages/Auth.jsx +55 -0
  103. package/my-test-app/src/client/pages/Authentication.jsx +236 -0
  104. package/my-test-app/src/client/pages/Database.jsx +426 -0
  105. package/my-test-app/src/client/pages/Feed.jsx +34 -0
  106. package/my-test-app/src/client/pages/FeedPost.jsx +37 -0
  107. package/my-test-app/src/client/pages/GettingStarted.jsx +136 -0
  108. package/my-test-app/src/client/pages/Home.jsx +206 -0
  109. package/my-test-app/src/client/pages/PostForm.jsx +69 -0
  110. package/my-test-app/src/client/pages/Posts.jsx +59 -0
  111. package/my-test-app/src/client/pages/Profile.jsx +68 -0
  112. package/my-test-app/src/client/pages/Routing.jsx +207 -0
  113. package/my-test-app/src/client/pages/Testing.jsx +251 -0
  114. package/my-test-app/src/client/pages/Validation.jsx +210 -0
  115. package/my-test-app/src/controllers/AuthController.js +81 -0
  116. package/my-test-app/src/controllers/HomeController.js +17 -0
  117. package/my-test-app/src/controllers/PostController.js +86 -0
  118. package/my-test-app/src/controllers/ProfileController.js +66 -0
  119. package/my-test-app/src/helpers/api.js +24 -0
  120. package/my-test-app/src/main.jsx +9 -0
  121. package/my-test-app/src/middleware/auth.js +16 -0
  122. package/my-test-app/src/models/Post.js +63 -0
  123. package/my-test-app/src/models/User.js +42 -0
  124. package/my-test-app/src/routes/App.jsx +38 -0
  125. package/my-test-app/src/routes/api/auth.js +7 -0
  126. package/my-test-app/src/routes/api/posts.js +15 -0
  127. package/my-test-app/src/routes/api/profile.js +8 -0
  128. package/my-test-app/src/server/index.js +16 -0
  129. package/my-test-app/vite.config.js +18 -0
  130. package/package.json +61 -0
  131. package/scripts/test-app.sh +59 -0
  132. package/src/auth/jwt.js +195 -0
  133. package/src/auth/password.js +132 -0
  134. package/src/cli/colors.js +31 -0
  135. package/src/cli/dispatcher.js +168 -0
  136. package/src/cli/parser.js +91 -0
  137. package/src/client/context.js +4 -0
  138. package/src/client/hooks.js +50 -0
  139. package/src/client/index.js +3 -0
  140. package/src/client/router.js +184 -0
  141. package/src/commands/build.js +155 -0
  142. package/src/commands/dev.js +206 -0
  143. package/src/commands/help.js +84 -0
  144. package/src/commands/make-controller.js +36 -0
  145. package/src/commands/make-middleware.js +44 -0
  146. package/src/commands/make-migration.js +51 -0
  147. package/src/commands/make-model.js +38 -0
  148. package/src/commands/make-route.js +36 -0
  149. package/src/commands/make-seed.js +38 -0
  150. package/src/commands/migrate-fresh.js +32 -0
  151. package/src/commands/migrate-rollback.js +30 -0
  152. package/src/commands/migrate-status.js +41 -0
  153. package/src/commands/migrate.js +30 -0
  154. package/src/commands/seed.js +47 -0
  155. package/src/commands/start.js +69 -0
  156. package/src/commands/test.js +46 -0
  157. package/src/db/Grammar.js +125 -0
  158. package/src/db/QueryBuilder.js +476 -0
  159. package/src/db/adapters/neon.js +170 -0
  160. package/src/db/adapters/planetscale.js +146 -0
  161. package/src/db/adapters/postgres.js +166 -0
  162. package/src/db/adapters/sqlite.js +125 -0
  163. package/src/db/adapters/turso.js +165 -0
  164. package/src/db/index.js +156 -0
  165. package/src/db/migrator.js +250 -0
  166. package/src/db/seeder.js +124 -0
  167. package/src/index.js +12 -0
  168. package/src/scaffolding/index.js +152 -0
  169. package/src/server/body-parser.js +159 -0
  170. package/src/server/cors.js +63 -0
  171. package/src/server/default-entry.js +13 -0
  172. package/src/server/http.js +221 -0
  173. package/src/server/index.js +168 -0
  174. package/src/server/loader.js +128 -0
  175. package/src/server/router.js +281 -0
  176. package/src/server/static.js +139 -0
  177. package/src/validation/index.js +436 -0
  178. package/src/vite/config.js +49 -0
  179. package/stubs/controller.stub +48 -0
  180. package/stubs/middleware-auth.stub +29 -0
  181. package/stubs/middleware.stub +9 -0
  182. package/stubs/migration.stub +17 -0
  183. package/stubs/model.stub +77 -0
  184. package/stubs/route.stub +13 -0
  185. package/stubs/seed.stub +16 -0
  186. package/stubs/vite.config.stub +18 -0
@@ -0,0 +1,35 @@
1
+ name: Publish to npm
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ jobs:
9
+ publish:
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: read
13
+ id-token: write # Required for Trusted Publishing
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - name: Setup Node.js
18
+ uses: actions/setup-node@v4
19
+ with:
20
+ node-version: '24'
21
+ registry-url: 'https://registry.npmjs.org'
22
+
23
+ - name: Run tests
24
+ run: npm test
25
+
26
+ - name: Publish @basicbenframework/core
27
+ run: npm publish --access public --provenance
28
+ env:
29
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
30
+
31
+ - name: Publish create-basicben-app
32
+ working-directory: ./create-basicben-app
33
+ run: npm publish --access public --provenance
34
+ env:
35
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
package/README.md ADDED
@@ -0,0 +1,588 @@
1
+ # BasicBen
2
+
3
+ > Ship faster with less. A full-stack framework for React. Zero runtime dependencies.
4
+
5
+ BasicBen gives you a productive, convention-driven structure for building React apps with a Node.js backend — without pulling in a bloated framework or locking you into vendor ecosystems.
6
+
7
+ ---
8
+
9
+ ## Why BasicBen?
10
+
11
+ Most JS frameworks make one of two mistakes: they do too much (Next.js, Remix) or they do nothing and leave you to wire everything yourself. BasicBen sits in the middle — conventions when you want them, escape hatches when you don't.
12
+
13
+ | Framework | Trade-off |
14
+ |-----------|-----------|
15
+ | Next.js / Remix | Too much magic, vendor lock-in |
16
+ | Express + Vite | Wire everything yourself |
17
+ | **BasicBen** | ✅ Conventions + control |
18
+
19
+ ### Core Principles
20
+
21
+ - **Zero runtime dependencies** — HTTP server, router, JWT auth, validation — all written from scratch using Node.js built-ins
22
+ - **Laravel-inspired DX** — migrations, controllers, models, and scaffolding commands that feel familiar
23
+ - **No lock-in** — just React, Node.js, and Vite. Eject anytime — your code is still your code
24
+ - **Escape hatches** — every convention can be overridden via `basicben.config.js`
25
+
26
+ ---
27
+
28
+ ## Requirements
29
+
30
+ - Node.js 24.14+
31
+ - npm 9+
32
+
33
+ ---
34
+
35
+ ## Quick Start
36
+
37
+ ```bash
38
+ npx create-basicben-app my-app
39
+ cd my-app
40
+ npm install
41
+ npx basicben migrate
42
+ npx basicben dev
43
+ ```
44
+
45
+ Your app is running at `http://localhost:3000` with a fully functional blog app — user auth, posts, and profiles included.
46
+
47
+ ### Local Development
48
+
49
+ To develop against a local copy of the framework:
50
+
51
+ ```bash
52
+ npx create-basicben-app my-app --local
53
+ ```
54
+
55
+ This sets the `basicben` dependency to `file:../basicben-framework` instead of fetching from npm.
56
+
57
+ ---
58
+
59
+ ## Project Structure
60
+
61
+ A new BasicBen project looks like this:
62
+
63
+ ```
64
+ my-app/
65
+ ├── index.html # Vite entry point
66
+ ├── src/
67
+ │ ├── main.jsx # React entry point
68
+ │ ├── routes/
69
+ │ │ ├── App.jsx # Client routes
70
+ │ │ └── api/ # Auto-loaded API routes
71
+ │ │ ├── auth.js
72
+ │ │ ├── posts.js
73
+ │ │ └── profile.js
74
+ │ ├── controllers/ # Business logic
75
+ │ │ ├── AuthController.js
76
+ │ │ ├── PostController.js
77
+ │ │ └── ProfileController.js
78
+ │ ├── models/ # DB query wrappers
79
+ │ │ ├── User.js
80
+ │ │ └── Post.js
81
+ │ ├── middleware/ # Route middleware
82
+ │ │ └── auth.js
83
+ │ ├── helpers/ # Utility functions
84
+ │ │ └── api.js # Fetch wrapper with auth
85
+ │ └── client/ # React frontend
86
+ │ ├── layouts/ # Layout components
87
+ │ │ ├── AppLayout.jsx
88
+ │ │ ├── AuthLayout.jsx
89
+ │ │ └── DocsLayout.jsx
90
+ │ ├── pages/ # Page components
91
+ │ │ ├── Home.jsx
92
+ │ │ ├── Auth.jsx
93
+ │ │ ├── Feed.jsx
94
+ │ │ ├── Posts.jsx
95
+ │ │ ├── Profile.jsx
96
+ │ │ └── ...
97
+ │ └── components/ # Reusable UI components
98
+ │ ├── Button.jsx
99
+ │ ├── Card.jsx
100
+ │ ├── Input.jsx
101
+ │ └── ...
102
+ ├── migrations/
103
+ │ ├── 001_create_users.js
104
+ │ └── 002_create_posts.js
105
+ ├── public/
106
+ └── basicben.config.js
107
+ ```
108
+
109
+ Routes, middleware, and models are loaded automatically — no manual imports needed.
110
+
111
+ ---
112
+
113
+ ## Starter Features
114
+
115
+ Every new BasicBen project includes a fully functional blog app:
116
+
117
+ ### Authentication
118
+ - User registration and login with JWT
119
+ - Protected routes with auth middleware
120
+ - Password hashing with `node:crypto`
121
+
122
+ ### User Profile
123
+ - View and edit profile (name, email)
124
+ - Change password
125
+
126
+ ### Blog Posts
127
+ - Create, edit, delete posts
128
+ - Publish/draft toggle
129
+ - List your own posts
130
+
131
+ ### Public Feed
132
+ - View all published posts
133
+ - Single post view with author info
134
+
135
+ ### React Components
136
+ The frontend uses reusable components:
137
+ - `Button`, `Input`, `Textarea`, `Card` — form elements
138
+ - `Alert`, `Loading`, `Empty` — feedback states
139
+ - `PageHeader`, `BackLink`, `Avatar` — layout helpers
140
+ - `ThemeContext` — light/dark mode support
141
+
142
+ ---
143
+
144
+ ## CLI
145
+
146
+ ```bash
147
+ # Development
148
+ basicben dev # Start Vite + Node dev server
149
+ basicben build # Bundle client + server for production
150
+ basicben build --static # Build client only (for static hosts)
151
+ basicben start # Run production server
152
+ basicben test # Run tests with Vitest
153
+
154
+ # Scaffolding
155
+ basicben make:controller <name> # Generate a controller
156
+ basicben make:route <name> # Generate a route file
157
+ basicben make:model <name> # Generate a model
158
+ basicben make:migration <name> # Generate a migration file
159
+ basicben make:middleware <name> # Generate middleware (auth template if name is 'auth')
160
+
161
+ # Database
162
+ basicben migrate # Run all pending migrations
163
+ basicben migrate:rollback # Roll back the last batch
164
+ basicben migrate:fresh # Drop everything and re-run all
165
+ basicben migrate:status # Show which migrations have run
166
+
167
+ # Help
168
+ basicben help # Show all commands
169
+ basicben help <command> # Show help for a specific command
170
+ ```
171
+
172
+ ---
173
+
174
+ ## Routing
175
+
176
+ ### API Routes
177
+
178
+ Create a file in `src/routes/api/` and export a default function that receives the router:
179
+
180
+ ```js
181
+ // src/routes/api/users.js
182
+ import { UserController } from '../../controllers/UserController.js'
183
+
184
+ export default (router) => {
185
+ router.get('/api/users', UserController.index)
186
+ router.get('/api/users/:id', UserController.show)
187
+ router.post('/api/users', UserController.create)
188
+ router.put('/api/users/:id', UserController.update)
189
+ router.delete('/api/users/:id', UserController.destroy)
190
+ }
191
+ ```
192
+
193
+ All files in `src/routes/api/` are registered automatically on startup.
194
+
195
+ ### Client Routes
196
+
197
+ Client-side routing is configured in `src/routes/App.jsx`:
198
+
199
+ ```js
200
+ // src/routes/App.jsx
201
+ import { createClientApp } from '@basicbenframework/core/client'
202
+ import { AppLayout } from '../client/layouts/AppLayout'
203
+ import { Home } from '../client/pages/Home'
204
+ import { Posts } from '../client/pages/Posts'
205
+
206
+ export default createClientApp({
207
+ layout: AppLayout,
208
+ routes: {
209
+ '/': Home,
210
+ '/posts': { component: Posts, auth: true },
211
+ }
212
+ })
213
+ ```
214
+
215
+ ---
216
+
217
+ ## Controllers
218
+
219
+ Generate one with:
220
+
221
+ ```bash
222
+ basicben make:controller UserController
223
+ ```
224
+
225
+ ```js
226
+ // src/controllers/UserController.js
227
+ import { User } from '../models/User.js'
228
+
229
+ export const UserController = {
230
+ index: async (req, res) => {
231
+ const users = await User.all()
232
+ res.json(users)
233
+ },
234
+
235
+ show: async (req, res) => {
236
+ const user = await User.find(req.params.id)
237
+ if (!user) return res.status(404).json({ error: 'Not found' })
238
+ res.json(user)
239
+ },
240
+
241
+ create: async (req, res) => {
242
+ const user = await User.create(req.body)
243
+ res.status(201).json(user)
244
+ },
245
+
246
+ update: async (req, res) => {
247
+ const user = await User.update(req.params.id, req.body)
248
+ res.json(user)
249
+ },
250
+
251
+ destroy: async (req, res) => {
252
+ await User.destroy(req.params.id)
253
+ res.status(204).send()
254
+ }
255
+ }
256
+ ```
257
+
258
+ ---
259
+
260
+ ## Models
261
+
262
+ Generate one with:
263
+
264
+ ```bash
265
+ basicben make:model User
266
+ ```
267
+
268
+ Models are thin wrappers around raw DB queries — no ORM, no magic.
269
+
270
+ ```js
271
+ // src/models/User.js
272
+ import { db } from '../db/index.js'
273
+
274
+ export const User = {
275
+ all: () => db.all(`SELECT * FROM users`),
276
+ find: (id) => db.get(`SELECT * FROM users WHERE id = ?`, id),
277
+ create: (data) => db.run(`INSERT INTO users (name, email) VALUES (?, ?)`, [data.name, data.email]),
278
+ update: (id, data) => db.run(`UPDATE users SET name = ?, email = ? WHERE id = ?`, [data.name, data.email, id]),
279
+ destroy: (id) => db.run(`DELETE FROM users WHERE id = ?`, id)
280
+ }
281
+ ```
282
+
283
+ ---
284
+
285
+ ## Migrations
286
+
287
+ Generate a migration with:
288
+
289
+ ```bash
290
+ basicben make:migration create_users
291
+ ```
292
+
293
+ This creates a timestamped file in `migrations/`:
294
+
295
+ ```js
296
+ // migrations/001_create_users.js
297
+ export const up = (db) => {
298
+ db.run(`
299
+ CREATE TABLE users (
300
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
301
+ name TEXT NOT NULL,
302
+ email TEXT UNIQUE NOT NULL,
303
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
304
+ )
305
+ `)
306
+ }
307
+
308
+ export const down = (db) => {
309
+ db.run(`DROP TABLE users`)
310
+ }
311
+ ```
312
+
313
+ Then run:
314
+
315
+ ```bash
316
+ basicben migrate
317
+ ```
318
+
319
+ BasicBen tracks which migrations have run in a `_migrations` table. Running `migrate` again is always safe.
320
+
321
+ ### Rolling back
322
+
323
+ ```bash
324
+ basicben migrate:rollback # Undo the last batch
325
+ basicben migrate:fresh # Drop everything and start over
326
+ basicben migrate:status # See what's run and what hasn't
327
+ ```
328
+
329
+ ---
330
+
331
+ ## Middleware
332
+
333
+ Create a file in `src/middleware/` and export a default function. Middleware is loaded automatically before routes, in filename order.
334
+
335
+ ```js
336
+ // src/middleware/auth.js
337
+ export default (req, res, next) => {
338
+ const token = req.headers.authorization?.split(' ')[1]
339
+ if (!token) return res.status(401).json({ error: 'Unauthorized' })
340
+ // verify token...
341
+ next()
342
+ }
343
+ ```
344
+
345
+ ---
346
+
347
+ ## Validation
348
+
349
+ BasicBen includes a lightweight validation system with 20+ built-in rules:
350
+
351
+ ```js
352
+ import { validate, rules } from 'basicben/validation'
353
+
354
+ const result = await validate(req.body, {
355
+ email: [rules.required, rules.email],
356
+ password: [rules.required, rules.min(8)],
357
+ age: [rules.optional, rules.integer, rules.between(18, 120)]
358
+ })
359
+
360
+ if (result.fails()) {
361
+ return res.status(422).json({ errors: result.errors })
362
+ }
363
+
364
+ // result.data contains validated data
365
+ ```
366
+
367
+ ### Built-in Rules
368
+
369
+ `required`, `optional`, `string`, `numeric`, `integer`, `boolean`, `array`, `email`, `url`, `min`, `max`, `between`, `in`, `notIn`, `regex`, `confirmed`, `different`, `length`, `alpha`, `alphanumeric`, `date`, `before`, `after`
370
+
371
+ ### Custom Rules
372
+
373
+ ```js
374
+ const uniqueEmail = async (value) => {
375
+ const exists = await db.get('SELECT 1 FROM users WHERE email = ?', value)
376
+ return exists ? 'Email already exists' : null
377
+ }
378
+
379
+ await validate(req.body, {
380
+ email: [rules.required, rules.email, uniqueEmail]
381
+ })
382
+ ```
383
+
384
+ ---
385
+
386
+ ## Authentication
387
+
388
+ BasicBen provides JWT helpers using Node's built-in `crypto` module — no `jsonwebtoken` dependency:
389
+
390
+ ```js
391
+ import { signJwt, verifyJwt } from 'basicben/auth'
392
+
393
+ // Sign a token
394
+ const token = signJwt({ userId: 1 }, process.env.APP_KEY, { expiresIn: '7d' })
395
+
396
+ // Verify a token
397
+ const payload = verifyJwt(token, process.env.APP_KEY)
398
+ if (!payload) {
399
+ // Invalid or expired
400
+ }
401
+ ```
402
+
403
+ The starter template includes a complete auth system:
404
+
405
+ ```js
406
+ // src/middleware/auth.js
407
+ import { verifyJwt } from 'basicben/auth'
408
+
409
+ export const auth = async (req, res, next) => {
410
+ const token = req.headers.authorization?.replace('Bearer ', '')
411
+ if (!token) return res.json({ error: 'Unauthorized' }, 401)
412
+
413
+ const payload = verifyJwt(token, process.env.APP_KEY)
414
+ if (!payload) return res.json({ error: 'Invalid token' }, 401)
415
+
416
+ req.userId = payload.userId
417
+ next()
418
+ }
419
+ ```
420
+
421
+ Use it in your routes:
422
+
423
+ ```js
424
+ // src/routes/api/posts.js
425
+ import { auth } from '../../middleware/auth.js'
426
+ import { PostController } from '../../controllers/PostController.js'
427
+
428
+ export default (router) => {
429
+ router.get('/api/posts', auth, PostController.index)
430
+ router.post('/api/posts', auth, PostController.store)
431
+ }
432
+ ```
433
+
434
+ ---
435
+
436
+ ## Testing
437
+
438
+ BasicBen uses Vitest for application tests:
439
+
440
+ ```bash
441
+ basicben test # Run once
442
+ basicben test --watch # Watch mode
443
+ basicben test --coverage # With coverage report
444
+ basicben test --ui # Open Vitest UI
445
+ ```
446
+
447
+ Create test files with `.test.js` or `.spec.js` suffix:
448
+
449
+ ```js
450
+ // src/controllers/UserController.test.js
451
+ import { describe, it, expect } from 'vitest'
452
+ import { UserController } from './UserController.js'
453
+
454
+ describe('UserController', () => {
455
+ it('returns users list', async () => {
456
+ const res = { json: vi.fn() }
457
+ await UserController.index({}, res)
458
+ expect(res.json).toHaveBeenCalled()
459
+ })
460
+ })
461
+ ```
462
+
463
+ ---
464
+
465
+ ## Environment Variables
466
+
467
+ BasicBen uses Node 20's built-in `--env-file` support. No `dotenv` required.
468
+
469
+ Create a `.env` file at your project root:
470
+
471
+ ```env
472
+ PORT=3000
473
+ DATABASE_URL=./database.sqlite
474
+ APP_KEY=your-secret-key
475
+ ```
476
+
477
+ A `.env.example` is included in every new project. Commit that, not `.env`.
478
+
479
+ ---
480
+
481
+ ## Configuration
482
+
483
+ Override defaults in `basicben.config.js` at your project root:
484
+
485
+ ```js
486
+ // basicben.config.js
487
+ export default {
488
+ // Server port (API)
489
+ port: 3001,
490
+
491
+ // CORS settings
492
+ cors: {
493
+ origin: '*',
494
+ methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
495
+ credentials: true
496
+ },
497
+
498
+ // Body parser
499
+ bodyParser: {
500
+ limit: '1mb'
501
+ },
502
+
503
+ // Static files
504
+ static: {
505
+ dir: 'public'
506
+ },
507
+
508
+ // Database
509
+ db: {
510
+ driver: 'sqlite', // or 'postgres'
511
+ url: process.env.DATABASE_URL || './data.db'
512
+ },
513
+
514
+ // Auto-load routes from src/routes (default: true)
515
+ autoloadRoutes: true,
516
+
517
+ // Auto-load middleware from src/middleware (default: true)
518
+ autoloadMiddleware: true
519
+ }
520
+ ```
521
+
522
+ ---
523
+
524
+ ## Dependencies
525
+
526
+ BasicBen has **zero runtime dependencies**:
527
+
528
+ ```json
529
+ {
530
+ "dependencies": {},
531
+ "peerDependencies": {
532
+ "react": ">=18",
533
+ "react-dom": ">=18",
534
+ "vite": ">=7",
535
+ "@vitejs/plugin-react": ">=5"
536
+ },
537
+ "optionalDependencies": {
538
+ "better-sqlite3": ">=12",
539
+ "pg": ">=8"
540
+ }
541
+ }
542
+ ```
543
+
544
+ **Everything is written from scratch:**
545
+
546
+ - HTTP server (uses node:http)
547
+ - CLI argument parser (no Commander)
548
+ - Router with groups, middleware, named routes
549
+ - Validation (no Zod/Joi)
550
+ - JWT auth (no jsonwebtoken, uses node:crypto)
551
+ - Migrations (no Knex/Sequelize)
552
+ - Environment variables (uses Node's built-in --env-file)
553
+
554
+ ---
555
+
556
+ ## Guiding Principles
557
+
558
+ 1. **Write it yourself before adding a dependency** — if it's under 200 lines, own it
559
+ 2. **Conventions over configuration** — sensible defaults, optional overrides
560
+ 3. **Error messages are features** — tell you exactly what went wrong and how to fix it
561
+ 4. **Stay boring** — resist clever abstractions until they're obviously needed
562
+
563
+ ---
564
+
565
+ ## Contributing
566
+
567
+ BasicBen is early. Contributions, issues, and ideas are welcome.
568
+
569
+ ```bash
570
+ git clone https://github.com/BasicBenFramework/basicben-framework
571
+ cd basicben-framework
572
+ npm install
573
+ npm run dev
574
+ ```
575
+
576
+ Please read `CONTRIBUTING.md` before opening a PR.
577
+
578
+ ---
579
+
580
+ ## Inspiration
581
+
582
+ BasicBen takes cues from Laravel's developer experience — migrations, controllers, models, and scaffolding commands that feel familiar to PHP developers. If you've used Laravel and wished the JS ecosystem felt that good, this is for you.
583
+
584
+ ---
585
+
586
+ ## License
587
+
588
+ MIT
package/bin/cli.js ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { parseArgs } from '../src/cli/parser.js'
4
+ import { dispatch } from '../src/cli/dispatcher.js'
5
+
6
+ const { command, args, flags } = parseArgs(process.argv.slice(2))
7
+
8
+ dispatch(command, args, flags)