get-fake-api 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +634 -2
- package/data/auth.js +36 -0
- package/data/orders.js +137 -0
- package/data/posts.js +214 -0
- package/data/products.js +260 -0
- package/data/users.js +377 -0
- package/index.js +74 -0
- package/package.json +31 -4
- package/test.js +113 -0
package/data/orders.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
const baseOrders = [
|
|
2
|
+
{
|
|
3
|
+
id: 1,
|
|
4
|
+
orderNumber: "ORD-2026-9041",
|
|
5
|
+
userId: 1,
|
|
6
|
+
items: [
|
|
7
|
+
{ productId: 1, title: "Pro Wireless Noise-Cancelling Headphones", price: 299.99, quantity: 1, total: 299.99 },
|
|
8
|
+
{ productId: 3, title: "Minimalist Mechanical Keyboard RGB", price: 139.50, quantity: 1, total: 139.50 }
|
|
9
|
+
],
|
|
10
|
+
totalAmount: 439.49,
|
|
11
|
+
currency: "USD",
|
|
12
|
+
paymentMethod: "credit_card",
|
|
13
|
+
status: "delivered",
|
|
14
|
+
trackingNumber: "TRK-9812-US",
|
|
15
|
+
createdAt: "2026-10-01T09:14:00Z"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: 2,
|
|
19
|
+
orderNumber: "ORD-2026-9042",
|
|
20
|
+
userId: 2,
|
|
21
|
+
items: [
|
|
22
|
+
{ productId: 4, title: "TitanBook 16-inch M-Pro Laptop", price: 1899.99, quantity: 1, total: 1899.99 }
|
|
23
|
+
],
|
|
24
|
+
totalAmount: 1899.99,
|
|
25
|
+
currency: "USD",
|
|
26
|
+
paymentMethod: "apple_pay",
|
|
27
|
+
status: "shipped",
|
|
28
|
+
trackingNumber: "TRK-9813-US",
|
|
29
|
+
createdAt: "2026-10-08T15:22:00Z"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: 3,
|
|
33
|
+
orderNumber: "ORD-2026-9043",
|
|
34
|
+
userId: 3,
|
|
35
|
+
items: [
|
|
36
|
+
{ productId: 6, title: "Nordic Minimalist Ceramic Desk Lamp", price: 79.90, quantity: 2, total: 159.80 },
|
|
37
|
+
{ productId: 5, title: "Artisan Roasted Single-Origin Coffee Beans (1kg)", price: 34.00, quantity: 1, total: 34.00 }
|
|
38
|
+
],
|
|
39
|
+
totalAmount: 193.80,
|
|
40
|
+
currency: "USD",
|
|
41
|
+
paymentMethod: "paypal",
|
|
42
|
+
status: "processing",
|
|
43
|
+
trackingNumber: "TRK-9814-UK",
|
|
44
|
+
createdAt: "2026-10-12T11:45:00Z"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: 4,
|
|
48
|
+
orderNumber: "ORD-2026-9044",
|
|
49
|
+
userId: 4,
|
|
50
|
+
items: [
|
|
51
|
+
{ productId: 8, title: "Clean Code & System Design Handbook", price: 49.99, quantity: 1, total: 49.99 }
|
|
52
|
+
],
|
|
53
|
+
totalAmount: 49.99,
|
|
54
|
+
currency: "USD",
|
|
55
|
+
paymentMethod: "credit_card",
|
|
56
|
+
status: "pending",
|
|
57
|
+
trackingNumber: null,
|
|
58
|
+
createdAt: "2026-10-15T18:05:00Z"
|
|
59
|
+
}
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
const paymentMethods = ["credit_card", "paypal", "apple_pay", "stripe"];
|
|
63
|
+
const orderStatuses = ["pending", "processing", "shipped", "delivered", "cancelled"];
|
|
64
|
+
|
|
65
|
+
function generateOrder(id) {
|
|
66
|
+
const status = orderStatuses[id % orderStatuses.length];
|
|
67
|
+
const paymentMethod = paymentMethods[id % paymentMethods.length];
|
|
68
|
+
const qty = 1 + (id % 3);
|
|
69
|
+
const price = Number((25.00 + (id * 19.5) % 300).toFixed(2));
|
|
70
|
+
const total = Number((price * qty).toFixed(2));
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
id,
|
|
74
|
+
orderNumber: `ORD-2026-${9000 + id}`,
|
|
75
|
+
userId: 1 + (id % 10),
|
|
76
|
+
items: [
|
|
77
|
+
{
|
|
78
|
+
productId: 1 + (id % 10),
|
|
79
|
+
title: `Product Item #${1 + (id % 10)}`,
|
|
80
|
+
price,
|
|
81
|
+
quantity: qty,
|
|
82
|
+
total
|
|
83
|
+
}
|
|
84
|
+
],
|
|
85
|
+
totalAmount: total,
|
|
86
|
+
currency: "USD",
|
|
87
|
+
paymentMethod,
|
|
88
|
+
status,
|
|
89
|
+
trackingNumber: status === "pending" || status === "cancelled" ? null : `TRK-${1000 + id}-GL`,
|
|
90
|
+
createdAt: new Date(Date.now() - id * 43200000).toISOString()
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function getOrders(optionsOrCount) {
|
|
95
|
+
let count = 4;
|
|
96
|
+
let filters = {};
|
|
97
|
+
|
|
98
|
+
if (typeof optionsOrCount === "number") {
|
|
99
|
+
count = optionsOrCount <= 0 ? 0 : optionsOrCount;
|
|
100
|
+
} else if (typeof optionsOrCount === "object" && optionsOrCount !== null) {
|
|
101
|
+
if (typeof optionsOrCount.count === "number") count = optionsOrCount.count;
|
|
102
|
+
else if (typeof optionsOrCount.limit === "number") count = optionsOrCount.limit;
|
|
103
|
+
filters = optionsOrCount;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const result = [];
|
|
107
|
+
const targetCount = count > 0 ? count : 0;
|
|
108
|
+
const poolSize = Math.max(targetCount, baseOrders.length);
|
|
109
|
+
|
|
110
|
+
for (let i = 0; i < poolSize; i++) {
|
|
111
|
+
const order = i < baseOrders.length ? baseOrders[i] : generateOrder(i + 1);
|
|
112
|
+
|
|
113
|
+
if (filters.status && order.status.toLowerCase() !== filters.status.toLowerCase()) continue;
|
|
114
|
+
if (filters.userId && order.userId !== Number(filters.userId)) continue;
|
|
115
|
+
if (filters.paymentMethod && order.paymentMethod.toLowerCase() !== filters.paymentMethod.toLowerCase()) continue;
|
|
116
|
+
|
|
117
|
+
result.push(order);
|
|
118
|
+
if (result.length >= targetCount) break;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function getOrderById(id) {
|
|
125
|
+
const numericId = Number(id);
|
|
126
|
+
if (!numericId || numericId <= 0) return null;
|
|
127
|
+
if (numericId <= baseOrders.length) {
|
|
128
|
+
return baseOrders.find(o => o.id === numericId) || null;
|
|
129
|
+
}
|
|
130
|
+
return generateOrder(numericId);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
module.exports = {
|
|
134
|
+
getOrders,
|
|
135
|
+
getOrderById,
|
|
136
|
+
baseOrders
|
|
137
|
+
};
|
package/data/posts.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
const basePosts = [
|
|
2
|
+
{
|
|
3
|
+
id: 1,
|
|
4
|
+
userId: 1,
|
|
5
|
+
title: "Mastering Asynchronous JavaScript in Modern Web Apps",
|
|
6
|
+
body: "Promises and async/await have fundamentally transformed how JavaScript handles concurrency. Understanding microtasks, macrotasks, and the event loop is crucial for building performant user experiences.",
|
|
7
|
+
tags: ["javascript", "webdev", "programming"],
|
|
8
|
+
reactions: { likes: 142, dislikes: 3 },
|
|
9
|
+
views: 1250,
|
|
10
|
+
createdAt: "2026-09-12T10:30:00Z"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
id: 2,
|
|
14
|
+
userId: 2,
|
|
15
|
+
title: "10 Principles for Crafting Clean API Contracts",
|
|
16
|
+
body: "Designing intuitive REST and GraphQL APIs starts with consistent error envelopes, predictable pagination structures, and semantic HTTP status codes.",
|
|
17
|
+
tags: ["api", "architecture", "backend"],
|
|
18
|
+
reactions: { likes: 218, dislikes: 5 },
|
|
19
|
+
views: 3410,
|
|
20
|
+
createdAt: "2026-09-15T14:20:00Z"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: 3,
|
|
24
|
+
userId: 3,
|
|
25
|
+
title: "The Art of Micro-interactions in Design Systems",
|
|
26
|
+
body: "Micro-interactions provide sensory feedback that makes user interfaces feel tangible and alive. From subtle button spring animations to smooth page transitions, details define quality.",
|
|
27
|
+
tags: ["ui", "ux", "design"],
|
|
28
|
+
reactions: { likes: 95, dislikes: 1 },
|
|
29
|
+
views: 890,
|
|
30
|
+
createdAt: "2026-09-20T08:15:00Z"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: 4,
|
|
34
|
+
userId: 4,
|
|
35
|
+
title: "Zero-Downtime Deployments with Docker and Kubernetes",
|
|
36
|
+
body: "Rolling updates and health check probes ensure your users never encounter 502 bad gateway errors during peak traffic releases.",
|
|
37
|
+
tags: ["devops", "docker", "cloud"],
|
|
38
|
+
reactions: { likes: 310, dislikes: 8 },
|
|
39
|
+
views: 4500,
|
|
40
|
+
createdAt: "2026-09-24T16:45:00Z"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: 5,
|
|
44
|
+
userId: 5,
|
|
45
|
+
title: "Building Real-time Dashboards with WebSockets",
|
|
46
|
+
body: "Learn how to establish low-latency bidirectional connections between Node.js backends and browser frontends using native WebSockets.",
|
|
47
|
+
tags: ["nodejs", "realtime", "frontend"],
|
|
48
|
+
reactions: { likes: 178, dislikes: 4 },
|
|
49
|
+
views: 2100,
|
|
50
|
+
createdAt: "2026-10-01T11:00:00Z"
|
|
51
|
+
}
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
const baseComments = [
|
|
55
|
+
{
|
|
56
|
+
id: 1,
|
|
57
|
+
postId: 1,
|
|
58
|
+
user: { id: 2, username: "johndoe", fullName: "John Doe" },
|
|
59
|
+
body: "Great explanation of the event loop! The microtask queue distinction cleared up a tricky bug I had.",
|
|
60
|
+
createdAt: "2026-09-12T11:45:00Z"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: 2,
|
|
64
|
+
postId: 1,
|
|
65
|
+
user: { id: 4, username: "liamc", fullName: "Liam Chen" },
|
|
66
|
+
body: "Async/await with Promise.allSettled is a game changer for resilient error handling.",
|
|
67
|
+
createdAt: "2026-09-12T13:20:00Z"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: 3,
|
|
71
|
+
postId: 2,
|
|
72
|
+
user: { id: 1, username: "sconnor", fullName: "Sarah Connor" },
|
|
73
|
+
body: "Standardizing error response schemas is honestly the #1 thing front-end engineers appreciate.",
|
|
74
|
+
createdAt: "2026-09-15T15:10:00Z"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: 4,
|
|
78
|
+
postId: 3,
|
|
79
|
+
user: { id: 7, username: "cdubois", fullName: "Chloe Dubois" },
|
|
80
|
+
body: "Agreed! Even a 150ms spring transition gives the interface a delightful native feel.",
|
|
81
|
+
createdAt: "2026-09-20T09:30:00Z"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: 5,
|
|
85
|
+
postId: 4,
|
|
86
|
+
user: { id: 8, username: "arjunp", fullName: "Arjun Patel" },
|
|
87
|
+
body: "Readiness probes combined with terminationGracePeriodSeconds is essential.",
|
|
88
|
+
createdAt: "2026-09-24T18:00:00Z"
|
|
89
|
+
}
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
function generatePost(id) {
|
|
93
|
+
const titles = [
|
|
94
|
+
"Understanding State Management Patterns in 2026",
|
|
95
|
+
"Optimizing Core Web Vitals for Lightning-Fast Page Loads",
|
|
96
|
+
"How to Write Bulletproof Unit and Integration Tests",
|
|
97
|
+
"Securing JWT Authentication in Modern Single Page Apps",
|
|
98
|
+
"Exploring Edge Computing and Serverless Architecture"
|
|
99
|
+
];
|
|
100
|
+
const tagsList = [
|
|
101
|
+
["react", "state", "architecture"],
|
|
102
|
+
["performance", "seo", "webdev"],
|
|
103
|
+
["testing", "jest", "qa"],
|
|
104
|
+
["security", "auth", "jwt"],
|
|
105
|
+
["edge", "cloud", "serverless"]
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
const index = id % titles.length;
|
|
109
|
+
return {
|
|
110
|
+
id,
|
|
111
|
+
userId: 1 + (id % 10),
|
|
112
|
+
title: `${titles[index]} (Part ${id})`,
|
|
113
|
+
body: `Deep dive exploration into architectural strategies and practical code samples for building robust applications. Article #${id}.`,
|
|
114
|
+
tags: tagsList[index],
|
|
115
|
+
reactions: { likes: 50 + (id * 19) % 300, dislikes: (id * 3) % 15 },
|
|
116
|
+
views: 400 + (id * 73) % 5000,
|
|
117
|
+
createdAt: new Date(Date.now() - id * 86400000).toISOString()
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function generateComment(id) {
|
|
122
|
+
return {
|
|
123
|
+
id,
|
|
124
|
+
postId: 1 + (id % 5),
|
|
125
|
+
user: {
|
|
126
|
+
id: 1 + (id % 10),
|
|
127
|
+
username: `user_${id}`,
|
|
128
|
+
fullName: `User ${id}`
|
|
129
|
+
},
|
|
130
|
+
body: `Insightful post! Really enjoyed reading through section #${id % 4 + 1}.`,
|
|
131
|
+
createdAt: new Date(Date.now() - id * 3600000).toISOString()
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function getPosts(optionsOrCount) {
|
|
136
|
+
let count = 5;
|
|
137
|
+
let filters = {};
|
|
138
|
+
|
|
139
|
+
if (typeof optionsOrCount === "number") {
|
|
140
|
+
count = optionsOrCount <= 0 ? 0 : optionsOrCount;
|
|
141
|
+
} else if (typeof optionsOrCount === "object" && optionsOrCount !== null) {
|
|
142
|
+
if (typeof optionsOrCount.count === "number") count = optionsOrCount.count;
|
|
143
|
+
else if (typeof optionsOrCount.limit === "number") count = optionsOrCount.limit;
|
|
144
|
+
filters = optionsOrCount;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const result = [];
|
|
148
|
+
const targetCount = count > 0 ? count : 0;
|
|
149
|
+
const poolSize = Math.max(targetCount, basePosts.length);
|
|
150
|
+
|
|
151
|
+
for (let i = 0; i < poolSize; i++) {
|
|
152
|
+
const post = i < basePosts.length ? basePosts[i] : generatePost(i + 1);
|
|
153
|
+
|
|
154
|
+
if (filters.userId && post.userId !== Number(filters.userId)) continue;
|
|
155
|
+
if (filters.tag && !post.tags.includes(filters.tag.toLowerCase())) continue;
|
|
156
|
+
if (filters.q) {
|
|
157
|
+
const q = filters.q.toLowerCase();
|
|
158
|
+
if (!post.title.toLowerCase().includes(q) && !post.body.toLowerCase().includes(q)) continue;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
result.push(post);
|
|
162
|
+
if (result.length >= targetCount) break;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function getPostById(id) {
|
|
169
|
+
const numericId = Number(id);
|
|
170
|
+
if (!numericId || numericId <= 0) return null;
|
|
171
|
+
if (numericId <= basePosts.length) {
|
|
172
|
+
return basePosts.find(p => p.id === numericId) || null;
|
|
173
|
+
}
|
|
174
|
+
return generatePost(numericId);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function getComments(optionsOrCount) {
|
|
178
|
+
let count = 5;
|
|
179
|
+
let filters = {};
|
|
180
|
+
|
|
181
|
+
if (typeof optionsOrCount === "number") {
|
|
182
|
+
count = optionsOrCount <= 0 ? 0 : optionsOrCount;
|
|
183
|
+
} else if (typeof optionsOrCount === "object" && optionsOrCount !== null) {
|
|
184
|
+
if (typeof optionsOrCount.count === "number") count = optionsOrCount.count;
|
|
185
|
+
else if (typeof optionsOrCount.limit === "number") count = optionsOrCount.limit;
|
|
186
|
+
filters = optionsOrCount;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const result = [];
|
|
190
|
+
const targetCount = count > 0 ? count : 0;
|
|
191
|
+
const poolSize = Math.max(targetCount, baseComments.length);
|
|
192
|
+
|
|
193
|
+
for (let i = 0; i < poolSize; i++) {
|
|
194
|
+
const comment = i < baseComments.length ? baseComments[i] : generateComment(i + 1);
|
|
195
|
+
if (filters.postId && comment.postId !== Number(filters.postId)) continue;
|
|
196
|
+
result.push(comment);
|
|
197
|
+
if (result.length >= targetCount) break;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return result;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function getCommentsByPostId(postId) {
|
|
204
|
+
return getComments({ postId: Number(postId), count: 10 });
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
module.exports = {
|
|
208
|
+
getPosts,
|
|
209
|
+
getPostById,
|
|
210
|
+
getComments,
|
|
211
|
+
getCommentsByPostId,
|
|
212
|
+
basePosts,
|
|
213
|
+
baseComments
|
|
214
|
+
};
|
package/data/products.js
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
const baseProducts = [
|
|
2
|
+
{
|
|
3
|
+
id: 1,
|
|
4
|
+
title: "Pro Wireless Noise-Cancelling Headphones",
|
|
5
|
+
description: "Premium over-ear wireless headphones with active noise cancellation, 40-hour battery life, and spatial audio support.",
|
|
6
|
+
price: 299.99,
|
|
7
|
+
discountPercentage: 12.5,
|
|
8
|
+
rating: 4.8,
|
|
9
|
+
stock: 45,
|
|
10
|
+
brand: "AuraSound",
|
|
11
|
+
category: "electronics",
|
|
12
|
+
thumbnail: "https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=500&auto=format&fit=crop&q=80",
|
|
13
|
+
images: [
|
|
14
|
+
"https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=500&auto=format&fit=crop&q=80",
|
|
15
|
+
"https://images.unsplash.com/photo-1484704849700-f032a568e944?w=500&auto=format&fit=crop&q=80"
|
|
16
|
+
],
|
|
17
|
+
isAvailable: true
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: 2,
|
|
21
|
+
title: "UltraSlim Flagship Smartphone 256GB",
|
|
22
|
+
description: "6.7-inch Super AMOLED 120Hz display, quad-camera system with 108MP main sensor, and all-day fast-charge battery.",
|
|
23
|
+
price: 899.00,
|
|
24
|
+
discountPercentage: 8.0,
|
|
25
|
+
rating: 4.7,
|
|
26
|
+
stock: 28,
|
|
27
|
+
brand: "Vortex",
|
|
28
|
+
category: "smartphones",
|
|
29
|
+
thumbnail: "https://images.unsplash.com/photo-1511707171634-5f897ff02aa9?w=500&auto=format&fit=crop&q=80",
|
|
30
|
+
images: [
|
|
31
|
+
"https://images.unsplash.com/photo-1511707171634-5f897ff02aa9?w=500&auto=format&fit=crop&q=80"
|
|
32
|
+
],
|
|
33
|
+
isAvailable: true
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: 3,
|
|
37
|
+
title: "Minimalist Mechanical Keyboard RGB",
|
|
38
|
+
description: "Compact 75% hot-swappable mechanical keyboard with lubricated linear switches, aluminum frame, and customizable PBT keycaps.",
|
|
39
|
+
price: 139.50,
|
|
40
|
+
discountPercentage: 15.0,
|
|
41
|
+
rating: 4.9,
|
|
42
|
+
stock: 62,
|
|
43
|
+
brand: "KeyPulse",
|
|
44
|
+
category: "electronics",
|
|
45
|
+
thumbnail: "https://images.unsplash.com/photo-1587829741301-dc798b83add3?w=500&auto=format&fit=crop&q=80",
|
|
46
|
+
images: [
|
|
47
|
+
"https://images.unsplash.com/photo-1587829741301-dc798b83add3?w=500&auto=format&fit=crop&q=80"
|
|
48
|
+
],
|
|
49
|
+
isAvailable: true
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: 4,
|
|
53
|
+
title: "TitanBook 16-inch M-Pro Laptop",
|
|
54
|
+
description: "High-performance creator laptop featuring 32GB unified RAM, 1TB NVMe SSD, and 12-core processing architecture.",
|
|
55
|
+
price: 1899.99,
|
|
56
|
+
discountPercentage: 5.0,
|
|
57
|
+
rating: 4.9,
|
|
58
|
+
stock: 14,
|
|
59
|
+
brand: "Titan",
|
|
60
|
+
category: "laptops",
|
|
61
|
+
thumbnail: "https://images.unsplash.com/photo-1517336714731-489689fd1ca8?w=500&auto=format&fit=crop&q=80",
|
|
62
|
+
images: [
|
|
63
|
+
"https://images.unsplash.com/photo-1517336714731-489689fd1ca8?w=500&auto=format&fit=crop&q=80"
|
|
64
|
+
],
|
|
65
|
+
isAvailable: true
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: 5,
|
|
69
|
+
title: "Artisan Roasted Single-Origin Coffee Beans (1kg)",
|
|
70
|
+
description: "Specialty Ethiopian Yirgacheffe medium roast with tasting notes of jasmine, bergamot, and sweet peach.",
|
|
71
|
+
price: 34.00,
|
|
72
|
+
discountPercentage: 0.0,
|
|
73
|
+
rating: 4.6,
|
|
74
|
+
stock: 120,
|
|
75
|
+
brand: "RoastMasters",
|
|
76
|
+
category: "groceries",
|
|
77
|
+
thumbnail: "https://images.unsplash.com/photo-1559056199-641a0ac8b55e?w=500&auto=format&fit=crop&q=80",
|
|
78
|
+
images: [
|
|
79
|
+
"https://images.unsplash.com/photo-1559056199-641a0ac8b55e?w=500&auto=format&fit=crop&q=80"
|
|
80
|
+
],
|
|
81
|
+
isAvailable: true
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: 6,
|
|
85
|
+
title: "Nordic Minimalist Ceramic Desk Lamp",
|
|
86
|
+
description: "Warm LED dimmable ambient lamp with matte ceramic base and brushed brass accents, touch control dimmer.",
|
|
87
|
+
price: 79.90,
|
|
88
|
+
discountPercentage: 10.0,
|
|
89
|
+
rating: 4.5,
|
|
90
|
+
stock: 35,
|
|
91
|
+
brand: "Lumina Home",
|
|
92
|
+
category: "home-decoration",
|
|
93
|
+
thumbnail: "https://images.unsplash.com/photo-1507473885765-e6ed057f782c?w=500&auto=format&fit=crop&q=80",
|
|
94
|
+
images: [
|
|
95
|
+
"https://images.unsplash.com/photo-1507473885765-e6ed057f782c?w=500&auto=format&fit=crop&q=80"
|
|
96
|
+
],
|
|
97
|
+
isAvailable: true
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
id: 7,
|
|
101
|
+
title: "Classic Waterproof Chronograph Watch",
|
|
102
|
+
description: "Stainless steel case, sapphire crystal glass, Japanese quartz movement, 100m water resistance, and genuine leather strap.",
|
|
103
|
+
price: 249.00,
|
|
104
|
+
discountPercentage: 20.0,
|
|
105
|
+
rating: 4.7,
|
|
106
|
+
stock: 19,
|
|
107
|
+
brand: "Chronos",
|
|
108
|
+
category: "fashion",
|
|
109
|
+
thumbnail: "https://images.unsplash.com/photo-1524592094714-0f0654e20314?w=500&auto=format&fit=crop&q=80",
|
|
110
|
+
images: [
|
|
111
|
+
"https://images.unsplash.com/photo-1524592094714-0f0654e20314?w=500&auto=format&fit=crop&q=80"
|
|
112
|
+
],
|
|
113
|
+
isAvailable: true
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
id: 8,
|
|
117
|
+
title: "Clean Code & System Design Handbook",
|
|
118
|
+
description: "The essential guide to writing scalable, maintainable, and high-performance software systems for modern engineers.",
|
|
119
|
+
price: 49.99,
|
|
120
|
+
discountPercentage: 15.0,
|
|
121
|
+
rating: 4.95,
|
|
122
|
+
stock: 80,
|
|
123
|
+
brand: "TechPress",
|
|
124
|
+
category: "books",
|
|
125
|
+
thumbnail: "https://images.unsplash.com/photo-1532012164546-f432f2e3edd4?w=500&auto=format&fit=crop&q=80",
|
|
126
|
+
images: [
|
|
127
|
+
"https://images.unsplash.com/photo-1532012164546-f432f2e3edd4?w=500&auto=format&fit=crop&q=80"
|
|
128
|
+
],
|
|
129
|
+
isAvailable: true
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
id: 9,
|
|
133
|
+
title: "Botanical Hydrating Facial Serum 50ml",
|
|
134
|
+
description: "Hyaluronic acid and vitamin C enriched antioxidant serum for radiant skin revitalization and 24h deep hydration.",
|
|
135
|
+
price: 42.50,
|
|
136
|
+
discountPercentage: 5.0,
|
|
137
|
+
rating: 4.4,
|
|
138
|
+
stock: 55,
|
|
139
|
+
brand: "PureGlow",
|
|
140
|
+
category: "skincare",
|
|
141
|
+
thumbnail: "https://images.unsplash.com/photo-1608248597359-5489725f3c95?w=500&auto=format&fit=crop&q=80",
|
|
142
|
+
images: [
|
|
143
|
+
"https://images.unsplash.com/photo-1608248597359-5489725f3c95?w=500&auto=format&fit=crop&q=80"
|
|
144
|
+
],
|
|
145
|
+
isAvailable: true
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
id: 10,
|
|
149
|
+
title: "Ergonomic Mesh Executive Chair",
|
|
150
|
+
description: "Adjustable 4D armrests, dynamic lumbar support, breathable mesh back, and smooth-rolling silent casters.",
|
|
151
|
+
price: 389.00,
|
|
152
|
+
discountPercentage: 18.0,
|
|
153
|
+
rating: 4.8,
|
|
154
|
+
stock: 22,
|
|
155
|
+
brand: "ErgoForm",
|
|
156
|
+
category: "home-decoration",
|
|
157
|
+
thumbnail: "https://images.unsplash.com/photo-1580481077197-28564117b43a?w=500&auto=format&fit=crop&q=80",
|
|
158
|
+
images: [
|
|
159
|
+
"https://images.unsplash.com/photo-1580481077197-28564117b43a?w=500&auto=format&fit=crop&q=80"
|
|
160
|
+
],
|
|
161
|
+
isAvailable: true
|
|
162
|
+
}
|
|
163
|
+
];
|
|
164
|
+
|
|
165
|
+
const categories = ["electronics", "smartphones", "laptops", "groceries", "home-decoration", "fashion", "books", "skincare"];
|
|
166
|
+
const brands = ["AuraSound", "Vortex", "KeyPulse", "Titan", "RoastMasters", "Lumina Home", "Chronos", "TechPress", "PureGlow", "ErgoForm"];
|
|
167
|
+
|
|
168
|
+
function generateProduct(id) {
|
|
169
|
+
const category = categories[id % categories.length];
|
|
170
|
+
const brand = brands[id % brands.length];
|
|
171
|
+
const price = Number((19.99 + (id * 27.5) % 450).toFixed(2));
|
|
172
|
+
const discount = Number(((id * 3) % 25).toFixed(1));
|
|
173
|
+
const rating = Number((3.8 + ((id * 7) % 12) / 10).toFixed(1));
|
|
174
|
+
const stock = 10 + (id * 17) % 150;
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
id,
|
|
178
|
+
title: `${brand} Standard Edition Item #${id}`,
|
|
179
|
+
description: `High-quality ${category} item designed with durability and premium performance in mind. Product ID: ${id}.`,
|
|
180
|
+
price,
|
|
181
|
+
discountPercentage: discount,
|
|
182
|
+
rating: Math.min(5.0, rating),
|
|
183
|
+
stock,
|
|
184
|
+
brand,
|
|
185
|
+
category,
|
|
186
|
+
thumbnail: `https://images.unsplash.com/photo-${1510000000000 + id}?w=500&auto=format&fit=crop&q=80`,
|
|
187
|
+
images: [
|
|
188
|
+
`https://images.unsplash.com/photo-${1510000000000 + id}?w=500&auto=format&fit=crop&q=80`
|
|
189
|
+
],
|
|
190
|
+
isAvailable: stock > 0
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function getProducts(optionsOrCount) {
|
|
195
|
+
let count = 10;
|
|
196
|
+
let filters = {};
|
|
197
|
+
|
|
198
|
+
if (typeof optionsOrCount === "number") {
|
|
199
|
+
count = optionsOrCount <= 0 ? 0 : optionsOrCount;
|
|
200
|
+
} else if (typeof optionsOrCount === "object" && optionsOrCount !== null) {
|
|
201
|
+
if (typeof optionsOrCount.count === "number") {
|
|
202
|
+
count = optionsOrCount.count <= 0 ? 0 : optionsOrCount.count;
|
|
203
|
+
} else if (typeof optionsOrCount.limit === "number") {
|
|
204
|
+
count = optionsOrCount.limit <= 0 ? 0 : optionsOrCount.limit;
|
|
205
|
+
}
|
|
206
|
+
filters = optionsOrCount;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const result = [];
|
|
210
|
+
const targetCount = count > 0 ? count : 0;
|
|
211
|
+
const poolSize = Math.max(targetCount, baseProducts.length);
|
|
212
|
+
|
|
213
|
+
for (let i = 0; i < poolSize; i++) {
|
|
214
|
+
const product = i < baseProducts.length ? baseProducts[i] : generateProduct(i + 1);
|
|
215
|
+
|
|
216
|
+
if (filters.category && product.category.toLowerCase() !== filters.category.toLowerCase()) continue;
|
|
217
|
+
if (filters.brand && product.brand.toLowerCase() !== filters.brand.toLowerCase()) continue;
|
|
218
|
+
if (typeof filters.minPrice === "number" && product.price < filters.minPrice) continue;
|
|
219
|
+
if (typeof filters.maxPrice === "number" && product.price > filters.maxPrice) continue;
|
|
220
|
+
if (typeof filters.rating === "number" && product.rating < filters.rating) continue;
|
|
221
|
+
if (typeof filters.isAvailable === "boolean" && product.isAvailable !== filters.isAvailable) continue;
|
|
222
|
+
if (filters.q) {
|
|
223
|
+
const q = filters.q.toLowerCase();
|
|
224
|
+
const match = product.title.toLowerCase().includes(q) ||
|
|
225
|
+
product.description.toLowerCase().includes(q) ||
|
|
226
|
+
product.brand.toLowerCase().includes(q);
|
|
227
|
+
if (!match) continue;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
result.push(product);
|
|
231
|
+
if (result.length >= targetCount) break;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (filters.sortField) {
|
|
235
|
+
const field = filters.sortField;
|
|
236
|
+
const order = filters.sortOrder === "desc" ? -1 : 1;
|
|
237
|
+
result.sort((a, b) => {
|
|
238
|
+
if (a[field] < b[field]) return -1 * order;
|
|
239
|
+
if (a[field] > b[field]) return 1 * order;
|
|
240
|
+
return 0;
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return result;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function getProductById(id) {
|
|
248
|
+
const numericId = Number(id);
|
|
249
|
+
if (!numericId || numericId <= 0) return null;
|
|
250
|
+
if (numericId <= baseProducts.length) {
|
|
251
|
+
return baseProducts.find(p => p.id === numericId) || null;
|
|
252
|
+
}
|
|
253
|
+
return generateProduct(numericId);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
module.exports = {
|
|
257
|
+
getProducts,
|
|
258
|
+
getProductById,
|
|
259
|
+
baseProducts
|
|
260
|
+
};
|