@exyconn/common 2.0.0 → 2.3.2

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