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.
Files changed (182) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/README.md +268 -315
  3. package/bin/baraqex.js +150 -12
  4. package/dist/browser.d.ts +1 -1
  5. package/dist/browser.d.ts.map +1 -1
  6. package/dist/browser.js +2319 -205
  7. package/dist/browser.js.map +4 -4
  8. package/dist/core/batch.d.ts +10 -0
  9. package/dist/core/batch.d.ts.map +1 -0
  10. package/dist/core/component.d.ts +69 -0
  11. package/dist/core/component.d.ts.map +1 -0
  12. package/dist/core/context.d.ts +22 -0
  13. package/dist/core/context.d.ts.map +1 -0
  14. package/dist/core/errors.d.ts +125 -0
  15. package/dist/core/errors.d.ts.map +1 -0
  16. package/dist/core/event-bus.d.ts +29 -0
  17. package/dist/core/event-bus.d.ts.map +1 -0
  18. package/dist/core/forms.d.ts +128 -0
  19. package/dist/core/forms.d.ts.map +1 -0
  20. package/dist/core/hooks.d.ts +84 -0
  21. package/dist/core/hooks.d.ts.map +1 -0
  22. package/dist/core/index.d.ts +23 -0
  23. package/dist/core/index.d.ts.map +1 -0
  24. package/dist/core/jsx-runtime.d.ts +45 -0
  25. package/dist/core/jsx-runtime.d.ts.map +1 -0
  26. package/dist/core/lifecycle-events.d.ts +71 -0
  27. package/dist/core/lifecycle-events.d.ts.map +1 -0
  28. package/dist/core/renderer.d.ts +39 -0
  29. package/dist/core/renderer.d.ts.map +1 -0
  30. package/dist/core/router.d.ts +108 -0
  31. package/dist/core/router.d.ts.map +1 -0
  32. package/dist/core/server-renderer.d.ts +26 -0
  33. package/dist/core/server-renderer.d.ts.map +1 -0
  34. package/dist/core/store.d.ts +102 -0
  35. package/dist/core/store.d.ts.map +1 -0
  36. package/dist/core/types.d.ts +66 -0
  37. package/dist/core/types.d.ts.map +1 -0
  38. package/dist/core/utils.d.ts +153 -0
  39. package/dist/core/utils.d.ts.map +1 -0
  40. package/dist/core/vdom.d.ts +29 -0
  41. package/dist/core/vdom.d.ts.map +1 -0
  42. package/dist/index.d.ts +39 -35
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +2592 -508
  45. package/dist/index.js.map +4 -4
  46. package/dist/server/auth.d.ts +8 -3
  47. package/dist/server/auth.d.ts.map +1 -1
  48. package/dist/server/index.d.ts +2 -2
  49. package/dist/server/index.d.ts.map +1 -1
  50. package/dist/server/index.js +173 -112
  51. package/dist/server/index.js.map +4 -4
  52. package/dist/server/middleware.d.ts +10 -1
  53. package/dist/server/middleware.d.ts.map +1 -1
  54. package/package.json +224 -124
  55. package/templates/basic-app/src/main.jsx +336 -0
  56. package/templates/complete-app/api/hello.js +0 -0
  57. package/templates/complete-app/client.js +58 -0
  58. package/templates/complete-app/lib/frontend-hamroun.js +182 -0
  59. package/templates/complete-app/package.json +18 -0
  60. package/templates/complete-app/pages/about.js +119 -0
  61. package/templates/complete-app/pages/about.jsx +0 -0
  62. package/templates/complete-app/pages/index.js +157 -0
  63. package/templates/complete-app/pages/index.jsx +0 -0
  64. package/templates/complete-app/pages/wasm-demo.js +290 -0
  65. package/templates/complete-app/pages/wasm-demo.jsx +0 -0
  66. package/templates/complete-app/public/client.js +89 -0
  67. package/templates/complete-app/public/index.html +118 -0
  68. package/templates/complete-app/public/styles.css +76 -0
  69. package/templates/complete-app/readme.md +188 -0
  70. package/templates/complete-app/server.js +226 -0
  71. package/templates/complete-app/server.ts +275 -0
  72. package/templates/complete-app/src/App.tsx +59 -0
  73. package/templates/complete-app/src/client.ts +61 -0
  74. package/templates/complete-app/src/client.tsx +18 -0
  75. package/templates/complete-app/src/pages/index.tsx +51 -0
  76. package/templates/complete-app/src/server.ts +218 -0
  77. package/templates/complete-app/tsconfig.json +22 -0
  78. package/templates/complete-app/tsconfig.server.json +19 -0
  79. package/templates/complete-app/vite.config.js +57 -0
  80. package/templates/complete-app/vite.config.ts +30 -0
  81. package/templates/complete-app/wasm/build.bat +0 -0
  82. package/templates/complete-app/wasm/build.sh +0 -0
  83. package/templates/complete-app/wasm/example.go +0 -0
  84. package/templates/fullstack-app/README.md +37 -0
  85. package/templates/fullstack-app/api/hello.js +11 -0
  86. package/templates/fullstack-app/api/hello.ts +18 -0
  87. package/templates/fullstack-app/api/users/[id].ts +73 -0
  88. package/templates/fullstack-app/api/users/index.ts +32 -0
  89. package/templates/fullstack-app/build/main.css +874 -0
  90. package/templates/fullstack-app/build/main.css.map +7 -0
  91. package/templates/fullstack-app/build/main.js +967 -0
  92. package/templates/fullstack-app/build/main.js.map +7 -0
  93. package/templates/fullstack-app/build.ts +210 -0
  94. package/templates/fullstack-app/index.html +36 -0
  95. package/templates/fullstack-app/package.json +35 -0
  96. package/templates/fullstack-app/postcss.config.js +6 -0
  97. package/templates/fullstack-app/process-tailwind.js +45 -0
  98. package/templates/fullstack-app/public/_redirects +1 -0
  99. package/templates/fullstack-app/public/route-handler.js +47 -0
  100. package/templates/fullstack-app/public/spa-fix.html +17 -0
  101. package/templates/fullstack-app/public/styles.css +975 -0
  102. package/templates/fullstack-app/public/tailwind.css +15 -0
  103. package/templates/fullstack-app/server.js +267 -0
  104. package/templates/fullstack-app/server.ts +474 -0
  105. package/templates/fullstack-app/src/README.md +55 -0
  106. package/templates/fullstack-app/src/client.js +87 -0
  107. package/templates/fullstack-app/src/components/ClientHome.tsx +0 -0
  108. package/templates/fullstack-app/src/components/ErrorBoundary.tsx +36 -0
  109. package/templates/fullstack-app/src/components/Layout.tsx +42 -0
  110. package/templates/fullstack-app/src/components/StateDemo.tsx +207 -0
  111. package/templates/fullstack-app/src/components/UserList.tsx +44 -0
  112. package/templates/fullstack-app/src/config.ts +42 -0
  113. package/templates/fullstack-app/src/data/api.ts +206 -0
  114. package/templates/fullstack-app/src/main.tsx +155 -0
  115. package/templates/fullstack-app/src/middleware.ts +28 -0
  116. package/templates/fullstack-app/src/pages/404.tsx +28 -0
  117. package/templates/fullstack-app/src/pages/[id].tsx +0 -0
  118. package/templates/fullstack-app/src/pages/_app.tsx +11 -0
  119. package/templates/fullstack-app/src/pages/_document.tsx +25 -0
  120. package/templates/fullstack-app/src/pages/_error.tsx +45 -0
  121. package/templates/fullstack-app/src/pages/about/index.tsx +67 -0
  122. package/templates/fullstack-app/src/pages/about.tsx +71 -0
  123. package/templates/fullstack-app/src/pages/api/users/[id].ts +73 -0
  124. package/templates/fullstack-app/src/pages/api/users/index.ts +43 -0
  125. package/templates/fullstack-app/src/pages/index.tsx +110 -0
  126. package/templates/fullstack-app/src/pages/users/[id].tsx +153 -0
  127. package/templates/fullstack-app/src/pages/users.tsx +60 -0
  128. package/templates/fullstack-app/src/pages/wasm-demo.tsx +1 -0
  129. package/templates/fullstack-app/src/router.ts +255 -0
  130. package/templates/fullstack-app/src/styles.css +5 -0
  131. package/templates/fullstack-app/tailwind.config.js +11 -0
  132. package/templates/fullstack-app/tsconfig.json +18 -0
  133. package/templates/fullstack-app/vite.config.js +87 -0
  134. package/templates/go/build.bat +36 -0
  135. package/templates/go/build.sh +43 -0
  136. package/templates/go/example.go +205 -0
  137. package/templates/go-wasm-app/README.md +38 -0
  138. package/templates/go-wasm-app/babel.config.js +21 -0
  139. package/templates/go-wasm-app/build-client.js +49 -0
  140. package/templates/go-wasm-app/build-wasm.js +237 -0
  141. package/templates/go-wasm-app/build.config.js +62 -0
  142. package/templates/go-wasm-app/build.js +218 -0
  143. package/templates/go-wasm-app/package.json +32 -0
  144. package/templates/go-wasm-app/public/index.html +128 -0
  145. package/templates/go-wasm-app/public/styles.css +197 -0
  146. package/templates/go-wasm-app/public/wasm/example.wasm +0 -0
  147. package/templates/go-wasm-app/public/wasm/wasm_exec.js +561 -0
  148. package/templates/go-wasm-app/public/wasm/wasm_exec_node.js +39 -0
  149. package/templates/go-wasm-app/server.js +70 -0
  150. package/templates/go-wasm-app/src/App.jsx +38 -0
  151. package/templates/go-wasm-app/src/app.js +173 -0
  152. package/templates/go-wasm-app/src/client.js +57 -0
  153. package/templates/go-wasm-app/src/components/Footer.jsx +13 -0
  154. package/templates/go-wasm-app/src/components/Header.jsx +19 -0
  155. package/templates/go-wasm-app/src/components/WasmDemo.jsx +120 -0
  156. package/templates/go-wasm-app/src/main.jsx +12 -0
  157. package/templates/go-wasm-app/src/wasm/example.go +75 -0
  158. package/templates/go-wasm-app/tsconfig.server.json +18 -0
  159. package/templates/go-wasm-app/vite.config.js +45 -0
  160. package/dist/forms/index.d.ts +0 -2
  161. package/dist/forms/index.d.ts.map +0 -1
  162. package/dist/forms/types.d.ts +0 -2
  163. package/dist/forms/types.d.ts.map +0 -1
  164. package/dist/frontend/components/WasmLoader.d.ts +0 -2
  165. package/dist/frontend/components/WasmLoader.d.ts.map +0 -1
  166. package/dist/frontend/hooks/useWasm.d.ts +0 -2
  167. package/dist/frontend/hooks/useWasm.d.ts.map +0 -1
  168. package/dist/frontend/index.d.ts +0 -2
  169. package/dist/frontend/index.d.ts.map +0 -1
  170. package/dist/router/index.d.ts +0 -2
  171. package/dist/router/index.d.ts.map +0 -1
  172. package/dist/router/types.d.ts +0 -2
  173. package/dist/router/types.d.ts.map +0 -1
  174. package/dist/store/index.d.ts +0 -2
  175. package/dist/store/index.d.ts.map +0 -1
  176. package/dist/store/types.d.ts +0 -2
  177. package/dist/store/types.d.ts.map +0 -1
  178. package/templates/basic-app/package-lock.json +0 -7173
  179. package/templates/fullstack-template/package-lock.json +0 -3558
  180. package/templates/ssr-template/package-lock.json +0 -5380
  181. package/templates/wasm/package-lock.json +0 -5347
  182. 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>&copy; 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
+ });