@basicbenframework/core 0.1.0 → 0.1.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.
Files changed (75) hide show
  1. package/.github/workflows/publish.yml +4 -5
  2. package/LICENSE +9 -0
  3. package/README.md +5 -5
  4. package/create-basicben-app/index.js +11 -9
  5. package/create-basicben-app/package.json +4 -4
  6. package/create-basicben-app/template/README.md +2 -2
  7. package/create-basicben-app/template/gitignore +31 -0
  8. package/create-basicben-app/template/src/client/pages/GettingStarted.jsx +2 -2
  9. package/create-basicben-app/template/src/client/pages/Home.jsx +2 -2
  10. package/package.json +11 -11
  11. package/scripts/publish.sh +125 -0
  12. package/my-test-app/.env.example +0 -24
  13. package/my-test-app/README.md +0 -59
  14. package/my-test-app/basicben.config.js +0 -33
  15. package/my-test-app/database.sqlite-shm +0 -0
  16. package/my-test-app/database.sqlite-wal +0 -0
  17. package/my-test-app/index.html +0 -54
  18. package/my-test-app/migrations/001_create_users.js +0 -15
  19. package/my-test-app/migrations/002_create_posts.js +0 -18
  20. package/my-test-app/package-lock.json +0 -2160
  21. package/my-test-app/package.json +0 -29
  22. package/my-test-app/public/.gitkeep +0 -0
  23. package/my-test-app/seeds/01_users.js +0 -29
  24. package/my-test-app/seeds/02_posts.js +0 -43
  25. package/my-test-app/src/client/components/Alert.jsx +0 -11
  26. package/my-test-app/src/client/components/Avatar.jsx +0 -11
  27. package/my-test-app/src/client/components/BackLink.jsx +0 -10
  28. package/my-test-app/src/client/components/Button.jsx +0 -19
  29. package/my-test-app/src/client/components/Card.jsx +0 -10
  30. package/my-test-app/src/client/components/Empty.jsx +0 -6
  31. package/my-test-app/src/client/components/Input.jsx +0 -12
  32. package/my-test-app/src/client/components/Loading.jsx +0 -6
  33. package/my-test-app/src/client/components/Logo.jsx +0 -40
  34. package/my-test-app/src/client/components/Nav/DarkModeToggle.jsx +0 -23
  35. package/my-test-app/src/client/components/Nav/DesktopNav.jsx +0 -32
  36. package/my-test-app/src/client/components/Nav/MobileNav.jsx +0 -107
  37. package/my-test-app/src/client/components/NavLink.jsx +0 -10
  38. package/my-test-app/src/client/components/PageHeader.jsx +0 -8
  39. package/my-test-app/src/client/components/PostCard.jsx +0 -19
  40. package/my-test-app/src/client/components/Textarea.jsx +0 -12
  41. package/my-test-app/src/client/components/ThemeContext.jsx +0 -5
  42. package/my-test-app/src/client/contexts/AppContext.jsx +0 -13
  43. package/my-test-app/src/client/contexts/ToastContext.jsx +0 -94
  44. package/my-test-app/src/client/layouts/AppLayout.jsx +0 -60
  45. package/my-test-app/src/client/layouts/AuthLayout.jsx +0 -33
  46. package/my-test-app/src/client/layouts/DocsLayout.jsx +0 -60
  47. package/my-test-app/src/client/layouts/RootLayout.jsx +0 -25
  48. package/my-test-app/src/client/pages/Auth.jsx +0 -55
  49. package/my-test-app/src/client/pages/Authentication.jsx +0 -236
  50. package/my-test-app/src/client/pages/Database.jsx +0 -426
  51. package/my-test-app/src/client/pages/Feed.jsx +0 -34
  52. package/my-test-app/src/client/pages/FeedPost.jsx +0 -37
  53. package/my-test-app/src/client/pages/GettingStarted.jsx +0 -136
  54. package/my-test-app/src/client/pages/Home.jsx +0 -206
  55. package/my-test-app/src/client/pages/PostForm.jsx +0 -69
  56. package/my-test-app/src/client/pages/Posts.jsx +0 -59
  57. package/my-test-app/src/client/pages/Profile.jsx +0 -68
  58. package/my-test-app/src/client/pages/Routing.jsx +0 -207
  59. package/my-test-app/src/client/pages/Testing.jsx +0 -251
  60. package/my-test-app/src/client/pages/Validation.jsx +0 -210
  61. package/my-test-app/src/controllers/AuthController.js +0 -81
  62. package/my-test-app/src/controllers/HomeController.js +0 -17
  63. package/my-test-app/src/controllers/PostController.js +0 -86
  64. package/my-test-app/src/controllers/ProfileController.js +0 -66
  65. package/my-test-app/src/helpers/api.js +0 -24
  66. package/my-test-app/src/main.jsx +0 -9
  67. package/my-test-app/src/middleware/auth.js +0 -16
  68. package/my-test-app/src/models/Post.js +0 -63
  69. package/my-test-app/src/models/User.js +0 -42
  70. package/my-test-app/src/routes/App.jsx +0 -38
  71. package/my-test-app/src/routes/api/auth.js +0 -7
  72. package/my-test-app/src/routes/api/posts.js +0 -15
  73. package/my-test-app/src/routes/api/profile.js +0 -8
  74. package/my-test-app/src/server/index.js +0 -16
  75. package/my-test-app/vite.config.js +0 -18
@@ -1,66 +0,0 @@
1
- import { validate, rules } from '@basicbenframework/core/validation'
2
- import { User } from '../models/User.js'
3
- import { createHash } from 'node:crypto'
4
-
5
- function hashPassword(password) {
6
- return createHash('sha256').update(password).digest('hex')
7
- }
8
-
9
- export const ProfileController = {
10
- async show(req, res) {
11
- const user = await User.find(req.userId)
12
- if (!user) {
13
- return res.json({ error: 'User not found' }, 404)
14
- }
15
- res.json({
16
- user: { id: user.id, name: user.name, email: user.email, created_at: user.created_at }
17
- })
18
- },
19
-
20
- async update(req, res) {
21
- const result = await validate(req.body, {
22
- name: [rules.required, rules.string, rules.min(2)],
23
- email: [rules.required, rules.email]
24
- })
25
-
26
- if (result.fails()) {
27
- return res.json({ errors: result.errors }, 422)
28
- }
29
-
30
- const { name, email } = req.body
31
- const user = await User.find(req.userId)
32
-
33
- if (email !== user.email) {
34
- const existing = await User.findByEmail(email)
35
- if (existing) {
36
- return res.json({ error: 'Email already taken' }, 400)
37
- }
38
- }
39
-
40
- const updated = await User.update(req.userId, { name, email })
41
- res.json({
42
- user: { id: updated.id, name: updated.name, email: updated.email }
43
- })
44
- },
45
-
46
- async changePassword(req, res) {
47
- const result = await validate(req.body, {
48
- currentPassword: [rules.required],
49
- newPassword: [rules.required, rules.min(8)]
50
- })
51
-
52
- if (result.fails()) {
53
- return res.json({ errors: result.errors }, 422)
54
- }
55
-
56
- const { currentPassword, newPassword } = req.body
57
- const user = await User.find(req.userId)
58
-
59
- if (user.password !== hashPassword(currentPassword)) {
60
- return res.json({ error: 'Current password is incorrect' }, 400)
61
- }
62
-
63
- await User.update(req.userId, { password: hashPassword(newPassword) })
64
- res.json({ message: 'Password updated successfully' })
65
- }
66
- }
@@ -1,24 +0,0 @@
1
- export const api = async (path, options = {}) => {
2
- const token = localStorage.getItem('token')
3
- let res
4
- try {
5
- res = await fetch(path, {
6
- ...options,
7
- headers: {
8
- 'Content-Type': 'application/json',
9
- ...(token ? { Authorization: `Bearer ${token}` } : {}),
10
- ...options.headers
11
- }
12
- })
13
- } catch {
14
- throw new Error('Unable to connect to server')
15
- }
16
- let data
17
- try {
18
- data = await res.json()
19
- } catch {
20
- throw new Error(res.ok ? 'Invalid response from server' : `Server error (${res.status})`)
21
- }
22
- if (!res.ok) throw new Error(data.error || Object.values(data.errors || {})[0]?.[0] || 'Request failed')
23
- return data
24
- }
@@ -1,9 +0,0 @@
1
- import React from 'react'
2
- import ReactDOM from 'react-dom/client'
3
- import App from './routes/App.jsx'
4
-
5
- ReactDOM.createRoot(document.getElementById('root')).render(
6
- <React.StrictMode>
7
- <App />
8
- </React.StrictMode>
9
- )
@@ -1,16 +0,0 @@
1
- import { verifyJwt } from '@basicbenframework/core/auth'
2
-
3
- export const auth = async (req, res, next) => {
4
- const token = req.headers.authorization?.replace('Bearer ', '')
5
- if (!token) {
6
- return res.json({ error: 'Unauthorized' }, 401)
7
- }
8
-
9
- const payload = verifyJwt(token, process.env.APP_KEY)
10
- if (!payload) {
11
- return res.json({ error: 'Invalid token' }, 401)
12
- }
13
-
14
- req.userId = payload.userId
15
- next()
16
- }
@@ -1,63 +0,0 @@
1
- import { getDb } from '@basicbenframework/core/db'
2
-
3
- export const Post = {
4
- async all() {
5
- const db = await getDb()
6
- return db.all('SELECT * FROM posts ORDER BY created_at DESC')
7
- },
8
-
9
- async find(id) {
10
- const db = await getDb()
11
- return db.get('SELECT * FROM posts WHERE id = ?', [id])
12
- },
13
-
14
- async findByUser(userId) {
15
- const db = await getDb()
16
- return db.all('SELECT * FROM posts WHERE user_id = ? ORDER BY created_at DESC', [userId])
17
- },
18
-
19
- async findPublished() {
20
- const db = await getDb()
21
- return db.all(`
22
- SELECT posts.*, users.name as author_name
23
- FROM posts
24
- JOIN users ON posts.user_id = users.id
25
- WHERE posts.published = 1
26
- ORDER BY posts.created_at DESC
27
- `)
28
- },
29
-
30
- async findPublishedById(id) {
31
- const db = await getDb()
32
- return db.get(`
33
- SELECT posts.*, users.name as author_name
34
- FROM posts
35
- JOIN users ON posts.user_id = users.id
36
- WHERE posts.id = ? AND posts.published = 1
37
- `, [id])
38
- },
39
-
40
- async create(data) {
41
- const db = await getDb()
42
- const result = await db.run(
43
- 'INSERT INTO posts (user_id, title, content, published) VALUES (?, ?, ?, ?)',
44
- [data.user_id, data.title, data.content, data.published ? 1 : 0]
45
- )
46
- return { id: result.lastInsertRowid, ...data }
47
- },
48
-
49
- async update(id, data) {
50
- const db = await getDb()
51
- const fields = Object.keys(data).map(k => `${k} = ?`).join(', ')
52
- await db.run(
53
- `UPDATE posts SET ${fields}, updated_at = CURRENT_TIMESTAMP WHERE id = ?`,
54
- [...Object.values(data), id]
55
- )
56
- return this.find(id)
57
- },
58
-
59
- async delete(id) {
60
- const db = await getDb()
61
- return db.run('DELETE FROM posts WHERE id = ?', [id])
62
- }
63
- }
@@ -1,42 +0,0 @@
1
- import { getDb } from '@basicbenframework/core/db'
2
-
3
- export const User = {
4
- async all() {
5
- const db = await getDb()
6
- return db.all('SELECT * FROM users')
7
- },
8
-
9
- async find(id) {
10
- const db = await getDb()
11
- return db.get('SELECT * FROM users WHERE id = ?', [id])
12
- },
13
-
14
- async findByEmail(email) {
15
- const db = await getDb()
16
- return db.get('SELECT * FROM users WHERE email = ?', [email])
17
- },
18
-
19
- async create(data) {
20
- const db = await getDb()
21
- const result = await db.run(
22
- 'INSERT INTO users (name, email, password) VALUES (?, ?, ?)',
23
- [data.name, data.email, data.password]
24
- )
25
- return { id: result.lastInsertRowid, ...data }
26
- },
27
-
28
- async update(id, data) {
29
- const db = await getDb()
30
- const fields = Object.keys(data).map(k => `${k} = ?`).join(', ')
31
- await db.run(
32
- `UPDATE users SET ${fields} WHERE id = ?`,
33
- [...Object.values(data), id]
34
- )
35
- return this.find(id)
36
- },
37
-
38
- async delete(id) {
39
- const db = await getDb()
40
- return db.run('DELETE FROM users WHERE id = ?', [id])
41
- }
42
- }
@@ -1,38 +0,0 @@
1
- import { createClientApp } from '@basicbenframework/core/client'
2
- import { AppLayout } from '../client/layouts/AppLayout'
3
- import { AuthLayout } from '../client/layouts/AuthLayout'
4
- import { DocsLayout } from '../client/layouts/DocsLayout'
5
- import { Home } from '../client/pages/Home'
6
- import { Auth } from '../client/pages/Auth'
7
- import { Feed } from '../client/pages/Feed'
8
- import { FeedPost } from '../client/pages/FeedPost'
9
- import { Posts } from '../client/pages/Posts'
10
- import { PostForm } from '../client/pages/PostForm'
11
- import { Profile } from '../client/pages/Profile'
12
- import { GettingStarted } from '../client/pages/GettingStarted'
13
- import { Database } from '../client/pages/Database'
14
- import { Routing } from '../client/pages/Routing'
15
- import { Authentication } from '../client/pages/Authentication'
16
- import { Validation } from '../client/pages/Validation'
17
- import { Testing } from '../client/pages/Testing'
18
-
19
- export default createClientApp({
20
- layout: AppLayout,
21
- routes: {
22
- '/': Home,
23
- '/login': { component: Auth, layout: AuthLayout, guest: true },
24
- '/register': { component: Auth, layout: AuthLayout, guest: true },
25
- '/feed': Feed,
26
- '/feed/:id': FeedPost,
27
- '/posts': { component: Posts, auth: true },
28
- '/posts/new': { component: PostForm, auth: true },
29
- '/posts/:id/edit': { component: PostForm, auth: true },
30
- '/profile': { component: Profile, auth: true },
31
- '/docs': { component: GettingStarted, layout: DocsLayout },
32
- '/docs/routing': { component: Routing, layout: DocsLayout },
33
- '/docs/database': { component: Database, layout: DocsLayout },
34
- '/docs/authentication': { component: Authentication, layout: DocsLayout },
35
- '/docs/validation': { component: Validation, layout: DocsLayout },
36
- '/docs/testing': { component: Testing, layout: DocsLayout },
37
- }
38
- })
@@ -1,7 +0,0 @@
1
- import { AuthController } from '../../controllers/AuthController.js'
2
-
3
- export default (router) => {
4
- router.post('/api/auth/register', AuthController.register)
5
- router.post('/api/auth/login', AuthController.login)
6
- router.get('/api/user', AuthController.user)
7
- }
@@ -1,15 +0,0 @@
1
- import { PostController } from '../../controllers/PostController.js'
2
- import { auth } from '../../middleware/auth.js'
3
-
4
- export default (router) => {
5
- // Public feed routes
6
- router.get('/api/feed', PostController.feed)
7
- router.get('/api/feed/:id', PostController.feedShow)
8
-
9
- // Authenticated post routes
10
- router.get('/api/posts', auth, PostController.index)
11
- router.post('/api/posts', auth, PostController.store)
12
- router.get('/api/posts/:id', auth, PostController.show)
13
- router.put('/api/posts/:id', auth, PostController.update)
14
- router.delete('/api/posts/:id', auth, PostController.destroy)
15
- }
@@ -1,8 +0,0 @@
1
- import { ProfileController } from '../../controllers/ProfileController.js'
2
- import { auth } from '../../middleware/auth.js'
3
-
4
- export default (router) => {
5
- router.get('/api/profile', auth, ProfileController.show)
6
- router.put('/api/profile', auth, ProfileController.update)
7
- router.put('/api/profile/password', auth, ProfileController.changePassword)
8
- }
@@ -1,16 +0,0 @@
1
- /**
2
- * Server entry point (optional)
3
- *
4
- * Delete this file to use the default server.
5
- * Customize here for websockets, custom middleware, etc.
6
- */
7
-
8
- import { createServer } from '@basicbenframework/core/server'
9
-
10
- const app = await createServer()
11
-
12
- const port = process.env.PORT || 3001
13
-
14
- app.listen(port, () => {
15
- console.log(`Server running at http://localhost:${port}`)
16
- })
@@ -1,18 +0,0 @@
1
- import { defineConfig } from 'vite'
2
- import react from '@vitejs/plugin-react'
3
-
4
- export default defineConfig({
5
- plugins: [react()],
6
- server: {
7
- port: parseInt(process.env.VITE_PORT || 3000),
8
- proxy: {
9
- '/api': {
10
- target: `http://localhost:${process.env.PORT || 3001}`,
11
- changeOrigin: true
12
- }
13
- }
14
- },
15
- build: {
16
- outDir: 'dist/client'
17
- }
18
- })