@exyconn/common 2.1.0 → 2.3.3

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 (142) hide show
  1. package/README.md +969 -261
  2. package/dist/client/hooks/index.d.mts +1042 -0
  3. package/dist/client/hooks/index.d.ts +1042 -0
  4. package/dist/client/hooks/index.js +2276 -0
  5. package/dist/client/hooks/index.js.map +1 -0
  6. package/dist/client/hooks/index.mjs +2217 -0
  7. package/dist/client/hooks/index.mjs.map +1 -0
  8. package/dist/client/http/index.d.mts +217 -49
  9. package/dist/client/http/index.d.ts +217 -49
  10. package/dist/client/http/index.js +473 -94
  11. package/dist/client/http/index.js.map +1 -1
  12. package/dist/client/http/index.mjs +441 -84
  13. package/dist/client/http/index.mjs.map +1 -1
  14. package/dist/client/index.d.mts +6 -4
  15. package/dist/client/index.d.ts +6 -4
  16. package/dist/client/index.js +481 -319
  17. package/dist/client/index.js.map +1 -1
  18. package/dist/client/index.mjs +449 -290
  19. package/dist/client/index.mjs.map +1 -1
  20. package/dist/client/utils/index.d.mts +3 -279
  21. package/dist/client/utils/index.d.ts +3 -279
  22. package/dist/client/web/index.d.mts +1461 -0
  23. package/dist/client/web/index.d.ts +1461 -0
  24. package/dist/client/web/index.js +2681 -0
  25. package/dist/client/web/index.js.map +1 -0
  26. package/dist/client/web/index.mjs +2618 -0
  27. package/dist/client/web/index.mjs.map +1 -0
  28. package/dist/data/brand-identity.d.mts +149 -0
  29. package/dist/data/brand-identity.d.ts +149 -0
  30. package/dist/data/brand-identity.js +235 -0
  31. package/dist/data/brand-identity.js.map +1 -0
  32. package/dist/data/brand-identity.mjs +220 -0
  33. package/dist/data/brand-identity.mjs.map +1 -0
  34. package/dist/data/countries.d.mts +61 -0
  35. package/dist/data/countries.d.ts +61 -0
  36. package/dist/data/countries.js +987 -0
  37. package/dist/data/countries.js.map +1 -0
  38. package/dist/data/countries.mjs +971 -0
  39. package/dist/data/countries.mjs.map +1 -0
  40. package/dist/data/currencies.d.mts +19 -0
  41. package/dist/data/currencies.d.ts +19 -0
  42. package/dist/data/currencies.js +162 -0
  43. package/dist/data/currencies.js.map +1 -0
  44. package/dist/data/currencies.mjs +153 -0
  45. package/dist/data/currencies.mjs.map +1 -0
  46. package/dist/data/index.d.mts +7 -0
  47. package/dist/data/index.d.ts +7 -0
  48. package/dist/data/index.js +2087 -0
  49. package/dist/data/index.js.map +1 -0
  50. package/dist/data/index.mjs +1948 -0
  51. package/dist/data/index.mjs.map +1 -0
  52. package/dist/data/phone-codes.d.mts +15 -0
  53. package/dist/data/phone-codes.d.ts +15 -0
  54. package/dist/data/phone-codes.js +219 -0
  55. package/dist/data/phone-codes.js.map +1 -0
  56. package/dist/data/phone-codes.mjs +211 -0
  57. package/dist/data/phone-codes.mjs.map +1 -0
  58. package/dist/data/regex.d.mts +287 -0
  59. package/dist/data/regex.d.ts +287 -0
  60. package/dist/data/regex.js +306 -0
  61. package/dist/data/regex.js.map +1 -0
  62. package/dist/data/regex.mjs +208 -0
  63. package/dist/data/regex.mjs.map +1 -0
  64. package/dist/data/timezones.d.mts +16 -0
  65. package/dist/data/timezones.d.ts +16 -0
  66. package/dist/data/timezones.js +98 -0
  67. package/dist/data/timezones.js.map +1 -0
  68. package/dist/data/timezones.mjs +89 -0
  69. package/dist/data/timezones.mjs.map +1 -0
  70. package/dist/index-BZf42T3R.d.mts +305 -0
  71. package/dist/index-CF0D8PGE.d.ts +305 -0
  72. package/dist/index-Ckhm_HaX.d.mts +138 -0
  73. package/dist/index-DKn4raO7.d.ts +222 -0
  74. package/dist/index-NS8dS0p9.d.mts +222 -0
  75. package/dist/index-Nqm5_lwT.d.ts +188 -0
  76. package/dist/index-br6POSyA.d.ts +138 -0
  77. package/dist/index-jBi3V6e5.d.mts +188 -0
  78. package/dist/index.d.mts +21 -580
  79. package/dist/index.d.ts +21 -580
  80. package/dist/index.js +1839 -347
  81. package/dist/index.js.map +1 -1
  82. package/dist/index.mjs +1850 -359
  83. package/dist/index.mjs.map +1 -1
  84. package/dist/packageCheck-B_qfsD6R.d.ts +280 -0
  85. package/dist/packageCheck-C2_FT_Rl.d.mts +280 -0
  86. package/dist/server/configs/index.d.mts +602 -0
  87. package/dist/server/configs/index.d.ts +602 -0
  88. package/dist/server/configs/index.js +707 -0
  89. package/dist/server/configs/index.js.map +1 -0
  90. package/dist/server/configs/index.mjs +665 -0
  91. package/dist/server/configs/index.mjs.map +1 -0
  92. package/dist/server/index.d.mts +4 -1
  93. package/dist/server/index.d.ts +4 -1
  94. package/dist/server/index.js +1330 -0
  95. package/dist/server/index.js.map +1 -1
  96. package/dist/server/index.mjs +1286 -2
  97. package/dist/server/index.mjs.map +1 -1
  98. package/dist/server/middleware/index.d.mts +283 -2
  99. package/dist/server/middleware/index.d.ts +283 -2
  100. package/dist/server/middleware/index.js +761 -0
  101. package/dist/server/middleware/index.js.map +1 -1
  102. package/dist/server/middleware/index.mjs +751 -1
  103. package/dist/server/middleware/index.mjs.map +1 -1
  104. package/dist/shared/config/index.d.mts +40 -0
  105. package/dist/shared/config/index.d.ts +40 -0
  106. package/dist/shared/config/index.js +58 -0
  107. package/dist/shared/config/index.js.map +1 -0
  108. package/dist/shared/config/index.mjs +51 -0
  109. package/dist/shared/config/index.mjs.map +1 -0
  110. package/dist/shared/constants/index.d.mts +593 -0
  111. package/dist/shared/constants/index.d.ts +593 -0
  112. package/dist/shared/constants/index.js +391 -0
  113. package/dist/shared/constants/index.js.map +1 -0
  114. package/dist/shared/constants/index.mjs +360 -0
  115. package/dist/shared/constants/index.mjs.map +1 -0
  116. package/dist/shared/index.d.mts +5 -1
  117. package/dist/shared/index.d.ts +5 -1
  118. package/dist/shared/types/index.d.mts +140 -0
  119. package/dist/shared/types/index.d.ts +140 -0
  120. package/dist/shared/types/index.js +4 -0
  121. package/dist/shared/types/index.js.map +1 -0
  122. package/dist/shared/types/index.mjs +3 -0
  123. package/dist/shared/types/index.mjs.map +1 -0
  124. package/dist/shared/utils/index.d.mts +255 -0
  125. package/dist/shared/utils/index.d.ts +255 -0
  126. package/dist/shared/utils/index.js +623 -0
  127. package/dist/shared/utils/index.js.map +1 -0
  128. package/dist/shared/utils/index.mjs +324 -0
  129. package/dist/shared/utils/index.mjs.map +1 -0
  130. package/dist/shared/validation/index.d.mts +258 -0
  131. package/dist/shared/validation/index.d.ts +258 -0
  132. package/dist/shared/validation/index.js +185 -0
  133. package/dist/shared/validation/index.js.map +1 -0
  134. package/dist/shared/validation/index.mjs +172 -0
  135. package/dist/shared/validation/index.mjs.map +1 -0
  136. package/package.json +127 -62
  137. package/dist/index-BcxL4_V4.d.ts +0 -2946
  138. package/dist/index-DEzgM15j.d.ts +0 -67
  139. package/dist/index-DNFVgQx8.d.ts +0 -1375
  140. package/dist/index-DbV04Dx8.d.mts +0 -67
  141. package/dist/index-DfqEP6Oe.d.mts +0 -1375
  142. package/dist/index-bvvCev9Q.d.mts +0 -2946
package/README.md CHANGED
@@ -1,6 +1,39 @@
1
1
  # @exyconn/common
2
2
 
3
- Common utilities, hooks, types, and data shared across all Exyconn projects (botify.life, exyconn.com, partywings.fun, sibera.work, spentiva.com).
3
+ [![npm version](https://img.shields.io/npm/v/@exyconn/common.svg)](https://www.npmjs.com/package/@exyconn/common)
4
+ [![CI](https://github.com/exyconn/common/actions/workflows/ci.yml/badge.svg)](https://github.com/exyconn/common/actions/workflows/ci.yml)
5
+ [![Coverage](https://img.shields.io/codecov/c/github/exyconn/common)](https://codecov.io/gh/exyconn/common)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.3-blue.svg)](https://www.typescriptlang.org/)
8
+ [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@exyconn/common)](https://bundlephobia.com/package/@exyconn/common)
9
+ [![Documentation](https://img.shields.io/badge/docs-common--docs.exyconn.com-blue)](https://common-docs.exyconn.com)
10
+
11
+ Production-ready common utilities, hooks, types, and data shared across all Exyconn projects (botify.life, exyconn.com, partywings.fun, sibera.work, spentiva.com).
12
+
13
+ ## 📚 Documentation
14
+
15
+ **Full documentation available at: [common-docs.exyconn.com](https://common-docs.exyconn.com)**
16
+
17
+ ---
18
+
19
+ ## Table of Contents
20
+
21
+ - [Installation](#installation)
22
+ - [Features](#features)
23
+ - [Quick Start](#quick-start)
24
+ - [Module Reference](#module-reference)
25
+ - [Server](#server-module)
26
+ - [Client](#client-module)
27
+ - [Shared](#shared-module)
28
+ - [Data](#data-module)
29
+ - [React Hooks](#react-hooks)
30
+ - [API Reference](#api-reference)
31
+ - [Development](#development)
32
+ - [Peer Dependencies](#peer-dependencies)
33
+ - [Contributing](#contributing)
34
+ - [License](#license)
35
+
36
+ ---
4
37
 
5
38
  ## Installation
6
39
 
@@ -12,333 +45,1008 @@ yarn add @exyconn/common
12
45
  pnpm add @exyconn/common
13
46
  ```
14
47
 
48
+ ### Requirements
49
+
50
+ - Node.js >= 18.0.0
51
+ - React >= 18.0.0 (for hooks)
52
+ - TypeScript >= 5.0.0 (recommended)
53
+
15
54
  ## Features
16
55
 
17
- - 🖥️ **Server utilities** - Response helpers, middleware, logging, database connections
18
- - 🌐 **Client utilities** - HTTP clients, React hooks, response parsing
19
- - 📝 **Shared types** - TypeScript interfaces for API responses, users, etc.
20
- - 🗃️ **Data modules** - Countries, currencies, phone codes, timezones, brand logos
21
- - **Validation** - Common patterns, regex, and validation helpers
22
- - 📅 **Date utilities** - Enhanced date-fns with timezone support
23
- - 🎨 **Brand Identity** - Complete brand configs with logos, colors, and SEO
24
- - 🔢 **Enums & Constants** - STATUS, SORT, ROLE, BREAKPOINTS, and more
56
+ | Category | Description |
57
+ |----------|-------------|
58
+ | 🖥️ **Server utilities** | Response helpers, middleware, logging, database connections, dynamic configs |
59
+ | 🌐 **Client utilities** | HTTP clients, React hooks (54+), response parsing |
60
+ | 📝 **Shared types** | TypeScript interfaces for API responses, users, etc. |
61
+ | 🗃️ **Data modules** | Countries, currencies, phone codes, timezones, brand logos |
62
+ | **Validation** | Common patterns, regex, and validation helpers (Zod integration) |
63
+ | 📅 **Date utilities** | Enhanced date-fns with timezone support |
64
+ | 🎨 **Brand Identity** | Complete brand configs with logos, colors, and SEO |
65
+ | 🔢 **Enums & Constants** | STATUS, SORT, ROLE, BREAKPOINTS, and more |
66
+ | ⚙️ **Dynamic Configs** | Production-ready CORS, Rate Limiting, Server configs |
67
+ | 🧪 **Fully Tested** | Comprehensive test coverage with Vitest |
68
+
69
+ ---
70
+
71
+ ## Quick Start
72
+
73
+ ### Import by Module (Recommended)
74
+
75
+ ```typescript
76
+ // Server utilities
77
+ import { successResponse, errorResponse } from '@exyconn/common/server/response';
78
+ import { createCorsOptions, createRateLimiter } from '@exyconn/common/server/configs';
79
+ import { createLogger } from '@exyconn/common/server/logger';
80
+ import { connectDB } from '@exyconn/common/server/db';
81
+ import { createCrudControllers, queryParser, queryPagination } from '@exyconn/common/server/middleware';
82
+
83
+ // Client utilities
84
+ import { useLocalStorage, useDebounce } from '@exyconn/common/client/hooks';
85
+ import { getRequest, postRequest, extractData, isSuccess } from '@exyconn/common/client/http';
86
+
87
+ // Shared utilities
88
+ import { isValidEmail, VALIDATION_PATTERNS } from '@exyconn/common/shared/validation';
89
+ import { getEnv, isProd } from '@exyconn/common/shared/config';
25
90
 
26
- ## Usage
91
+ // Data modules
92
+ import { countries, getCountryByCode } from '@exyconn/common/data/countries';
93
+ import { BRANDS, getBrandById } from '@exyconn/common/data/brand-identity';
94
+ ```
27
95
 
28
- ### Import Everything
96
+ ### Import Everything (Not Recommended for Bundle Size)
29
97
 
30
98
  ```typescript
31
99
  import { server, client, shared, data } from '@exyconn/common';
32
100
  ```
33
101
 
34
- ### Server-side
102
+ ---
103
+
104
+ ## Module Reference
105
+
106
+ ### Server Module
107
+
108
+ **Import:** `@exyconn/common/server` or specific submodules
109
+
110
+ #### Server Configs (`@exyconn/common/server/configs`)
111
+
112
+ Dynamic configuration system for production applications.
113
+
114
+ ##### ConfigBuilder
35
115
 
36
116
  ```typescript
37
- // Response helpers
38
- import { successResponse, errorResponse, paginatedResponse } from '@exyconn/common/server/response';
117
+ import {
118
+ createConfig,
119
+ buildConfig,
120
+ ConfigBuilder,
121
+ // Types
122
+ type AppConfig,
123
+ type ServerConfig,
124
+ type DatabaseConfig,
125
+ type AuthConfig,
126
+ type LoggingConfig,
127
+ } from '@exyconn/common/server/configs';
39
128
 
40
- // Status codes & messages
41
- import { STATUS_CODES, STATUS_MESSAGES } from '@exyconn/common/server/enums';
129
+ // Method 1: Using ConfigBuilder (fluent API)
130
+ const config = createConfig()
131
+ .setServer({
132
+ name: 'my-api-server',
133
+ port: 4000,
134
+ environment: 'production',
135
+ })
136
+ .setDatabase({
137
+ uri: process.env.MONGODB_URI!,
138
+ maxPoolSize: 50,
139
+ })
140
+ .setAuth({
141
+ jwtSecret: process.env.JWT_SECRET!,
142
+ jwtExpiresIn: '7d',
143
+ })
144
+ .setLogging({
145
+ level: 'info',
146
+ file: true,
147
+ })
148
+ .addProductionOrigin('https://myapp.com')
149
+ .addProductionOrigin('https://api.myapp.com')
150
+ .addCorsPattern('.myapp.com')
151
+ .addRateLimitTier('upload', {
152
+ windowMs: 60000,
153
+ maxRequests: 5,
154
+ message: 'Upload limit exceeded',
155
+ })
156
+ .setCustom('featureFlags', { newFeature: true })
157
+ .loadFromEnv()
158
+ .build();
42
159
 
43
- // Winston logger
44
- import { createLogger, logger } from '@exyconn/common/server/logger';
160
+ // Method 2: Quick build from partial config
161
+ const quickConfig = buildConfig({
162
+ server: { name: 'quick-server', port: 3000 },
163
+ database: { uri: 'mongodb://localhost/mydb' },
164
+ });
45
165
 
46
- // MongoDB connection
47
- import { connectDB } from '@exyconn/common/server/db';
166
+ // Validate configuration
167
+ const validation = createConfig().setServer({ name: '' }).validate();
168
+ if (!validation.valid) {
169
+ console.error('Config errors:', validation.errors);
170
+ }
171
+ ```
172
+
173
+ **ConfigBuilder Methods:**
174
+
175
+ | Method | Parameters | Description |
176
+ |--------|------------|-------------|
177
+ | `setServer(config)` | `Partial<ServerConfig>` | Set server configuration |
178
+ | `setDatabase(config)` | `Partial<DatabaseConfig>` | Set database configuration |
179
+ | `setAuth(config)` | `Partial<AuthConfig>` | Set auth configuration |
180
+ | `setLogging(config)` | `Partial<LoggingConfig>` | Set logging configuration |
181
+ | `setCorsOrigins(config)` | `Partial<CorsOriginsConfig>` | Set CORS origins |
182
+ | `addProductionOrigin(origin)` | `string` | Add a production CORS origin |
183
+ | `addDevelopmentOrigin(origin)` | `string` | Add a development CORS origin |
184
+ | `addCorsPattern(pattern)` | `string` | Add subdomain pattern |
185
+ | `setRateLimit(config)` | `Partial<RateLimitConfig>` | Set rate limit config |
186
+ | `addRateLimitTier(name, tier)` | `string, RateLimitTier` | Add custom rate limit tier |
187
+ | `setCustom(key, value)` | `string, unknown` | Set custom config value |
188
+ | `loadFromEnv()` | - | Load config from environment variables |
189
+ | `validate()` | - | Validate configuration, returns `{ valid, errors }` |
190
+ | `build()` | - | Build final configuration |
48
191
 
49
- // Auth middleware
50
- import { authMiddleware, apiKeyMiddleware } from '@exyconn/common/server/middleware';
192
+ ##### CORS Configuration
193
+
194
+ ```typescript
195
+ import {
196
+ createCorsOptions,
197
+ createBrandCorsOptions,
198
+ createMultiBrandCorsOptions,
199
+ // Presets
200
+ DEFAULT_CORS_CONFIG,
201
+ EXYCONN_CORS_CONFIG,
202
+ STRICT_CORS_CONFIG,
203
+ PERMISSIVE_CORS_CONFIG,
204
+ // Types
205
+ type CorsConfig,
206
+ } from '@exyconn/common/server/configs';
207
+
208
+ // Custom CORS configuration
209
+ const corsOptions = createCorsOptions({
210
+ productionOrigins: ['https://myapp.com', 'https://api.myapp.com'],
211
+ developmentOrigins: ['http://localhost:3000', 'http://localhost:5173'],
212
+ allowedSubdomains: ['.myapp.com'],
213
+ originPatterns: [/\.myapp\.(com|io)$/],
214
+ allowNoOrigin: true, // Allow mobile apps, curl
215
+ allowAllInDev: true, // Allow all in development
216
+ credentials: true,
217
+ methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
218
+ allowedHeaders: ['Content-Type', 'Authorization', 'X-API-Key'],
219
+ exposedHeaders: ['X-Total-Count'],
220
+ maxAge: 86400, // 24 hours preflight cache
221
+ customValidator: (origin) => origin.includes('trusted'), // Custom validation
222
+ });
223
+
224
+ // Single brand CORS (auto-includes www and subdomains)
225
+ const brandCors = createBrandCorsOptions('myapp.com', {
226
+ credentials: true,
227
+ });
228
+
229
+ // Multi-brand CORS
230
+ const multiBrandCors = createMultiBrandCorsOptions(
231
+ ['myapp.com', 'myapp.io', 'api.myapp.com'],
232
+ { allowNoOrigin: false }
233
+ );
234
+
235
+ // Usage with Express
236
+ import cors from 'cors';
237
+ app.use(cors(corsOptions));
51
238
  ```
52
239
 
53
- ### Client-side
240
+ **CorsConfig Options:**
241
+
242
+ | Option | Type | Default | Required | Description |
243
+ |--------|------|---------|----------|-------------|
244
+ | `productionOrigins` | `string[]` | `[]` | No | Allowed production origins |
245
+ | `developmentOrigins` | `string[]` | Common localhost ports | No | Allowed development origins |
246
+ | `allowedSubdomains` | `string[]` | `[]` | No | Subdomain patterns (e.g., `.myapp.com`) |
247
+ | `originPatterns` | `RegExp[]` | `[]` | No | Regex patterns for origin matching |
248
+ | `allowNoOrigin` | `boolean` | `true` | No | Allow requests with no origin |
249
+ | `allowAllInDev` | `boolean` | `true` | No | Allow all origins in development |
250
+ | `customValidator` | `(origin: string) => boolean` | - | No | Custom origin validator |
251
+ | `credentials` | `boolean` | `true` | No | Include credentials |
252
+ | `methods` | `string[]` | All standard methods | No | Allowed HTTP methods |
253
+ | `allowedHeaders` | `string[]` | Common headers | No | Allowed request headers |
254
+ | `exposedHeaders` | `string[]` | Common response headers | No | Exposed response headers |
255
+ | `maxAge` | `number` | `86400` | No | Preflight cache duration (seconds) |
256
+
257
+ ##### Rate Limiter Configuration
54
258
 
55
259
  ```typescript
56
- // HTTP client
57
- import { createHttpClient, httpGet, httpPost } from '@exyconn/common/client/http';
260
+ import {
261
+ // Factory functions
262
+ createRateLimiter,
263
+ createStandardRateLimiter,
264
+ createStrictRateLimiter,
265
+ createDdosRateLimiter,
266
+ createApiRateLimiter,
267
+ // Builder
268
+ rateLimiter,
269
+ RateLimiterBuilder,
270
+ // Key generators
271
+ defaultKeyGenerator,
272
+ createPrefixedKeyGenerator,
273
+ createUserKeyGenerator,
274
+ createApiKeyGenerator,
275
+ // Constants
276
+ DEFAULT_RATE_LIMIT_TIERS,
277
+ // Types
278
+ type RateLimitTierConfig,
279
+ } from '@exyconn/common/server/configs';
280
+
281
+ // Method 1: Factory functions with defaults
282
+ const standardLimiter = createStandardRateLimiter(); // 100 req/15min
283
+ const strictLimiter = createStrictRateLimiter(); // 20 req/15min
284
+ const ddosLimiter = createDdosRateLimiter(); // 60 req/1min
285
+ const apiLimiter = createApiRateLimiter(); // 30 req/1min (by API key)
286
+
287
+ // Method 2: Custom configuration
288
+ const customLimiter = createRateLimiter({
289
+ windowMs: 5 * 60 * 1000, // 5 minutes
290
+ maxRequests: 50,
291
+ message: 'Too many requests, please slow down.',
292
+ skipSuccessfulRequests: false,
293
+ skipFailedRequests: false,
294
+ }, {
295
+ standardHeaders: true,
296
+ legacyHeaders: false,
297
+ keyGenerator: defaultKeyGenerator,
298
+ skip: (req) => req.headers['x-skip-rate-limit'] === 'true',
299
+ });
300
+
301
+ // Method 3: Builder pattern (most flexible)
302
+ const uploadLimiter = rateLimiter('STRICT')
303
+ .windowMinutes(5)
304
+ .max(10)
305
+ .message('Upload limit exceeded. Please wait.')
306
+ .keyByIp()
307
+ .skipWhen((req) => req.user?.isPremium)
308
+ .build();
309
+
310
+ // User-based rate limiting
311
+ const userLimiter = rateLimiter()
312
+ .windowHours(1)
313
+ .max(1000)
314
+ .keyBy((req) => req.userId || defaultKeyGenerator(req))
315
+ .build();
316
+
317
+ // API key based rate limiting
318
+ const apiKeyLimiter = rateLimiter('API')
319
+ .keyByApiKey('x-api-key')
320
+ .build();
58
321
 
59
- // React hooks
322
+ // Usage with Express
323
+ app.use('/api/', ddosLimiter);
324
+ app.use('/api/', standardLimiter);
325
+ app.post('/api/auth/login', strictLimiter);
326
+ app.post('/api/upload', uploadLimiter);
327
+ ```
328
+
329
+ **RateLimiterBuilder Methods:**
330
+
331
+ | Method | Parameters | Description |
332
+ |--------|------------|-------------|
333
+ | `windowMs(ms)` | `number` | Set window in milliseconds |
334
+ | `windowMinutes(minutes)` | `number` | Set window in minutes |
335
+ | `windowHours(hours)` | `number` | Set window in hours |
336
+ | `max(requests)` | `number` | Set max requests in window |
337
+ | `message(msg)` | `string` | Set error message |
338
+ | `skipSuccessful(skip?)` | `boolean` | Skip successful requests (default: true) |
339
+ | `skipFailed(skip?)` | `boolean` | Skip failed requests (default: true) |
340
+ | `keyBy(generator)` | `(req) => string` | Custom key generator |
341
+ | `keyByIp()` | - | Key by IP address (default) |
342
+ | `keyByApiKey(headerName?)` | `string` | Key by API key header |
343
+ | `skipWhen(predicate)` | `(req) => boolean` | Skip when condition is true |
344
+ | `build()` | - | Build rate limiter middleware |
345
+
346
+ **Available Rate Limit Tiers:**
347
+
348
+ | Tier | Window | Max Requests | Use Case |
349
+ |------|--------|--------------|----------|
350
+ | `STANDARD` | 15 min | 100 | General API endpoints |
351
+ | `STRICT` | 15 min | 20 | Auth endpoints (login, signup) |
352
+ | `DDOS` | 1 min | 60 | Global DDoS protection |
353
+ | `VERY_STRICT` | 1 hour | 5 | Password reset, sensitive actions |
354
+ | `RELAXED` | 15 min | 500 | High-traffic endpoints |
355
+ | `API` | 1 min | 30 | Third-party API access |
356
+
357
+ #### Response Helpers (`@exyconn/common/server/response`)
358
+
359
+ ```typescript
60
360
  import {
61
- useLocalStorage,
62
- useDebounce,
63
- useCopyToClipboard,
64
- usePageTitle,
65
- useSnackbar,
66
- useMediaQuery,
67
- useIsMobile,
68
- useThemeDetector,
69
- useInterval,
70
- useOnClickOutside,
71
- useWindowSize
72
- } from '@exyconn/common/client/hooks';
73
-
74
- // Utils
361
+ // Success responses
362
+ successResponse, // 200 OK
363
+ successResponseArr, // 200 OK with pagination
364
+ createdResponse, // 201 Created
365
+ noContentResponse, // 204 No Content
366
+
367
+ // Error responses
368
+ badRequestResponse, // 400 Bad Request
369
+ unauthorizedResponse, // 401 Unauthorized
370
+ forbiddenResponse, // 403 Forbidden
371
+ notFoundResponse, // 404 Not Found
372
+ conflictResponse, // 409 Conflict
373
+ serverErrorResponse, // 500 Internal Server Error
374
+
375
+ // Utilities
376
+ extractColumns,
377
+
378
+ // Types
379
+ type ApiResponse,
380
+ type PaginationData,
381
+ type ColumnMetadata,
382
+ } from '@exyconn/common/server/response';
383
+
384
+ // Basic success response
385
+ app.get('/api/user/:id', async (req, res) => {
386
+ const user = await User.findById(req.params.id);
387
+ return successResponse(res, user, 'User retrieved successfully');
388
+ });
389
+ // Response: { status: 'success', statusCode: 200, message: '...', data: {...} }
390
+
391
+ // Paginated array response (auto-extracts columns for table rendering)
392
+ app.get('/api/users', async (req, res) => {
393
+ const { page = 1, limit = 10 } = req.query;
394
+ const users = await User.find().skip((page - 1) * limit).limit(limit);
395
+ const total = await User.countDocuments();
396
+
397
+ return successResponseArr(res, users, {
398
+ total,
399
+ page,
400
+ limit,
401
+ totalPages: Math.ceil(total / limit),
402
+ hasNextPage: page < Math.ceil(total / limit),
403
+ hasPrevPage: page > 1,
404
+ }, 'Users retrieved');
405
+ });
406
+
407
+ // Error responses
408
+ return badRequestResponse(res, 'Invalid email format', { field: 'email' });
409
+ return unauthorizedResponse(res, 'Token expired');
410
+ return forbiddenResponse(res, 'Insufficient permissions');
411
+ return notFoundResponse(res, 'User not found');
412
+ return serverErrorResponse(res, 'Database connection failed');
413
+ ```
414
+
415
+ **Response Functions:**
416
+
417
+ | Function | Status | Parameters | Description |
418
+ |----------|--------|------------|-------------|
419
+ | `successResponse` | 200 | `(res, data, message?)` | Standard success |
420
+ | `successResponseArr` | 200 | `(res, data[], pagination?, message?)` | Paginated array |
421
+ | `createdResponse` | 201 | `(res, data, message?)` | Resource created |
422
+ | `noContentResponse` | 200* | `(res, data?, message?)` | No data found |
423
+ | `badRequestResponse` | 400 | `(res, message?, errors?)` | Invalid request |
424
+ | `unauthorizedResponse` | 401 | `(res, message?)` | Authentication required |
425
+ | `forbiddenResponse` | 403 | `(res, message?)` | Access denied |
426
+ | `notFoundResponse` | 404 | `(res, message?)` | Resource not found |
427
+ | `conflictResponse` | 409 | `(res, message?)` | Resource conflict |
428
+ | `serverErrorResponse` | 500 | `(res, message?, error?)` | Server error |
429
+
430
+ #### Logger (`@exyconn/common/server/logger`)
431
+
432
+ ```typescript
75
433
  import {
76
- formatDate,
77
- copyToClipboard,
78
- toSlug,
79
- isSuccessResponse,
80
- getErrorMessage
81
- } from '@exyconn/common/client/utils';
434
+ createLogger,
435
+ logger, // Default instance
436
+ simpleLogger, // Console-only logger
437
+ createMorganStream,
438
+ stream, // Morgan stream for default logger
439
+ type LoggerConfig,
440
+ } from '@exyconn/common/server/logger';
441
+
442
+ // Default logger (writes to console + files)
443
+ logger.info('Server started', { port: 3000 });
444
+ logger.error('Database error', { error: err.message, stack: err.stack });
445
+ logger.warn('Rate limit approaching');
446
+ logger.debug('Request received', { method: 'GET', path: '/api/users' });
447
+
448
+ // Custom logger
449
+ const customLogger = createLogger({
450
+ level: 'debug', // 'error' | 'warn' | 'info' | 'http' | 'debug'
451
+ logsDir: 'logs', // Directory for log files
452
+ maxSize: '20m', // Max file size before rotation
453
+ maxFiles: '14d', // Keep logs for 14 days
454
+ errorMaxFiles: '30d', // Keep error logs longer
455
+ });
456
+
457
+ // Simple logger (no files, just console)
458
+ simpleLogger.info('Quick debug message');
459
+
460
+ // With Morgan HTTP logger
461
+ import morgan from 'morgan';
462
+ app.use(morgan('combined', { stream }));
82
463
  ```
83
464
 
84
- ### Shared Types
465
+ #### Database (`@exyconn/common/server/db`)
85
466
 
86
467
  ```typescript
87
- import type {
88
- ApiResponse,
89
- PaginatedResponse,
90
- User,
91
- AuthResponse,
92
- JwtPayload
93
- } from '@exyconn/common/shared/types';
468
+ import {
469
+ connectDB,
470
+ disconnectDB,
471
+ getConnectionStatus,
472
+ type DbConnectionOptions,
473
+ } from '@exyconn/common/server/db';
474
+
475
+ // Connect with default options
476
+ await connectDB(process.env.MONGODB_URI!, {}, logger);
477
+
478
+ // Connect with custom options
479
+ await connectDB(process.env.MONGODB_URI!, {
480
+ maxPoolSize: 50,
481
+ minPoolSize: 10,
482
+ socketTimeoutMS: 45000,
483
+ retryWrites: true,
484
+ }, logger);
485
+
486
+ // Check status
487
+ const status = getConnectionStatus(); // 'connected' | 'disconnected' | ...
488
+
489
+ // Disconnect gracefully
490
+ await disconnectDB(logger);
94
491
  ```
95
492
 
96
- ### Validation
493
+ #### Middleware (`@exyconn/common/server/middleware`)
494
+
495
+ ##### CRUD Controller Factory
496
+
497
+ ```typescript
498
+ import { createCrudControllers } from '@exyconn/common/server/middleware';
499
+ import { z } from 'zod';
500
+ import { User } from './models/User';
501
+
502
+ const userController = createCrudControllers({
503
+ model: User,
504
+ resourceName: 'User',
505
+ createSchema: z.object({ name: z.string(), email: z.string().email() }),
506
+ updateSchema: z.object({ name: z.string().optional() }),
507
+ searchFields: ['name', 'email'],
508
+ withOrganization: true,
509
+ });
510
+
511
+ // Auto-generated routes
512
+ router.get('/users', userController.getAll);
513
+ router.get('/users/:id', userController.getById);
514
+ router.post('/users', userController.create);
515
+ router.put('/users/:id', userController.update);
516
+ router.delete('/users/:id', userController.deleteOne);
517
+ router.delete('/users', userController.bulkDelete);
518
+ ```
519
+
520
+ ##### Query Parser & Pagination
521
+
522
+ ```typescript
523
+ import { queryParser, queryPagination } from '@exyconn/common/server/middleware';
524
+
525
+ router.get('/users', queryParser, async (req, res) => {
526
+ const { page, limit, sort, search, filter } = req.parsedQuery;
527
+ // page: 1, limit: 10, sort: { createdAt: 'desc' }, search: 'john'
528
+
529
+ await queryPagination(User, {
530
+ searchFields: ['name', 'email'],
531
+ populate: ['department'],
532
+ }, true)(req, res, () => {});
533
+
534
+ res.json(res.paginatedResult);
535
+ // { data: [...], meta: { total, page, limit, totalPages }, columns: [...] }
536
+ });
537
+ ```
538
+
539
+ ##### Authentication Middleware
540
+
541
+ ```typescript
542
+ import {
543
+ authenticateJWT,
544
+ optionalAuthenticateJWT,
545
+ authenticateApiKey,
546
+ extractOrganization,
547
+ type AuthRequest,
548
+ } from '@exyconn/common/server/middleware';
549
+
550
+ // JWT Authentication (required)
551
+ app.use('/api/protected', authenticateJWT(process.env.JWT_SECRET!));
552
+
553
+ // JWT Authentication (optional)
554
+ app.use('/api/public', optionalAuthenticateJWT(process.env.JWT_SECRET!));
555
+
556
+ // API Key Authentication
557
+ app.use('/api/external', authenticateApiKey(async (key) => {
558
+ const apiKey = await ApiKey.findOne({ key, isActive: true });
559
+ return { valid: !!apiKey, organizationId: apiKey?.organizationId };
560
+ }));
561
+
562
+ // Access auth data in routes
563
+ app.get('/api/profile', authenticateJWT(secret), (req: AuthRequest, res) => {
564
+ const userId = req.userId;
565
+ const orgId = req.organizationId;
566
+ });
567
+ ```
568
+
569
+ #### Server Utils (`@exyconn/common/server/utils`)
570
+
571
+ ```typescript
572
+ import {
573
+ buildFilter,
574
+ buildPagination,
575
+ buildPaginationMeta,
576
+ } from '@exyconn/common/server/utils';
577
+
578
+ // Build MongoDB filter dynamically
579
+ const filter = buildFilter({
580
+ organizationId: req.organizationId,
581
+ search: req.query.q,
582
+ searchFields: ['name', 'email', 'phone'],
583
+ status: req.query.status,
584
+ startDate: req.query.from,
585
+ endDate: req.query.to,
586
+ });
587
+
588
+ // Calculate pagination
589
+ const pagination = buildPagination({
590
+ page: parseInt(req.query.page) || 1,
591
+ limit: parseInt(req.query.limit),
592
+ defaultLimit: 10,
593
+ maxLimit: 100,
594
+ });
595
+
596
+ // Build pagination meta
597
+ const meta = buildPaginationMeta(totalCount, pagination.page, pagination.limit);
598
+ ```
599
+
600
+ ---
601
+
602
+ ### Client Module
603
+
604
+ **Import:** `@exyconn/common/client` or specific submodules
605
+
606
+ #### React Hooks (`@exyconn/common/client/hooks`)
607
+
608
+ 50+ production-ready React hooks organized by category.
609
+
610
+ ##### State & Logic Hooks
611
+
612
+ | Hook | Description | Example |
613
+ |------|-------------|---------|
614
+ | `useToggle` | Boolean toggle | `const [isOpen, toggle] = useToggle(false)` |
615
+ | `useCounter` | Numeric counter | `const { count, increment, decrement } = useCounter(0)` |
616
+ | `usePrevious` | Track previous value | `const prevValue = usePrevious(value)` |
617
+ | `useObjectState` | Partial state updates | `const [state, setState] = useObjectState({ a: 1 })` |
618
+ | `useHistoryState` | State with undo/redo | `const [value, setValue, { undo, redo }] = useHistoryState('')` |
619
+ | `useList` | Array operations | `const [list, { push, removeAt }] = useList([])` |
620
+ | `useMap` | Map operations | `const [map, { set, remove }] = useMap()` |
621
+ | `useSet` | Set operations | `const [set, { add, toggle }] = useSet()` |
622
+
623
+ ##### Side Effects & Timing Hooks
624
+
625
+ | Hook | Description | Example |
626
+ |------|-------------|---------|
627
+ | `useDebounce` | Debounce value | `const debouncedSearch = useDebounce(search, 500)` |
628
+ | `useThrottle` | Throttle value | `const throttled = useThrottle(value, 100)` |
629
+ | `useTimeout` | Execute after delay | `const { reset, clear } = useTimeout(fn, 3000)` |
630
+ | `useInterval` | Repeated execution | `const { start, stop } = useInterval(fn, 1000)` |
631
+ | `useCountdown` | Countdown timer | `const { count, start, stop } = useCountdown({ seconds: 60 })` |
632
+
633
+ ##### Browser & Document Hooks
634
+
635
+ | Hook | Description | Example |
636
+ |------|-------------|---------|
637
+ | `useWindowSize` | Track dimensions | `const { width, height } = useWindowSize()` |
638
+ | `useWindowScroll` | Track scroll | `const { y, scrollToTop } = useWindowScroll()` |
639
+ | `useDocumentTitle` | Set title | `useDocumentTitle('My Page')` |
640
+ | `useVisibilityChange` | Tab visibility | `const isVisible = useVisibilityChange()` |
641
+ | `useLockBodyScroll` | Prevent scroll | `useLockBodyScroll(isModalOpen)` |
642
+ | `useIsClient` | Client check | `const isClient = useIsClient()` |
643
+
644
+ ##### Events & Interaction Hooks
645
+
646
+ | Hook | Description | Example |
647
+ |------|-------------|---------|
648
+ | `useEventListener` | Attach events | `useEventListener('keydown', handler)` |
649
+ | `useKeyPress` | Detect key | `const isEnter = useKeyPress('Enter')` |
650
+ | `useHover` | Track hover | `const [ref, isHovered] = useHover()` |
651
+ | `useClickAway` | Click outside | `useClickAway(ref, closeHandler)` |
652
+ | `useLongPress` | Long press | `const props = useLongPress(handler, { delay: 500 })` |
653
+ | `useCopyToClipboard` | Copy text | `const [copied, copy] = useCopyToClipboard()` |
654
+
655
+ ##### Media & Device Hooks
656
+
657
+ | Hook | Description | Example |
658
+ |------|-------------|---------|
659
+ | `useMediaQuery` | Responsive | `const isMobile = useMediaQuery('(max-width: 768px)')` |
660
+ | `useBattery` | Battery status | `const { level, charging } = useBattery()` |
661
+ | `useNetworkState` | Network info | `const { online, effectiveType } = useNetworkState()` |
662
+ | `useIdle` | User inactivity | `const isIdle = useIdle(30000)` |
663
+ | `useGeolocation` | User location | `const { latitude, longitude } = useGeolocation()` |
664
+ | `useThemeDetector` | System theme | `const isDark = useThemeDetector()` |
665
+
666
+ ##### Storage Hooks
667
+
668
+ | Hook | Description | Example |
669
+ |------|-------------|---------|
670
+ | `useLocalStorage` | Persist in localStorage | `const [value, setValue] = useLocalStorage('key', initial)` |
671
+ | `useSessionStorage` | Session storage | `const [value, setValue] = useSessionStorage('key', initial)` |
672
+
673
+ ##### Data Fetching Hooks
674
+
675
+ | Hook | Description | Example |
676
+ |------|-------------|---------|
677
+ | `useFetch` | Data fetching | `const { data, loading, error } = useFetch('/api/data')` |
678
+ | `useScript` | Load scripts | `const { loaded, error } = useScript('https://...')` |
679
+
680
+ ##### Performance Hooks
681
+
682
+ | Hook | Description | Example |
683
+ |------|-------------|---------|
684
+ | `useRenderCount` | Count renders | `const count = useRenderCount()` |
685
+ | `useMeasure` | Element dimensions | `const [ref, { width, height }] = useMeasure()` |
686
+ | `useIntersectionObserver` | Visibility detection | `const [ref, entry] = useIntersectionObserver()` |
687
+
688
+ #### HTTP Client (`@exyconn/common/client/http`)
689
+
690
+ ```typescript
691
+ import {
692
+ getRequest,
693
+ postRequest,
694
+ putRequest,
695
+ patchRequest,
696
+ deleteRequest,
697
+ uploadFile,
698
+ extractData,
699
+ extractPaginatedData,
700
+ isSuccess,
701
+ parseError,
702
+ } from '@exyconn/common/client/http';
703
+
704
+ // GET request
705
+ const response = await getRequest('/api/users');
706
+ const users = extractData(response);
707
+
708
+ // POST request
709
+ const createResponse = await postRequest('/api/users', { name: 'John' });
710
+ if (isSuccess(createResponse)) {
711
+ console.log('User created!');
712
+ }
713
+
714
+ // Paginated response
715
+ const paginatedResponse = await getRequest('/api/users', { page: 1, limit: 10 });
716
+ const { items, total, page, totalPages } = extractPaginatedData(paginatedResponse);
717
+
718
+ // File upload
719
+ const uploadResponse = await uploadFile('/api/upload', file, { folder: 'avatars' });
720
+
721
+ // Error handling
722
+ try {
723
+ await postRequest('/api/users', invalidData);
724
+ } catch (error) {
725
+ const { message, statusCode } = parseError(error);
726
+ }
727
+ ```
728
+
729
+ **HTTP Functions:**
730
+
731
+ | Function | Parameters | Returns | Description |
732
+ |----------|------------|---------|-------------|
733
+ | `getRequest` | `url, params?, headers?` | `Promise<AxiosResponse>` | GET request |
734
+ | `postRequest` | `url, data?, headers?` | `Promise<AxiosResponse>` | POST request |
735
+ | `putRequest` | `url, data?, headers?` | `Promise<AxiosResponse>` | PUT request |
736
+ | `patchRequest` | `url, data?, headers?` | `Promise<AxiosResponse>` | PATCH request |
737
+ | `deleteRequest` | `url, params?, headers?` | `Promise<AxiosResponse>` | DELETE request |
738
+ | `uploadFile` | `url, file, data?` | `Promise<AxiosResponse>` | File upload |
739
+
740
+ **Response Utilities:**
741
+
742
+ | Function | Description |
743
+ |----------|-------------|
744
+ | `extractData` | Extract data from axios response |
745
+ | `extractMessage` | Extract message from response |
746
+ | `extractPaginatedData` | Extract paginated data with meta |
747
+ | `isSuccess` | Check if response status is 2xx |
748
+ | `isSuccessResponse` | Check response data for success |
749
+ | `parseError` | Parse error to standardized format |
750
+ | `parseResponseData` | Parse data from raw response |
751
+ | `parsePaginatedResponse` | Parse paginated response data |
752
+ | `safeJsonParse` | Safe JSON parsing with fallback |
753
+
754
+ **Slug Utilities:**
755
+
756
+ ```typescript
757
+ import { generateSlug, generateUrlSlug, generateSnakeSlug } from '@exyconn/common/client/http';
758
+
759
+ generateSlug('Hello World'); // 'helloWorld'
760
+ generateUrlSlug('Hello World'); // 'hello-world'
761
+ generateSnakeSlug('Hello World'); // 'hello_world'
762
+ ```
763
+
764
+ ---
765
+
766
+ ### Shared Module
767
+
768
+ **Import:** `@exyconn/common/shared` or specific submodules
769
+
770
+ #### Validation (`@exyconn/common/shared/validation`)
97
771
 
98
772
  ```typescript
99
773
  import {
100
774
  VALIDATION_PATTERNS,
101
- VALIDATION_MESSAGES,
102
775
  isValidEmail,
103
776
  isValidPassword,
104
777
  isValidPhone,
105
- isValidUrl
778
+ isValidUrl,
106
779
  } from '@exyconn/common/shared/validation';
780
+
781
+ isValidEmail('test@example.com'); // true
782
+ isValidPassword('Password1!', 'strong'); // true
783
+ isValidPhone('+1 234 567 8901'); // true
784
+
785
+ // Use patterns directly
786
+ VALIDATION_PATTERNS.EMAIL.test('test@example.com');
787
+ VALIDATION_PATTERNS.SLUG.test('my-blog-post');
107
788
  ```
108
789
 
109
- ### Date/Time Utilities
790
+ **Available Patterns:**
791
+
792
+ | Pattern | Description |
793
+ |---------|-------------|
794
+ | `EMAIL` | Email validation |
795
+ | `PASSWORD_STRONG` | Strong password (8+ chars, upper, lower, number, special) |
796
+ | `PASSWORD_MEDIUM` | Medium password (8+ chars, upper, lower, number) |
797
+ | `PHONE_INTERNATIONAL` | International phone |
798
+ | `URL` / `URL_STRICT` | URL validation |
799
+ | `SLUG` | Kebab-case slug |
800
+ | `USERNAME` | Username (3-30 chars, alphanumeric, _, -) |
801
+ | `IPV4` | IPv4 address |
802
+ | `HEX_COLOR` | Hex color code |
803
+ | `DATE_ISO` | ISO date format |
804
+
805
+ #### Environment Config (`@exyconn/common/shared/config`)
110
806
 
111
807
  ```typescript
112
- import {
113
- formatDate,
114
- formatDateTime,
115
- formatDateInTimezone,
116
- formatRelativeTime,
117
- formatSmartDate,
118
- toTimezone,
119
- fromTimezone,
120
- nowInTimezone,
121
- addTime,
122
- subtractTime,
123
- getDayBoundaries,
124
- getAge,
125
- isWeekend,
126
- DATE_FORMATS
127
- } from '@exyconn/common/shared';
808
+ import { getEnv, getEnvOptional, isProd, isDev, validateEnv } from '@exyconn/common/shared/config';
809
+
810
+ const port = getEnv('PORT', 3000); // Returns number
811
+ const secret = getEnv('JWT_SECRET'); // Required, throws if missing
812
+ const optional = getEnvOptional('OPTIONAL'); // Returns undefined if missing
813
+
814
+ if (isProd()) { /* Production only */ }
815
+ if (isDev()) { /* Development only */ }
816
+
817
+ validateEnv(['DATABASE_URL', 'JWT_SECRET']); // Throws with missing vars
128
818
  ```
129
819
 
130
- ### Data Modules
820
+ ---
821
+
822
+ ### Data Module
823
+
824
+ **Import:** `@exyconn/common/data` or specific files
825
+
826
+ #### Countries (`@exyconn/common/data/countries`)
131
827
 
132
828
  ```typescript
133
- // Countries with nested states/cities + flags
134
829
  import {
135
- countries,
136
- getCountryByCode,
137
- getStatesByCountry,
138
- getCitiesByState,
830
+ default as countries,
831
+ getCountryByCode,
832
+ getStatesByCountry,
139
833
  searchCountries,
140
834
  getFlag,
141
- getAllCountriesWithFlags,
142
- codeToFlag
143
835
  } from '@exyconn/common/data/countries';
144
836
 
145
- // Currencies
146
- import {
147
- currencies,
148
- getCurrencyByCode,
149
- formatCurrency,
150
- formatCurrencyNative
151
- } from '@exyconn/common/data/currencies';
837
+ const usa = getCountryByCode('US');
838
+ const states = getStatesByCountry('US');
839
+ const matches = searchCountries('united');
840
+ const flag = getFlag('US'); // '🇺🇸'
841
+ ```
152
842
 
153
- // Phone codes
154
- import { phoneCodes, getPhoneCodeByCountry } from '@exyconn/common/data/phone-codes';
843
+ #### Currencies (`@exyconn/common/data/currencies`)
155
844
 
156
- // Timezones
157
- import {
158
- timezones,
159
- getTimezoneByCode,
160
- searchTimezones,
161
- getCommonTimezones
162
- } from '@exyconn/common/data/timezones';
845
+ ```typescript
846
+ import { getCurrencyByCode, formatCurrency } from '@exyconn/common/data/currencies';
163
847
 
164
- // Regex patterns
165
- import {
166
- REGEX,
167
- EMAIL,
168
- PASSWORD_STRONG,
169
- PHONE_INTERNATIONAL,
170
- UUID,
171
- URL_STRICT
172
- } from '@exyconn/common/data/regex';
173
-
174
- // Brand Identity
175
- import {
176
- BRANDS,
177
- APPS,
178
- getBrandById,
179
- getBrandByDomain,
180
- getThemedLogo,
181
- createAppConfig
182
- } from '@exyconn/common/data/brand-identity';
848
+ const usd = getCurrencyByCode('USD');
849
+ formatCurrency(1234.56, 'USD'); // '$1,234.56'
183
850
  ```
184
851
 
185
- ### Enums & Constants
852
+ #### Phone Codes (`@exyconn/common/data/phone-codes`)
186
853
 
187
854
  ```typescript
188
- import {
189
- // Status enums
190
- STATUS,
191
- USER_STATUS,
192
- ORDER_STATUS,
193
- PAYMENT_STATUS,
194
- TASK_STATUS,
195
-
196
- // Sort options
197
- SORT,
198
- SORT_DIRECTION,
199
-
200
- // Roles & permissions
201
- ROLE,
202
- PERMISSION_LEVEL,
203
-
204
- // UI constants
205
- BREAKPOINTS,
206
- MEDIA_QUERIES,
207
- THEME,
208
-
209
- // Other
210
- PRIORITY,
211
- VISIBILITY,
212
- NOTIFICATION_TYPE
213
- } from '@exyconn/common/shared/constants/enums';
855
+ import { getPhoneCodeByCountry } from '@exyconn/common/data/phone-codes';
856
+
857
+ const usCode = getPhoneCodeByCountry('US');
858
+ // { country: 'United States', dial_code: '+1', flag: '🇺🇸' }
214
859
  ```
215
860
 
216
- ## Data Module Details
217
-
218
- ### Countries
219
- - 50+ countries with full details
220
- - Nested states/cities for major countries
221
- - Includes phone codes, currencies, timezones
222
- - **NEW:** Emoji flags with `getFlag()` and `codeToFlag()` helpers
223
-
224
- ### Currencies
225
- - 100+ world currencies
226
- - Symbol, name, and native formatting
227
- - formatCurrency(amount, code) helper
228
-
229
- ### Phone Codes
230
- - 190+ international phone codes
231
- - Country flags (emoji)
232
-
233
- ### Timezones
234
- - 65+ timezones with UTC offsets
235
- - Common timezone presets
236
- - Search and filter functions
237
-
238
- ### Regex Patterns
239
- 100+ common regex patterns organized by category:
240
- - **Email** - Basic, RFC5322, common domains
241
- - **Password** - Weak to very strong
242
- - **Phone** - International, US, India, UK
243
- - **Postal** - ZIP, PIN, UK, Canada, Germany
244
- - **IDs** - UUID, MongoDB ObjectId, Aadhaar, PAN, SSN
245
- - **URL** - Basic, strict, domain, localhost
246
- - **Credit Card** - Visa, Mastercard, Amex, etc.
247
- - **Date/Time** - ISO, various formats
248
- - **Colors** - Hex, RGB, RGBA, HSL
249
- - **And more!**
250
-
251
- ### Brand Identity
252
- Complete brand configuration for all 5 Exyconn projects:
253
- - **Logo variants:** light, dark, logoOnly, darkLogoOnly
254
- - **Colors:** primary, secondary, accent
255
- - **Contact:** support email, sales email
256
- - **Social links:** Twitter, LinkedIn, GitHub, etc.
257
- - **SEO config:** title, description, keywords
258
-
259
- Projects:
260
- - **botify.life** - AI/Bot platform
261
- - **exyconn.com** - Main Exyconn brand
262
- - **partywings.fun** - Event platform
263
- - **sibera.work** - Work management
264
- - **spentiva.com** - Finance platform
265
-
266
- ### Enums & Breakpoints
267
- Comprehensive enums for consistent data handling:
268
- - **STATUS** - active, pending, approved, archived...
269
- - **USER_STATUS** - active, suspended, banned...
270
- - **ORDER_STATUS** - pending, confirmed, shipped...
271
- - **PAYMENT_STATUS** - pending, completed, refunded...
272
- - **TASK_STATUS** - todo, in_progress, done...
273
- - **SORT** - newest, oldest, alphabetical, popular...
274
- - **ROLE** - super_admin, admin, user, viewer...
275
- - **PRIORITY** - low, medium, high, critical
276
- - **BREAKPOINTS** - xs, sm, md, lg, xl, 2xl (Tailwind-compatible)
277
-
278
- ## React Hooks
279
-
280
- | Hook | Description |
281
- |------|-------------|
282
- | useLocalStorage | Persist state in localStorage with cross-tab sync |
283
- | useDebounce | Debounce a value with configurable delay |
284
- | useCopyToClipboard | Copy text to clipboard with status |
285
- | usePageTitle | Set document title with suffix |
286
- | useSnackbar | Toast/snackbar notification state |
287
- | useMediaQuery | Track media query matches |
288
- | useIsMobile / useIsDesktop | Responsive breakpoint hooks |
289
- | useThemeDetector | Detect system light/dark mode |
290
- | useInterval | Safely run intervals with cleanup |
291
- | useOnClickOutside | Detect clicks outside element |
292
- | useWindowSize | Track window dimensions |
861
+ #### Timezones (`@exyconn/common/data/timezones`)
293
862
 
294
- ## Peer Dependencies
863
+ ```typescript
864
+ import { getTimezoneByCode, searchTimezones } from '@exyconn/common/data/timezones';
295
865
 
296
- All peer dependencies are optional - only install what you need:
297
-
298
- ```json
299
- {
300
- "axios": "^1.6.0",
301
- "date-fns": "^3.0.0",
302
- "date-fns-tz": "^3.0.0",
303
- "express": "^4.18.0",
304
- "jsonwebtoken": "^9.0.0",
305
- "mongoose": "^8.0.0",
306
- "react": "^18.0.0",
307
- "winston": "^3.11.0"
308
- }
866
+ const pst = getTimezoneByCode('America/Los_Angeles');
867
+ const matches = searchTimezones('india');
868
+ ```
869
+
870
+ #### Regex Patterns (`@exyconn/common/data/regex`)
871
+
872
+ ```typescript
873
+ import REGEX from '@exyconn/common/data/regex';
874
+
875
+ REGEX.EMAIL.BASIC.test('test@example.com');
876
+ REGEX.PASSWORD.STRONG.test('Test@123');
877
+ REGEX.CREDIT_CARD.VISA.test('4111111111111111');
309
878
  ```
310
879
 
311
- ## Package Exports
880
+ #### Brand Identity (`@exyconn/common/data/brand-identity`)
881
+
882
+ ```typescript
883
+ import { BRANDS, getBrandById, getBrandByDomain, getThemedLogo } from '@exyconn/common/data/brand-identity';
884
+
885
+ const exyconn = getBrandById('exyconn');
886
+ const brand = getBrandByDomain('botify.life');
887
+ const logo = getThemedLogo('exyconn', 'dark');
888
+ ```
889
+
890
+ ---
891
+
892
+ ## Package Exports Map
312
893
 
313
894
  ```
314
895
  @exyconn/common
315
- ├── /server # Server-side utilities
316
- │ ├── /response # Response helpers
317
- │ ├── /enums # Status codes/messages
318
- │ ├── /logger # Winston logger
319
- │ ├── /db # Database connections
320
- │ ├── /middleware # Auth middleware
321
- └── /utils # Server utilities
322
- ├── /client # Client-side utilities
323
- ├── /http # Axios HTTP client
324
- │ ├── /hooks # React hooks
325
- │ ├── /logger # Browser logger
326
- └── /utils # Client utilities
327
- ├── /shared # Shared between server/client
328
- ├── /types # TypeScript types
329
- ├── /validation # Validation patterns
330
- │ ├── /constants # Enums, breakpoints, status codes
331
- └── /utils # Date-time utilities
332
- └── /data # Static data modules
333
- ├── /countries # Countries with states/cities/flags
334
- ├── /currencies # World currencies
335
- ├── /phone-codes # International phone codes
336
- ├── /timezones # Timezones
337
- ├── /regex # Common regex patterns
338
- ├── /brand-identity # Complete brand configs
339
- └── /logos # Brand logos (deprecated, use brand-identity)
896
+ ├── /server # Server utilities
897
+ │ ├── /response # Response helpers
898
+ │ ├── /enums # Status codes/messages
899
+ │ ├── /logger # Winston logger
900
+ │ ├── /db # Database connections
901
+ │ ├── /middleware # Auth middleware
902
+ ├── /utils # Server utilities
903
+ │ └── /configs # Dynamic configurations
904
+ ├── /client # Client utilities
905
+ │ ├── /http # Axios HTTP client
906
+ │ ├── /hooks # React hooks (50+)
907
+ ├── /logger # Browser logger
908
+ ├── /utils # Client utilities
909
+ └── /web # Web utilities
910
+ ├── /shared # Shared between server/client
911
+ │ ├── /types # TypeScript types
912
+ ├── /validation # Validation patterns
913
+ │ ├── /constants # Enums, breakpoints
914
+ ├── /config # Environment config
915
+ │ └── /utils # Date-time utilities
916
+ └── /data # Static data modules
917
+ ├── /countries # Countries with states/cities
918
+ ├── /currencies # World currencies
919
+ ├── /phone-codes # Phone codes
920
+ ├── /timezones # Timezones
921
+ ├── /regex # Regex patterns
922
+ └── /brand-identity # Brand configs
923
+ ```
924
+
925
+ ---
926
+
927
+ ## Peer Dependencies
928
+
929
+ All peer dependencies are **optional**. Install only what you need:
930
+
931
+ | Package | Version | Required For |
932
+ |---------|---------|--------------|
933
+ | `react` | ^17.0.0 \|\| ^18.0.0 \|\| ^19.0.0 | Client hooks |
934
+ | `express` | ^4.18.0 \|\| ^5.0.0 | Server utilities |
935
+ | `express-rate-limit` | ^7.0.0 | Rate limiter configs |
936
+ | `cors` | ^2.8.5 | CORS configs |
937
+ | `mongoose` | ^8.0.0 | Database utilities |
938
+ | `winston` | ^3.11.0 | Server logger |
939
+ | `jsonwebtoken` | ^9.0.0 | Auth middleware |
940
+ | `axios` | ^1.6.0 | HTTP client |
941
+ | `date-fns` | ^3.0.0 | Date utilities |
942
+
943
+ ---
944
+
945
+ ## TypeScript Support
946
+
947
+ Full TypeScript support with exported types:
948
+
949
+ ```typescript
950
+ import type {
951
+ ApiResponse,
952
+ CorsConfig,
953
+ RateLimitTierConfig,
954
+ AuthRequest,
955
+ } from '@exyconn/common/server';
340
956
  ```
341
957
 
958
+ ---
959
+
960
+ ## Node.js Version
961
+
962
+ Requires Node.js >= 18.0.0
963
+
964
+ ---
965
+
966
+ ## Development
967
+
968
+ ### Setup
969
+
970
+ ```bash
971
+ # Clone the repository
972
+ git clone https://github.com/exyconn/common.git
973
+ cd common
974
+
975
+ # Install dependencies
976
+ npm install
977
+
978
+ # Build the package
979
+ npm run build
980
+
981
+ # Run tests
982
+ npm run test
983
+
984
+ # Run tests with coverage
985
+ npm run test:coverage
986
+ ```
987
+
988
+ ### Available Scripts
989
+
990
+ | Command | Description |
991
+ |---------|-------------|
992
+ | `npm run build` | Build the package with tsup |
993
+ | `npm run dev` | Watch mode for development |
994
+ | `npm run test` | Run tests with Vitest |
995
+ | `npm run test:coverage` | Run tests with coverage report |
996
+ | `npm run lint` | Lint the codebase |
997
+ | `npm run type-check` | TypeScript type checking |
998
+ | `npm run docs:dev` | Start docs dev server (port 4006) |
999
+ | `npm run docs:build` | Build documentation |
1000
+ | `npm run docs:start` | Start production docs server |
1001
+
1002
+ ### Documentation Development
1003
+
1004
+ ```bash
1005
+ # Install docs dependencies
1006
+ npm run docs:install
1007
+
1008
+ # Start documentation site locally
1009
+ npm run docs:dev
1010
+
1011
+ # Open http://localhost:4006
1012
+ ```
1013
+
1014
+ ### Running with Docker
1015
+
1016
+ ```bash
1017
+ # Build the docs Docker image
1018
+ cd docs
1019
+ docker build -t common-docs .
1020
+
1021
+ # Run the container
1022
+ docker run -p 4006:4006 common-docs
1023
+ ```
1024
+
1025
+ ---
1026
+
1027
+ ## Contributing
1028
+
1029
+ Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.
1030
+
1031
+ 1. Fork the repository
1032
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
1033
+ 3. Commit your changes (`git commit -m 'feat: add amazing feature'`)
1034
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
1035
+ 5. Open a Pull Request
1036
+
1037
+ ### Commit Convention
1038
+
1039
+ We use [Conventional Commits](https://www.conventionalcommits.org/):
1040
+
1041
+ - `feat:` - New features
1042
+ - `fix:` - Bug fixes
1043
+ - `docs:` - Documentation changes
1044
+ - `test:` - Adding or updating tests
1045
+ - `refactor:` - Code refactoring
1046
+ - `chore:` - Maintenance tasks
1047
+
1048
+ ---
1049
+
342
1050
  ## License
343
1051
 
344
1052
  MIT © Exyconn