baraqex 1.0.76 → 2.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.
- package/CHANGELOG.md +73 -0
- package/README.md +268 -315
- package/bin/baraqex.js +150 -12
- package/dist/browser.d.ts +1 -1
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +2319 -205
- package/dist/browser.js.map +4 -4
- package/dist/core/batch.d.ts +10 -0
- package/dist/core/batch.d.ts.map +1 -0
- package/dist/core/component.d.ts +69 -0
- package/dist/core/component.d.ts.map +1 -0
- package/dist/core/context.d.ts +22 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/errors.d.ts +125 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/event-bus.d.ts +29 -0
- package/dist/core/event-bus.d.ts.map +1 -0
- package/dist/core/forms.d.ts +128 -0
- package/dist/core/forms.d.ts.map +1 -0
- package/dist/core/hooks.d.ts +84 -0
- package/dist/core/hooks.d.ts.map +1 -0
- package/dist/core/index.d.ts +23 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/jsx-runtime.d.ts +45 -0
- package/dist/core/jsx-runtime.d.ts.map +1 -0
- package/dist/core/lifecycle-events.d.ts +71 -0
- package/dist/core/lifecycle-events.d.ts.map +1 -0
- package/dist/core/renderer.d.ts +39 -0
- package/dist/core/renderer.d.ts.map +1 -0
- package/dist/core/router.d.ts +108 -0
- package/dist/core/router.d.ts.map +1 -0
- package/dist/core/server-renderer.d.ts +26 -0
- package/dist/core/server-renderer.d.ts.map +1 -0
- package/dist/core/store.d.ts +102 -0
- package/dist/core/store.d.ts.map +1 -0
- package/dist/core/types.d.ts +66 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/utils.d.ts +153 -0
- package/dist/core/utils.d.ts.map +1 -0
- package/dist/core/vdom.d.ts +29 -0
- package/dist/core/vdom.d.ts.map +1 -0
- package/dist/index.d.ts +39 -35
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2592 -508
- package/dist/index.js.map +4 -4
- package/dist/server/auth.d.ts +8 -3
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +173 -112
- package/dist/server/index.js.map +4 -4
- package/dist/server/middleware.d.ts +10 -1
- package/dist/server/middleware.d.ts.map +1 -1
- package/package.json +224 -124
- package/templates/basic-app/src/main.jsx +336 -0
- package/templates/complete-app/api/hello.js +0 -0
- package/templates/complete-app/client.js +58 -0
- package/templates/complete-app/lib/frontend-hamroun.js +182 -0
- package/templates/complete-app/package.json +18 -0
- package/templates/complete-app/pages/about.js +119 -0
- package/templates/complete-app/pages/about.jsx +0 -0
- package/templates/complete-app/pages/index.js +157 -0
- package/templates/complete-app/pages/index.jsx +0 -0
- package/templates/complete-app/pages/wasm-demo.js +290 -0
- package/templates/complete-app/pages/wasm-demo.jsx +0 -0
- package/templates/complete-app/public/client.js +89 -0
- package/templates/complete-app/public/index.html +118 -0
- package/templates/complete-app/public/styles.css +76 -0
- package/templates/complete-app/readme.md +188 -0
- package/templates/complete-app/server.js +226 -0
- package/templates/complete-app/server.ts +275 -0
- package/templates/complete-app/src/App.tsx +59 -0
- package/templates/complete-app/src/client.ts +61 -0
- package/templates/complete-app/src/client.tsx +18 -0
- package/templates/complete-app/src/pages/index.tsx +51 -0
- package/templates/complete-app/src/server.ts +218 -0
- package/templates/complete-app/tsconfig.json +22 -0
- package/templates/complete-app/tsconfig.server.json +19 -0
- package/templates/complete-app/vite.config.js +57 -0
- package/templates/complete-app/vite.config.ts +30 -0
- package/templates/complete-app/wasm/build.bat +0 -0
- package/templates/complete-app/wasm/build.sh +0 -0
- package/templates/complete-app/wasm/example.go +0 -0
- package/templates/fullstack-app/README.md +37 -0
- package/templates/fullstack-app/api/hello.js +11 -0
- package/templates/fullstack-app/api/hello.ts +18 -0
- package/templates/fullstack-app/api/users/[id].ts +73 -0
- package/templates/fullstack-app/api/users/index.ts +32 -0
- package/templates/fullstack-app/build/main.css +874 -0
- package/templates/fullstack-app/build/main.css.map +7 -0
- package/templates/fullstack-app/build/main.js +967 -0
- package/templates/fullstack-app/build/main.js.map +7 -0
- package/templates/fullstack-app/build.ts +210 -0
- package/templates/fullstack-app/index.html +36 -0
- package/templates/fullstack-app/package.json +35 -0
- package/templates/fullstack-app/postcss.config.js +6 -0
- package/templates/fullstack-app/process-tailwind.js +45 -0
- package/templates/fullstack-app/public/_redirects +1 -0
- package/templates/fullstack-app/public/route-handler.js +47 -0
- package/templates/fullstack-app/public/spa-fix.html +17 -0
- package/templates/fullstack-app/public/styles.css +975 -0
- package/templates/fullstack-app/public/tailwind.css +15 -0
- package/templates/fullstack-app/server.js +267 -0
- package/templates/fullstack-app/server.ts +474 -0
- package/templates/fullstack-app/src/README.md +55 -0
- package/templates/fullstack-app/src/client.js +87 -0
- package/templates/fullstack-app/src/components/ClientHome.tsx +0 -0
- package/templates/fullstack-app/src/components/ErrorBoundary.tsx +36 -0
- package/templates/fullstack-app/src/components/Layout.tsx +42 -0
- package/templates/fullstack-app/src/components/StateDemo.tsx +207 -0
- package/templates/fullstack-app/src/components/UserList.tsx +44 -0
- package/templates/fullstack-app/src/config.ts +42 -0
- package/templates/fullstack-app/src/data/api.ts +206 -0
- package/templates/fullstack-app/src/main.tsx +155 -0
- package/templates/fullstack-app/src/middleware.ts +28 -0
- package/templates/fullstack-app/src/pages/404.tsx +28 -0
- package/templates/fullstack-app/src/pages/[id].tsx +0 -0
- package/templates/fullstack-app/src/pages/_app.tsx +11 -0
- package/templates/fullstack-app/src/pages/_document.tsx +25 -0
- package/templates/fullstack-app/src/pages/_error.tsx +45 -0
- package/templates/fullstack-app/src/pages/about/index.tsx +67 -0
- package/templates/fullstack-app/src/pages/about.tsx +71 -0
- package/templates/fullstack-app/src/pages/api/users/[id].ts +73 -0
- package/templates/fullstack-app/src/pages/api/users/index.ts +43 -0
- package/templates/fullstack-app/src/pages/index.tsx +110 -0
- package/templates/fullstack-app/src/pages/users/[id].tsx +153 -0
- package/templates/fullstack-app/src/pages/users.tsx +60 -0
- package/templates/fullstack-app/src/pages/wasm-demo.tsx +1 -0
- package/templates/fullstack-app/src/router.ts +255 -0
- package/templates/fullstack-app/src/styles.css +5 -0
- package/templates/fullstack-app/tailwind.config.js +11 -0
- package/templates/fullstack-app/tsconfig.json +18 -0
- package/templates/fullstack-app/vite.config.js +87 -0
- package/templates/go/build.bat +36 -0
- package/templates/go/build.sh +43 -0
- package/templates/go/example.go +205 -0
- package/templates/go-wasm-app/README.md +38 -0
- package/templates/go-wasm-app/babel.config.js +21 -0
- package/templates/go-wasm-app/build-client.js +49 -0
- package/templates/go-wasm-app/build-wasm.js +237 -0
- package/templates/go-wasm-app/build.config.js +62 -0
- package/templates/go-wasm-app/build.js +218 -0
- package/templates/go-wasm-app/package.json +32 -0
- package/templates/go-wasm-app/public/index.html +128 -0
- package/templates/go-wasm-app/public/styles.css +197 -0
- package/templates/go-wasm-app/public/wasm/example.wasm +0 -0
- package/templates/go-wasm-app/public/wasm/wasm_exec.js +561 -0
- package/templates/go-wasm-app/public/wasm/wasm_exec_node.js +39 -0
- package/templates/go-wasm-app/server.js +70 -0
- package/templates/go-wasm-app/src/App.jsx +38 -0
- package/templates/go-wasm-app/src/app.js +173 -0
- package/templates/go-wasm-app/src/client.js +57 -0
- package/templates/go-wasm-app/src/components/Footer.jsx +13 -0
- package/templates/go-wasm-app/src/components/Header.jsx +19 -0
- package/templates/go-wasm-app/src/components/WasmDemo.jsx +120 -0
- package/templates/go-wasm-app/src/main.jsx +12 -0
- package/templates/go-wasm-app/src/wasm/example.go +75 -0
- package/templates/go-wasm-app/tsconfig.server.json +18 -0
- package/templates/go-wasm-app/vite.config.js +45 -0
- package/dist/forms/index.d.ts +0 -2
- package/dist/forms/index.d.ts.map +0 -1
- package/dist/forms/types.d.ts +0 -2
- package/dist/forms/types.d.ts.map +0 -1
- package/dist/frontend/components/WasmLoader.d.ts +0 -2
- package/dist/frontend/components/WasmLoader.d.ts.map +0 -1
- package/dist/frontend/hooks/useWasm.d.ts +0 -2
- package/dist/frontend/hooks/useWasm.d.ts.map +0 -1
- package/dist/frontend/index.d.ts +0 -2
- package/dist/frontend/index.d.ts.map +0 -1
- package/dist/router/index.d.ts +0 -2
- package/dist/router/index.d.ts.map +0 -1
- package/dist/router/types.d.ts +0 -2
- package/dist/router/types.d.ts.map +0 -1
- package/dist/store/index.d.ts +0 -2
- package/dist/store/index.d.ts.map +0 -1
- package/dist/store/types.d.ts +0 -2
- package/dist/store/types.d.ts.map +0 -1
- package/templates/basic-app/package-lock.json +0 -7173
- package/templates/fullstack-template/package-lock.json +0 -3558
- package/templates/ssr-template/package-lock.json +0 -5380
- package/templates/wasm/package-lock.json +0 -5347
- package/templates/wasm/public/example.wasm +0 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Static Fallback - Frontend Hamroun</title>
|
|
7
|
+
<link href="/styles.css" rel="stylesheet" type="text/css">
|
|
8
|
+
<style>
|
|
9
|
+
body {
|
|
10
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
11
|
+
background-color: #f8f9fa;
|
|
12
|
+
color: #212529;
|
|
13
|
+
line-height: 1.5;
|
|
14
|
+
margin: 0;
|
|
15
|
+
padding: 0;
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
min-height: 100vh;
|
|
19
|
+
}
|
|
20
|
+
.container {
|
|
21
|
+
max-width: 800px;
|
|
22
|
+
margin: 0 auto;
|
|
23
|
+
padding: 2rem;
|
|
24
|
+
flex: 1;
|
|
25
|
+
display: flex;
|
|
26
|
+
flex-direction: column;
|
|
27
|
+
justify-content: center;
|
|
28
|
+
}
|
|
29
|
+
.alert {
|
|
30
|
+
background-color: #f8d7da;
|
|
31
|
+
color: #721c24;
|
|
32
|
+
border: 1px solid #f5c6cb;
|
|
33
|
+
border-radius: 4px;
|
|
34
|
+
padding: 1.5rem;
|
|
35
|
+
margin-bottom: 2rem;
|
|
36
|
+
}
|
|
37
|
+
.warning {
|
|
38
|
+
background-color: #fff3cd;
|
|
39
|
+
color: #856404;
|
|
40
|
+
border: 1px solid #ffeeba;
|
|
41
|
+
border-radius: 4px;
|
|
42
|
+
padding: 1.5rem;
|
|
43
|
+
margin-bottom: 2rem;
|
|
44
|
+
}
|
|
45
|
+
.steps {
|
|
46
|
+
background-color: #e9ecef;
|
|
47
|
+
border-radius: 4px;
|
|
48
|
+
padding: 1.5rem;
|
|
49
|
+
}
|
|
50
|
+
h1 {
|
|
51
|
+
margin-top: 0;
|
|
52
|
+
color: #0066cc;
|
|
53
|
+
}
|
|
54
|
+
footer {
|
|
55
|
+
text-align: center;
|
|
56
|
+
padding: 1rem;
|
|
57
|
+
background-color: #f1f1f1;
|
|
58
|
+
font-size: 0.875rem;
|
|
59
|
+
color: #6c757d;
|
|
60
|
+
}
|
|
61
|
+
code {
|
|
62
|
+
background-color: #f1f1f1;
|
|
63
|
+
padding: 0.2rem 0.4rem;
|
|
64
|
+
border-radius: 3px;
|
|
65
|
+
}
|
|
66
|
+
.logo {
|
|
67
|
+
font-size: 2rem;
|
|
68
|
+
margin-bottom: 2rem;
|
|
69
|
+
color: #0066cc;
|
|
70
|
+
font-weight: bold;
|
|
71
|
+
text-align: center;
|
|
72
|
+
}
|
|
73
|
+
ul {
|
|
74
|
+
margin-bottom: 0;
|
|
75
|
+
}
|
|
76
|
+
li {
|
|
77
|
+
margin-bottom: 0.5rem;
|
|
78
|
+
}
|
|
79
|
+
li:last-child {
|
|
80
|
+
margin-bottom: 0;
|
|
81
|
+
}
|
|
82
|
+
</style>
|
|
83
|
+
</head>
|
|
84
|
+
<body>
|
|
85
|
+
<div class="container">
|
|
86
|
+
<div class="logo">Frontend Hamroun</div>
|
|
87
|
+
|
|
88
|
+
<div class="alert">
|
|
89
|
+
<h1>STATIC INDEX.HTML FILE</h1>
|
|
90
|
+
<p><strong>You should NOT be seeing this page if the server is running correctly.</strong></p>
|
|
91
|
+
<p>This is a static file that should only be used as a fallback when the server is not running.</p>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<div class="warning">
|
|
95
|
+
<p>If you're seeing this while running <code>npm run dev</code>, there's likely an issue with the Express route handling.</p>
|
|
96
|
+
<p>Try clearing your browser cache and refreshing the page.</p>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<div class="steps">
|
|
100
|
+
<h2>Troubleshooting Steps:</h2>
|
|
101
|
+
<ul>
|
|
102
|
+
<li>Check your terminal for any error messages</li>
|
|
103
|
+
<li>Verify that you've installed all dependencies with <code>npm install</code></li>
|
|
104
|
+
<li>Check that the server port (default: 3000) is not already in use</li>
|
|
105
|
+
<li>Make sure your Express routes are configured correctly</li>
|
|
106
|
+
<li>Try restarting the server with <code>npm run dev</code></li>
|
|
107
|
+
<li>Check that all required environment variables are set</li>
|
|
108
|
+
</ul>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<footer class="footer">
|
|
113
|
+
<div class="container">
|
|
114
|
+
<p>© 2025 Frontend Hamroun - A lightweight full-stack JavaScript framework</p>
|
|
115
|
+
</div>
|
|
116
|
+
</footer>
|
|
117
|
+
</body>
|
|
118
|
+
</html>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/* Color scheme */
|
|
2
|
+
:root {
|
|
3
|
+
--primary-color: #0066cc;
|
|
4
|
+
--primary-hover: #004c99;
|
|
5
|
+
--secondary-color: #6c757d;
|
|
6
|
+
--light-bg: #f8f9fa;
|
|
7
|
+
--light-border: #dee2e6;
|
|
8
|
+
--dark-text: #212529;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
body {
|
|
12
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
13
|
+
background-color: var(--light-bg);
|
|
14
|
+
color: var(--dark-text);
|
|
15
|
+
line-height: 1.5;
|
|
16
|
+
margin: 0;
|
|
17
|
+
padding: 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.container {
|
|
21
|
+
max-width: 1140px;
|
|
22
|
+
margin: 0 auto;
|
|
23
|
+
padding: 2rem 1rem;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.logo {
|
|
27
|
+
font-size: 2rem;
|
|
28
|
+
font-weight: bold;
|
|
29
|
+
color: var(--primary-color);
|
|
30
|
+
margin-bottom: 1.5rem;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
h1, h2, h3 {
|
|
34
|
+
margin-top: 0;
|
|
35
|
+
margin-bottom: 1rem;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
ul {
|
|
39
|
+
padding-left: 1.5rem;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
li {
|
|
43
|
+
margin-bottom: 0.5rem;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.button, button {
|
|
47
|
+
display: inline-block;
|
|
48
|
+
font-weight: 400;
|
|
49
|
+
color: #fff;
|
|
50
|
+
text-align: center;
|
|
51
|
+
vertical-align: middle;
|
|
52
|
+
background-color: var(--primary-color);
|
|
53
|
+
border: 1px solid var(--primary-color);
|
|
54
|
+
padding: 0.375rem 0.75rem;
|
|
55
|
+
font-size: 1rem;
|
|
56
|
+
line-height: 1.5;
|
|
57
|
+
border-radius: 0.25rem;
|
|
58
|
+
cursor: pointer;
|
|
59
|
+
text-decoration: none;
|
|
60
|
+
transition: background-color 0.15s ease-in-out;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.button:hover, button:hover {
|
|
64
|
+
background-color: var(--primary-hover);
|
|
65
|
+
border-color: var(--primary-hover);
|
|
66
|
+
text-decoration: none;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.footer {
|
|
70
|
+
padding: 1.5rem 0;
|
|
71
|
+
margin-top: 3rem;
|
|
72
|
+
background-color: #f1f1f1;
|
|
73
|
+
color: var(--secondary-color);
|
|
74
|
+
text-align: center;
|
|
75
|
+
font-size: 0.875rem;
|
|
76
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# Frontend Hamroun SSR Template
|
|
2
|
+
|
|
3
|
+
This is a comprehensive server-side rendering (SSR) example using Frontend Hamroun.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
1. Install dependencies:
|
|
8
|
+
```
|
|
9
|
+
npm install
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
2. Start the server:
|
|
13
|
+
```
|
|
14
|
+
npm start
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
3. Open your browser at http://localhost:3000
|
|
18
|
+
|
|
19
|
+
## Core Features
|
|
20
|
+
|
|
21
|
+
This template demonstrates:
|
|
22
|
+
|
|
23
|
+
### Server-Side Rendering
|
|
24
|
+
- Pre-rendering of components on the server
|
|
25
|
+
- Hydration of server-rendered content on the client
|
|
26
|
+
- Data fetching during server rendering
|
|
27
|
+
- AI-powered meta tag generation
|
|
28
|
+
|
|
29
|
+
### Automatic File-Based Routing
|
|
30
|
+
- Pages are automatically rendered based on their file path in the `pages` directory
|
|
31
|
+
- For example:
|
|
32
|
+
- `/pages/index.js` → `/` route
|
|
33
|
+
- `/pages/about.js` → `/about` route
|
|
34
|
+
- `/pages/blog/index.js` → `/blog` route
|
|
35
|
+
- `/pages/users/[id].js` → `/users/:id` dynamic route
|
|
36
|
+
|
|
37
|
+
### API Integration
|
|
38
|
+
- RESTful API endpoints
|
|
39
|
+
- Dynamic API routing
|
|
40
|
+
- API middleware for validation and security
|
|
41
|
+
- File-based API structure
|
|
42
|
+
|
|
43
|
+
### Database Integration
|
|
44
|
+
- MongoDB, MySQL, and PostgreSQL support
|
|
45
|
+
- ORM-like query interface
|
|
46
|
+
- Connection pooling
|
|
47
|
+
- Transaction support
|
|
48
|
+
|
|
49
|
+
### Authentication & Authorization
|
|
50
|
+
- JWT-based authentication
|
|
51
|
+
- Role-based access control
|
|
52
|
+
- Password hashing and validation
|
|
53
|
+
- Token refresh mechanism
|
|
54
|
+
|
|
55
|
+
### Performance Optimization
|
|
56
|
+
- Caching strategies
|
|
57
|
+
- Response compression
|
|
58
|
+
- Static asset optimization
|
|
59
|
+
- Efficient metadata handling
|
|
60
|
+
|
|
61
|
+
## Implementation Examples
|
|
62
|
+
|
|
63
|
+
### Creating Components
|
|
64
|
+
|
|
65
|
+
Use the `jsx` or `createElement` function from 'frontend-hamroun':
|
|
66
|
+
|
|
67
|
+
```jsx
|
|
68
|
+
import { jsx } from 'frontend-hamroun';
|
|
69
|
+
|
|
70
|
+
export default function MyComponent(props) {
|
|
71
|
+
return jsx('div', { className: "container" }, [
|
|
72
|
+
jsx('h1', {}, "Hello World"),
|
|
73
|
+
jsx('p', {}, `Props value: ${props.value}`)
|
|
74
|
+
]);
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Creating API Routes
|
|
79
|
+
|
|
80
|
+
Create files in the `api` directory following this pattern:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
// api/users/index.ts
|
|
84
|
+
import { Request, Response } from 'express';
|
|
85
|
+
|
|
86
|
+
export const get = (req: Request, res: Response) => {
|
|
87
|
+
res.json({ users: [...] });
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export const post = (req: Request, res: Response) => {
|
|
91
|
+
// Create user
|
|
92
|
+
res.status(201).json({ success: true });
|
|
93
|
+
};
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Database Usage
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { Server } from 'frontend-hamroun/server';
|
|
100
|
+
|
|
101
|
+
const server = new Server({
|
|
102
|
+
db: {
|
|
103
|
+
url: process.env.DATABASE_URL,
|
|
104
|
+
type: 'mongodb' // or 'mysql', 'postgres'
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Get typed database instance
|
|
109
|
+
const db = server.getDatabase();
|
|
110
|
+
const users = await db.query('SELECT * FROM users'); // For SQL
|
|
111
|
+
const docs = await db.getMongoDb().collection('users').find().toArray(); // For MongoDB
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Authentication
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
import { AuthService } from 'frontend-hamroun/server';
|
|
118
|
+
|
|
119
|
+
const auth = new AuthService({
|
|
120
|
+
secret: process.env.JWT_SECRET,
|
|
121
|
+
expiresIn: '24h'
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Protect routes
|
|
125
|
+
app.get('/api/protected', auth.requireAuth(), (req, res) => {
|
|
126
|
+
res.json({ message: "Authenticated!" });
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Create user & login
|
|
130
|
+
const hashedPassword = await auth.hashPassword(password);
|
|
131
|
+
const token = auth.generateToken(user);
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Advanced Middleware
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import { rateLimit, requestLogger, errorHandler } from 'frontend-hamroun/server';
|
|
138
|
+
|
|
139
|
+
app.use(requestLogger);
|
|
140
|
+
app.use('/api', rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }));
|
|
141
|
+
app.use(errorHandler);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## File-Based Routing Examples
|
|
145
|
+
|
|
146
|
+
### Static Routes
|
|
147
|
+
Create files in the `pages` directory:
|
|
148
|
+
|
|
149
|
+
```jsx
|
|
150
|
+
// pages/index.js - Maps to "/"
|
|
151
|
+
export default function HomePage() {
|
|
152
|
+
return <h1>Home Page</h1>;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// pages/about.js - Maps to "/about"
|
|
156
|
+
export default function AboutPage() {
|
|
157
|
+
return <h1>About Us</h1>;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// pages/contact/index.js - Maps to "/contact"
|
|
161
|
+
export default function ContactPage() {
|
|
162
|
+
return <h1>Contact Us</h1>;
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Dynamic Routes
|
|
167
|
+
Use brackets in filenames to define dynamic parameters:
|
|
168
|
+
|
|
169
|
+
```jsx
|
|
170
|
+
// pages/users/[id].js - Maps to "/users/:id"
|
|
171
|
+
export default function UserPage({ params }) {
|
|
172
|
+
return <h1>User Profile: {params.id}</h1>;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// pages/blog/[category]/[slug].js - Maps to "/blog/:category/:slug"
|
|
176
|
+
export default function BlogPost({ params }) {
|
|
177
|
+
return (
|
|
178
|
+
<div>
|
|
179
|
+
<h1>Blog Post: {params.slug}</h1>
|
|
180
|
+
<p>Category: {params.category}</p>
|
|
181
|
+
</div>
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Next Steps
|
|
187
|
+
|
|
188
|
+
Explore the full API documentation for more advanced features and customization options.
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
// Fix imports by using only the exports that exist
|
|
6
|
+
import {
|
|
7
|
+
renderToString,
|
|
8
|
+
jsx,
|
|
9
|
+
requestLogger,
|
|
10
|
+
errorHandler,
|
|
11
|
+
notFoundHandler,
|
|
12
|
+
rateLimit
|
|
13
|
+
} from './lib/frontend-hamroun.js';
|
|
14
|
+
import dotenv from 'dotenv';
|
|
15
|
+
import compression from 'compression';
|
|
16
|
+
import cors from 'cors';
|
|
17
|
+
|
|
18
|
+
// Load environment variables
|
|
19
|
+
dotenv.config();
|
|
20
|
+
|
|
21
|
+
// Get __dirname equivalent in ESM
|
|
22
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
23
|
+
const __dirname = path.dirname(__filename);
|
|
24
|
+
|
|
25
|
+
// Create Express app
|
|
26
|
+
const app = express();
|
|
27
|
+
const PORT = process.env.PORT || 3000;
|
|
28
|
+
|
|
29
|
+
// Middleware
|
|
30
|
+
app.use(compression()); // Compress responses
|
|
31
|
+
app.use(express.json()); // Parse JSON requests
|
|
32
|
+
app.use(express.urlencoded({ extended: true })); // Parse URL-encoded requests
|
|
33
|
+
app.use(cors()); // Enable CORS
|
|
34
|
+
app.use(requestLogger); // Log all requests
|
|
35
|
+
|
|
36
|
+
// Add rate limiting to prevent abuse
|
|
37
|
+
app.use(rateLimit({
|
|
38
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
39
|
+
max: 100 // limit each IP to 100 requests per windowMs
|
|
40
|
+
}));
|
|
41
|
+
|
|
42
|
+
// Serve static files from the public directory
|
|
43
|
+
// Important: This middleware should be defined BEFORE your catch-all route
|
|
44
|
+
app.use(express.static(path.join(__dirname, 'public')));
|
|
45
|
+
|
|
46
|
+
// Add correct MIME type for client.js module
|
|
47
|
+
app.get('/client.js', (req, res) => {
|
|
48
|
+
res.type('application/javascript').sendFile(path.join(__dirname, 'public', 'client.js'));
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Serve WebAssembly files with correct MIME type
|
|
52
|
+
app.get('*.wasm', (req, res, next) => {
|
|
53
|
+
res.type('application/wasm');
|
|
54
|
+
next();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Add API routes example
|
|
58
|
+
app.get('/api/hello', (req, res) => {
|
|
59
|
+
res.json({
|
|
60
|
+
message: 'Hello from the API!',
|
|
61
|
+
serverTime: new Date().toISOString()
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Find the pages directory
|
|
66
|
+
const getPagesDirectory = () => {
|
|
67
|
+
return path.join(__dirname, 'pages');
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Helper to check if a file exists
|
|
71
|
+
const fileExists = async (filePath) => {
|
|
72
|
+
try {
|
|
73
|
+
await fs.promises.access(filePath);
|
|
74
|
+
return true;
|
|
75
|
+
} catch {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// Map URL path to component path
|
|
81
|
+
const getComponentPath = async (urlPath) => {
|
|
82
|
+
const pagesDir = getPagesDirectory();
|
|
83
|
+
|
|
84
|
+
// Handle root path
|
|
85
|
+
if (urlPath === '/') {
|
|
86
|
+
const indexPath = path.join(pagesDir, 'index.js');
|
|
87
|
+
if (await fileExists(indexPath)) {
|
|
88
|
+
return {
|
|
89
|
+
componentPath: indexPath,
|
|
90
|
+
params: {}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Try direct match (e.g., /about -> /pages/about.js)
|
|
96
|
+
const possibleExtensions = ['.js'];
|
|
97
|
+
|
|
98
|
+
for (const ext of possibleExtensions) {
|
|
99
|
+
const directPath = path.join(pagesDir, `${urlPath.slice(1)}${ext}`);
|
|
100
|
+
if (await fileExists(directPath)) {
|
|
101
|
+
return {
|
|
102
|
+
componentPath: directPath,
|
|
103
|
+
params: {}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Try directory index (e.g., /about -> /pages/about/index.js)
|
|
109
|
+
for (const ext of possibleExtensions) {
|
|
110
|
+
const dirIndexPath = path.join(pagesDir, urlPath.slice(1), `index${ext}`);
|
|
111
|
+
if (await fileExists(dirIndexPath)) {
|
|
112
|
+
return {
|
|
113
|
+
componentPath: dirIndexPath,
|
|
114
|
+
params: {}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// No match found
|
|
120
|
+
return null;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// Handle all GET routes with SSR - explicitly exclude /public/ paths
|
|
124
|
+
app.get('*', async (req, res, next) => {
|
|
125
|
+
try {
|
|
126
|
+
// Skip API routes
|
|
127
|
+
if (req.path.startsWith('/api/')) {
|
|
128
|
+
return next();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Skip static assets - check file extensions that should be handled as static
|
|
132
|
+
if (req.path.match(/\.(js|css|ico|png|jpg|jpeg|gif|svg|wasm|txt|pdf|json|map)$/)) {
|
|
133
|
+
return next();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Try to find the matching component
|
|
137
|
+
const routeResult = await getComponentPath(req.path);
|
|
138
|
+
|
|
139
|
+
if (!routeResult) {
|
|
140
|
+
return res.status(404).send(`
|
|
141
|
+
<!DOCTYPE html>
|
|
142
|
+
<html>
|
|
143
|
+
<head>
|
|
144
|
+
<title>404 - Page Not Found</title>
|
|
145
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
146
|
+
<link href="/styles.css" rel="stylesheet" type="text/css">
|
|
147
|
+
</head>
|
|
148
|
+
<body>
|
|
149
|
+
<div id="app">
|
|
150
|
+
<div class="container">
|
|
151
|
+
<h1>404 - Page Not Found</h1>
|
|
152
|
+
<p>The page you requested could not be found.</p>
|
|
153
|
+
<a href="/" class="button">Go to Home</a>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
<script id="__APP_DATA__" type="application/json">${JSON.stringify({
|
|
157
|
+
path: req.path,
|
|
158
|
+
error: 'not_found'
|
|
159
|
+
})}</script>
|
|
160
|
+
<script type="module" src="/client.js"></script>
|
|
161
|
+
</body>
|
|
162
|
+
</html>
|
|
163
|
+
`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Import the component
|
|
167
|
+
try {
|
|
168
|
+
const componentUrl = `file://${routeResult.componentPath}`;
|
|
169
|
+
const moduleImport = await import(componentUrl);
|
|
170
|
+
const PageComponent = moduleImport.default || moduleImport;
|
|
171
|
+
|
|
172
|
+
if (!PageComponent || typeof PageComponent !== 'function') {
|
|
173
|
+
throw new Error(`Invalid component in ${routeResult.componentPath}`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Create props with route data
|
|
177
|
+
const initialProps = {
|
|
178
|
+
params: routeResult.params,
|
|
179
|
+
path: req.path,
|
|
180
|
+
query: req.query,
|
|
181
|
+
api: {
|
|
182
|
+
serverTime: new Date().toISOString()
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// Render the component
|
|
187
|
+
const result = PageComponent(initialProps);
|
|
188
|
+
let html = renderToString(result);
|
|
189
|
+
|
|
190
|
+
// Send complete HTML with hydration data
|
|
191
|
+
res.send(`
|
|
192
|
+
<!DOCTYPE html>
|
|
193
|
+
<html lang="en">
|
|
194
|
+
<head>
|
|
195
|
+
<meta charset="UTF-8">
|
|
196
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
197
|
+
<title>Frontend Hamroun App</title>
|
|
198
|
+
<link href="/styles.css" rel="stylesheet" type="text/css">
|
|
199
|
+
</head>
|
|
200
|
+
<body>
|
|
201
|
+
<div id="app">${html}</div>
|
|
202
|
+
<script id="__APP_DATA__" type="application/json">${JSON.stringify(initialProps)}</script>
|
|
203
|
+
<script type="module" src="/client.js"></script>
|
|
204
|
+
</body>
|
|
205
|
+
</html>
|
|
206
|
+
`);
|
|
207
|
+
} catch (error) {
|
|
208
|
+
console.error('Error rendering component:', error);
|
|
209
|
+
next(error);
|
|
210
|
+
}
|
|
211
|
+
} catch (error) {
|
|
212
|
+
next(error);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Add error handler middleware
|
|
217
|
+
app.use(errorHandler);
|
|
218
|
+
|
|
219
|
+
// Add 404 handler for API routes
|
|
220
|
+
app.use(notFoundHandler);
|
|
221
|
+
|
|
222
|
+
// Start the server
|
|
223
|
+
app.listen(PORT, () => {
|
|
224
|
+
console.log(`Server running at http://localhost:${PORT}`);
|
|
225
|
+
console.log(`Mode: ${process.env.NODE_ENV || 'development'}`);
|
|
226
|
+
});
|