create-aziz-app 2.0.11 → 2.0.12

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-aziz-app",
3
- "version": "2.0.11",
3
+ "version": "2.0.12",
4
4
  "description": "A React-like framework with state management, routing, and API routes - Create apps with auto-import, live reload, and Next.js-like features",
5
5
  "keywords": [
6
6
  "react",
@@ -125,10 +125,12 @@ navigate("about");
125
125
 
126
126
  ### API Routes
127
127
  ```javascript
128
- // api/todos.js
129
- registerApiRoute('todos', async (req, res) => {
130
- return res.status(200).json({ todos: [] });
131
- });
128
+ // api/todos.js - Runs on SERVER (Node.js)!
129
+ module.exports = async function handler(req, res) {
130
+ if (req.method === 'GET') {
131
+ return res.status(200).json({ todos: [] });
132
+ }
133
+ };
132
134
 
133
135
  // Use in components
134
136
  const response = await fetchApi('/api/todos');
@@ -152,9 +154,11 @@ The CLI will automatically set up your chosen framework!
152
154
 
153
155
  - **[Getting Started](docs/GETTING-STARTED.md)** - Complete setup guide
154
156
  - **[Auto-Registration](docs/AUTO-REGISTRATION.md)** - How pages auto-register
155
- - **[API Guide](docs/API-GUIDE.md)** - How to create API routes
157
+ - **[API Routes](docs/API-ROUTES.md)** - Server-side API endpoints (like Next.js!)
158
+ - **[API Guide](docs/API-GUIDE.md)** - Legacy API guide
156
159
  - **[Auto-Import](docs/AUTO-IMPORT.md)** - Auto-import system details
157
160
  - **[Dev Server](docs/DEV-SERVER.md)** - Live reload and development
161
+ - **[How It Works](docs/HOW-IT-WORKS.md)** - System architecture
158
162
  - **[Troubleshooting](docs/TROUBLESHOOTING.md)** - Fix common issues
159
163
  - **[Quick Start](docs/QUICK-START.md)** - Quick examples
160
164
 
@@ -1,9 +1,8 @@
1
- /** @jsx h */
1
+ // API Route: /api/hello
2
+ // This runs on the SERVER (Node.js), not in the browser!
2
3
 
3
- // Example API route: /api/hello
4
- // Simple hello world API endpoint
5
-
6
- registerApiRoute('hello', async (req, res) => {
4
+ // Export the handler function (like Next.js)
5
+ module.exports = async function handler(req, res) {
7
6
  const name = req.query.name || 'World';
8
7
 
9
8
  return res.status(200).json({
@@ -11,4 +10,4 @@ registerApiRoute('hello', async (req, res) => {
11
10
  timestamp: new Date().toISOString(),
12
11
  method: req.method
13
12
  });
14
- });
13
+ };
@@ -1,17 +1,15 @@
1
- /** @jsx h */
1
+ // API Route: /api/users
2
+ // This runs on the SERVER (Node.js), not in the browser!
2
3
 
3
- // Example API route: /api/users
4
- // This simulates a backend API endpoint
5
-
6
- // Mock database
4
+ // Mock database (in real app, use a real database)
7
5
  const users = [
8
6
  { id: 1, name: 'Aziz Ahmed', email: 'aziz@example.com' },
9
7
  { id: 2, name: 'John Doe', email: 'john@example.com' },
10
8
  { id: 3, name: 'Jane Smith', email: 'jane@example.com' }
11
9
  ];
12
10
 
13
- // Register the API route
14
- registerApiRoute('users', async (req, res) => {
11
+ // Export the handler function (like Next.js)
12
+ module.exports = async function handler(req, res) {
15
13
  // Handle different HTTP methods
16
14
  switch (req.method) {
17
15
  case 'GET':
@@ -59,4 +57,4 @@ registerApiRoute('users', async (req, res) => {
59
57
  default:
60
58
  return res.status(405).json({ error: 'Method not allowed' });
61
59
  }
62
- });
60
+ };
package/template/app.html CHANGED
@@ -28,31 +28,27 @@
28
28
  <!-- Footer is always visible -->
29
29
  <div id="footer"></div>
30
30
 
31
- <!-- Load core modules -->
32
- <script type="text/babel" src="modules/router.js"></script>
33
- <script type="text/babel" src="modules/state.js"></script>
34
- <script type="text/babel" src="modules/api.js"></script>
35
-
36
- <!-- Load API routes -->
37
- <script type="text/babel" src="api/hello.js"></script>
38
- <script type="text/babel" src="api/users.js"></script>
39
-
40
- <!-- Load shared components -->
41
- <script type="text/babel" src="components/Counter.jsx"></script>
42
- <script type="text/babel" src="components/Footer.jsx"></script>
43
- <script type="text/babel" src="components/Navbar.jsx"></script>
44
-
45
- <!-- Load pages -->
46
- <script type="text/babel" src="pages/About.jsx"></script>
47
- <script type="text/babel" src="pages/ApiDemo.jsx"></script>
48
- <script type="text/babel" src="pages/Contact.jsx"></script>
49
- <script type="text/babel" src="pages/Example.jsx"></script>
50
- <script type="text/babel" src="pages/Home.jsx"></script>
51
- <script type="text/babel" src="pages/test.jsx"></script>
52
-
53
- <!-- Start the app -->
54
- <script type="text/babel">
55
- startApp();
31
+ <!-- Load core modules -->
32
+ <script type="text/babel" src="modules/router.js"></script>
33
+ <script type="text/babel" src="modules/state.js"></script>
34
+ <script type="text/babel" src="modules/api.js"></script>
35
+
36
+ <!-- Load shared components -->
37
+ <script type="text/babel" src="components/Counter.jsx"></script>
38
+ <script type="text/babel" src="components/Footer.jsx"></script>
39
+ <script type="text/babel" src="components/Navbar.jsx"></script>
40
+
41
+ <!-- Load pages -->
42
+ <script type="text/babel" src="pages/About.jsx"></script>
43
+ <script type="text/babel" src="pages/ApiDemo.jsx"></script>
44
+ <script type="text/babel" src="pages/Contact.jsx"></script>
45
+ <script type="text/babel" src="pages/Example.jsx"></script>
46
+ <script type="text/babel" src="pages/Home.jsx"></script>
47
+ <script type="text/babel" src="pages/test.jsx"></script>
48
+
49
+ <!-- Start the app -->
50
+ <script type="text/babel">
51
+ startApp();
56
52
  </script>
57
53
 
58
54
  </body>
@@ -0,0 +1,538 @@
1
+ # API Routes Guide
2
+
3
+ ## Overview
4
+
5
+ API routes run on the **SERVER** (Node.js), just like Next.js! They're real backend endpoints, not client-side mocks.
6
+
7
+ ## How It Works
8
+
9
+ ```
10
+ Browser Dev Server (Node.js)
11
+ │ │
12
+ │ GET /api/users │
13
+ ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā–ŗā”‚
14
+ │ │ Loads api/users.js
15
+ │ │ Executes handler()
16
+ │ │
17
+ │ { users: [...] } │
18
+ │◄─────────────────────────────┤
19
+ │ │
20
+ ```
21
+
22
+ ## Creating an API Route
23
+
24
+ ### File Structure
25
+
26
+ ```
27
+ api/
28
+ ā”œā”€ā”€ hello.js → /api/hello
29
+ ā”œā”€ā”€ users.js → /api/users
30
+ └── posts.js → /api/posts
31
+ ```
32
+
33
+ Each file in `api/` becomes an endpoint!
34
+
35
+ ### Basic Example
36
+
37
+ ```javascript
38
+ // api/hello.js
39
+
40
+ module.exports = async function handler(req, res) {
41
+ return res.status(200).json({
42
+ message: 'Hello from the server!'
43
+ });
44
+ };
45
+ ```
46
+
47
+ ### Request Object
48
+
49
+ The `req` object contains:
50
+
51
+ ```javascript
52
+ {
53
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE',
54
+ body: {}, // Parsed JSON body
55
+ query: {}, // URL query parameters
56
+ headers: {}, // Request headers
57
+ url: '/api/users?id=1'
58
+ }
59
+ ```
60
+
61
+ ### Response Object
62
+
63
+ The `res` object has these methods:
64
+
65
+ ```javascript
66
+ // Set status code
67
+ res.status(200)
68
+
69
+ // Send JSON response
70
+ res.json({ data: 'value' })
71
+
72
+ // Send text response
73
+ res.send('Hello')
74
+
75
+ // Set custom header
76
+ res.setHeader('X-Custom', 'value')
77
+
78
+ // Chain methods
79
+ res.status(201).json({ created: true })
80
+ ```
81
+
82
+ ## Examples
83
+
84
+ ### GET Request
85
+
86
+ ```javascript
87
+ // api/users.js
88
+
89
+ const users = [
90
+ { id: 1, name: 'Aziz' },
91
+ { id: 2, name: 'John' }
92
+ ];
93
+
94
+ module.exports = async function handler(req, res) {
95
+ if (req.method === 'GET') {
96
+ // Get specific user
97
+ if (req.query.id) {
98
+ const user = users.find(u => u.id === parseInt(req.query.id));
99
+ if (user) {
100
+ return res.status(200).json(user);
101
+ }
102
+ return res.status(404).json({ error: 'User not found' });
103
+ }
104
+
105
+ // Get all users
106
+ return res.status(200).json(users);
107
+ }
108
+
109
+ return res.status(405).json({ error: 'Method not allowed' });
110
+ };
111
+ ```
112
+
113
+ **Usage:**
114
+ ```javascript
115
+ // Get all users
116
+ const response = await fetchApi('/api/users');
117
+ const users = await response.json();
118
+
119
+ // Get specific user
120
+ const response = await fetchApi('/api/users?id=1');
121
+ const user = await response.json();
122
+ ```
123
+
124
+ ### POST Request
125
+
126
+ ```javascript
127
+ // api/users.js
128
+
129
+ module.exports = async function handler(req, res) {
130
+ if (req.method === 'POST') {
131
+ const { name, email } = req.body;
132
+
133
+ // Validate
134
+ if (!name || !email) {
135
+ return res.status(400).json({
136
+ error: 'Name and email are required'
137
+ });
138
+ }
139
+
140
+ // Create user
141
+ const newUser = {
142
+ id: Date.now(),
143
+ name,
144
+ email
145
+ };
146
+
147
+ return res.status(201).json(newUser);
148
+ }
149
+ };
150
+ ```
151
+
152
+ **Usage:**
153
+ ```javascript
154
+ const response = await fetchApi('/api/users', {
155
+ method: 'POST',
156
+ body: JSON.stringify({
157
+ name: 'Aziz',
158
+ email: 'aziz@example.com'
159
+ })
160
+ });
161
+ const user = await response.json();
162
+ ```
163
+
164
+ ### PUT Request
165
+
166
+ ```javascript
167
+ // api/users.js
168
+
169
+ module.exports = async function handler(req, res) {
170
+ if (req.method === 'PUT') {
171
+ const userId = req.query.id;
172
+ const updates = req.body;
173
+
174
+ // Update user logic here
175
+
176
+ return res.status(200).json({
177
+ message: 'User updated',
178
+ user: updatedUser
179
+ });
180
+ }
181
+ };
182
+ ```
183
+
184
+ **Usage:**
185
+ ```javascript
186
+ const response = await fetchApi('/api/users?id=1', {
187
+ method: 'PUT',
188
+ body: JSON.stringify({
189
+ name: 'New Name'
190
+ })
191
+ });
192
+ ```
193
+
194
+ ### DELETE Request
195
+
196
+ ```javascript
197
+ // api/users.js
198
+
199
+ module.exports = async function handler(req, res) {
200
+ if (req.method === 'DELETE') {
201
+ const userId = req.query.id;
202
+
203
+ // Delete user logic here
204
+
205
+ return res.status(200).json({
206
+ message: 'User deleted'
207
+ });
208
+ }
209
+ };
210
+ ```
211
+
212
+ **Usage:**
213
+ ```javascript
214
+ const response = await fetchApi('/api/users?id=1', {
215
+ method: 'DELETE'
216
+ });
217
+ ```
218
+
219
+ ### Multiple Methods
220
+
221
+ ```javascript
222
+ // api/users.js
223
+
224
+ module.exports = async function handler(req, res) {
225
+ switch (req.method) {
226
+ case 'GET':
227
+ // Handle GET
228
+ return res.status(200).json({ method: 'GET' });
229
+
230
+ case 'POST':
231
+ // Handle POST
232
+ return res.status(201).json({ method: 'POST' });
233
+
234
+ case 'PUT':
235
+ // Handle PUT
236
+ return res.status(200).json({ method: 'PUT' });
237
+
238
+ case 'DELETE':
239
+ // Handle DELETE
240
+ return res.status(200).json({ method: 'DELETE' });
241
+
242
+ default:
243
+ return res.status(405).json({
244
+ error: 'Method not allowed'
245
+ });
246
+ }
247
+ };
248
+ ```
249
+
250
+ ## Using in Components
251
+
252
+ ### Basic Fetch
253
+
254
+ ```jsx
255
+ function MyComponent() {
256
+ const [data, setData] = useState(null);
257
+ const [loading, setLoading] = useState(false);
258
+
259
+ const loadData = async () => {
260
+ setLoading(true);
261
+ try {
262
+ const response = await fetchApi('/api/users');
263
+ const users = await response.json();
264
+ setData(users);
265
+ } catch (error) {
266
+ console.error('Error:', error);
267
+ }
268
+ setLoading(false);
269
+ };
270
+
271
+ return (
272
+ <div>
273
+ <button onClick={loadData}>Load Users</button>
274
+ {loading && <p>Loading...</p>}
275
+ {data && <pre>{JSON.stringify(data, null, 2)}</pre>}
276
+ </div>
277
+ );
278
+ }
279
+ ```
280
+
281
+ ### With Error Handling
282
+
283
+ ```jsx
284
+ const [error, setError] = useState(null);
285
+
286
+ const loadData = async () => {
287
+ try {
288
+ const response = await fetchApi('/api/users');
289
+
290
+ if (!response.ok) {
291
+ throw new Error('Failed to fetch');
292
+ }
293
+
294
+ const users = await response.json();
295
+ setData(users);
296
+ setError(null);
297
+ } catch (err) {
298
+ setError(err.message);
299
+ setData(null);
300
+ }
301
+ };
302
+ ```
303
+
304
+ ## Database Integration
305
+
306
+ ### Using a Real Database
307
+
308
+ ```javascript
309
+ // api/users.js
310
+
311
+ // Example with a database (you need to install the package)
312
+ // npm install better-sqlite3
313
+
314
+ const Database = require('better-sqlite3');
315
+ const db = new Database('mydb.sqlite');
316
+
317
+ module.exports = async function handler(req, res) {
318
+ if (req.method === 'GET') {
319
+ const users = db.prepare('SELECT * FROM users').all();
320
+ return res.status(200).json(users);
321
+ }
322
+
323
+ if (req.method === 'POST') {
324
+ const { name, email } = req.body;
325
+ const result = db.prepare(
326
+ 'INSERT INTO users (name, email) VALUES (?, ?)'
327
+ ).run(name, email);
328
+
329
+ return res.status(201).json({
330
+ id: result.lastInsertRowid,
331
+ name,
332
+ email
333
+ });
334
+ }
335
+ };
336
+ ```
337
+
338
+ ### Using External APIs
339
+
340
+ ```javascript
341
+ // api/weather.js
342
+
343
+ module.exports = async function handler(req, res) {
344
+ const city = req.query.city || 'London';
345
+
346
+ try {
347
+ const response = await fetch(
348
+ `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=YOUR_KEY`
349
+ );
350
+ const data = await response.json();
351
+
352
+ return res.status(200).json(data);
353
+ } catch (error) {
354
+ return res.status(500).json({
355
+ error: 'Failed to fetch weather'
356
+ });
357
+ }
358
+ };
359
+ ```
360
+
361
+ ## Environment Variables
362
+
363
+ ```javascript
364
+ // api/config.js
365
+
366
+ module.exports = async function handler(req, res) {
367
+ // Access environment variables
368
+ const apiKey = process.env.API_KEY;
369
+ const dbUrl = process.env.DATABASE_URL;
370
+
371
+ return res.status(200).json({
372
+ hasApiKey: !!apiKey,
373
+ hasDbUrl: !!dbUrl
374
+ });
375
+ };
376
+ ```
377
+
378
+ Set environment variables:
379
+ ```bash
380
+ # Windows
381
+ set API_KEY=your_key
382
+ npm run dev
383
+
384
+ # Mac/Linux
385
+ API_KEY=your_key npm run dev
386
+ ```
387
+
388
+ ## Hot Reload
389
+
390
+ API routes support hot reload! When you save an API file:
391
+
392
+ 1. Dev server detects the change
393
+ 2. Reloads the API handler
394
+ 3. Next request uses the new code
395
+ 4. No server restart needed!
396
+
397
+ ## CORS
398
+
399
+ CORS is automatically enabled for all API routes:
400
+ ```
401
+ Access-Control-Allow-Origin: *
402
+ Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
403
+ Access-Control-Allow-Headers: Content-Type
404
+ ```
405
+
406
+ ## Error Handling
407
+
408
+ ### Server Errors
409
+
410
+ ```javascript
411
+ module.exports = async function handler(req, res) {
412
+ try {
413
+ // Your code here
414
+ const data = await someAsyncOperation();
415
+ return res.status(200).json(data);
416
+ } catch (error) {
417
+ console.error('API Error:', error);
418
+ return res.status(500).json({
419
+ error: 'Internal server error',
420
+ message: error.message
421
+ });
422
+ }
423
+ };
424
+ ```
425
+
426
+ ### Validation Errors
427
+
428
+ ```javascript
429
+ module.exports = async function handler(req, res) {
430
+ if (req.method === 'POST') {
431
+ const { name, email } = req.body;
432
+
433
+ if (!name) {
434
+ return res.status(400).json({
435
+ error: 'Name is required'
436
+ });
437
+ }
438
+
439
+ if (!email || !email.includes('@')) {
440
+ return res.status(400).json({
441
+ error: 'Valid email is required'
442
+ });
443
+ }
444
+
445
+ // Process valid data
446
+ }
447
+ };
448
+ ```
449
+
450
+ ## Status Codes
451
+
452
+ Common HTTP status codes:
453
+
454
+ - `200` - OK (successful GET, PUT, DELETE)
455
+ - `201` - Created (successful POST)
456
+ - `400` - Bad Request (validation error)
457
+ - `401` - Unauthorized (authentication required)
458
+ - `403` - Forbidden (no permission)
459
+ - `404` - Not Found (resource doesn't exist)
460
+ - `405` - Method Not Allowed (wrong HTTP method)
461
+ - `500` - Internal Server Error (server error)
462
+
463
+ ## Best Practices
464
+
465
+ ### 1. Always Handle Methods
466
+
467
+ ```javascript
468
+ module.exports = async function handler(req, res) {
469
+ if (req.method === 'GET') {
470
+ // Handle GET
471
+ } else {
472
+ return res.status(405).json({
473
+ error: 'Method not allowed'
474
+ });
475
+ }
476
+ };
477
+ ```
478
+
479
+ ### 2. Validate Input
480
+
481
+ ```javascript
482
+ if (!req.body.name || typeof req.body.name !== 'string') {
483
+ return res.status(400).json({ error: 'Invalid name' });
484
+ }
485
+ ```
486
+
487
+ ### 3. Use Try-Catch
488
+
489
+ ```javascript
490
+ try {
491
+ const data = await database.query();
492
+ return res.status(200).json(data);
493
+ } catch (error) {
494
+ return res.status(500).json({ error: error.message });
495
+ }
496
+ ```
497
+
498
+ ### 4. Return Early
499
+
500
+ ```javascript
501
+ if (!user) {
502
+ return res.status(404).json({ error: 'Not found' });
503
+ }
504
+
505
+ // Continue with logic
506
+ ```
507
+
508
+ ### 5. Use Async/Await
509
+
510
+ ```javascript
511
+ module.exports = async function handler(req, res) {
512
+ const data = await fetchData();
513
+ return res.status(200).json(data);
514
+ };
515
+ ```
516
+
517
+ ## Comparison with Next.js
518
+
519
+ | Feature | Aziz App | Next.js |
520
+ |---------|----------|---------|
521
+ | File-based routing | āœ… | āœ… |
522
+ | Server-side execution | āœ… | āœ… |
523
+ | Hot reload | āœ… | āœ… |
524
+ | Request/Response API | āœ… | āœ… |
525
+ | Dynamic routes | āŒ | āœ… |
526
+ | Middleware | āŒ | āœ… |
527
+ | Edge runtime | āŒ | āœ… |
528
+
529
+ ## Summary
530
+
531
+ - API routes run on the **server** (Node.js)
532
+ - Each file in `api/` becomes an endpoint
533
+ - Use `module.exports` to export the handler
534
+ - Access via `fetchApi('/api/routename')`
535
+ - Supports GET, POST, PUT, DELETE
536
+ - Hot reload enabled
537
+ - CORS enabled by default
538
+ - Just like Next.js API routes!
@@ -1,96 +1,12 @@
1
1
  /** @jsx h */
2
2
 
3
3
  // ============================================================
4
- // API ROUTE SYSTEM
5
- // Next.js-like API routes for client-side
6
- // Can be easily replaced with real backend calls
4
+ // API CLIENT
5
+ // Fetch-like API for making requests to backend API routes
6
+ // API routes run on the SERVER (Node.js), not in the browser
7
7
  // ============================================================
8
8
 
9
- // API routes registry
10
- const apiRoutes = {};
11
-
12
- // Register an API route
13
- function registerApiRoute(path, handler) {
14
- apiRoutes[path] = handler;
15
- console.log(`Registered API route: /api/${path}`);
16
- }
17
-
18
- // API request/response helpers
19
- class ApiRequest {
20
- constructor(method, body, query, params) {
21
- this.method = method;
22
- this.body = body;
23
- this.query = query;
24
- this.params = params;
25
- }
26
- }
27
-
28
- class ApiResponse {
29
- constructor() {
30
- this.statusCode = 200;
31
- this.headers = {};
32
- this.data = null;
33
- }
34
-
35
- status(code) {
36
- this.statusCode = code;
37
- return this;
38
- }
39
-
40
- json(data) {
41
- this.data = data;
42
- this.headers['Content-Type'] = 'application/json';
43
- return this;
44
- }
45
-
46
- send(data) {
47
- this.data = data;
48
- return this;
49
- }
50
- }
51
-
52
- // Execute an API route
53
- async function callApi(path, options = {}) {
54
- const {
55
- method = 'GET',
56
- body = null,
57
- query = {},
58
- params = {}
59
- } = options;
60
-
61
- // Find the route handler
62
- const handler = apiRoutes[path];
63
-
64
- if (!handler) {
65
- return {
66
- status: 404,
67
- data: { error: 'API route not found' }
68
- };
69
- }
70
-
71
- // Create request and response objects
72
- const req = new ApiRequest(method, body, query, params);
73
- const res = new ApiResponse();
74
-
75
- try {
76
- // Call the handler
77
- await handler(req, res);
78
-
79
- return {
80
- status: res.statusCode,
81
- data: res.data,
82
- headers: res.headers
83
- };
84
- } catch (error) {
85
- console.error(`API Error on ${path}:`, error);
86
- return {
87
- status: 500,
88
- data: { error: error.message }
89
- };
90
- }
91
- }
92
-
93
- // Fetch-like API for making requests
9
+ // Fetch-like API for making requests to backend
94
10
  async function fetchApi(path, options = {}) {
95
11
  const {
96
12
  method = 'GET',
@@ -98,51 +14,31 @@ async function fetchApi(path, options = {}) {
98
14
  headers = {}
99
15
  } = options;
100
16
 
101
- // Parse query params from path
102
- const [routePath, queryString] = path.split('?');
103
- const query = {};
104
- if (queryString) {
105
- queryString.split('&').forEach(param => {
106
- const [key, value] = param.split('=');
107
- query[decodeURIComponent(key)] = decodeURIComponent(value);
108
- });
109
- }
110
-
111
- // Parse body if it's JSON
112
- let parsedBody = body;
113
- if (body && typeof body === 'string') {
114
- try {
115
- parsedBody = JSON.parse(body);
116
- } catch (e) {
117
- parsedBody = body;
17
+ const fetchOptions = {
18
+ method,
19
+ headers: {
20
+ 'Content-Type': 'application/json',
21
+ ...headers
118
22
  }
119
- }
23
+ };
120
24
 
121
- const result = await callApi(routePath.replace('/api/', ''), {
122
- method,
123
- body: parsedBody,
124
- query
125
- });
25
+ if (body) {
26
+ fetchOptions.body = typeof body === 'string' ? body : JSON.stringify(body);
27
+ }
126
28
 
127
- // Return a fetch-like response
128
- return {
129
- ok: result.status >= 200 && result.status < 300,
130
- status: result.status,
131
- statusText: result.status === 200 ? 'OK' : 'Error',
132
- headers: result.headers,
133
- json: async () => result.data,
134
- text: async () => JSON.stringify(result.data)
135
- };
29
+ try {
30
+ const response = await fetch(path, fetchOptions);
31
+ return response;
32
+ } catch (error) {
33
+ console.error('API Error:', error);
34
+ throw error;
35
+ }
136
36
  }
137
37
 
138
38
  // Export to global scope
139
- window.registerApiRoute = registerApiRoute;
140
39
  window.fetchApi = fetchApi;
141
- window.callApi = callApi;
142
40
 
143
41
  // Also make available without window prefix
144
42
  if (typeof globalThis !== 'undefined') {
145
- globalThis.registerApiRoute = registerApiRoute;
146
43
  globalThis.fetchApi = fetchApi;
147
- globalThis.callApi = callApi;
148
44
  }
@@ -7,9 +7,152 @@ const { exec } = require('child_process');
7
7
 
8
8
  const PORT = process.env.PORT || 3000;
9
9
  const clients = new Set();
10
+ const apiHandlers = {};
10
11
 
11
12
  console.log('šŸš€ Dev server starting...\n');
12
13
 
14
+ // Load API routes from api/ folder
15
+ function loadApiRoutes() {
16
+ const apiDir = path.join(process.cwd(), 'api');
17
+ if (!fs.existsSync(apiDir)) {
18
+ console.log('āš ļø No api/ folder found\n');
19
+ return;
20
+ }
21
+
22
+ const files = fs.readdirSync(apiDir).filter(f => f.endsWith('.js'));
23
+ console.log(`šŸ“” Loading ${files.length} API routes...\n`);
24
+
25
+ files.forEach(file => {
26
+ const routeName = path.basename(file, '.js');
27
+ const filePath = path.join(apiDir, file);
28
+
29
+ try {
30
+ // Clear require cache to allow hot reload
31
+ delete require.cache[require.resolve(filePath)];
32
+
33
+ // Load the API handler
34
+ const handler = require(filePath);
35
+
36
+ if (typeof handler === 'function') {
37
+ apiHandlers[routeName] = handler;
38
+ console.log(` āœ… /api/${routeName}`);
39
+ } else if (handler.default && typeof handler.default === 'function') {
40
+ apiHandlers[routeName] = handler.default;
41
+ console.log(` āœ… /api/${routeName}`);
42
+ } else {
43
+ console.log(` āš ļø /api/${routeName} - No default export`);
44
+ }
45
+ } catch (error) {
46
+ console.error(` āŒ /api/${routeName} - ${error.message}`);
47
+ }
48
+ });
49
+
50
+ console.log('');
51
+ }
52
+
53
+ // Parse request body
54
+ function parseBody(req) {
55
+ return new Promise((resolve, reject) => {
56
+ let body = '';
57
+ req.on('data', chunk => {
58
+ body += chunk.toString();
59
+ });
60
+ req.on('end', () => {
61
+ try {
62
+ if (body && req.headers['content-type']?.includes('application/json')) {
63
+ resolve(JSON.parse(body));
64
+ } else {
65
+ resolve(body);
66
+ }
67
+ } catch (e) {
68
+ resolve(body);
69
+ }
70
+ });
71
+ req.on('error', reject);
72
+ });
73
+ }
74
+
75
+ // Parse query string
76
+ function parseQuery(url) {
77
+ const query = {};
78
+ const queryString = url.split('?')[1];
79
+ if (queryString) {
80
+ queryString.split('&').forEach(param => {
81
+ const [key, value] = param.split('=');
82
+ query[decodeURIComponent(key)] = decodeURIComponent(value || '');
83
+ });
84
+ }
85
+ return query;
86
+ }
87
+
88
+ // Handle API requests
89
+ async function handleApiRequest(req, res) {
90
+ const urlPath = req.url.split('?')[0];
91
+ const routeName = urlPath.replace('/api/', '');
92
+
93
+ const handler = apiHandlers[routeName];
94
+
95
+ if (!handler) {
96
+ res.writeHead(404, { 'Content-Type': 'application/json' });
97
+ res.end(JSON.stringify({ error: 'API route not found' }));
98
+ return;
99
+ }
100
+
101
+ try {
102
+ // Parse request
103
+ const body = await parseBody(req);
104
+ const query = parseQuery(req.url);
105
+
106
+ // Create Next.js-like req/res objects
107
+ const apiReq = {
108
+ method: req.method,
109
+ body: body,
110
+ query: query,
111
+ headers: req.headers,
112
+ url: req.url
113
+ };
114
+
115
+ const apiRes = {
116
+ statusCode: 200,
117
+ headers: {},
118
+ status(code) {
119
+ this.statusCode = code;
120
+ return this;
121
+ },
122
+ json(data) {
123
+ res.writeHead(this.statusCode, {
124
+ 'Content-Type': 'application/json',
125
+ 'Access-Control-Allow-Origin': '*',
126
+ ...this.headers
127
+ });
128
+ res.end(JSON.stringify(data));
129
+ return this;
130
+ },
131
+ send(data) {
132
+ res.writeHead(this.statusCode, {
133
+ 'Content-Type': 'text/plain',
134
+ 'Access-Control-Allow-Origin': '*',
135
+ ...this.headers
136
+ });
137
+ res.end(data);
138
+ return this;
139
+ },
140
+ setHeader(key, value) {
141
+ this.headers[key] = value;
142
+ return this;
143
+ }
144
+ };
145
+
146
+ // Call the handler
147
+ await handler(apiReq, apiRes);
148
+
149
+ } catch (error) {
150
+ console.error(`āŒ API Error on /api/${routeName}:`, error);
151
+ res.writeHead(500, { 'Content-Type': 'application/json' });
152
+ res.end(JSON.stringify({ error: error.message }));
153
+ }
154
+ }
155
+
13
156
  // Function to generate imports
14
157
  function generateImports() {
15
158
  console.log('šŸ”„ Regenerating imports...');
@@ -38,7 +181,24 @@ function notifyClients() {
38
181
  }
39
182
 
40
183
  // Create HTTP server
41
- const server = http.createServer((req, res) => {
184
+ const server = http.createServer(async (req, res) => {
185
+ // Handle API routes
186
+ if (req.url.startsWith('/api/')) {
187
+ await handleApiRequest(req, res);
188
+ return;
189
+ }
190
+
191
+ // Handle CORS preflight
192
+ if (req.method === 'OPTIONS') {
193
+ res.writeHead(200, {
194
+ 'Access-Control-Allow-Origin': '*',
195
+ 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
196
+ 'Access-Control-Allow-Headers': 'Content-Type'
197
+ });
198
+ res.end();
199
+ return;
200
+ }
201
+
42
202
  // Strip query parameters for file serving (cache busting)
43
203
  let filePath = '.' + req.url.split('?')[0];
44
204
  if (filePath === './') {
@@ -170,6 +330,12 @@ watchDirs.forEach(dir => {
170
330
  clearTimeout(reloadTimeout);
171
331
  }
172
332
 
333
+ // Reload API routes if api/ folder changed
334
+ if (dir === 'api' && filename.endsWith('.js')) {
335
+ console.log('šŸ”„ Reloading API routes...');
336
+ loadApiRoutes();
337
+ }
338
+
173
339
  // For CSS changes, just reload without regenerating imports
174
340
  if (filename.endsWith('.css')) {
175
341
  reloadTimeout = setTimeout(() => {
@@ -190,6 +356,9 @@ console.log('\nāœ… Dev server running with live reload!');
190
356
  console.log('šŸ’” Create/modify files and browser will auto-refresh');
191
357
  console.log('ā¹ļø Press Ctrl+C to stop\n');
192
358
 
359
+ // Load API routes
360
+ loadApiRoutes();
361
+
193
362
  // Start server
194
363
  startServer(PORT);
195
364
 
@@ -31,11 +31,9 @@ function scanDirectory(dir, extensions = []) {
31
31
  }
32
32
 
33
33
  // Scan for files
34
- const apiRoutes = scanDirectory('api', ['.js']);
35
34
  const components = scanDirectory('components', ['.jsx', '.js']);
36
35
  const pages = scanDirectory('pages', ['.jsx', '.js']);
37
36
 
38
- console.log(`šŸ“” Found ${apiRoutes.length} API routes`);
39
37
  console.log(`🧩 Found ${components.length} components`);
40
38
  console.log(`šŸ“„ Found ${pages.length} pages\n`);
41
39
 
@@ -48,14 +46,6 @@ scriptTags += ' <script type="text/babel" src="modules/router.js"></script>\n
48
46
  scriptTags += ' <script type="text/babel" src="modules/state.js"></script>\n';
49
47
  scriptTags += ' <script type="text/babel" src="modules/api.js"></script>\n\n';
50
48
 
51
- if (apiRoutes.length > 0) {
52
- scriptTags += ' <!-- Load API routes -->\n';
53
- apiRoutes.forEach(route => {
54
- scriptTags += ` <script type="text/babel" src="${route}"></script>\n`;
55
- });
56
- scriptTags += '\n';
57
- }
58
-
59
49
  if (components.length > 0) {
60
50
  scriptTags += ' <!-- Load shared components -->\n';
61
51
  components.forEach(component => {