create-aziz-app 2.0.12 → 2.0.14
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 +3 -2
- package/template/README.md +18 -24
- package/template/api/createUser.js +69 -0
- package/template/api/getUser.js +60 -0
- package/template/api/getUserWithDB.js +65 -0
- package/template/api/hello.js +19 -6
- package/template/api/loginUser.js +61 -0
- package/template/api/users.js +132 -37
- package/template/components/Navbar.jsx +7 -6
- package/template/docs/NEXTJS-APP-ROUTER.md +536 -0
- package/template/docs/NEXTJS-COMPARISON.md +473 -0
- package/template/lib/db.js +67 -0
- package/template/models/User.js +102 -0
- package/template/modules/next-response.js +58 -0
- package/template/modules/state.js +225 -31
- package/template/pages/HooksDemo.jsx +194 -0
- package/template/scripts/dev-server.js +108 -47
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
# Next.js Comparison
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Aziz App is a **lightweight Next.js clone** with all the core benefits but zero dependencies and minimal complexity.
|
|
6
|
+
|
|
7
|
+
## Feature Comparison
|
|
8
|
+
|
|
9
|
+
| Feature | Aziz App | Next.js | Notes |
|
|
10
|
+
|---------|----------|---------|-------|
|
|
11
|
+
| **React Hooks** | ✅ | ✅ | useState, useEffect, useMemo, useCallback, useRef, useReducer |
|
|
12
|
+
| **File-based Routing** | ✅ | ✅ | pages/ folder → routes |
|
|
13
|
+
| **API Routes** | ✅ | ✅ | api/ folder → endpoints |
|
|
14
|
+
| **Server-side API** | ✅ | ✅ | Real Node.js backend |
|
|
15
|
+
| **Hot Reload** | ✅ | ✅ | WebSocket-based |
|
|
16
|
+
| **Auto Import** | ✅ | ✅ | No manual imports needed |
|
|
17
|
+
| **Zero Config** | ✅ | ❌ | No config files needed |
|
|
18
|
+
| **Bundle Size** | **~50KB** | ~300KB+ | 6x smaller! |
|
|
19
|
+
| **Dependencies** | **0** | 20+ | No node_modules bloat |
|
|
20
|
+
| **Build Time** | **Instant** | Slow | No build step |
|
|
21
|
+
| **SSR** | ❌ | ✅ | Client-side only |
|
|
22
|
+
| **SSG** | ❌ | ✅ | Client-side only |
|
|
23
|
+
| **Image Optimization** | ❌ | ✅ | Use CDN instead |
|
|
24
|
+
| **TypeScript** | ❌ | ✅ | Pure JavaScript |
|
|
25
|
+
| **Middleware** | ❌ | ✅ | Keep it simple |
|
|
26
|
+
|
|
27
|
+
## React Hooks - Identical API
|
|
28
|
+
|
|
29
|
+
### useState
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
// Next.js
|
|
33
|
+
import { useState } from 'react';
|
|
34
|
+
const [count, setCount] = useState(0);
|
|
35
|
+
|
|
36
|
+
// Aziz App - EXACTLY THE SAME!
|
|
37
|
+
const [count, setCount] = useState(0);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### useEffect
|
|
41
|
+
|
|
42
|
+
```javascript
|
|
43
|
+
// Next.js
|
|
44
|
+
import { useEffect } from 'react';
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
console.log('Mounted!');
|
|
47
|
+
return () => console.log('Cleanup!');
|
|
48
|
+
}, [dependency]);
|
|
49
|
+
|
|
50
|
+
// Aziz App - EXACTLY THE SAME!
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
console.log('Mounted!');
|
|
53
|
+
return () => console.log('Cleanup!');
|
|
54
|
+
}, [dependency]);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### useMemo
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
// Next.js
|
|
61
|
+
import { useMemo } from 'react';
|
|
62
|
+
const value = useMemo(() => expensiveCalc(), [dep]);
|
|
63
|
+
|
|
64
|
+
// Aziz App - EXACTLY THE SAME!
|
|
65
|
+
const value = useMemo(() => expensiveCalc(), [dep]);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### useCallback
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
// Next.js
|
|
72
|
+
import { useCallback } from 'react';
|
|
73
|
+
const callback = useCallback(() => doSomething(), [dep]);
|
|
74
|
+
|
|
75
|
+
// Aziz App - EXACTLY THE SAME!
|
|
76
|
+
const callback = useCallback(() => doSomething(), [dep]);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### useRef
|
|
80
|
+
|
|
81
|
+
```javascript
|
|
82
|
+
// Next.js
|
|
83
|
+
import { useRef } from 'react';
|
|
84
|
+
const ref = useRef(null);
|
|
85
|
+
|
|
86
|
+
// Aziz App - EXACTLY THE SAME!
|
|
87
|
+
const ref = useRef(null);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### useReducer
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
// Next.js
|
|
94
|
+
import { useReducer } from 'react';
|
|
95
|
+
const [state, dispatch] = useReducer(reducer, initialState);
|
|
96
|
+
|
|
97
|
+
// Aziz App - EXACTLY THE SAME!
|
|
98
|
+
const [state, dispatch] = useReducer(reducer, initialState);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## API Routes - Identical API
|
|
102
|
+
|
|
103
|
+
### Basic Route
|
|
104
|
+
|
|
105
|
+
```javascript
|
|
106
|
+
// Next.js (pages/api/hello.js)
|
|
107
|
+
export default async function handler(req, res) {
|
|
108
|
+
res.status(200).json({ message: 'Hello' });
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Aziz App (api/hello.js) - EXACTLY THE SAME!
|
|
112
|
+
export default async function handler(req, res) {
|
|
113
|
+
res.status(200).json({ message: 'Hello' });
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Request Object
|
|
118
|
+
|
|
119
|
+
```javascript
|
|
120
|
+
// Both Next.js and Aziz App
|
|
121
|
+
{
|
|
122
|
+
method: 'GET' | 'POST' | 'PUT' | 'DELETE',
|
|
123
|
+
body: {}, // Parsed JSON
|
|
124
|
+
query: {}, // URL parameters
|
|
125
|
+
headers: {}, // Request headers
|
|
126
|
+
url: string // Full URL
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Response Methods
|
|
131
|
+
|
|
132
|
+
```javascript
|
|
133
|
+
// Both Next.js and Aziz App
|
|
134
|
+
res.status(200) // Set status
|
|
135
|
+
res.json({ data: 'value' }) // Send JSON
|
|
136
|
+
res.send('text') // Send text
|
|
137
|
+
res.setHeader('X-Custom', 'value') // Set header
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### CRUD Example
|
|
141
|
+
|
|
142
|
+
```javascript
|
|
143
|
+
// Works identically in both!
|
|
144
|
+
export default async function handler(req, res) {
|
|
145
|
+
switch (req.method) {
|
|
146
|
+
case 'GET':
|
|
147
|
+
return res.status(200).json({ users: [] });
|
|
148
|
+
case 'POST':
|
|
149
|
+
return res.status(201).json({ created: true });
|
|
150
|
+
case 'PUT':
|
|
151
|
+
return res.status(200).json({ updated: true });
|
|
152
|
+
case 'DELETE':
|
|
153
|
+
return res.status(200).json({ deleted: true });
|
|
154
|
+
default:
|
|
155
|
+
return res.status(405).json({ error: 'Method not allowed' });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## File-based Routing
|
|
161
|
+
|
|
162
|
+
### Pages
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
// Next.js
|
|
166
|
+
pages/
|
|
167
|
+
├── index.js → /
|
|
168
|
+
├── about.js → /about
|
|
169
|
+
└── contact.js → /contact
|
|
170
|
+
|
|
171
|
+
// Aziz App - Same concept!
|
|
172
|
+
pages/
|
|
173
|
+
├── Home.jsx → #/home
|
|
174
|
+
├── About.jsx → #/about
|
|
175
|
+
└── Contact.jsx → #/contact
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Auto-Registration
|
|
179
|
+
|
|
180
|
+
```javascript
|
|
181
|
+
// Next.js - Automatic
|
|
182
|
+
// Just create the file
|
|
183
|
+
|
|
184
|
+
// Aziz App - Automatic too!
|
|
185
|
+
// Just name your function: AboutPage()
|
|
186
|
+
function AboutPage() {
|
|
187
|
+
return <div><h1>About</h1></div>;
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Data Fetching
|
|
192
|
+
|
|
193
|
+
### Client-side Fetching
|
|
194
|
+
|
|
195
|
+
```javascript
|
|
196
|
+
// Next.js
|
|
197
|
+
import { useState, useEffect } from 'react';
|
|
198
|
+
|
|
199
|
+
function Page() {
|
|
200
|
+
const [data, setData] = useState(null);
|
|
201
|
+
|
|
202
|
+
useEffect(() => {
|
|
203
|
+
fetch('/api/users')
|
|
204
|
+
.then(res => res.json())
|
|
205
|
+
.then(setData);
|
|
206
|
+
}, []);
|
|
207
|
+
|
|
208
|
+
return <div>{data?.message}</div>;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Aziz App - EXACTLY THE SAME!
|
|
212
|
+
function Page() {
|
|
213
|
+
const [data, setData] = useState(null);
|
|
214
|
+
|
|
215
|
+
useEffect(() => {
|
|
216
|
+
fetch('/api/users')
|
|
217
|
+
.then(res => res.json())
|
|
218
|
+
.then(setData);
|
|
219
|
+
}, []);
|
|
220
|
+
|
|
221
|
+
return <div>{data?.message}</div>;
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Custom Hook
|
|
226
|
+
|
|
227
|
+
```javascript
|
|
228
|
+
// Both Next.js and Aziz App
|
|
229
|
+
function useFetch(url) {
|
|
230
|
+
const [data, setData] = useState(null);
|
|
231
|
+
const [loading, setLoading] = useState(true);
|
|
232
|
+
|
|
233
|
+
useEffect(() => {
|
|
234
|
+
fetch(url)
|
|
235
|
+
.then(res => res.json())
|
|
236
|
+
.then(data => {
|
|
237
|
+
setData(data);
|
|
238
|
+
setLoading(false);
|
|
239
|
+
});
|
|
240
|
+
}, [url]);
|
|
241
|
+
|
|
242
|
+
return { data, loading };
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## JSX Syntax
|
|
247
|
+
|
|
248
|
+
### Components
|
|
249
|
+
|
|
250
|
+
```jsx
|
|
251
|
+
// Next.js
|
|
252
|
+
export default function Button({ onClick, children }) {
|
|
253
|
+
return <button onClick={onClick}>{children}</button>;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Aziz App - Same JSX!
|
|
257
|
+
function Button({ onClick, children }) {
|
|
258
|
+
return <button onClick={onClick}>{children}</button>;
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Props
|
|
263
|
+
|
|
264
|
+
```jsx
|
|
265
|
+
// Both support the same props
|
|
266
|
+
<div
|
|
267
|
+
class="container"
|
|
268
|
+
style={{ color: 'red' }}
|
|
269
|
+
onClick={() => alert('Hi')}
|
|
270
|
+
>
|
|
271
|
+
Content
|
|
272
|
+
</div>
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Development Experience
|
|
276
|
+
|
|
277
|
+
### Hot Reload
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
// Next.js
|
|
281
|
+
1. Save file
|
|
282
|
+
2. Fast Refresh
|
|
283
|
+
3. State preserved
|
|
284
|
+
|
|
285
|
+
// Aziz App
|
|
286
|
+
1. Save file
|
|
287
|
+
2. WebSocket reload
|
|
288
|
+
3. Full page reload (state reset)
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Error Messages
|
|
292
|
+
|
|
293
|
+
```
|
|
294
|
+
// Next.js
|
|
295
|
+
- Detailed error overlay
|
|
296
|
+
- Stack traces
|
|
297
|
+
- Suggestions
|
|
298
|
+
|
|
299
|
+
// Aziz App
|
|
300
|
+
- Browser console errors
|
|
301
|
+
- Simpler debugging
|
|
302
|
+
- Less magic
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## When to Use Each
|
|
306
|
+
|
|
307
|
+
### Use Aziz App When:
|
|
308
|
+
|
|
309
|
+
✅ Building simple SPAs
|
|
310
|
+
✅ Learning React concepts
|
|
311
|
+
✅ Prototyping quickly
|
|
312
|
+
✅ Want zero dependencies
|
|
313
|
+
✅ Don't need SSR/SSG
|
|
314
|
+
✅ Want instant startup
|
|
315
|
+
✅ Prefer simplicity
|
|
316
|
+
|
|
317
|
+
### Use Next.js When:
|
|
318
|
+
|
|
319
|
+
✅ Need SEO (SSR/SSG)
|
|
320
|
+
✅ Building large apps
|
|
321
|
+
✅ Need image optimization
|
|
322
|
+
✅ Want TypeScript
|
|
323
|
+
✅ Need middleware
|
|
324
|
+
✅ Want edge functions
|
|
325
|
+
✅ Building production apps
|
|
326
|
+
|
|
327
|
+
## Migration Path
|
|
328
|
+
|
|
329
|
+
### From Aziz App to Next.js
|
|
330
|
+
|
|
331
|
+
1. **Pages** - Rename files, adjust exports
|
|
332
|
+
2. **API Routes** - Copy as-is (same API!)
|
|
333
|
+
3. **Hooks** - No changes needed (same API!)
|
|
334
|
+
4. **Components** - Minor adjustments
|
|
335
|
+
5. **Styling** - Add CSS modules if needed
|
|
336
|
+
|
|
337
|
+
### From Next.js to Aziz App
|
|
338
|
+
|
|
339
|
+
1. **Remove SSR/SSG** - Convert to client-side
|
|
340
|
+
2. **Pages** - Adjust file names
|
|
341
|
+
3. **API Routes** - Copy as-is (same API!)
|
|
342
|
+
4. **Hooks** - No changes needed (same API!)
|
|
343
|
+
5. **Remove dependencies** - Delete node_modules
|
|
344
|
+
|
|
345
|
+
## Performance
|
|
346
|
+
|
|
347
|
+
### Bundle Size
|
|
348
|
+
|
|
349
|
+
```
|
|
350
|
+
Next.js Production Build:
|
|
351
|
+
- Framework: ~300KB
|
|
352
|
+
- Runtime: ~100KB
|
|
353
|
+
- Total: ~400KB+
|
|
354
|
+
|
|
355
|
+
Aziz App:
|
|
356
|
+
- Framework: ~50KB
|
|
357
|
+
- Runtime: 0KB (browser native)
|
|
358
|
+
- Total: ~50KB
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Startup Time
|
|
362
|
+
|
|
363
|
+
```
|
|
364
|
+
Next.js:
|
|
365
|
+
- npm install: 2-5 minutes
|
|
366
|
+
- npm run dev: 10-30 seconds
|
|
367
|
+
- First load: 2-5 seconds
|
|
368
|
+
|
|
369
|
+
Aziz App:
|
|
370
|
+
- npm install: 5 seconds
|
|
371
|
+
- npm run dev: <1 second
|
|
372
|
+
- First load: <1 second
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Build Time
|
|
376
|
+
|
|
377
|
+
```
|
|
378
|
+
Next.js:
|
|
379
|
+
- Development: 10-30 seconds
|
|
380
|
+
- Production: 1-5 minutes
|
|
381
|
+
|
|
382
|
+
Aziz App:
|
|
383
|
+
- Development: Instant
|
|
384
|
+
- Production: No build needed
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
## Code Examples
|
|
388
|
+
|
|
389
|
+
### Counter Component
|
|
390
|
+
|
|
391
|
+
```jsx
|
|
392
|
+
// Works identically in both!
|
|
393
|
+
function Counter() {
|
|
394
|
+
const [count, setCount] = useState(0);
|
|
395
|
+
|
|
396
|
+
return (
|
|
397
|
+
<div>
|
|
398
|
+
<p>Count: {count}</p>
|
|
399
|
+
<button onClick={() => setCount(count + 1)}>
|
|
400
|
+
Increment
|
|
401
|
+
</button>
|
|
402
|
+
</div>
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Form with Validation
|
|
408
|
+
|
|
409
|
+
```jsx
|
|
410
|
+
// Works identically in both!
|
|
411
|
+
function ContactForm() {
|
|
412
|
+
const [name, setName] = useState('');
|
|
413
|
+
const [email, setEmail] = useState('');
|
|
414
|
+
const [error, setError] = useState('');
|
|
415
|
+
|
|
416
|
+
const handleSubmit = async (e) => {
|
|
417
|
+
e.preventDefault();
|
|
418
|
+
|
|
419
|
+
if (!name || !email) {
|
|
420
|
+
setError('All fields required');
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const res = await fetch('/api/contact', {
|
|
425
|
+
method: 'POST',
|
|
426
|
+
headers: { 'Content-Type': 'application/json' },
|
|
427
|
+
body: JSON.stringify({ name, email })
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
if (res.ok) {
|
|
431
|
+
alert('Sent!');
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
return (
|
|
436
|
+
<form onSubmit={handleSubmit}>
|
|
437
|
+
<input
|
|
438
|
+
value={name}
|
|
439
|
+
onChange={(e) => setName(e.target.value)}
|
|
440
|
+
placeholder="Name"
|
|
441
|
+
/>
|
|
442
|
+
<input
|
|
443
|
+
value={email}
|
|
444
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
445
|
+
placeholder="Email"
|
|
446
|
+
/>
|
|
447
|
+
{error && <p>{error}</p>}
|
|
448
|
+
<button type="submit">Submit</button>
|
|
449
|
+
</form>
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
## Summary
|
|
455
|
+
|
|
456
|
+
Aziz App is a **lightweight Next.js clone** that provides:
|
|
457
|
+
|
|
458
|
+
- ✅ **Same React Hooks API** - useState, useEffect, etc.
|
|
459
|
+
- ✅ **Same API Routes** - Identical req/res objects
|
|
460
|
+
- ✅ **Same JSX Syntax** - Write components the same way
|
|
461
|
+
- ✅ **Same Development Flow** - File-based routing, hot reload
|
|
462
|
+
- ✅ **Zero Dependencies** - No node_modules bloat
|
|
463
|
+
- ✅ **Instant Startup** - No build step
|
|
464
|
+
- ✅ **6x Smaller** - Minimal bundle size
|
|
465
|
+
|
|
466
|
+
Perfect for:
|
|
467
|
+
- 🎓 Learning React/Next.js concepts
|
|
468
|
+
- 🚀 Rapid prototyping
|
|
469
|
+
- 📱 Simple SPAs
|
|
470
|
+
- 🎨 Portfolio sites
|
|
471
|
+
- 🧪 Experiments
|
|
472
|
+
|
|
473
|
+
**It's Next.js, but lightweight!** 🎉
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// Database connection helper
|
|
2
|
+
// This is a mock - replace with real database connection
|
|
3
|
+
|
|
4
|
+
let isConnected = false;
|
|
5
|
+
|
|
6
|
+
async function connectDB() {
|
|
7
|
+
if (isConnected) {
|
|
8
|
+
console.log('✅ Using existing database connection');
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
// In production, connect to real database here:
|
|
14
|
+
// await mongoose.connect(process.env.MONGODB_URI);
|
|
15
|
+
// or
|
|
16
|
+
// db = await new Database(process.env.DATABASE_URL);
|
|
17
|
+
|
|
18
|
+
console.log('✅ Database connected (mock)');
|
|
19
|
+
isConnected = true;
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error('❌ Database connection failed:', error);
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
module.exports = connectDB;
|
|
27
|
+
|
|
28
|
+
// Example usage with MongoDB:
|
|
29
|
+
/*
|
|
30
|
+
const mongoose = require('mongoose');
|
|
31
|
+
|
|
32
|
+
async function connectDB() {
|
|
33
|
+
if (mongoose.connections[0].readyState) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
await mongoose.connect(process.env.MONGODB_URI, {
|
|
38
|
+
useNewUrlParser: true,
|
|
39
|
+
useUnifiedTopology: true,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
console.log('✅ MongoDB connected');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
module.exports = connectDB;
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
// Example usage with PostgreSQL:
|
|
49
|
+
/*
|
|
50
|
+
const { Pool } = require('pg');
|
|
51
|
+
|
|
52
|
+
const pool = new Pool({
|
|
53
|
+
connectionString: process.env.DATABASE_URL,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
async function connectDB() {
|
|
57
|
+
try {
|
|
58
|
+
await pool.query('SELECT NOW()');
|
|
59
|
+
console.log('✅ PostgreSQL connected');
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error('❌ PostgreSQL connection failed:', error);
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = connectDB;
|
|
67
|
+
*/
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// User Model
|
|
2
|
+
// This is a mock - replace with real database model
|
|
3
|
+
|
|
4
|
+
// Mock in-memory database
|
|
5
|
+
let users = [
|
|
6
|
+
{ _id: '1', name: 'Aziz Ahmed', email: 'aziz@example.com', role: 'admin', phone: '123-456-7890' },
|
|
7
|
+
{ _id: '2', name: 'John Doe', email: 'john@example.com', role: 'user', phone: '098-765-4321' }
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
class User {
|
|
11
|
+
// Find one user
|
|
12
|
+
static async findOne(query) {
|
|
13
|
+
const user = users.find(u => {
|
|
14
|
+
return Object.keys(query).every(key => u[key] === query[key]);
|
|
15
|
+
});
|
|
16
|
+
return user || null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Find by ID
|
|
20
|
+
static async findById(id) {
|
|
21
|
+
return users.find(u => u._id === id) || null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Find all users
|
|
25
|
+
static async find(query = {}) {
|
|
26
|
+
if (Object.keys(query).length === 0) {
|
|
27
|
+
return users;
|
|
28
|
+
}
|
|
29
|
+
return users.filter(u => {
|
|
30
|
+
return Object.keys(query).every(key => u[key] === query[key]);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Create new user
|
|
35
|
+
static async create(userData) {
|
|
36
|
+
const newUser = {
|
|
37
|
+
_id: String(users.length + 1),
|
|
38
|
+
...userData,
|
|
39
|
+
createdAt: new Date().toISOString()
|
|
40
|
+
};
|
|
41
|
+
users.push(newUser);
|
|
42
|
+
return newUser;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Update user
|
|
46
|
+
static async findByIdAndUpdate(id, updates) {
|
|
47
|
+
const index = users.findIndex(u => u._id === id);
|
|
48
|
+
if (index === -1) return null;
|
|
49
|
+
|
|
50
|
+
users[index] = { ...users[index], ...updates, updatedAt: new Date().toISOString() };
|
|
51
|
+
return users[index];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Delete user
|
|
55
|
+
static async findByIdAndDelete(id) {
|
|
56
|
+
const index = users.findIndex(u => u._id === id);
|
|
57
|
+
if (index === -1) return null;
|
|
58
|
+
|
|
59
|
+
const deleted = users.splice(index, 1)[0];
|
|
60
|
+
return deleted;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Select specific fields
|
|
64
|
+
select(fields) {
|
|
65
|
+
// This is a chainable method for field selection
|
|
66
|
+
// In real Mongoose, this would be: User.findOne().select('name email')
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = User;
|
|
72
|
+
|
|
73
|
+
// Example usage with Mongoose:
|
|
74
|
+
/*
|
|
75
|
+
const mongoose = require('mongoose');
|
|
76
|
+
|
|
77
|
+
const userSchema = new mongoose.Schema({
|
|
78
|
+
name: {
|
|
79
|
+
type: String,
|
|
80
|
+
required: true
|
|
81
|
+
},
|
|
82
|
+
email: {
|
|
83
|
+
type: String,
|
|
84
|
+
required: true,
|
|
85
|
+
unique: true
|
|
86
|
+
},
|
|
87
|
+
password: {
|
|
88
|
+
type: String,
|
|
89
|
+
required: true
|
|
90
|
+
},
|
|
91
|
+
role: {
|
|
92
|
+
type: String,
|
|
93
|
+
enum: ['user', 'admin'],
|
|
94
|
+
default: 'user'
|
|
95
|
+
},
|
|
96
|
+
phone: String
|
|
97
|
+
}, {
|
|
98
|
+
timestamps: true
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
module.exports = mongoose.models.User || mongoose.model('User', userSchema);
|
|
102
|
+
*/
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// NextResponse - Next.js-compatible response helper
|
|
2
|
+
class NextResponse {
|
|
3
|
+
constructor(body, init = {}) {
|
|
4
|
+
this.body = body;
|
|
5
|
+
this.status = init.status || 200;
|
|
6
|
+
this.headers = new Map(Object.entries(init.headers || {}));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
static json(data, init = {}) {
|
|
10
|
+
return new NextResponse(JSON.stringify(data), {
|
|
11
|
+
...init,
|
|
12
|
+
headers: {
|
|
13
|
+
'Content-Type': 'application/json',
|
|
14
|
+
...(init.headers || {})
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static text(text, init = {}) {
|
|
20
|
+
return new NextResponse(text, {
|
|
21
|
+
...init,
|
|
22
|
+
headers: {
|
|
23
|
+
'Content-Type': 'text/plain',
|
|
24
|
+
...(init.headers || {})
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static redirect(url, init = {}) {
|
|
30
|
+
return new NextResponse(null, {
|
|
31
|
+
...init,
|
|
32
|
+
status: init.status || 307,
|
|
33
|
+
headers: {
|
|
34
|
+
'Location': url,
|
|
35
|
+
...(init.headers || {})
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static error() {
|
|
41
|
+
return new NextResponse(JSON.stringify({ error: 'Internal Server Error' }), {
|
|
42
|
+
status: 500,
|
|
43
|
+
headers: {
|
|
44
|
+
'Content-Type': 'application/json'
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Export for Node.js (server-side)
|
|
51
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
52
|
+
module.exports = { NextResponse };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Export for browser (if needed)
|
|
56
|
+
if (typeof window !== 'undefined') {
|
|
57
|
+
window.NextResponse = NextResponse;
|
|
58
|
+
}
|