@xeplr/utils 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,296 @@
1
+ {
2
+ "STATES": {
3
+ "IN": [
4
+ {
5
+ "code": "AN",
6
+ "name": "Andaman and Nicobar Islands"
7
+ },
8
+ {
9
+ "code": "AP",
10
+ "name": "Andhra Pradesh"
11
+ },
12
+ {
13
+ "code": "AR",
14
+ "name": "Arunachal Pradesh"
15
+ },
16
+ {
17
+ "code": "AS",
18
+ "name": "Assam"
19
+ },
20
+ {
21
+ "code": "BR",
22
+ "name": "Bihar"
23
+ },
24
+ {
25
+ "code": "CH",
26
+ "name": "Chandigarh"
27
+ },
28
+ {
29
+ "code": "CT",
30
+ "name": "Chhattisgarh"
31
+ },
32
+ {
33
+ "code": "DN",
34
+ "name": "Dadra and Nagar Haveli and Daman and Diu"
35
+ },
36
+ {
37
+ "code": "DL",
38
+ "name": "Delhi"
39
+ },
40
+ {
41
+ "code": "GA",
42
+ "name": "Goa"
43
+ },
44
+ {
45
+ "code": "GJ",
46
+ "name": "Gujarat"
47
+ },
48
+ {
49
+ "code": "HR",
50
+ "name": "Haryana"
51
+ },
52
+ {
53
+ "code": "HP",
54
+ "name": "Himachal Pradesh"
55
+ },
56
+ {
57
+ "code": "JK",
58
+ "name": "Jammu and Kashmir"
59
+ },
60
+ {
61
+ "code": "JH",
62
+ "name": "Jharkhand"
63
+ },
64
+ {
65
+ "code": "KA",
66
+ "name": "Karnataka"
67
+ },
68
+ {
69
+ "code": "KL",
70
+ "name": "Kerala"
71
+ },
72
+ {
73
+ "code": "LA",
74
+ "name": "Ladakh"
75
+ },
76
+ {
77
+ "code": "LD",
78
+ "name": "Lakshadweep"
79
+ },
80
+ {
81
+ "code": "MP",
82
+ "name": "Madhya Pradesh"
83
+ },
84
+ {
85
+ "code": "MH",
86
+ "name": "Maharashtra"
87
+ },
88
+ {
89
+ "code": "MN",
90
+ "name": "Manipur"
91
+ },
92
+ {
93
+ "code": "ML",
94
+ "name": "Meghalaya"
95
+ },
96
+ {
97
+ "code": "MZ",
98
+ "name": "Mizoram"
99
+ },
100
+ {
101
+ "code": "NL",
102
+ "name": "Nagaland"
103
+ },
104
+ {
105
+ "code": "OR",
106
+ "name": "Odisha"
107
+ },
108
+ {
109
+ "code": "PY",
110
+ "name": "Puducherry"
111
+ },
112
+ {
113
+ "code": "PB",
114
+ "name": "Punjab"
115
+ },
116
+ {
117
+ "code": "RJ",
118
+ "name": "Rajasthan"
119
+ },
120
+ {
121
+ "code": "SK",
122
+ "name": "Sikkim"
123
+ },
124
+ {
125
+ "code": "TN",
126
+ "name": "Tamil Nadu"
127
+ },
128
+ {
129
+ "code": "TG",
130
+ "name": "Telangana"
131
+ },
132
+ {
133
+ "code": "TR",
134
+ "name": "Tripura"
135
+ },
136
+ {
137
+ "code": "UP",
138
+ "name": "Uttar Pradesh"
139
+ },
140
+ {
141
+ "code": "UT",
142
+ "name": "Uttarakhand"
143
+ },
144
+ {
145
+ "code": "WB",
146
+ "name": "West Bengal"
147
+ }
148
+ ]
149
+ },
150
+ "STATES_IN": [
151
+ {
152
+ "code": "AN",
153
+ "name": "Andaman and Nicobar Islands"
154
+ },
155
+ {
156
+ "code": "AP",
157
+ "name": "Andhra Pradesh"
158
+ },
159
+ {
160
+ "code": "AR",
161
+ "name": "Arunachal Pradesh"
162
+ },
163
+ {
164
+ "code": "AS",
165
+ "name": "Assam"
166
+ },
167
+ {
168
+ "code": "BR",
169
+ "name": "Bihar"
170
+ },
171
+ {
172
+ "code": "CH",
173
+ "name": "Chandigarh"
174
+ },
175
+ {
176
+ "code": "CT",
177
+ "name": "Chhattisgarh"
178
+ },
179
+ {
180
+ "code": "DN",
181
+ "name": "Dadra and Nagar Haveli and Daman and Diu"
182
+ },
183
+ {
184
+ "code": "DL",
185
+ "name": "Delhi"
186
+ },
187
+ {
188
+ "code": "GA",
189
+ "name": "Goa"
190
+ },
191
+ {
192
+ "code": "GJ",
193
+ "name": "Gujarat"
194
+ },
195
+ {
196
+ "code": "HR",
197
+ "name": "Haryana"
198
+ },
199
+ {
200
+ "code": "HP",
201
+ "name": "Himachal Pradesh"
202
+ },
203
+ {
204
+ "code": "JK",
205
+ "name": "Jammu and Kashmir"
206
+ },
207
+ {
208
+ "code": "JH",
209
+ "name": "Jharkhand"
210
+ },
211
+ {
212
+ "code": "KA",
213
+ "name": "Karnataka"
214
+ },
215
+ {
216
+ "code": "KL",
217
+ "name": "Kerala"
218
+ },
219
+ {
220
+ "code": "LA",
221
+ "name": "Ladakh"
222
+ },
223
+ {
224
+ "code": "LD",
225
+ "name": "Lakshadweep"
226
+ },
227
+ {
228
+ "code": "MP",
229
+ "name": "Madhya Pradesh"
230
+ },
231
+ {
232
+ "code": "MH",
233
+ "name": "Maharashtra"
234
+ },
235
+ {
236
+ "code": "MN",
237
+ "name": "Manipur"
238
+ },
239
+ {
240
+ "code": "ML",
241
+ "name": "Meghalaya"
242
+ },
243
+ {
244
+ "code": "MZ",
245
+ "name": "Mizoram"
246
+ },
247
+ {
248
+ "code": "NL",
249
+ "name": "Nagaland"
250
+ },
251
+ {
252
+ "code": "OR",
253
+ "name": "Odisha"
254
+ },
255
+ {
256
+ "code": "PY",
257
+ "name": "Puducherry"
258
+ },
259
+ {
260
+ "code": "PB",
261
+ "name": "Punjab"
262
+ },
263
+ {
264
+ "code": "RJ",
265
+ "name": "Rajasthan"
266
+ },
267
+ {
268
+ "code": "SK",
269
+ "name": "Sikkim"
270
+ },
271
+ {
272
+ "code": "TN",
273
+ "name": "Tamil Nadu"
274
+ },
275
+ {
276
+ "code": "TG",
277
+ "name": "Telangana"
278
+ },
279
+ {
280
+ "code": "TR",
281
+ "name": "Tripura"
282
+ },
283
+ {
284
+ "code": "UP",
285
+ "name": "Uttar Pradesh"
286
+ },
287
+ {
288
+ "code": "UT",
289
+ "name": "Uttarakhand"
290
+ },
291
+ {
292
+ "code": "WB",
293
+ "name": "West Bengal"
294
+ }
295
+ ]
296
+ }
package/lib/cache.js ADDED
@@ -0,0 +1,166 @@
1
+ const Redis = require('ioredis');
2
+
3
+ let _client = null;
4
+ let _config = {};
5
+
6
+ /**
7
+ * Configure the Redis cache.
8
+ * @param {object} config
9
+ * @param {string} [config.host='127.0.0.1']
10
+ * @param {number} [config.port=6379]
11
+ * @param {string} [config.password]
12
+ * @param {number} [config.db=0]
13
+ * @param {string} [config.keyPrefix='xeplr:']
14
+ * @param {number} [config.defaultTTL=300] - Default TTL in seconds (5 min)
15
+ * @param {number} [config.maxRetriesPerRequest=3]
16
+ * @param {boolean} [config.enableOfflineQueue=true]
17
+ * @param {boolean} [config.lazyConnect=true] - Don't connect until first use
18
+ */
19
+ function configureCache(config = {}) {
20
+ _config = {
21
+ host: config.host || process.env.REDIS_HOST || '127.0.0.1',
22
+ port: parseInt(config.port || process.env.REDIS_PORT || '6379'),
23
+ password: config.password || process.env.REDIS_PASSWORD || undefined,
24
+ db: config.db || parseInt(process.env.REDIS_DB || '0'),
25
+ keyPrefix: config.keyPrefix || process.env.REDIS_PREFIX || 'xeplr:',
26
+ defaultTTL: config.defaultTTL || 300,
27
+ maxRetriesPerRequest: config.maxRetriesPerRequest || 3,
28
+ enableOfflineQueue: config.enableOfflineQueue !== false,
29
+ lazyConnect: config.lazyConnect !== false
30
+ };
31
+
32
+ // Disconnect existing client if reconfiguring
33
+ if (_client) {
34
+ _client.disconnect();
35
+ _client = null;
36
+ }
37
+ }
38
+
39
+ function getClient() {
40
+ if (_client) return _client;
41
+
42
+ const opts = {
43
+ host: _config.host || process.env.REDIS_HOST || '127.0.0.1',
44
+ port: parseInt(_config.port || process.env.REDIS_PORT || '6379'),
45
+ password: _config.password || process.env.REDIS_PASSWORD || undefined,
46
+ db: _config.db || parseInt(process.env.REDIS_DB || '0'),
47
+ keyPrefix: _config.keyPrefix || process.env.REDIS_PREFIX || 'xeplr:',
48
+ lazyConnect: _config.lazyConnect !== false,
49
+
50
+ // Performance: limit retries so requests don't pile up
51
+ maxRetriesPerRequest: _config.maxRetriesPerRequest || 3,
52
+
53
+ // Keep offline queue so commands are buffered during brief disconnects
54
+ enableOfflineQueue: _config.enableOfflineQueue !== false,
55
+
56
+ // Reconnect with exponential backoff, cap at 3s
57
+ retryStrategy(times) {
58
+ if (times > 10) return null; // stop reconnecting after 10 attempts
59
+ return Math.min(times * 200, 3000);
60
+ },
61
+
62
+ // Connection pool: ioredis uses a single connection with pipelining,
63
+ // which handles high concurrency better than connection pools for most cases.
64
+ // For extreme throughput, use Cluster mode instead.
65
+ };
66
+
67
+ _client = new Redis(opts);
68
+
69
+ _client.on('error', (err) => {
70
+ // Silently handle — don't crash the server if Redis is down
71
+ // The get/set methods below fall through gracefully
72
+ });
73
+
74
+ if (opts.lazyConnect) {
75
+ _client.connect().catch(() => {});
76
+ }
77
+
78
+ return _client;
79
+ }
80
+
81
+ /**
82
+ * Get a cached value.
83
+ * Returns null if not found or Redis is unavailable.
84
+ */
85
+ async function get(key) {
86
+ try {
87
+ const client = getClient();
88
+ const raw = await client.get(key);
89
+ return raw ? JSON.parse(raw) : null;
90
+ } catch (e) {
91
+ return null; // Cache miss on error — fall through to DB
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Set a cached value with TTL.
97
+ * @param {string} key
98
+ * @param {any} value - Will be JSON.stringify'd
99
+ * @param {number} [ttl] - TTL in seconds (default: configured defaultTTL)
100
+ */
101
+ async function set(key, value, ttl) {
102
+ try {
103
+ const client = getClient();
104
+ const seconds = ttl || _config.defaultTTL || 300;
105
+ await client.set(key, JSON.stringify(value), 'EX', seconds);
106
+ } catch (e) {
107
+ // Silently fail — cache is non-critical
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Delete a specific key.
113
+ */
114
+ async function del(key) {
115
+ try {
116
+ const client = getClient();
117
+ await client.del(key);
118
+ } catch (e) {
119
+ // Silently fail
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Delete all keys matching a pattern.
125
+ * Uses SCAN to avoid blocking Redis on large keyspaces.
126
+ * @param {string} pattern - e.g. 'access:user:*'
127
+ */
128
+ async function delPattern(pattern) {
129
+ try {
130
+ const client = getClient();
131
+ const prefix = _config.keyPrefix || '';
132
+ let cursor = '0';
133
+ do {
134
+ // SCAN with the full prefixed pattern
135
+ const [nextCursor, keys] = await client.scan(cursor, 'MATCH', prefix + pattern, 'COUNT', 100);
136
+ cursor = nextCursor;
137
+ if (keys.length > 0) {
138
+ // Strip prefix since ioredis adds it automatically
139
+ const stripped = keys.map(k => k.startsWith(prefix) ? k.slice(prefix.length) : k);
140
+ await client.del(...stripped);
141
+ }
142
+ } while (cursor !== '0');
143
+ } catch (e) {
144
+ // Silently fail
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Disconnect Redis client (for graceful shutdown).
150
+ */
151
+ async function disconnectCache() {
152
+ if (_client) {
153
+ await _client.quit();
154
+ _client = null;
155
+ }
156
+ }
157
+
158
+ module.exports = {
159
+ configureCache,
160
+ get,
161
+ set,
162
+ del,
163
+ delPattern,
164
+ disconnectCache,
165
+ getClient
166
+ };