3a-ecommerce-utils 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.
Files changed (45) hide show
  1. package/README.md +163 -0
  2. package/dist/chunk-PEAZVBSD.mjs +597 -0
  3. package/dist/client-DYGi_pyp.d.mts +87 -0
  4. package/dist/client-DYGi_pyp.d.ts +87 -0
  5. package/dist/index.d.mts +496 -0
  6. package/dist/index.d.ts +496 -0
  7. package/dist/index.js +17707 -0
  8. package/dist/index.mjs +17043 -0
  9. package/dist/validation/server.d.mts +50 -0
  10. package/dist/validation/server.d.ts +50 -0
  11. package/dist/validation/server.js +518 -0
  12. package/dist/validation/server.mjs +168 -0
  13. package/package.json +69 -0
  14. package/src/api/address.queries.ts +96 -0
  15. package/src/api/category.queries.ts +85 -0
  16. package/src/api/coupon.queries.ts +120 -0
  17. package/src/api/dashboard.queries.ts +35 -0
  18. package/src/api/errorHandler.ts +164 -0
  19. package/src/api/graphqlClient.ts +113 -0
  20. package/src/api/index.ts +10 -0
  21. package/src/api/logger.client.ts +89 -0
  22. package/src/api/logger.ts +135 -0
  23. package/src/api/order.queries.ts +211 -0
  24. package/src/api/product.queries.ts +144 -0
  25. package/src/api/review.queries.ts +56 -0
  26. package/src/api/user.queries.ts +232 -0
  27. package/src/assets/3A.png +0 -0
  28. package/src/assets/index.ts +1 -0
  29. package/src/assets.d.ts +29 -0
  30. package/src/auth.ts +176 -0
  31. package/src/config/jest.backend.config.js +42 -0
  32. package/src/config/jest.frontend.config.js +50 -0
  33. package/src/config/postcss.config.js +6 -0
  34. package/src/config/tailwind.config.ts +70 -0
  35. package/src/config/tsconfig.base.json +36 -0
  36. package/src/config/vite.config.ts +86 -0
  37. package/src/config/vitest.base.config.ts +74 -0
  38. package/src/config/webpack.base.config.ts +126 -0
  39. package/src/constants/index.ts +312 -0
  40. package/src/cookies.ts +104 -0
  41. package/src/helpers.ts +400 -0
  42. package/src/index.ts +32 -0
  43. package/src/validation/client.ts +287 -0
  44. package/src/validation/index.ts +3 -0
  45. package/src/validation/server.ts +32 -0
@@ -0,0 +1,312 @@
1
+
2
+ export const SHELL_APP_URL = 'http://localhost:3000';
3
+ export const ADMIN_APP_URL = 'http://localhost:3001';
4
+ export const SELLER_APP_URL = 'http://localhost:3002';
5
+ export const STOREFRONT_APP_URL = 'http://localhost:3003';
6
+
7
+ // PORT CONFIGURATIONS
8
+ // auth-3011, category-3012, coupon-3013, product-3014, order-3015, graphql-4000
9
+ export const PORT_CONFIG = {
10
+ AUTH_SERVICE: 3011,
11
+ CATEGORY_SERVICE: 3012,
12
+ COUPON_SERVICE: 3013,
13
+ PRODUCT_SERVICE: 3014,
14
+ ORDER_SERVICE: 3015,
15
+ GRAPHQL_GATEWAY: 4000,
16
+ STOREFRONT_APP: 3000,
17
+ ADMIN_APP: 3001,
18
+ SELLER_APP: 3002,
19
+ SHELL_APP: 3003,
20
+ };
21
+
22
+ // SERVICE URLS
23
+ export const SERVICE_URLS = {
24
+ AUTH_SERVICE: `http://localhost:${PORT_CONFIG.AUTH_SERVICE}`,
25
+ CATEGORY_SERVICE: `http://localhost:${PORT_CONFIG.CATEGORY_SERVICE}`,
26
+ COUPON_SERVICE: `http://localhost:${PORT_CONFIG.COUPON_SERVICE}`,
27
+ PRODUCT_SERVICE: `http://localhost:${PORT_CONFIG.PRODUCT_SERVICE}`,
28
+ ORDER_SERVICE: `http://localhost:${PORT_CONFIG.ORDER_SERVICE}`,
29
+ GRAPHQL_GATEWAY: `http://localhost:${PORT_CONFIG.GRAPHQL_GATEWAY}/graphql`,
30
+ AUTH_API: `http://localhost:${PORT_CONFIG.AUTH_SERVICE}/api`,
31
+ CATEGORY_API: `http://localhost:${PORT_CONFIG.CATEGORY_SERVICE}/api`,
32
+ COUPON_API: `http://localhost:${PORT_CONFIG.COUPON_SERVICE}/api`,
33
+ PRODUCT_API: `http://localhost:${PORT_CONFIG.PRODUCT_SERVICE}/api`,
34
+ ORDER_API: `http://localhost:${PORT_CONFIG.ORDER_SERVICE}/api`,
35
+ };
36
+
37
+ // DATABASE CONFIGURATION
38
+ export const DATABASE_CONFIG = {
39
+ MONGODB_URI: 'mongodb+srv://admin:admin@cluster0.wei5wdz.mongodb.net/ecommerce?appName=Cluster0',
40
+ REDIS_URL: 'redis://localhost:6379',
41
+ };
42
+
43
+ // CORS ALLOWED ORIGINS
44
+ export const DEFAULT_CORS_ORIGINS = [
45
+ 'http://localhost:3000',
46
+ 'http://localhost:3001',
47
+ 'http://localhost:3002',
48
+ 'http://localhost:3003',
49
+ ];
50
+
51
+ // JWT & AUTH CONFIGURATION
52
+ export const JWT_CONFIG = {
53
+ ACCESS_TOKEN_EXPIRY: '1h',
54
+ REFRESH_TOKEN_EXPIRY: '7d',
55
+ PASSWORD_MIN_LENGTH: 8,
56
+ PASSWORD_PATTERN: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/,
57
+ };
58
+
59
+ // PAGINATION CONFIGURATION
60
+ export const PAGINATION = {
61
+ DEFAULT_PAGE: 1,
62
+ DEFAULT_LIMIT: 10,
63
+ DEFAULT_PAGE_SIZE: 20,
64
+ MAX_PAGE_SIZE: 100,
65
+ MIN_PAGE_SIZE: 1,
66
+ DEFAULT_SORT_BY: 'createdAt',
67
+ DEFAULT_SORT_ORDER: 'DESC' as const,
68
+ };
69
+
70
+ // PRODUCT CONFIGURATION
71
+ export const PRODUCT_CONFIG = {
72
+ MIN_PRICE: 0,
73
+ MAX_PRICE: 999999.99,
74
+ MIN_STOCK: 0,
75
+ MAX_RATING: 5,
76
+ MIN_RATING: 0,
77
+ DEFAULT_RATING: 0,
78
+ MAX_IMAGE_SIZE: 5 * 1024 * 1024, // 5MB
79
+ ALLOWED_IMAGE_TYPES: ['image/jpeg', 'image/png', 'image/webp'],
80
+ };
81
+
82
+ // ORDER CONFIGURATION
83
+ export const ORDER_CONFIG = {
84
+ TAX_RATE: 0.1, // 10% tax
85
+ SHIPPING_COST_STANDARD: 50,
86
+ SHIPPING_COST_EXPRESS: 150,
87
+ SHIPPING_COST_OVERNIGHT: 300,
88
+ MIN_ORDER_AMOUNT: 0,
89
+ MAX_ORDER_ITEMS: 1000,
90
+ };
91
+
92
+ // COUPON CONFIGURATION
93
+ export const COUPON_CONFIG = {
94
+ CODE_LENGTH: 6,
95
+ CODE_UPPERCASE: true,
96
+ MAX_DISCOUNT_PERCENTAGE: 100,
97
+ MAX_DISCOUNT_FIXED: 999999.99,
98
+ MIN_PURCHASE_REQUIRED: 0,
99
+ };
100
+
101
+ // API ENDPOINTS (PATHS)
102
+ export const API_ENDPOINTS = {
103
+ AUTH: {
104
+ LOGIN: '/api/auth/login',
105
+ REGISTER: '/api/auth/register',
106
+ LOGOUT: '/api/auth/logout',
107
+ PROFILE: '/api/auth/profile',
108
+ REFRESH: '/api/auth/refresh',
109
+ VERIFY: '/api/auth/verify',
110
+ },
111
+ PRODUCTS: {
112
+ LIST: '/api/products',
113
+ CREATE: '/api/products',
114
+ GET: '/api/products/:id',
115
+ UPDATE: '/api/products/:id',
116
+ DELETE: '/api/products/:id',
117
+ SEARCH: '/api/products/search',
118
+ },
119
+ ORDERS: {
120
+ LIST: '/api/orders',
121
+ CREATE: '/api/orders',
122
+ GET: '/api/orders/:id',
123
+ UPDATE: '/api/orders/:id',
124
+ CANCEL: '/api/orders/:id/cancel',
125
+ TRACK: '/api/orders/:id/track',
126
+ },
127
+ CATEGORIES: {
128
+ LIST: '/api/categories',
129
+ CREATE: '/api/categories',
130
+ GET: '/api/categories/:id',
131
+ UPDATE: '/api/categories/:id',
132
+ DELETE: '/api/categories/:id',
133
+ },
134
+ COUPONS: {
135
+ LIST: '/api/coupons',
136
+ CREATE: '/api/coupons',
137
+ GET: '/api/coupons/:id',
138
+ UPDATE: '/api/coupons/:id',
139
+ DELETE: '/api/coupons/:id',
140
+ VALIDATE: '/api/coupons/validate/:code',
141
+ },
142
+ };
143
+
144
+ // HTTP STATUS CODES
145
+ export const HTTP_STATUS = {
146
+ OK: 200,
147
+ CREATED: 201,
148
+ NO_CONTENT: 204,
149
+ BAD_REQUEST: 400,
150
+ UNAUTHORIZED: 401,
151
+ FORBIDDEN: 403,
152
+ NOT_FOUND: 404,
153
+ CONFLICT: 409,
154
+ UNPROCESSABLE_ENTITY: 422,
155
+ INTERNAL_SERVER_ERROR: 500,
156
+ SERVICE_UNAVAILABLE: 503,
157
+ };
158
+
159
+ // ERROR MESSAGES
160
+ export const ERROR_MESSAGES = {
161
+ // Auth errors
162
+ UNAUTHORIZED: 'Unauthorized access',
163
+ FORBIDDEN: 'Forbidden access',
164
+ NO_TOKEN: 'No token provided. Access denied.',
165
+ INVALID_TOKEN: 'Invalid or expired token',
166
+ INVALID_CREDENTIALS: 'Invalid email or password',
167
+ USER_EXISTS: 'User with this email already exists',
168
+ USER_NOT_FOUND: 'User not found',
169
+ ACCOUNT_DEACTIVATED: 'Account is deactivated. Please contact support.',
170
+ EMAIL_PASSWORD_MISMATCH: 'Email and password does not match.',
171
+
172
+ // General errors
173
+ NOT_FOUND: 'Resource not found',
174
+ VALIDATION_FAILED: 'Validation failed',
175
+ INTERNAL_ERROR: 'Internal server error',
176
+ SERVICE_UNAVAILABLE: 'Service temporarily unavailable',
177
+ FAILED_TO_FETCH: 'Failed to fetch data',
178
+
179
+ // Product errors
180
+ PRODUCT_NOT_FOUND: 'Product not found',
181
+ INSUFFICIENT_STOCK: 'Insufficient stock available',
182
+ FAILED_TO_GET_PRODUCTS: 'Failed to get products',
183
+ FAILED_TO_CREATE_PRODUCT: 'Failed to create product',
184
+ FAILED_TO_UPDATE_PRODUCT: 'Failed to update product',
185
+ FAILED_TO_DELETE_PRODUCT: 'Failed to delete product',
186
+
187
+ // Category errors
188
+ CATEGORY_NOT_FOUND: 'Category not found',
189
+ FAILED_TO_GET_CATEGORIES: 'Failed to get categories',
190
+ FAILED_TO_CREATE_CATEGORY: 'Failed to create category',
191
+ FAILED_TO_UPDATE_CATEGORY: 'Failed to update category',
192
+ FAILED_TO_DELETE_CATEGORY: 'Failed to delete category',
193
+
194
+ // Order errors
195
+ ORDER_NOT_FOUND: 'Order not found',
196
+ INVALID_ORDER_STATUS: 'Invalid order status',
197
+ FAILED_TO_GET_ORDERS: 'Failed to get orders',
198
+ FAILED_TO_CREATE_ORDER: 'Failed to create order',
199
+ FAILED_TO_UPDATE_ORDER: 'Failed to update order',
200
+
201
+ // Coupon errors
202
+ INVALID_COUPON: 'Invalid or expired coupon',
203
+ COUPON_NOT_FOUND: 'Coupon not found',
204
+ COUPON_EXPIRED: 'Coupon has expired',
205
+ COUPON_LIMIT_REACHED: 'Coupon usage limit reached',
206
+ FAILED_TO_GET_COUPONS: 'Failed to get coupons',
207
+ FAILED_TO_CREATE_COUPON: 'Failed to create coupon',
208
+ FAILED_TO_UPDATE_COUPON: 'Failed to update coupon',
209
+ FAILED_TO_DELETE_COUPON: 'Failed to delete coupon',
210
+
211
+ // Review errors
212
+ REVIEW_NOT_FOUND: 'Review not found',
213
+ DUPLICATE_REVIEW: 'You have already reviewed this product',
214
+ OWN_REVIEW_ONLY: 'You can only delete your own reviews',
215
+ FAILED_TO_GET_REVIEWS: 'Failed to get reviews',
216
+ FAILED_TO_CREATE_REVIEW: 'Failed to create review',
217
+ FAILED_TO_DELETE_REVIEW: 'Failed to delete review',
218
+
219
+ // Address errors
220
+ ADDRESS_NOT_FOUND: 'Address not found',
221
+ FAILED_TO_GET_ADDRESSES: 'Failed to get addresses',
222
+ };
223
+
224
+ // SUCCESS MESSAGES
225
+ export const SUCCESS_MESSAGES = {
226
+ // General
227
+ CREATED: 'Resource created successfully',
228
+ UPDATED: 'Resource updated successfully',
229
+ DELETED: 'Resource deleted successfully',
230
+ FETCHED: 'Data fetched successfully',
231
+
232
+ // Auth
233
+ USER_REGISTERED: 'User registered successfully',
234
+ LOGIN_SUCCESS: 'Login successful',
235
+ LOGOUT_SUCCESS: 'Logout successful',
236
+ PROFILE_UPDATED: 'Profile updated successfully',
237
+ PASSWORD_CHANGED: 'Password changed successfully',
238
+
239
+ // Product
240
+ PRODUCT_CREATED: 'Product created successfully',
241
+ PRODUCT_UPDATED: 'Product updated successfully',
242
+ PRODUCT_DELETED: 'Product deleted successfully',
243
+
244
+ // Category
245
+ CATEGORY_CREATED: 'Category created successfully',
246
+ CATEGORY_UPDATED: 'Category updated successfully',
247
+ CATEGORY_DELETED: 'Category deleted successfully',
248
+
249
+ // Order
250
+ ORDER_PLACED: 'Order placed successfully',
251
+ ORDER_UPDATED: 'Order updated successfully',
252
+ ORDER_CANCELLED: 'Order cancelled successfully',
253
+
254
+ // Coupon
255
+ COUPON_CREATED: 'Coupon created successfully',
256
+ COUPON_UPDATED: 'Coupon updated successfully',
257
+ COUPON_DELETED: 'Coupon deleted successfully',
258
+ COUPON_APPLIED: 'Coupon applied successfully',
259
+
260
+ // Review
261
+ REVIEW_SUBMITTED: 'Review submitted successfully',
262
+ REVIEW_DELETED: 'Review deleted successfully',
263
+
264
+ // Payment
265
+ PAYMENT_SUCCESSFUL: 'Payment processed successfully',
266
+ };
267
+
268
+ // CACHE CONFIGURATION
269
+ export const CACHE_CONFIG = {
270
+ DASHBOARD_STATS_TTL: 30000, // 30 seconds
271
+ DASHBOARD_STATS_REFETCH: 60000, // 1 minute
272
+ PRODUCTS_TTL: 60000, // 1 minute
273
+ CATEGORIES_TTL: 120000, // 2 minutes
274
+ USER_PROFILE_TTL: 300000, // 5 minutes
275
+ ORDERS_TTL: 30000, // 30 seconds
276
+ };
277
+
278
+ // TIMEOUT CONFIGURATION (milliseconds)
279
+ export const TIMEOUT_CONFIG = {
280
+ API_REQUEST: 30000, // 30 seconds
281
+ DATABASE: 10000, // 10 seconds
282
+ GRAPHQL: 15000, // 15 seconds
283
+ };
284
+
285
+ // REGEX PATTERNS (for validation)
286
+ export const REGEX_PATTERNS = {
287
+ EMAIL: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
288
+ PHONE: /^[\d\-\s()]{10,}$/,
289
+ POSTAL_CODE: /^\d{5,6}$/,
290
+ COUPON_CODE: /^[A-Z0-9]{6,20}$/,
291
+ PRODUCT_SKU: /^[A-Z0-9\-]{3,20}$/,
292
+ URL: /^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w.-]*)*\/?$/,
293
+ };
294
+
295
+ // ENVIRONMENT PRESETS
296
+ export const ENV_PRESETS = {
297
+ DEVELOPMENT: {
298
+ corsOrigins: DEFAULT_CORS_ORIGINS,
299
+ logLevel: 'debug',
300
+ apiTimeout: TIMEOUT_CONFIG.API_REQUEST,
301
+ },
302
+ PRODUCTION: {
303
+ corsOrigins: ['https://ecommerce.example.com', 'https://admin.ecommerce.example.com'],
304
+ logLevel: 'info',
305
+ apiTimeout: TIMEOUT_CONFIG.API_REQUEST,
306
+ },
307
+ TESTING: {
308
+ corsOrigins: ['http://localhost:*'],
309
+ logLevel: 'error',
310
+ apiTimeout: TIMEOUT_CONFIG.API_REQUEST,
311
+ },
312
+ };
package/src/cookies.ts ADDED
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Cookie utility functions for secure authentication storage
3
+ */
4
+
5
+ export interface CookieOptions {
6
+ expires?: number; // days
7
+ path?: string;
8
+ domain?: string;
9
+ secure?: boolean;
10
+ sameSite?: 'Strict' | 'Lax' | 'None';
11
+ }
12
+
13
+ const DEFAULT_OPTIONS: CookieOptions = {
14
+ path: '/',
15
+ secure: process.env.NODE_ENV === 'production',
16
+ sameSite: 'Lax',
17
+ };
18
+
19
+ /**
20
+ * Set a cookie with the given name, value, and options
21
+ */
22
+ export const setCookie = (name: string, value: string, options: CookieOptions = {}): void => {
23
+ if (typeof document === 'undefined') return;
24
+
25
+ const opts = { ...DEFAULT_OPTIONS, ...options };
26
+ let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
27
+
28
+ if (opts.expires) {
29
+ const date = new Date();
30
+ date.setTime(date.getTime() + opts.expires * 24 * 60 * 60 * 1000);
31
+ cookieString += `; expires=${date.toUTCString()}`;
32
+ }
33
+
34
+ if (opts.path) {
35
+ cookieString += `; path=${opts.path}`;
36
+ }
37
+
38
+ if (opts.domain) {
39
+ cookieString += `; domain=${opts.domain}`;
40
+ }
41
+
42
+ if (opts.secure) {
43
+ cookieString += '; secure';
44
+ }
45
+
46
+ if (opts.sameSite) {
47
+ cookieString += `; samesite=${opts.sameSite}`;
48
+ }
49
+
50
+ document.cookie = cookieString;
51
+ };
52
+
53
+ /**
54
+ * Get a cookie value by name
55
+ */
56
+ export const getCookie = (name: string): string | null => {
57
+ if (typeof document === 'undefined') return null;
58
+
59
+ const nameEQ = `${encodeURIComponent(name)}=`;
60
+ const cookies = document.cookie.split(';');
61
+
62
+ for (let cookie of cookies) {
63
+ cookie = cookie.trim();
64
+ if (cookie.indexOf(nameEQ) === 0) {
65
+ return decodeURIComponent(cookie.substring(nameEQ.length));
66
+ }
67
+ }
68
+
69
+ return null;
70
+ };
71
+
72
+ /**
73
+ * Remove a cookie by name
74
+ */
75
+ export const removeCookie = (name: string, options: CookieOptions = {}): void => {
76
+ if (typeof document === 'undefined') return;
77
+
78
+ const opts = { ...DEFAULT_OPTIONS, ...options };
79
+ setCookie(name, '', { ...opts, expires: -1 });
80
+ };
81
+
82
+ /**
83
+ * Check if cookies are enabled in the browser
84
+ */
85
+ export const areCookiesEnabled = (): boolean => {
86
+ if (typeof document === 'undefined') return false;
87
+
88
+ try {
89
+ document.cookie = 'cookietest=1';
90
+ const result = document.cookie.indexOf('cookietest=') !== -1;
91
+ document.cookie = 'cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT';
92
+ return result;
93
+ } catch {
94
+ return false;
95
+ }
96
+ };
97
+
98
+ // Cookie names for auth data
99
+ export const AUTH_COOKIE_NAMES = {
100
+ ACCESS_TOKEN: 'accessToken',
101
+ REFRESH_TOKEN: 'refreshToken',
102
+ TOKEN_EXPIRY: 'tokenExpiry',
103
+ USER: 'user',
104
+ } as const;