create-aziz-app 2.0.10 → 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.
@@ -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!
@@ -2,15 +2,16 @@
2
2
 
3
3
  ## Overview
4
4
 
5
- The dev server provides a smooth development experience with live reload, automatic import generation, and file watching.
5
+ The dev server provides a smooth development experience with live reload using WebSocket, automatic import generation, and file watching.
6
6
 
7
7
  ## Features
8
8
 
9
- ### 🔄 Live Reload
9
+ ### 🔄 Live Reload (WebSocket-based)
10
10
  - **Automatic browser refresh** when you save files
11
11
  - **Visual indicator** in bottom-right corner shows connection status
12
- - **Smart caching** - forces cache clear on reload to always show latest changes
12
+ - **WebSocket connection** - reliable, fast, no caching issues
13
13
  - **CSS hot reload** - instant updates without regenerating imports
14
+ - **Always loaded** - script is part of your HTML, not injected
14
15
 
15
16
  ### 👀 File Watching
16
17
  The dev server watches these directories:
@@ -41,22 +42,36 @@ Then open the URL shown in console (usually `http://localhost:3000/`)
41
42
  ## Visual Indicators
42
43
 
43
44
  The live reload indicator in the bottom-right corner shows:
44
- - 🔌 **Connecting...** - Initial connection
45
- - ✅ **Live Reload Active** - Connected and watching (fades after 2s)
46
- - 🔄 **Reloading...** - Changes detected, refreshing page
47
- - ⚠️ **Reconnecting...** - Connection lost, attempting to reconnect
45
+ - 🔌 **Connecting...** - Initial connection (gray/green)
46
+ - ✅ **Live Reload** - Connected and watching (green, fades to 30%)
47
+ - 🔄 **Reloading...** - Changes detected, refreshing page (blue)
48
+ - ⚠️ **Disconnected** - Connection lost, attempting to reconnect (orange)
49
+ - ❌ **Offline** - Max reconnection attempts reached (red)
50
+
51
+ **Click the indicator** to manually reload the page.
48
52
 
49
53
  Hover over the indicator to make it fully visible.
50
54
 
51
55
  ## How It Works
52
56
 
53
57
  1. **Server starts** and generates initial imports
54
- 2. **Browser connects** via Server-Sent Events (SSE)
55
- 3. **File watcher** detects changes in watched directories
56
- 4. **Debouncing** prevents multiple rapid reloads (300ms for CSS, 500ms for JS)
57
- 5. **Import regeneration** (for JS/JSX changes only)
58
- 6. **Browser notification** via SSE
59
- 7. **Page reload** with cache busting
58
+ 2. **Browser loads** `live-reload-client.js` (always in HTML)
59
+ 3. **WebSocket connects** to dev server
60
+ 4. **File watcher** detects changes in watched directories
61
+ 5. **Debouncing** prevents multiple rapid reloads (300ms for CSS, 500ms for JS)
62
+ 6. **Import regeneration** (for JS/JSX changes only)
63
+ 7. **WebSocket message** sent to all connected browsers
64
+ 8. **Page reload** happens immediately
65
+
66
+ ## Why WebSocket?
67
+
68
+ Previous versions used Server-Sent Events (SSE) with runtime injection, which had caching issues. The new approach:
69
+
70
+ - ✅ **Always loaded** - Script is in HTML, not injected at runtime
71
+ - ✅ **No caching issues** - Browser always has the script
72
+ - ✅ **Bidirectional** - WebSocket allows two-way communication
73
+ - ✅ **Reliable** - Built-in reconnection logic
74
+ - ✅ **Fast** - Instant notifications, no polling
60
75
 
61
76
  ## Cache Control
62
77
 
@@ -67,28 +82,52 @@ Pragma: no-cache
67
82
  Expires: 0
68
83
  ```
69
84
 
70
- This ensures you always see the latest changes without needing Ctrl+Shift+R.
85
+ Plus, `app.html` has meta tags:
86
+ ```html
87
+ <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
88
+ <meta http-equiv="Pragma" content="no-cache">
89
+ <meta http-equiv="Expires" content="0">
90
+ ```
71
91
 
72
92
  ## Troubleshooting
73
93
 
94
+ ### Indicator stuck on "Connecting..."?
95
+
96
+ 1. **Check dev server is running** - Terminal should show "✅ Dev server running"
97
+ 2. **Check browser console** (F12) - Look for WebSocket errors
98
+ 3. **Check port** - Browser URL should match server URL
99
+ 4. **Firewall** - Allow Node.js through firewall
100
+ 5. **Try different browser** - Rule out browser-specific issues
101
+
74
102
  ### Changes not showing?
75
- 1. Check the visual indicator - is it green?
76
- 2. Open browser console - look for "✅ Live reload connected"
77
- 3. Check terminal - does it show "🔄 Notifying X browser(s) to reload..."?
78
- 4. Try hard refresh once: Ctrl+Shift+R (Windows) or Cmd+Shift+R (Mac)
103
+
104
+ 1. **Check indicator is green** - "✅ Live Reload"
105
+ 2. **Check terminal** - Should show "📝 Detected change: ..."
106
+ 3. **Check file was saved** - No unsaved indicator in editor
107
+ 4. **Check file location** - Must be in watched directories
108
+ 5. **Check for errors** - Browser console (F12) for JavaScript errors
109
+
110
+ ### WebSocket connection failed?
111
+
112
+ 1. **Port mismatch** - Check browser URL matches server port
113
+ 2. **Proxy/VPN** - May block WebSocket connections
114
+ 3. **Browser extension** - Ad blockers can interfere
115
+ 4. **Try incognito mode** - Rule out extensions
79
116
 
80
117
  ### Port already in use?
81
- The server will automatically try the next port (3001, 3002, etc.)
82
118
 
83
- ### Live reload disconnected?
84
- The page will automatically try to reconnect after 2 seconds.
119
+ The server automatically tries the next port. Check terminal for actual port:
120
+ ```
121
+ 🌐 Server running at http://localhost:3001/
122
+ ```
85
123
 
86
124
  ## Performance
87
125
 
88
126
  - **Debouncing** prevents reload spam when saving multiple files
89
127
  - **CSS-only changes** skip import regeneration for faster updates
90
- - **SSE connection** is lightweight and efficient
128
+ - **WebSocket** is lightweight and efficient
91
129
  - **Multiple browsers** can connect simultaneously
130
+ - **Automatic reconnection** if connection drops
92
131
 
93
132
  ## Development Tips
94
133
 
@@ -96,3 +135,50 @@ The page will automatically try to reconnect after 2 seconds.
96
135
  2. The visual indicator helps confirm live reload is working
97
136
  3. CSS changes are faster than JS changes (no import regeneration)
98
137
  4. Multiple browser tabs will all reload simultaneously
138
+ 5. Click the indicator to manually reload if needed
139
+
140
+ ## Production
141
+
142
+ The live reload script only runs in development (localhost). In production:
143
+ - Script detects non-localhost hostname
144
+ - Exits immediately without connecting
145
+ - No performance impact
146
+ - No visual indicator
147
+
148
+ ## Technical Details
149
+
150
+ ### WebSocket Protocol
151
+
152
+ The dev server implements a simple WebSocket server without external dependencies:
153
+ - Uses Node.js `http` module's `upgrade` event
154
+ - Performs WebSocket handshake manually
155
+ - Sends text frames to connected clients
156
+ - Handles connection cleanup automatically
157
+
158
+ ### Message Format
159
+
160
+ Server sends a single message type:
161
+ - `"reload"` - Triggers browser reload
162
+
163
+ ### Reconnection Logic
164
+
165
+ Client attempts to reconnect:
166
+ - Max 10 attempts
167
+ - 2-second delay between attempts
168
+ - Exponential backoff could be added if needed
169
+
170
+ ## Comparison with Other Tools
171
+
172
+ | Feature | Aziz App | Live Server | Vite |
173
+ |---------|----------|-------------|------|
174
+ | Setup | Zero config | Zero config | Config file |
175
+ | Speed | Fast | Fast | Very fast |
176
+ | WebSocket | ✅ | ✅ | ✅ |
177
+ | Auto-import | ✅ | ❌ | ✅ |
178
+ | Visual indicator | ✅ | ❌ | ❌ |
179
+ | Dependencies | None | None | Many |
180
+
181
+ ## Summary
182
+
183
+ The dev server provides a reliable, fast live reload experience using WebSocket. The script is always loaded (not injected), eliminating caching issues. File watching, debouncing, and automatic reconnection make development smooth and efficient.
184
+