baraqex 1.0.63 → 1.0.65
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/baraqex.js +1013 -1126
- package/dist/api/hello.d.ts +3 -0
- package/dist/api/hello.d.ts.map +1 -0
- package/dist/api/users/[id].d.ts +5 -0
- package/dist/api/users/[id].d.ts.map +1 -0
- package/dist/browser.d.ts +40 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +407 -1
- package/dist/browser.js.map +4 -4
- package/dist/browser.package.json +4 -0
- package/dist/forms/index.d.ts +2 -0
- package/dist/forms/index.d.ts.map +1 -0
- package/dist/forms/types.d.ts +2 -0
- package/dist/forms/types.d.ts.map +1 -0
- package/dist/frontend/components/WasmLoader.d.ts +2 -0
- package/dist/frontend/components/WasmLoader.d.ts.map +1 -0
- package/dist/frontend/hooks/useWasm.d.ts +2 -0
- package/dist/frontend/hooks/useWasm.d.ts.map +1 -0
- package/dist/frontend/index.d.ts +2 -0
- package/dist/frontend/index.d.ts.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +678 -317
- package/dist/index.js.map +4 -4
- package/dist/renderComponent.d.ts +9 -0
- package/dist/renderComponent.d.ts.map +1 -0
- package/dist/router/index.d.ts +2 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/router/types.d.ts +2 -0
- package/dist/router/types.d.ts.map +1 -0
- package/dist/server/api-router.d.ts +16 -0
- package/dist/server/api-router.d.ts.map +1 -0
- package/dist/server/auth.d.ts +25 -0
- package/dist/server/auth.d.ts.map +1 -0
- package/dist/server/database.d.ts +22 -0
- package/dist/server/database.d.ts.map +1 -0
- package/dist/server/index.d.ts +116 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/{server.js → server/index.js} +120 -23
- package/dist/server/index.js.map +7 -0
- package/dist/server/middleware.d.ts +11 -0
- package/dist/server/middleware.d.ts.map +1 -0
- package/dist/server/package.json +4 -0
- package/dist/server/templates.d.ts +31 -0
- package/dist/server/templates.d.ts.map +1 -0
- package/dist/server/types.d.ts +69 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/utils.d.ts +70 -0
- package/dist/server/utils.d.ts.map +1 -0
- package/dist/server/wasm.d.ts +29 -0
- package/dist/server/wasm.d.ts.map +1 -0
- package/dist/server-renderer.d.ts +5 -0
- package/dist/server-renderer.d.ts.map +1 -0
- package/dist/store/index.d.ts +2 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/types.d.ts +2 -0
- package/dist/store/types.d.ts.map +1 -0
- package/dist/wasm.d.ts +51 -0
- package/dist/wasm.d.ts.map +1 -0
- package/package.json +65 -56
- package/templates/basic-app/src/main.tsx +1 -0
- package/templates/fullstack-template/.env.example +42 -0
- package/templates/fullstack-template/README.md +38 -42
- package/templates/fullstack-template/package-lock.json +7932 -0
- package/templates/fullstack-template/package.json +58 -6
- package/templates/fullstack-template/server.js +28 -9
- package/templates/fullstack-template/src/App.tsx +94 -0
- package/templates/fullstack-template/src/api/auth/login.ts +75 -0
- package/templates/fullstack-template/src/api/auth/me.ts +66 -0
- package/templates/fullstack-template/src/api/auth/register.ts +59 -0
- package/templates/fullstack-template/src/api/todos/[id].ts +108 -0
- package/templates/fullstack-template/src/api/todos/index.ts +79 -0
- package/templates/fullstack-template/src/components/Dashboard.tsx +129 -0
- package/templates/fullstack-template/src/components/Header.tsx +76 -0
- package/templates/fullstack-template/src/contexts/ApiContext.tsx +69 -0
- package/templates/fullstack-template/src/contexts/AuthContext.tsx +155 -0
- package/templates/fullstack-template/src/server.ts +167 -0
- package/templates/fullstack-template/src/styles/App.css +446 -0
- package/templates/ssr-template/package-lock.json +38 -60
- package/templates/ssr-template/package.json +1 -1
- package/templates/ssr-template/src/App.tsx +4 -3
- package/templates/ssr-template/src/client.tsx +2 -1
- package/templates/wasm/App.tsx +564 -0
- package/templates/wasm/client.tsx +220 -0
- package/templates/wasm/index.tsx +21 -0
- package/templates/wasm/package-lock.json +5347 -5307
- package/templates/wasm/package.json +43 -25
- package/templates/wasm/public/example.wasm +0 -0
- package/templates/wasm/public/wasm_exec.js +1 -12
- package/templates/wasm/server.ts +145 -0
- package/templates/wasm/vite.config.ts +42 -24
- package/README_WASM.md +0 -472
- package/dist/server.js.map +0 -7
- package/templates/basic-app/src/App.jsx +0 -0
- package/templates/basic-app/src/App.tsx +0 -0
- package/templates/fullstack-template/src/api/hello.js +0 -17
- package/templates/fullstack-template/src/pages/index.js +0 -206
- /package/templates/{basic-app/server.js → wasm/go/wasm_exec.js} +0 -0
|
@@ -1,14 +1,66 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "fullstack-app",
|
|
3
|
-
"version": "1.0
|
|
2
|
+
"name": "fullstack-baraqex-app",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "A fullstack application built with Baraqex",
|
|
4
6
|
"type": "module",
|
|
5
7
|
"scripts": {
|
|
6
8
|
"dev": "node server.js",
|
|
7
|
-
"
|
|
8
|
-
"build": "
|
|
9
|
+
"build": "npm run build:client && npm run build:server",
|
|
10
|
+
"build:client": "esbuild src/client.tsx --bundle --outfile=dist/client.js --format=esm --target=es2020 --platform=browser --external:express --external:path --external:fs --external:http",
|
|
11
|
+
"build:server": "esbuild src/server.ts --bundle --outfile=dist/server.js --platform=node --target=node16 --format=esm --external:express --external:cors --external:jsonwebtoken --external:bcryptjs --external:mongodb --external:mysql2 --external:pg --sourcemap",
|
|
12
|
+
"start": "NODE_ENV=production node dist/server.js",
|
|
13
|
+
"test": "jest",
|
|
14
|
+
"lint": "eslint src --ext .ts,.tsx,.js,.jsx",
|
|
15
|
+
"format": "prettier --write src/**/*.{ts,tsx,js,jsx,json,css,md}",
|
|
16
|
+
"db:migrate": "node scripts/migrate.js",
|
|
17
|
+
"db:seed": "node scripts/seed.js"
|
|
9
18
|
},
|
|
10
19
|
"dependencies": {
|
|
20
|
+
"baraqex": "^1.0.60",
|
|
21
|
+
"bcryptjs": "^2.4.3",
|
|
22
|
+
"compression": "^1.7.4",
|
|
23
|
+
"cors": "^2.8.5",
|
|
24
|
+
"dotenv": "^16.3.1",
|
|
25
|
+
"express": "^4.18.2",
|
|
26
|
+
"express-rate-limit": "^6.10.0",
|
|
11
27
|
"frontend-hamroun": "latest",
|
|
12
|
-
"
|
|
13
|
-
|
|
28
|
+
"helmet": "^7.0.0",
|
|
29
|
+
"jsonwebtoken": "^9.0.2",
|
|
30
|
+
"morgan": "^1.10.0",
|
|
31
|
+
"multer": "latest"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/bcryptjs": "^2.4.2",
|
|
35
|
+
"@types/compression": "^1.7.2",
|
|
36
|
+
"@types/cors": "^2.8.13",
|
|
37
|
+
"@types/express": "^4.17.17",
|
|
38
|
+
"@types/jest": "^29.5.4",
|
|
39
|
+
"@types/jsonwebtoken": "^9.0.2",
|
|
40
|
+
"@types/morgan": "^1.9.4",
|
|
41
|
+
"@types/multer": "^1.4.7",
|
|
42
|
+
"@types/node": "^20.5.0",
|
|
43
|
+
"esbuild": "^0.19.0",
|
|
44
|
+
"eslint": "^8.47.0",
|
|
45
|
+
"jest": "^29.6.0",
|
|
46
|
+
"nodemon": "^3.0.1",
|
|
47
|
+
"prettier": "^3.0.0",
|
|
48
|
+
"typescript": "^5.0.0"
|
|
49
|
+
},
|
|
50
|
+
"optionalDependencies": {
|
|
51
|
+
"mongodb": "^5.7.0",
|
|
52
|
+
"mysql2": "^3.6.0",
|
|
53
|
+
"pg": "^8.11.3"
|
|
54
|
+
},
|
|
55
|
+
"keywords": [
|
|
56
|
+
"baraqex",
|
|
57
|
+
"fullstack",
|
|
58
|
+
"react",
|
|
59
|
+
"typescript",
|
|
60
|
+
"express",
|
|
61
|
+
"api",
|
|
62
|
+
"authentication"
|
|
63
|
+
],
|
|
64
|
+
"author": "",
|
|
65
|
+
"license": "MIT"
|
|
14
66
|
}
|
|
@@ -1,16 +1,35 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createServer } from 'baraqex';
|
|
2
|
+
import dotenv from 'dotenv';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
// Load environment variables
|
|
5
|
+
dotenv.config();
|
|
6
|
+
|
|
7
|
+
// Create development server
|
|
8
|
+
const server = createServer({
|
|
9
|
+
port: parseInt(process.env.PORT || '3000'),
|
|
10
|
+
apiDir: './src/api',
|
|
11
|
+
pagesDir: './src/pages',
|
|
12
|
+
staticDir: './public',
|
|
13
|
+
enableCors: true,
|
|
14
|
+
auth: {
|
|
15
|
+
secret: process.env.JWT_SECRET || 'dev-secret-key',
|
|
16
|
+
expiresIn: '7d'
|
|
17
|
+
}
|
|
6
18
|
});
|
|
7
19
|
|
|
8
|
-
// Enable SSR
|
|
20
|
+
// Enable SSR
|
|
9
21
|
server.enableSSR({ hydratable: true });
|
|
10
22
|
|
|
11
|
-
// Start
|
|
23
|
+
// Start server
|
|
24
|
+
console.log('🚀 Starting Fullstack Baraqex Development Server...');
|
|
25
|
+
|
|
12
26
|
server.start().then(() => {
|
|
13
|
-
console.log('
|
|
14
|
-
console.log('
|
|
15
|
-
console.log('API
|
|
27
|
+
console.log('✅ Server running successfully!');
|
|
28
|
+
console.log('🌐 Frontend: http://localhost:3000');
|
|
29
|
+
console.log('🔗 API: http://localhost:3000/api');
|
|
30
|
+
console.log('📋 API Docs: http://localhost:3000/api-docs');
|
|
31
|
+
console.log('💚 Health: http://localhost:3000/health');
|
|
32
|
+
}).catch(error => {
|
|
33
|
+
console.error('❌ Failed to start server:', error);
|
|
34
|
+
process.exit(1);
|
|
16
35
|
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { jsx, useState, useEffect } from 'frontend-hamroun';
|
|
2
|
+
import { AuthProvider, useAuth } from './contexts/AuthContext';
|
|
3
|
+
import { ApiProvider } from './contexts/ApiContext';
|
|
4
|
+
import { Header } from './components/Header';
|
|
5
|
+
import { Dashboard } from './components/Dashboard';
|
|
6
|
+
import { LoginForm } from './components/LoginForm';
|
|
7
|
+
import { TodoList } from './components/TodoList';
|
|
8
|
+
import { UserProfile } from './components/UserProfile';
|
|
9
|
+
import { LoadingSpinner } from './components/LoadingSpinner';
|
|
10
|
+
import './styles/App.css';
|
|
11
|
+
|
|
12
|
+
type View = 'dashboard' | 'todos' | 'profile' | 'login';
|
|
13
|
+
|
|
14
|
+
function AppContent() {
|
|
15
|
+
const { user, loading: authLoading } = useAuth();
|
|
16
|
+
const [currentView, setCurrentView] = useState<View>('dashboard');
|
|
17
|
+
const [loading, setLoading] = useState(true);
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
// Simulate app initialization
|
|
21
|
+
const timer = setTimeout(() => {
|
|
22
|
+
setLoading(false);
|
|
23
|
+
}, 1000);
|
|
24
|
+
|
|
25
|
+
return () => clearTimeout(timer);
|
|
26
|
+
}, []);
|
|
27
|
+
|
|
28
|
+
if (loading || authLoading) {
|
|
29
|
+
return <LoadingSpinner message="Loading application..." />;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!user) {
|
|
33
|
+
return (
|
|
34
|
+
<div className="app">
|
|
35
|
+
<Header
|
|
36
|
+
user={null}
|
|
37
|
+
onNavigate={setCurrentView}
|
|
38
|
+
currentView={currentView}
|
|
39
|
+
/>
|
|
40
|
+
<main className="main-content">
|
|
41
|
+
<LoginForm />
|
|
42
|
+
</main>
|
|
43
|
+
</div>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const renderView = () => {
|
|
48
|
+
switch (currentView) {
|
|
49
|
+
case 'dashboard':
|
|
50
|
+
return <Dashboard />;
|
|
51
|
+
case 'todos':
|
|
52
|
+
return <TodoList />;
|
|
53
|
+
case 'profile':
|
|
54
|
+
return <UserProfile />;
|
|
55
|
+
default:
|
|
56
|
+
return <Dashboard />;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<div className="app">
|
|
62
|
+
<Header
|
|
63
|
+
user={user}
|
|
64
|
+
onNavigate={setCurrentView}
|
|
65
|
+
currentView={currentView}
|
|
66
|
+
/>
|
|
67
|
+
<main className="main-content">
|
|
68
|
+
{renderView()}
|
|
69
|
+
</main>
|
|
70
|
+
<footer className="app-footer">
|
|
71
|
+
<p>© 2024 Fullstack Baraqex App. Built with ❤️ using Baraqex Framework.</p>
|
|
72
|
+
</footer>
|
|
73
|
+
</div>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export default function App() {
|
|
78
|
+
return (
|
|
79
|
+
<AuthProvider>
|
|
80
|
+
<ApiProvider>
|
|
81
|
+
<AppContent />
|
|
82
|
+
</ApiProvider>
|
|
83
|
+
</AuthProvider>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// SSR support
|
|
88
|
+
App.getTitle = () => "Fullstack Baraqex App";
|
|
89
|
+
App.getDescription = () => "A complete fullstack application with authentication, API integration, and modern UI";
|
|
90
|
+
App.getMeta = () => ({
|
|
91
|
+
'og:title': 'Fullstack Baraqex App',
|
|
92
|
+
'og:description': 'Complete fullstack solution with Baraqex',
|
|
93
|
+
'og:type': 'website'
|
|
94
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { AuthService, sendSuccess, sendError, validateFields } from 'baraqex';
|
|
2
|
+
|
|
3
|
+
// Login endpoint
|
|
4
|
+
export async function post(req: any, res: any) {
|
|
5
|
+
try {
|
|
6
|
+
// Validate required fields
|
|
7
|
+
const validation = validateFields(req, ['username', 'password']);
|
|
8
|
+
if (!validation.valid) {
|
|
9
|
+
return sendError(res, 'Missing required fields', 400, { missing: validation.missing });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const { username, password } = req.body;
|
|
13
|
+
|
|
14
|
+
// Get auth service from server
|
|
15
|
+
const authService = req.app.locals.authService as AuthService;
|
|
16
|
+
if (!authService) {
|
|
17
|
+
return sendError(res, 'Authentication service not available', 500);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// In a real app, you'd fetch user from database
|
|
21
|
+
// This is a demo implementation
|
|
22
|
+
const demoUsers = [
|
|
23
|
+
{
|
|
24
|
+
id: 1,
|
|
25
|
+
username: 'admin',
|
|
26
|
+
password: '$2a$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
|
|
27
|
+
email: 'admin@example.com',
|
|
28
|
+
roles: ['admin', 'user'],
|
|
29
|
+
name: 'Administrator'
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: 2,
|
|
33
|
+
username: 'user',
|
|
34
|
+
password: '$2a$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
|
|
35
|
+
email: 'user@example.com',
|
|
36
|
+
roles: ['user'],
|
|
37
|
+
name: 'Regular User'
|
|
38
|
+
}
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
// Find user
|
|
42
|
+
const user = demoUsers.find(u => u.username === username);
|
|
43
|
+
if (!user) {
|
|
44
|
+
return sendError(res, 'Invalid credentials', 401);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Verify password
|
|
48
|
+
const isValid = await authService.comparePasswords(password, user.password);
|
|
49
|
+
if (!isValid) {
|
|
50
|
+
return sendError(res, 'Invalid credentials', 401);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Generate token
|
|
54
|
+
const userForToken = {
|
|
55
|
+
id: user.id,
|
|
56
|
+
username: user.username,
|
|
57
|
+
email: user.email,
|
|
58
|
+
roles: user.roles,
|
|
59
|
+
name: user.name
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const token = authService.generateToken(userForToken);
|
|
63
|
+
|
|
64
|
+
// Send response
|
|
65
|
+
return sendSuccess(res, {
|
|
66
|
+
token,
|
|
67
|
+
user: userForToken,
|
|
68
|
+
expiresIn: '7d'
|
|
69
|
+
}, 'Login successful');
|
|
70
|
+
|
|
71
|
+
} catch (error: any) {
|
|
72
|
+
console.error('Login error:', error);
|
|
73
|
+
return sendError(res, 'Login failed', 500);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { sendSuccess, sendError } from 'baraqex';
|
|
2
|
+
|
|
3
|
+
// Middleware to require authentication
|
|
4
|
+
export const middleware = [
|
|
5
|
+
(req: any, res: any, next: any) => {
|
|
6
|
+
if (!req.user) {
|
|
7
|
+
return sendError(res, 'Authentication required', 401);
|
|
8
|
+
}
|
|
9
|
+
next();
|
|
10
|
+
}
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
// Get current user endpoint
|
|
14
|
+
export async function get(req: any, res: any) {
|
|
15
|
+
try {
|
|
16
|
+
const user = req.user;
|
|
17
|
+
|
|
18
|
+
// In a real app, you might fetch fresh user data from database
|
|
19
|
+
// For demo, we'll just return the user from token
|
|
20
|
+
|
|
21
|
+
return sendSuccess(res, {
|
|
22
|
+
user: {
|
|
23
|
+
id: user.id,
|
|
24
|
+
username: user.username,
|
|
25
|
+
email: user.email || `${user.username}@example.com`,
|
|
26
|
+
name: user.name || user.username,
|
|
27
|
+
roles: user.roles || ['user'],
|
|
28
|
+
lastLogin: new Date().toISOString()
|
|
29
|
+
}
|
|
30
|
+
}, 'User profile retrieved');
|
|
31
|
+
|
|
32
|
+
} catch (error: any) {
|
|
33
|
+
console.error('Get user error:', error);
|
|
34
|
+
return sendError(res, 'Failed to get user profile', 500);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Update user profile
|
|
39
|
+
export async function put(req: any, res: any) {
|
|
40
|
+
try {
|
|
41
|
+
const user = req.user;
|
|
42
|
+
const { name, email } = req.body;
|
|
43
|
+
|
|
44
|
+
// Basic validation
|
|
45
|
+
if (email && !email.includes('@')) {
|
|
46
|
+
return sendError(res, 'Invalid email format', 400);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// In a real app, you'd update the database
|
|
50
|
+
// For demo, we'll just return updated user data
|
|
51
|
+
const updatedUser = {
|
|
52
|
+
...user,
|
|
53
|
+
name: name || user.name,
|
|
54
|
+
email: email || user.email,
|
|
55
|
+
updatedAt: new Date().toISOString()
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return sendSuccess(res, {
|
|
59
|
+
user: updatedUser
|
|
60
|
+
}, 'Profile updated successfully');
|
|
61
|
+
|
|
62
|
+
} catch (error: any) {
|
|
63
|
+
console.error('Update user error:', error);
|
|
64
|
+
return sendError(res, 'Failed to update profile', 500);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { AuthService, sendSuccess, sendError, validateFields } from 'baraqex';
|
|
2
|
+
|
|
3
|
+
// Registration endpoint
|
|
4
|
+
export async function post(req: any, res: any) {
|
|
5
|
+
try {
|
|
6
|
+
// Validate required fields
|
|
7
|
+
const validation = validateFields(req, ['username', 'password', 'email', 'name']);
|
|
8
|
+
if (!validation.valid) {
|
|
9
|
+
return sendError(res, 'Missing required fields', 400, { missing: validation.missing });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const { username, password, email, name } = req.body;
|
|
13
|
+
|
|
14
|
+
// Basic validation
|
|
15
|
+
if (password.length < 6) {
|
|
16
|
+
return sendError(res, 'Password must be at least 6 characters long', 400);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (!email.includes('@')) {
|
|
20
|
+
return sendError(res, 'Invalid email format', 400);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Get auth service
|
|
24
|
+
const authService = req.app.locals.authService as AuthService;
|
|
25
|
+
if (!authService) {
|
|
26
|
+
return sendError(res, 'Authentication service not available', 500);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// In a real app, you'd check if user exists in database
|
|
30
|
+
// For demo purposes, we'll just simulate registration
|
|
31
|
+
|
|
32
|
+
// Hash password
|
|
33
|
+
const hashedPassword = await authService.hashPassword(password);
|
|
34
|
+
|
|
35
|
+
// Create user object (in real app, save to database)
|
|
36
|
+
const newUser = {
|
|
37
|
+
id: Date.now(), // In real app, this would be from database
|
|
38
|
+
username,
|
|
39
|
+
email,
|
|
40
|
+
name,
|
|
41
|
+
roles: ['user'],
|
|
42
|
+
createdAt: new Date().toISOString()
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Generate token
|
|
46
|
+
const token = authService.generateToken(newUser);
|
|
47
|
+
|
|
48
|
+
// Send response
|
|
49
|
+
return sendSuccess(res, {
|
|
50
|
+
token,
|
|
51
|
+
user: newUser,
|
|
52
|
+
expiresIn: '7d'
|
|
53
|
+
}, 'Registration successful');
|
|
54
|
+
|
|
55
|
+
} catch (error: any) {
|
|
56
|
+
console.error('Registration error:', error);
|
|
57
|
+
return sendError(res, 'Registration failed', 500);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { sendSuccess, sendError } from 'baraqex';
|
|
2
|
+
|
|
3
|
+
// Import the todos array from the index file
|
|
4
|
+
// In a real app, this would be in a database
|
|
5
|
+
let todos = [
|
|
6
|
+
{ id: 1, text: 'Learn Baraqex Framework', completed: false, userId: 1, createdAt: new Date().toISOString() },
|
|
7
|
+
{ id: 2, text: 'Build awesome fullstack app', completed: false, userId: 1, createdAt: new Date().toISOString() },
|
|
8
|
+
{ id: 3, text: 'Deploy to production', completed: false, userId: 1, createdAt: new Date().toISOString() }
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
// Require authentication
|
|
12
|
+
export const middleware = [
|
|
13
|
+
(req: any, res: any, next: any) => {
|
|
14
|
+
if (!req.user) {
|
|
15
|
+
return sendError(res, 'Authentication required', 401);
|
|
16
|
+
}
|
|
17
|
+
next();
|
|
18
|
+
}
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
// Get specific todo
|
|
22
|
+
export async function get(req: any, res: any) {
|
|
23
|
+
try {
|
|
24
|
+
const todoId = parseInt(req.params.id);
|
|
25
|
+
const userId = req.user.id;
|
|
26
|
+
|
|
27
|
+
if (isNaN(todoId)) {
|
|
28
|
+
return sendError(res, 'Invalid todo ID', 400);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const todo = todos.find(t => t.id === todoId && t.userId === userId);
|
|
32
|
+
if (!todo) {
|
|
33
|
+
return sendError(res, 'Todo not found', 404);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return sendSuccess(res, { todo }, 'Todo retrieved successfully');
|
|
37
|
+
|
|
38
|
+
} catch (error: any) {
|
|
39
|
+
console.error('Get todo error:', error);
|
|
40
|
+
return sendError(res, 'Failed to get todo', 500);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Update todo
|
|
45
|
+
export async function put(req: any, res: any) {
|
|
46
|
+
try {
|
|
47
|
+
const todoId = parseInt(req.params.id);
|
|
48
|
+
const userId = req.user.id;
|
|
49
|
+
const { text, completed } = req.body;
|
|
50
|
+
|
|
51
|
+
if (isNaN(todoId)) {
|
|
52
|
+
return sendError(res, 'Invalid todo ID', 400);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const todoIndex = todos.findIndex(t => t.id === todoId && t.userId === userId);
|
|
56
|
+
if (todoIndex === -1) {
|
|
57
|
+
return sendError(res, 'Todo not found', 404);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Update todo
|
|
61
|
+
if (text !== undefined) {
|
|
62
|
+
if (text.trim().length === 0) {
|
|
63
|
+
return sendError(res, 'Todo text cannot be empty', 400);
|
|
64
|
+
}
|
|
65
|
+
todos[todoIndex].text = text.trim();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (completed !== undefined) {
|
|
69
|
+
todos[todoIndex].completed = Boolean(completed);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
todos[todoIndex].updatedAt = new Date().toISOString();
|
|
73
|
+
|
|
74
|
+
return sendSuccess(res, { todo: todos[todoIndex] }, 'Todo updated successfully');
|
|
75
|
+
|
|
76
|
+
} catch (error: any) {
|
|
77
|
+
console.error('Update todo error:', error);
|
|
78
|
+
return sendError(res, 'Failed to update todo', 500);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Delete todo
|
|
83
|
+
export async function del(req: any, res: any) {
|
|
84
|
+
try {
|
|
85
|
+
const todoId = parseInt(req.params.id);
|
|
86
|
+
const userId = req.user.id;
|
|
87
|
+
|
|
88
|
+
if (isNaN(todoId)) {
|
|
89
|
+
return sendError(res, 'Invalid todo ID', 400);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const todoIndex = todos.findIndex(t => t.id === todoId && t.userId === userId);
|
|
93
|
+
if (todoIndex === -1) {
|
|
94
|
+
return sendError(res, 'Todo not found', 404);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const deletedTodo = todos.splice(todoIndex, 1)[0];
|
|
98
|
+
|
|
99
|
+
return sendSuccess(res, { todo: deletedTodo }, 'Todo deleted successfully');
|
|
100
|
+
|
|
101
|
+
} catch (error: any) {
|
|
102
|
+
console.error('Delete todo error:', error);
|
|
103
|
+
return sendError(res, 'Failed to delete todo', 500);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Export delete function with correct name
|
|
108
|
+
export { del as delete };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { sendSuccess, sendError, validateFields, getPagination } from 'baraqex';
|
|
2
|
+
|
|
3
|
+
// In-memory storage for demo (use database in real app)
|
|
4
|
+
let todos = [
|
|
5
|
+
{ id: 1, text: 'Learn Baraqex Framework', completed: false, userId: 1, createdAt: new Date().toISOString() },
|
|
6
|
+
{ id: 2, text: 'Build awesome fullstack app', completed: false, userId: 1, createdAt: new Date().toISOString() },
|
|
7
|
+
{ id: 3, text: 'Deploy to production', completed: false, userId: 1, createdAt: new Date().toISOString() }
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
// Require authentication for all todo endpoints
|
|
11
|
+
export const middleware = [
|
|
12
|
+
(req: any, res: any, next: any) => {
|
|
13
|
+
if (!req.user) {
|
|
14
|
+
return sendError(res, 'Authentication required', 401);
|
|
15
|
+
}
|
|
16
|
+
next();
|
|
17
|
+
}
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
// Get todos for current user
|
|
21
|
+
export async function get(req: any, res: any) {
|
|
22
|
+
try {
|
|
23
|
+
const userId = req.user.id;
|
|
24
|
+
const { page, limit, skip } = getPagination(req);
|
|
25
|
+
|
|
26
|
+
// Filter todos for current user
|
|
27
|
+
const userTodos = todos.filter(todo => todo.userId === userId);
|
|
28
|
+
|
|
29
|
+
// Apply pagination
|
|
30
|
+
const paginatedTodos = userTodos.slice(skip, skip + limit);
|
|
31
|
+
|
|
32
|
+
return sendSuccess(res, {
|
|
33
|
+
todos: paginatedTodos,
|
|
34
|
+
pagination: {
|
|
35
|
+
page,
|
|
36
|
+
limit,
|
|
37
|
+
total: userTodos.length,
|
|
38
|
+
pages: Math.ceil(userTodos.length / limit)
|
|
39
|
+
}
|
|
40
|
+
}, 'Todos retrieved successfully');
|
|
41
|
+
|
|
42
|
+
} catch (error: any) {
|
|
43
|
+
console.error('Get todos error:', error);
|
|
44
|
+
return sendError(res, 'Failed to get todos', 500);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Create new todo
|
|
49
|
+
export async function post(req: any, res: any) {
|
|
50
|
+
try {
|
|
51
|
+
const validation = validateFields(req, ['text']);
|
|
52
|
+
if (!validation.valid) {
|
|
53
|
+
return sendError(res, 'Missing required fields', 400, { missing: validation.missing });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const { text } = req.body;
|
|
57
|
+
const userId = req.user.id;
|
|
58
|
+
|
|
59
|
+
if (text.trim().length === 0) {
|
|
60
|
+
return sendError(res, 'Todo text cannot be empty', 400);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const newTodo = {
|
|
64
|
+
id: Date.now(),
|
|
65
|
+
text: text.trim(),
|
|
66
|
+
completed: false,
|
|
67
|
+
userId,
|
|
68
|
+
createdAt: new Date().toISOString()
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
todos.push(newTodo);
|
|
72
|
+
|
|
73
|
+
return sendSuccess(res, { todo: newTodo }, 'Todo created successfully');
|
|
74
|
+
|
|
75
|
+
} catch (error: any) {
|
|
76
|
+
console.error('Create todo error:', error);
|
|
77
|
+
return sendError(res, 'Failed to create todo', 500);
|
|
78
|
+
}
|
|
79
|
+
}
|