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.
- package/README.md +163 -0
- package/dist/chunk-PEAZVBSD.mjs +597 -0
- package/dist/client-DYGi_pyp.d.mts +87 -0
- package/dist/client-DYGi_pyp.d.ts +87 -0
- package/dist/index.d.mts +496 -0
- package/dist/index.d.ts +496 -0
- package/dist/index.js +17707 -0
- package/dist/index.mjs +17043 -0
- package/dist/validation/server.d.mts +50 -0
- package/dist/validation/server.d.ts +50 -0
- package/dist/validation/server.js +518 -0
- package/dist/validation/server.mjs +168 -0
- package/package.json +69 -0
- package/src/api/address.queries.ts +96 -0
- package/src/api/category.queries.ts +85 -0
- package/src/api/coupon.queries.ts +120 -0
- package/src/api/dashboard.queries.ts +35 -0
- package/src/api/errorHandler.ts +164 -0
- package/src/api/graphqlClient.ts +113 -0
- package/src/api/index.ts +10 -0
- package/src/api/logger.client.ts +89 -0
- package/src/api/logger.ts +135 -0
- package/src/api/order.queries.ts +211 -0
- package/src/api/product.queries.ts +144 -0
- package/src/api/review.queries.ts +56 -0
- package/src/api/user.queries.ts +232 -0
- package/src/assets/3A.png +0 -0
- package/src/assets/index.ts +1 -0
- package/src/assets.d.ts +29 -0
- package/src/auth.ts +176 -0
- package/src/config/jest.backend.config.js +42 -0
- package/src/config/jest.frontend.config.js +50 -0
- package/src/config/postcss.config.js +6 -0
- package/src/config/tailwind.config.ts +70 -0
- package/src/config/tsconfig.base.json +36 -0
- package/src/config/vite.config.ts +86 -0
- package/src/config/vitest.base.config.ts +74 -0
- package/src/config/webpack.base.config.ts +126 -0
- package/src/constants/index.ts +312 -0
- package/src/cookies.ts +104 -0
- package/src/helpers.ts +400 -0
- package/src/index.ts +32 -0
- package/src/validation/client.ts +287 -0
- package/src/validation/index.ts +3 -0
- 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;
|