@db-bridge/redis 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1676 @@
1
+ import { withTimeout, ConnectionError, CacheError } from '@db-bridge/core';
2
+ import Redis from 'ioredis';
3
+
4
+ var __create = Object.create;
5
+ var __defProp = Object.defineProperty;
6
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __getProtoOf = Object.getPrototypeOf;
9
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
10
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
11
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
12
+ }) : x)(function(x) {
13
+ if (typeof require !== "undefined") return require.apply(this, arguments);
14
+ throw Error('Dynamic require of "' + x + '" is not supported');
15
+ });
16
+ var __commonJS = (cb, mod) => function __require2() {
17
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
18
+ };
19
+ var __copyProps = (to, from, except, desc) => {
20
+ if (from && typeof from === "object" || typeof from === "function") {
21
+ for (let key of __getOwnPropNames(from))
22
+ if (!__hasOwnProp.call(to, key) && key !== except)
23
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
24
+ }
25
+ return to;
26
+ };
27
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
28
+ // If the importer is in node compatibility mode or this is not an ESM
29
+ // file that has been converted to a CommonJS file using a Babel-
30
+ // compatible transform (i.e. "__esModule" has not been set), then set
31
+ // "default" to the CommonJS "module.exports" for node compatibility.
32
+ __defProp(target, "default", { value: mod, enumerable: true }) ,
33
+ mod
34
+ ));
35
+
36
+ // ../../node_modules/eventemitter3/index.js
37
+ var require_eventemitter3 = __commonJS({
38
+ "../../node_modules/eventemitter3/index.js"(exports$1, module) {
39
+ var has = Object.prototype.hasOwnProperty;
40
+ var prefix = "~";
41
+ function Events() {
42
+ }
43
+ if (Object.create) {
44
+ Events.prototype = /* @__PURE__ */ Object.create(null);
45
+ if (!new Events().__proto__) prefix = false;
46
+ }
47
+ function EE(fn, context, once) {
48
+ this.fn = fn;
49
+ this.context = context;
50
+ this.once = once || false;
51
+ }
52
+ function addListener(emitter, event, fn, context, once) {
53
+ if (typeof fn !== "function") {
54
+ throw new TypeError("The listener must be a function");
55
+ }
56
+ var listener = new EE(fn, context || emitter, once), evt = prefix ? prefix + event : event;
57
+ if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;
58
+ else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);
59
+ else emitter._events[evt] = [emitter._events[evt], listener];
60
+ return emitter;
61
+ }
62
+ function clearEvent(emitter, evt) {
63
+ if (--emitter._eventsCount === 0) emitter._events = new Events();
64
+ else delete emitter._events[evt];
65
+ }
66
+ function EventEmitter2() {
67
+ this._events = new Events();
68
+ this._eventsCount = 0;
69
+ }
70
+ EventEmitter2.prototype.eventNames = function eventNames() {
71
+ var names = [], events, name;
72
+ if (this._eventsCount === 0) return names;
73
+ for (name in events = this._events) {
74
+ if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
75
+ }
76
+ if (Object.getOwnPropertySymbols) {
77
+ return names.concat(Object.getOwnPropertySymbols(events));
78
+ }
79
+ return names;
80
+ };
81
+ EventEmitter2.prototype.listeners = function listeners(event) {
82
+ var evt = prefix ? prefix + event : event, handlers = this._events[evt];
83
+ if (!handlers) return [];
84
+ if (handlers.fn) return [handlers.fn];
85
+ for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {
86
+ ee[i] = handlers[i].fn;
87
+ }
88
+ return ee;
89
+ };
90
+ EventEmitter2.prototype.listenerCount = function listenerCount(event) {
91
+ var evt = prefix ? prefix + event : event, listeners = this._events[evt];
92
+ if (!listeners) return 0;
93
+ if (listeners.fn) return 1;
94
+ return listeners.length;
95
+ };
96
+ EventEmitter2.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
97
+ var evt = prefix ? prefix + event : event;
98
+ if (!this._events[evt]) return false;
99
+ var listeners = this._events[evt], len = arguments.length, args, i;
100
+ if (listeners.fn) {
101
+ if (listeners.once) this.removeListener(event, listeners.fn, void 0, true);
102
+ switch (len) {
103
+ case 1:
104
+ return listeners.fn.call(listeners.context), true;
105
+ case 2:
106
+ return listeners.fn.call(listeners.context, a1), true;
107
+ case 3:
108
+ return listeners.fn.call(listeners.context, a1, a2), true;
109
+ case 4:
110
+ return listeners.fn.call(listeners.context, a1, a2, a3), true;
111
+ case 5:
112
+ return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
113
+ case 6:
114
+ return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
115
+ }
116
+ for (i = 1, args = new Array(len - 1); i < len; i++) {
117
+ args[i - 1] = arguments[i];
118
+ }
119
+ listeners.fn.apply(listeners.context, args);
120
+ } else {
121
+ var length = listeners.length, j;
122
+ for (i = 0; i < length; i++) {
123
+ if (listeners[i].once) this.removeListener(event, listeners[i].fn, void 0, true);
124
+ switch (len) {
125
+ case 1:
126
+ listeners[i].fn.call(listeners[i].context);
127
+ break;
128
+ case 2:
129
+ listeners[i].fn.call(listeners[i].context, a1);
130
+ break;
131
+ case 3:
132
+ listeners[i].fn.call(listeners[i].context, a1, a2);
133
+ break;
134
+ case 4:
135
+ listeners[i].fn.call(listeners[i].context, a1, a2, a3);
136
+ break;
137
+ default:
138
+ if (!args) for (j = 1, args = new Array(len - 1); j < len; j++) {
139
+ args[j - 1] = arguments[j];
140
+ }
141
+ listeners[i].fn.apply(listeners[i].context, args);
142
+ }
143
+ }
144
+ }
145
+ return true;
146
+ };
147
+ EventEmitter2.prototype.on = function on(event, fn, context) {
148
+ return addListener(this, event, fn, context, false);
149
+ };
150
+ EventEmitter2.prototype.once = function once(event, fn, context) {
151
+ return addListener(this, event, fn, context, true);
152
+ };
153
+ EventEmitter2.prototype.removeListener = function removeListener(event, fn, context, once) {
154
+ var evt = prefix ? prefix + event : event;
155
+ if (!this._events[evt]) return this;
156
+ if (!fn) {
157
+ clearEvent(this, evt);
158
+ return this;
159
+ }
160
+ var listeners = this._events[evt];
161
+ if (listeners.fn) {
162
+ if (listeners.fn === fn && (!once || listeners.once) && (!context || listeners.context === context)) {
163
+ clearEvent(this, evt);
164
+ }
165
+ } else {
166
+ for (var i = 0, events = [], length = listeners.length; i < length; i++) {
167
+ if (listeners[i].fn !== fn || once && !listeners[i].once || context && listeners[i].context !== context) {
168
+ events.push(listeners[i]);
169
+ }
170
+ }
171
+ if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
172
+ else clearEvent(this, evt);
173
+ }
174
+ return this;
175
+ };
176
+ EventEmitter2.prototype.removeAllListeners = function removeAllListeners(event) {
177
+ var evt;
178
+ if (event) {
179
+ evt = prefix ? prefix + event : event;
180
+ if (this._events[evt]) clearEvent(this, evt);
181
+ } else {
182
+ this._events = new Events();
183
+ this._eventsCount = 0;
184
+ }
185
+ return this;
186
+ };
187
+ EventEmitter2.prototype.off = EventEmitter2.prototype.removeListener;
188
+ EventEmitter2.prototype.addListener = EventEmitter2.prototype.on;
189
+ EventEmitter2.prefixed = prefix;
190
+ EventEmitter2.EventEmitter = EventEmitter2;
191
+ if ("undefined" !== typeof module) {
192
+ module.exports = EventEmitter2;
193
+ }
194
+ }
195
+ });
196
+
197
+ // ../../node_modules/eventemitter3/index.mjs
198
+ var import_index = __toESM(require_eventemitter3());
199
+
200
+ // src/commands/redis-commands.ts
201
+ var RedisCommands = class {
202
+ constructor(adapter) {
203
+ this.adapter = adapter;
204
+ }
205
+ get client() {
206
+ const client = this.adapter.getClient();
207
+ if (!client) {
208
+ throw new Error("Redis client not connected");
209
+ }
210
+ return client;
211
+ }
212
+ async hget(key, field) {
213
+ const result = await this.client.hget(this.adapter.getFullKey(key), field);
214
+ return result;
215
+ }
216
+ async hset(key, field, value) {
217
+ const result = await this.client.hset(this.adapter.getFullKey(key), field, value);
218
+ return result;
219
+ }
220
+ async hgetall(key) {
221
+ const result = await this.client.hgetall(this.adapter.getFullKey(key));
222
+ return result;
223
+ }
224
+ async hmset(key, data) {
225
+ const result = await this.client.hmset(this.adapter.getFullKey(key), data);
226
+ return result;
227
+ }
228
+ async hdel(key, ...fields) {
229
+ const result = await this.client.hdel(this.adapter.getFullKey(key), ...fields);
230
+ return result;
231
+ }
232
+ async lpush(key, ...values) {
233
+ const result = await this.client.lpush(this.adapter.getFullKey(key), ...values);
234
+ return result;
235
+ }
236
+ async rpush(key, ...values) {
237
+ const result = await this.client.rpush(this.adapter.getFullKey(key), ...values);
238
+ return result;
239
+ }
240
+ async lpop(key) {
241
+ const result = await this.client.lpop(this.adapter.getFullKey(key));
242
+ return result;
243
+ }
244
+ async rpop(key) {
245
+ const result = await this.client.rpop(this.adapter.getFullKey(key));
246
+ return result;
247
+ }
248
+ async lrange(key, start, stop) {
249
+ const result = await this.client.lrange(this.adapter.getFullKey(key), start, stop);
250
+ return result;
251
+ }
252
+ async llen(key) {
253
+ const result = await this.client.llen(this.adapter.getFullKey(key));
254
+ return result;
255
+ }
256
+ async sadd(key, ...members) {
257
+ const result = await this.client.sadd(this.adapter.getFullKey(key), ...members);
258
+ return result;
259
+ }
260
+ async srem(key, ...members) {
261
+ const result = await this.client.srem(this.adapter.getFullKey(key), ...members);
262
+ return result;
263
+ }
264
+ async smembers(key) {
265
+ const result = await this.client.smembers(this.adapter.getFullKey(key));
266
+ return result;
267
+ }
268
+ async sismember(key, member) {
269
+ const result = await this.client.sismember(this.adapter.getFullKey(key), member);
270
+ return result;
271
+ }
272
+ async scard(key) {
273
+ const result = await this.client.scard(this.adapter.getFullKey(key));
274
+ return result;
275
+ }
276
+ async zadd(key, ...args) {
277
+ const result = await this.client.zadd(this.adapter.getFullKey(key), ...args);
278
+ return result;
279
+ }
280
+ async zrem(key, ...members) {
281
+ const result = await this.client.zrem(this.adapter.getFullKey(key), ...members);
282
+ return result;
283
+ }
284
+ async zrange(key, start, stop, withScores) {
285
+ if (withScores) {
286
+ return this.client.zrange(this.adapter.getFullKey(key), start, stop, "WITHSCORES");
287
+ }
288
+ return this.client.zrange(this.adapter.getFullKey(key), start, stop);
289
+ }
290
+ async zrevrange(key, start, stop, withScores) {
291
+ if (withScores) {
292
+ return this.client.zrevrange(this.adapter.getFullKey(key), start, stop, "WITHSCORES");
293
+ }
294
+ return this.client.zrevrange(this.adapter.getFullKey(key), start, stop);
295
+ }
296
+ async zcard(key) {
297
+ const result = await this.client.zcard(this.adapter.getFullKey(key));
298
+ return result;
299
+ }
300
+ async publish(channel, message) {
301
+ const result = await this.client.publish(channel, message);
302
+ return result;
303
+ }
304
+ async subscribe(channels, callback) {
305
+ const subscriber = this.client.duplicate();
306
+ subscriber.on("message", callback);
307
+ await subscriber.subscribe(...channels);
308
+ }
309
+ async unsubscribe(channels) {
310
+ if (channels) {
311
+ await this.client.unsubscribe(...channels);
312
+ } else {
313
+ await this.client.unsubscribe();
314
+ }
315
+ }
316
+ };
317
+
318
+ // src/adapter/redis-adapter.ts
319
+ var RedisAdapter = class extends import_index.default {
320
+ client;
321
+ isConnected = false;
322
+ _commands;
323
+ options;
324
+ constructor(options = {}) {
325
+ super();
326
+ this.options = {
327
+ redis: options.redis || {},
328
+ keyPrefix: options.keyPrefix || "db-bridge:",
329
+ ttl: options.ttl || 3600,
330
+ logger: options.logger,
331
+ enableCompression: options.enableCompression || false,
332
+ connectionTimeout: options.connectionTimeout || 1e4,
333
+ commandTimeout: options.commandTimeout || 5e3,
334
+ retryOptions: {
335
+ maxRetries: options.retryOptions?.maxRetries ?? 3,
336
+ retryDelay: options.retryOptions?.retryDelay ?? 1e3
337
+ }
338
+ };
339
+ }
340
+ async connect(config) {
341
+ if (this.isConnected) {
342
+ return;
343
+ }
344
+ const redisConfig = {
345
+ ...this.options.redis,
346
+ ...config,
347
+ lazyConnect: true,
348
+ enableOfflineQueue: false,
349
+ retryStrategy: (times) => {
350
+ const retryOptions = this.options.retryOptions;
351
+ if (times > retryOptions.maxRetries) {
352
+ return null;
353
+ }
354
+ return Math.min(times * retryOptions.retryDelay, 5e3);
355
+ }
356
+ };
357
+ this.client = new Redis(redisConfig);
358
+ this.client.on("error", (error) => {
359
+ this.options.logger?.error("Redis client error", error);
360
+ this.emit("error", error);
361
+ });
362
+ this.client.on("connect", () => {
363
+ this.isConnected = true;
364
+ this.options.logger?.info("Connected to Redis");
365
+ this.emit("connect");
366
+ });
367
+ this.client.on("close", () => {
368
+ this.isConnected = false;
369
+ this.options.logger?.info("Disconnected from Redis");
370
+ this.emit("disconnect");
371
+ });
372
+ try {
373
+ await withTimeout(
374
+ this.client.connect(),
375
+ this.options.connectionTimeout,
376
+ "Redis connection timeout"
377
+ );
378
+ } catch (error) {
379
+ throw new ConnectionError("Failed to connect to Redis", error);
380
+ }
381
+ }
382
+ async disconnect() {
383
+ if (this.client && this.isConnected) {
384
+ await this.client.quit();
385
+ this.client = void 0;
386
+ this.isConnected = false;
387
+ }
388
+ }
389
+ async get(key) {
390
+ this.ensureConnected();
391
+ try {
392
+ const fullKey = this.getFullKey(key);
393
+ const value = await withTimeout(this.client.get(fullKey), this.options.commandTimeout);
394
+ if (!value) {
395
+ return null;
396
+ }
397
+ return this.deserialize(value);
398
+ } catch (error) {
399
+ throw new CacheError(`Failed to get key "${key}"`, key, error);
400
+ }
401
+ }
402
+ async set(key, value, ttl) {
403
+ this.ensureConnected();
404
+ try {
405
+ const fullKey = this.getFullKey(key);
406
+ const serialized = this.serialize(value);
407
+ const expiry = ttl || this.options.ttl;
408
+ if (expiry > 0) {
409
+ await withTimeout(
410
+ this.client.setex(fullKey, expiry, serialized),
411
+ this.options.commandTimeout
412
+ );
413
+ } else {
414
+ await withTimeout(this.client.set(fullKey, serialized), this.options.commandTimeout);
415
+ }
416
+ this.emit("set", { key, ttl: expiry });
417
+ } catch (error) {
418
+ throw new CacheError(`Failed to set key "${key}"`, key, error);
419
+ }
420
+ }
421
+ async delete(key) {
422
+ this.ensureConnected();
423
+ try {
424
+ const fullKey = this.getFullKey(key);
425
+ const result = await withTimeout(this.client.del(fullKey), this.options.commandTimeout);
426
+ const deleted = result > 0;
427
+ if (deleted) {
428
+ this.emit("delete", { key });
429
+ }
430
+ return deleted;
431
+ } catch (error) {
432
+ throw new CacheError(`Failed to delete key "${key}"`, key, error);
433
+ }
434
+ }
435
+ async exists(key) {
436
+ this.ensureConnected();
437
+ try {
438
+ const fullKey = this.getFullKey(key);
439
+ const result = await withTimeout(this.client.exists(fullKey), this.options.commandTimeout);
440
+ return result > 0;
441
+ } catch (error) {
442
+ throw new CacheError(`Failed to check existence of key "${key}"`, key, error);
443
+ }
444
+ }
445
+ async clear() {
446
+ this.ensureConnected();
447
+ try {
448
+ const pattern = `${this.options.keyPrefix}*`;
449
+ const keys = await this.keys(pattern);
450
+ if (keys.length > 0) {
451
+ const pipeline = this.client.pipeline();
452
+ keys.forEach((key) => pipeline.del(key));
453
+ await pipeline.exec();
454
+ }
455
+ this.emit("clear", { count: keys.length });
456
+ } catch (error) {
457
+ throw new CacheError("Failed to clear cache", void 0, error);
458
+ }
459
+ }
460
+ async mget(keys) {
461
+ this.ensureConnected();
462
+ if (keys.length === 0) {
463
+ return [];
464
+ }
465
+ try {
466
+ const fullKeys = keys.map((key) => this.getFullKey(key));
467
+ const values = await withTimeout(this.client.mget(...fullKeys), this.options.commandTimeout);
468
+ return values.map((value) => {
469
+ if (!value) {
470
+ return null;
471
+ }
472
+ return this.deserialize(value);
473
+ });
474
+ } catch (error) {
475
+ throw new CacheError("Failed to get multiple keys", void 0, error);
476
+ }
477
+ }
478
+ async mset(items) {
479
+ this.ensureConnected();
480
+ if (items.length === 0) {
481
+ return;
482
+ }
483
+ try {
484
+ const pipeline = this.client.pipeline();
485
+ items.forEach(({ key, value, ttl }) => {
486
+ const fullKey = this.getFullKey(key);
487
+ const serialized = this.serialize(value);
488
+ const expiry = ttl || this.options.ttl;
489
+ if (expiry > 0) {
490
+ pipeline.setex(fullKey, expiry, serialized);
491
+ } else {
492
+ pipeline.set(fullKey, serialized);
493
+ }
494
+ });
495
+ await pipeline.exec();
496
+ this.emit("mset", { count: items.length });
497
+ } catch (error) {
498
+ throw new CacheError("Failed to set multiple keys", void 0, error);
499
+ }
500
+ }
501
+ async keys(pattern = "*") {
502
+ this.ensureConnected();
503
+ try {
504
+ const fullPattern = pattern.startsWith(this.options.keyPrefix) ? pattern : this.getFullKey(pattern);
505
+ const keys = await withTimeout(this.scanKeys(fullPattern), this.options.commandTimeout * 5);
506
+ return keys.map((key) => key.replace(this.options.keyPrefix, ""));
507
+ } catch (error) {
508
+ throw new CacheError("Failed to get keys", void 0, error);
509
+ }
510
+ }
511
+ async ttl(key) {
512
+ this.ensureConnected();
513
+ try {
514
+ const fullKey = this.getFullKey(key);
515
+ const ttl = await withTimeout(this.client.ttl(fullKey), this.options.commandTimeout);
516
+ return ttl >= 0 ? ttl : -1;
517
+ } catch (error) {
518
+ throw new CacheError(`Failed to get TTL for key "${key}"`, key, error);
519
+ }
520
+ }
521
+ async expire(key, ttl) {
522
+ this.ensureConnected();
523
+ try {
524
+ const fullKey = this.getFullKey(key);
525
+ const result = await withTimeout(
526
+ this.client.expire(fullKey, ttl),
527
+ this.options.commandTimeout
528
+ );
529
+ return result === 1;
530
+ } catch (error) {
531
+ throw new CacheError(`Failed to set expiry for key "${key}"`, key, error);
532
+ }
533
+ }
534
+ async increment(key, value = 1) {
535
+ this.ensureConnected();
536
+ try {
537
+ const fullKey = this.getFullKey(key);
538
+ const result = await withTimeout(
539
+ this.client.incrby(fullKey, value),
540
+ this.options.commandTimeout
541
+ );
542
+ return result;
543
+ } catch (error) {
544
+ throw new CacheError(`Failed to increment key "${key}"`, key, error);
545
+ }
546
+ }
547
+ /**
548
+ * Alias for delete() to match Redis command naming
549
+ */
550
+ async del(key) {
551
+ return this.delete(key);
552
+ }
553
+ async decrement(key, value = 1) {
554
+ this.ensureConnected();
555
+ try {
556
+ const fullKey = this.getFullKey(key);
557
+ const result = await withTimeout(
558
+ this.client.decrby(fullKey, value),
559
+ this.options.commandTimeout
560
+ );
561
+ return result;
562
+ } catch (error) {
563
+ throw new CacheError(`Failed to decrement key "${key}"`, key, error);
564
+ }
565
+ }
566
+ async ping() {
567
+ this.ensureConnected();
568
+ return this.client.ping();
569
+ }
570
+ async flushdb() {
571
+ this.ensureConnected();
572
+ await this.client.flushdb();
573
+ }
574
+ async mdel(keys) {
575
+ this.ensureConnected();
576
+ if (keys.length === 0) {
577
+ return 0;
578
+ }
579
+ const fullKeys = keys.map((k) => this.getFullKey(k));
580
+ return this.client.del(...fullKeys);
581
+ }
582
+ async persist(key) {
583
+ this.ensureConnected();
584
+ const fullKey = this.getFullKey(key);
585
+ const result = await this.client.persist(fullKey);
586
+ return result === 1;
587
+ }
588
+ /**
589
+ * Set key with NX (only if not exists) - useful for distributed locking
590
+ */
591
+ async setNX(key, value, ttl) {
592
+ this.ensureConnected();
593
+ const fullKey = this.getFullKey(key);
594
+ const serialized = JSON.stringify(value);
595
+ if (ttl) {
596
+ const result = await this.client.set(fullKey, serialized, "EX", ttl, "NX");
597
+ return result === "OK";
598
+ } else {
599
+ const result = await this.client.setnx(fullKey, serialized);
600
+ return result === 1;
601
+ }
602
+ }
603
+ // Hash operations
604
+ async hset(key, field, value) {
605
+ this.ensureConnected();
606
+ return this.client.hset(this.getFullKey(key), field, value);
607
+ }
608
+ async hget(key, field) {
609
+ this.ensureConnected();
610
+ return this.client.hget(this.getFullKey(key), field);
611
+ }
612
+ async hgetall(key) {
613
+ this.ensureConnected();
614
+ return this.client.hgetall(this.getFullKey(key));
615
+ }
616
+ async hexists(key, field) {
617
+ this.ensureConnected();
618
+ const result = await this.client.hexists(this.getFullKey(key), field);
619
+ return result === 1;
620
+ }
621
+ async hdel(key, ...fields) {
622
+ this.ensureConnected();
623
+ return this.client.hdel(this.getFullKey(key), ...fields);
624
+ }
625
+ // List operations
626
+ async lpush(key, ...values) {
627
+ this.ensureConnected();
628
+ return this.client.lpush(this.getFullKey(key), ...values);
629
+ }
630
+ async rpush(key, ...values) {
631
+ this.ensureConnected();
632
+ return this.client.rpush(this.getFullKey(key), ...values);
633
+ }
634
+ async lpop(key) {
635
+ this.ensureConnected();
636
+ return this.client.lpop(this.getFullKey(key));
637
+ }
638
+ async rpop(key) {
639
+ this.ensureConnected();
640
+ return this.client.rpop(this.getFullKey(key));
641
+ }
642
+ async llen(key) {
643
+ this.ensureConnected();
644
+ return this.client.llen(this.getFullKey(key));
645
+ }
646
+ async lrange(key, start, stop) {
647
+ this.ensureConnected();
648
+ return this.client.lrange(this.getFullKey(key), start, stop);
649
+ }
650
+ // Set operations
651
+ async sadd(key, ...members) {
652
+ this.ensureConnected();
653
+ return this.client.sadd(this.getFullKey(key), ...members);
654
+ }
655
+ async srem(key, ...members) {
656
+ this.ensureConnected();
657
+ return this.client.srem(this.getFullKey(key), ...members);
658
+ }
659
+ async smembers(key) {
660
+ this.ensureConnected();
661
+ return this.client.smembers(this.getFullKey(key));
662
+ }
663
+ async sismember(key, member) {
664
+ this.ensureConnected();
665
+ const result = await this.client.sismember(this.getFullKey(key), member);
666
+ return result === 1;
667
+ }
668
+ async scard(key) {
669
+ this.ensureConnected();
670
+ return this.client.scard(this.getFullKey(key));
671
+ }
672
+ // Sorted set operations
673
+ async zadd(key, score, member) {
674
+ this.ensureConnected();
675
+ return this.client.zadd(this.getFullKey(key), score, member);
676
+ }
677
+ async zrem(key, ...members) {
678
+ this.ensureConnected();
679
+ return this.client.zrem(this.getFullKey(key), ...members);
680
+ }
681
+ async zrange(key, start, stop) {
682
+ this.ensureConnected();
683
+ return this.client.zrange(this.getFullKey(key), start, stop);
684
+ }
685
+ async zrangeWithScores(key, start, stop) {
686
+ this.ensureConnected();
687
+ const result = await this.client.zrange(this.getFullKey(key), start, stop, "WITHSCORES");
688
+ const pairs = [];
689
+ for (let i = 0; i < result.length; i += 2) {
690
+ const member = result[i];
691
+ const score = result[i + 1];
692
+ if (member !== void 0 && score !== void 0) {
693
+ pairs.push([member, Number.parseFloat(score)]);
694
+ }
695
+ }
696
+ return pairs;
697
+ }
698
+ async zscore(key, member) {
699
+ this.ensureConnected();
700
+ const result = await this.client.zscore(this.getFullKey(key), member);
701
+ return result === null ? null : Number.parseFloat(result);
702
+ }
703
+ async zcard(key) {
704
+ this.ensureConnected();
705
+ return this.client.zcard(this.getFullKey(key));
706
+ }
707
+ // Scan iterator
708
+ async *scan(pattern) {
709
+ this.ensureConnected();
710
+ const fullPattern = this.getFullKey(pattern);
711
+ let cursor = "0";
712
+ do {
713
+ const [nextCursor, keys] = await this.client.scan(
714
+ cursor,
715
+ "MATCH",
716
+ fullPattern,
717
+ "COUNT",
718
+ 100
719
+ );
720
+ cursor = nextCursor;
721
+ for (const key of keys) {
722
+ yield key.replace(this.options.keyPrefix, "");
723
+ }
724
+ } while (cursor !== "0");
725
+ }
726
+ ensureConnected() {
727
+ if (!this.client || !this.isConnected) {
728
+ throw new ConnectionError("Redis client not connected");
729
+ }
730
+ }
731
+ get commands() {
732
+ if (!this._commands) {
733
+ this._commands = new RedisCommands(this);
734
+ }
735
+ return this._commands;
736
+ }
737
+ getClient() {
738
+ return this.client;
739
+ }
740
+ getFullKey(key) {
741
+ return `${this.options.keyPrefix}${key}`;
742
+ }
743
+ serialize(value) {
744
+ try {
745
+ const json = JSON.stringify(value);
746
+ if (this.options.enableCompression && json.length > 1024) {
747
+ return this.compress(json);
748
+ }
749
+ return json;
750
+ } catch (error) {
751
+ throw new CacheError("Failed to serialize value", void 0, error);
752
+ }
753
+ }
754
+ deserialize(value) {
755
+ try {
756
+ if (this.options.enableCompression && this.isCompressed(value)) {
757
+ value = this.decompress(value);
758
+ }
759
+ return JSON.parse(value);
760
+ } catch (error) {
761
+ throw new CacheError("Failed to deserialize value", void 0, error);
762
+ }
763
+ }
764
+ compress(data) {
765
+ return data;
766
+ }
767
+ decompress(data) {
768
+ return data;
769
+ }
770
+ isCompressed(_data) {
771
+ return false;
772
+ }
773
+ async scanKeys(pattern) {
774
+ const keys = [];
775
+ let cursor = "0";
776
+ do {
777
+ const [nextCursor, scannedKeys] = await this.client.scan(
778
+ cursor,
779
+ "MATCH",
780
+ pattern,
781
+ "COUNT",
782
+ 1e3
783
+ );
784
+ cursor = nextCursor;
785
+ keys.push(...scannedKeys);
786
+ } while (cursor !== "0");
787
+ return keys;
788
+ }
789
+ };
790
+
791
+ // src/adapter/redis-cache-adapter.ts
792
+ var RedisCacheAdapter = class {
793
+ redis;
794
+ defaultTTL;
795
+ keyPrefix;
796
+ invalidationPatterns;
797
+ constructor(options) {
798
+ this.redis = options.redis;
799
+ this.defaultTTL = options.defaultTTL || 3600;
800
+ this.keyPrefix = options.keyPrefix || "query:";
801
+ this.invalidationPatterns = options.invalidationPatterns || /* @__PURE__ */ new Map();
802
+ }
803
+ async getCachedQuery(key, options) {
804
+ const fullKey = this.getQueryKey(key, options);
805
+ return this.redis.get(fullKey);
806
+ }
807
+ async setCachedQuery(key, result, options) {
808
+ const fullKey = this.getQueryKey(key, options);
809
+ const ttl = options?.ttl || this.defaultTTL;
810
+ await this.redis.set(fullKey, result, ttl);
811
+ if (options?.invalidateOn) {
812
+ await this.registerInvalidation(fullKey, options.invalidateOn);
813
+ }
814
+ }
815
+ async invalidateQueries(patterns) {
816
+ let invalidatedCount = 0;
817
+ for (const pattern of patterns) {
818
+ const keys = await this.redis.keys(`${this.keyPrefix}${pattern}`);
819
+ for (const key of keys) {
820
+ const deleted = await this.redis.delete(key);
821
+ if (deleted) {
822
+ invalidatedCount++;
823
+ }
824
+ }
825
+ const registeredKeys = this.invalidationPatterns.get(pattern) || [];
826
+ for (const key of registeredKeys) {
827
+ const deleted = await this.redis.delete(key);
828
+ if (deleted) {
829
+ invalidatedCount++;
830
+ }
831
+ }
832
+ }
833
+ return invalidatedCount;
834
+ }
835
+ async invalidateAll() {
836
+ const keys = await this.redis.keys(`${this.keyPrefix}*`);
837
+ if (keys.length > 0) {
838
+ await Promise.all(keys.map((key) => this.redis.delete(key)));
839
+ }
840
+ this.invalidationPatterns.clear();
841
+ }
842
+ async getStatistics() {
843
+ const keys = await this.redis.keys(`${this.keyPrefix}*`);
844
+ const totalSize = 0;
845
+ const patterns = /* @__PURE__ */ new Set();
846
+ return {
847
+ totalKeys: keys.length,
848
+ totalSize,
849
+ patterns: Array.from(patterns)
850
+ };
851
+ }
852
+ getQueryKey(key, options) {
853
+ if (options?.key) {
854
+ return `${this.keyPrefix}${options.key}`;
855
+ }
856
+ return `${this.keyPrefix}${key}`;
857
+ }
858
+ async registerInvalidation(key, patterns) {
859
+ for (const pattern of patterns) {
860
+ const existing = this.invalidationPatterns.get(pattern) || [];
861
+ existing.push(key);
862
+ this.invalidationPatterns.set(pattern, existing);
863
+ }
864
+ }
865
+ };
866
+ function createDatabaseAdapterWithCache(adapter, cacheAdapter, options) {
867
+ const cacheableCommands = options?.cacheableCommands || ["SELECT"];
868
+ const defaultTTL = options?.defaultTTL || 3600;
869
+ const originalQuery = adapter.query.bind(adapter);
870
+ adapter.query = async function(sql, params, queryOptions) {
871
+ const command = sql.trim().split(" ")[0]?.toUpperCase();
872
+ if (!queryOptions?.cache || !cacheableCommands.includes(command)) {
873
+ return originalQuery(sql, params, queryOptions);
874
+ }
875
+ const cacheOptions = typeof queryOptions.cache === "object" ? queryOptions.cache : {};
876
+ const cacheKey = generateQueryCacheKey(sql, params);
877
+ const cached = await cacheAdapter.get(cacheKey);
878
+ if (cached) {
879
+ return cached;
880
+ }
881
+ const result = await originalQuery(sql, params, queryOptions);
882
+ const ttl = cacheOptions.ttl || defaultTTL;
883
+ await cacheAdapter.set(cacheKey, result, ttl);
884
+ return result;
885
+ };
886
+ return adapter;
887
+ }
888
+ function generateQueryCacheKey(sql, params) {
889
+ const crypto = __require("crypto");
890
+ const hash = crypto.createHash("sha256");
891
+ hash.update(sql);
892
+ if (params) {
893
+ hash.update(JSON.stringify(params));
894
+ }
895
+ return hash.digest("hex");
896
+ }
897
+ var RedisConnectionManager = class extends import_index.default {
898
+ client;
899
+ isConnected = false;
900
+ config;
901
+ constructor(config = {}) {
902
+ super();
903
+ this.config = {
904
+ keyPrefix: config.keyPrefix || "db-bridge:",
905
+ connectionTimeout: config.connectionTimeout || 1e4,
906
+ retryOptions: {
907
+ maxRetries: config.retryOptions?.maxRetries ?? 3,
908
+ retryDelay: config.retryOptions?.retryDelay ?? 1e3
909
+ },
910
+ redis: config.redis || {}
911
+ };
912
+ }
913
+ async connect(overrideConfig) {
914
+ if (this.isConnected) {
915
+ return;
916
+ }
917
+ const redisConfig = {
918
+ ...this.config.redis,
919
+ ...overrideConfig,
920
+ lazyConnect: true,
921
+ enableOfflineQueue: false,
922
+ retryStrategy: (times) => {
923
+ if (times > this.config.retryOptions.maxRetries) {
924
+ return null;
925
+ }
926
+ return Math.min(times * this.config.retryOptions.retryDelay, 5e3);
927
+ }
928
+ };
929
+ this.client = new Redis(redisConfig);
930
+ this.setupEventHandlers();
931
+ try {
932
+ await withTimeout(
933
+ this.client.connect(),
934
+ this.config.connectionTimeout,
935
+ "Redis connection timeout"
936
+ );
937
+ } catch (error) {
938
+ throw new ConnectionError("Failed to connect to Redis", error);
939
+ }
940
+ }
941
+ async disconnect() {
942
+ if (this.client && this.isConnected) {
943
+ await this.client.quit();
944
+ this.client = void 0;
945
+ this.isConnected = false;
946
+ }
947
+ }
948
+ getClient() {
949
+ return this.client;
950
+ }
951
+ ensureConnected() {
952
+ if (!this.client || !this.isConnected) {
953
+ throw new ConnectionError("Redis client not connected");
954
+ }
955
+ }
956
+ getFullKey(key) {
957
+ return `${this.config.keyPrefix}${key}`;
958
+ }
959
+ setupEventHandlers() {
960
+ if (!this.client) {
961
+ return;
962
+ }
963
+ this.client.on("error", (error) => {
964
+ this.emit("error", error);
965
+ });
966
+ this.client.on("connect", () => {
967
+ this.isConnected = true;
968
+ this.emit("connect");
969
+ });
970
+ this.client.on("close", () => {
971
+ this.isConnected = false;
972
+ this.emit("disconnect");
973
+ });
974
+ }
975
+ };
976
+
977
+ // src/adapter/traits/basic-operations-trait.ts
978
+ var BasicOperationsTrait = class extends RedisConnectionManager {
979
+ commandTimeout = 5e3;
980
+ setCommandTimeout(timeout) {
981
+ this.commandTimeout = timeout;
982
+ }
983
+ async get(key) {
984
+ this.ensureConnected();
985
+ try {
986
+ const fullKey = this.getFullKey(key);
987
+ const value = await withTimeout(this.client.get(fullKey), this.commandTimeout);
988
+ if (!value) {
989
+ return null;
990
+ }
991
+ return this.deserialize(value);
992
+ } catch (error) {
993
+ throw new CacheError(`Failed to get key "${key}"`, key, error);
994
+ }
995
+ }
996
+ async set(key, value, ttl) {
997
+ this.ensureConnected();
998
+ try {
999
+ const fullKey = this.getFullKey(key);
1000
+ const serialized = this.serialize(value);
1001
+ if (ttl && ttl > 0) {
1002
+ await withTimeout(this.client.setex(fullKey, ttl, serialized), this.commandTimeout);
1003
+ } else {
1004
+ await withTimeout(this.client.set(fullKey, serialized), this.commandTimeout);
1005
+ }
1006
+ this.emit("set", { key, ttl });
1007
+ } catch (error) {
1008
+ throw new CacheError(`Failed to set key "${key}"`, key, error);
1009
+ }
1010
+ }
1011
+ async delete(key) {
1012
+ this.ensureConnected();
1013
+ try {
1014
+ const fullKey = this.getFullKey(key);
1015
+ const result = await withTimeout(this.client.del(fullKey), this.commandTimeout);
1016
+ const deleted = result > 0;
1017
+ if (deleted) {
1018
+ this.emit("delete", { key });
1019
+ }
1020
+ return deleted;
1021
+ } catch (error) {
1022
+ throw new CacheError(`Failed to delete key "${key}"`, key, error);
1023
+ }
1024
+ }
1025
+ async del(key) {
1026
+ return this.delete(key);
1027
+ }
1028
+ async exists(key) {
1029
+ this.ensureConnected();
1030
+ try {
1031
+ const fullKey = this.getFullKey(key);
1032
+ const result = await withTimeout(this.client.exists(fullKey), this.commandTimeout);
1033
+ return result > 0;
1034
+ } catch (error) {
1035
+ throw new CacheError(`Failed to check existence of key "${key}"`, key, error);
1036
+ }
1037
+ }
1038
+ async ttl(key) {
1039
+ this.ensureConnected();
1040
+ try {
1041
+ const fullKey = this.getFullKey(key);
1042
+ const ttl = await withTimeout(this.client.ttl(fullKey), this.commandTimeout);
1043
+ return ttl >= 0 ? ttl : -1;
1044
+ } catch (error) {
1045
+ throw new CacheError(`Failed to get TTL for key "${key}"`, key, error);
1046
+ }
1047
+ }
1048
+ async expire(key, ttl) {
1049
+ this.ensureConnected();
1050
+ try {
1051
+ const fullKey = this.getFullKey(key);
1052
+ const result = await withTimeout(this.client.expire(fullKey, ttl), this.commandTimeout);
1053
+ return result === 1;
1054
+ } catch (error) {
1055
+ throw new CacheError(`Failed to set expiry for key "${key}"`, key, error);
1056
+ }
1057
+ }
1058
+ serialize(value) {
1059
+ try {
1060
+ return JSON.stringify(value);
1061
+ } catch (error) {
1062
+ throw new CacheError("Failed to serialize value", void 0, error);
1063
+ }
1064
+ }
1065
+ deserialize(value) {
1066
+ try {
1067
+ return JSON.parse(value);
1068
+ } catch (error) {
1069
+ throw new CacheError("Failed to deserialize value", void 0, error);
1070
+ }
1071
+ }
1072
+ };
1073
+
1074
+ // src/adapter/traits/batch-operations-trait.ts
1075
+ var BatchOperationsTrait = class extends BasicOperationsTrait {
1076
+ async mget(keys) {
1077
+ this.ensureConnected();
1078
+ if (keys.length === 0) {
1079
+ return [];
1080
+ }
1081
+ try {
1082
+ const fullKeys = keys.map((key) => this.getFullKey(key));
1083
+ const values = await withTimeout(this.client.mget(...fullKeys), this.commandTimeout);
1084
+ return values.map((value) => {
1085
+ if (!value) {
1086
+ return null;
1087
+ }
1088
+ return this.deserialize(value);
1089
+ });
1090
+ } catch (error) {
1091
+ throw new CacheError("Failed to get multiple keys", void 0, error);
1092
+ }
1093
+ }
1094
+ async mset(items) {
1095
+ this.ensureConnected();
1096
+ if (items.length === 0) {
1097
+ return;
1098
+ }
1099
+ try {
1100
+ const pipeline = this.client.pipeline();
1101
+ items.forEach(({ key, value, ttl }) => {
1102
+ const fullKey = this.getFullKey(key);
1103
+ const serialized = this.serialize(value);
1104
+ if (ttl && ttl > 0) {
1105
+ pipeline.setex(fullKey, ttl, serialized);
1106
+ } else {
1107
+ pipeline.set(fullKey, serialized);
1108
+ }
1109
+ });
1110
+ await pipeline.exec();
1111
+ this.emit("mset", { count: items.length });
1112
+ } catch (error) {
1113
+ throw new CacheError("Failed to set multiple keys", void 0, error);
1114
+ }
1115
+ }
1116
+ async clear() {
1117
+ this.ensureConnected();
1118
+ try {
1119
+ const pattern = `${this.config.keyPrefix}*`;
1120
+ const keys = await this.scanKeys(pattern);
1121
+ if (keys.length > 0) {
1122
+ const pipeline = this.client.pipeline();
1123
+ keys.forEach((key) => pipeline.del(key));
1124
+ await pipeline.exec();
1125
+ }
1126
+ this.emit("clear", { count: keys.length });
1127
+ } catch (error) {
1128
+ throw new CacheError("Failed to clear cache", void 0, error);
1129
+ }
1130
+ }
1131
+ async keys(pattern = "*") {
1132
+ this.ensureConnected();
1133
+ try {
1134
+ const fullPattern = pattern.startsWith(this.config.keyPrefix) ? pattern : this.getFullKey(pattern);
1135
+ const keys = await withTimeout(this.scanKeys(fullPattern), this.commandTimeout * 5);
1136
+ return keys.map((key) => key.replace(this.config.keyPrefix, ""));
1137
+ } catch (error) {
1138
+ throw new CacheError("Failed to get keys", void 0, error);
1139
+ }
1140
+ }
1141
+ async scanKeys(pattern) {
1142
+ const keys = [];
1143
+ let cursor = "0";
1144
+ do {
1145
+ const [nextCursor, scannedKeys] = await this.client.scan(
1146
+ cursor,
1147
+ "MATCH",
1148
+ pattern,
1149
+ "COUNT",
1150
+ 1e3
1151
+ );
1152
+ cursor = nextCursor;
1153
+ keys.push(...scannedKeys);
1154
+ } while (cursor !== "0");
1155
+ return keys;
1156
+ }
1157
+ };
1158
+
1159
+ // src/adapter/traits/counter-operations-trait.ts
1160
+ var CounterOperationsTrait = class extends BatchOperationsTrait {
1161
+ async increment(key, value = 1) {
1162
+ this.ensureConnected();
1163
+ try {
1164
+ const fullKey = this.getFullKey(key);
1165
+ const result = await withTimeout(this.client.incrby(fullKey, value), this.commandTimeout);
1166
+ return result;
1167
+ } catch (error) {
1168
+ throw new CacheError(`Failed to increment key "${key}"`, key, error);
1169
+ }
1170
+ }
1171
+ async decrement(key, value = 1) {
1172
+ this.ensureConnected();
1173
+ try {
1174
+ const fullKey = this.getFullKey(key);
1175
+ const result = await withTimeout(this.client.decrby(fullKey, value), this.commandTimeout);
1176
+ return result;
1177
+ } catch (error) {
1178
+ throw new CacheError(`Failed to decrement key "${key}"`, key, error);
1179
+ }
1180
+ }
1181
+ async incr(key) {
1182
+ return this.increment(key, 1);
1183
+ }
1184
+ async decr(key) {
1185
+ return this.decrement(key, 1);
1186
+ }
1187
+ async incrby(key, value) {
1188
+ return this.increment(key, value);
1189
+ }
1190
+ async decrby(key, value) {
1191
+ return this.decrement(key, value);
1192
+ }
1193
+ async incrbyfloat(key, value) {
1194
+ this.ensureConnected();
1195
+ try {
1196
+ const fullKey = this.getFullKey(key);
1197
+ const result = await withTimeout(
1198
+ this.client.incrbyfloat(fullKey, value),
1199
+ this.commandTimeout
1200
+ );
1201
+ return result;
1202
+ } catch (error) {
1203
+ throw new CacheError(`Failed to increment float key "${key}"`, key, error);
1204
+ }
1205
+ }
1206
+ };
1207
+
1208
+ // src/adapter/modular-redis-adapter.ts
1209
+ var ModularRedisAdapter = class extends CounterOperationsTrait {
1210
+ _commands;
1211
+ defaultTtl;
1212
+ logger;
1213
+ enableCompression;
1214
+ constructor(options = {}) {
1215
+ super({
1216
+ redis: options.redis,
1217
+ keyPrefix: options.keyPrefix,
1218
+ connectionTimeout: options.connectionTimeout,
1219
+ retryOptions: options.retryOptions
1220
+ });
1221
+ this.defaultTtl = options.ttl || 3600;
1222
+ this.logger = options.logger;
1223
+ this.enableCompression = options.enableCompression || false;
1224
+ if (options.commandTimeout) {
1225
+ this.setCommandTimeout(options.commandTimeout);
1226
+ }
1227
+ this.setupLogging();
1228
+ }
1229
+ async connect(config) {
1230
+ await super.connect(config);
1231
+ this.logger?.info("Connected to Redis");
1232
+ }
1233
+ async disconnect() {
1234
+ await super.disconnect();
1235
+ this.logger?.info("Disconnected from Redis");
1236
+ }
1237
+ async set(key, value, ttl) {
1238
+ const effectiveTtl = ttl === void 0 ? this.defaultTtl : ttl;
1239
+ await super.set(key, value, effectiveTtl);
1240
+ }
1241
+ get commands() {
1242
+ if (!this._commands) {
1243
+ this._commands = new RedisCommands(this);
1244
+ }
1245
+ return this._commands;
1246
+ }
1247
+ serialize(value) {
1248
+ try {
1249
+ const json = super.serialize(value);
1250
+ if (this.enableCompression && json.length > 1024) {
1251
+ return this.compress(json);
1252
+ }
1253
+ return json;
1254
+ } catch (error) {
1255
+ this.logger?.error("Serialization error", error);
1256
+ throw error;
1257
+ }
1258
+ }
1259
+ deserialize(value) {
1260
+ try {
1261
+ if (this.enableCompression && this.isCompressed(value)) {
1262
+ value = this.decompress(value);
1263
+ }
1264
+ return super.deserialize(value);
1265
+ } catch (error) {
1266
+ this.logger?.error("Deserialization error", error);
1267
+ throw error;
1268
+ }
1269
+ }
1270
+ compress(data) {
1271
+ return data;
1272
+ }
1273
+ decompress(data) {
1274
+ return data;
1275
+ }
1276
+ isCompressed(_data) {
1277
+ return false;
1278
+ }
1279
+ setupLogging() {
1280
+ if (!this.logger) {
1281
+ return;
1282
+ }
1283
+ this.on("error", (error) => {
1284
+ this.logger?.error("Redis client error", error);
1285
+ });
1286
+ this.on("connect", () => {
1287
+ this.logger?.debug("Redis connected");
1288
+ });
1289
+ this.on("disconnect", () => {
1290
+ this.logger?.debug("Redis disconnected");
1291
+ });
1292
+ this.on("set", ({ key, ttl }) => {
1293
+ this.logger?.debug("Cache set", { key, ttl });
1294
+ });
1295
+ this.on("delete", ({ key }) => {
1296
+ this.logger?.debug("Cache delete", { key });
1297
+ });
1298
+ this.on("clear", ({ count }) => {
1299
+ this.logger?.debug("Cache cleared", { count });
1300
+ });
1301
+ this.on("mset", ({ count }) => {
1302
+ this.logger?.debug("Multiple cache set", { count });
1303
+ });
1304
+ }
1305
+ };
1306
+ var StreamBaseTrait = class extends import_index.default {
1307
+ constructor(client) {
1308
+ super();
1309
+ this.client = client;
1310
+ }
1311
+ parseEntries(raw) {
1312
+ return raw.map(([id, fields]) => ({
1313
+ id,
1314
+ fields: this.parseFields(fields)
1315
+ }));
1316
+ }
1317
+ parseFields(raw) {
1318
+ const fields = {};
1319
+ for (let i = 0; i < raw.length; i += 2) {
1320
+ fields[raw[i]] = raw[i + 1];
1321
+ }
1322
+ return fields;
1323
+ }
1324
+ parseStreamResults(raw) {
1325
+ return raw.map(([stream, entries]) => [stream, this.parseEntries(entries)]);
1326
+ }
1327
+ camelCase(str) {
1328
+ return str.replaceAll(/-([a-z])/g, (_, letter) => letter.toUpperCase());
1329
+ }
1330
+ throwError(message, key, error) {
1331
+ throw new CacheError(message, key, error);
1332
+ }
1333
+ };
1334
+
1335
+ // src/streams/traits/stream-crud-trait.ts
1336
+ var StreamCrudTrait = class extends StreamBaseTrait {
1337
+ async xadd(key, _id = "*", fields, options) {
1338
+ try {
1339
+ const args = [key];
1340
+ if (options?.maxlen) {
1341
+ args.push("MAXLEN");
1342
+ if (options.approximate) {
1343
+ args.push("~");
1344
+ }
1345
+ args.push(options.maxlen);
1346
+ }
1347
+ args.push(_id);
1348
+ Object.entries(fields).forEach(([field, value]) => {
1349
+ args.push(field, String(value));
1350
+ });
1351
+ const resultId = await this.client.xadd(
1352
+ key,
1353
+ args[1],
1354
+ ...args.slice(2)
1355
+ );
1356
+ return resultId || "";
1357
+ } catch (error) {
1358
+ this.throwError(`Failed to add to stream ${key}`, key, error);
1359
+ }
1360
+ }
1361
+ async xdel(key, ...ids) {
1362
+ try {
1363
+ return await this.client.xdel(key, ...ids);
1364
+ } catch (error) {
1365
+ this.throwError(`Failed to delete from stream ${key}`, key, error);
1366
+ }
1367
+ }
1368
+ async xtrim(key, maxlen, approximate = false) {
1369
+ try {
1370
+ const args = [key, "MAXLEN"];
1371
+ if (approximate) {
1372
+ args.push("~");
1373
+ }
1374
+ args.push(maxlen);
1375
+ return approximate ? await this.client.xtrim(key, "MAXLEN", "~", maxlen) : await this.client.xtrim(key, "MAXLEN", maxlen);
1376
+ } catch (error) {
1377
+ this.throwError(`Failed to trim stream ${key}`, key, error);
1378
+ }
1379
+ }
1380
+ async xlen(key) {
1381
+ try {
1382
+ return await this.client.xlen(key);
1383
+ } catch (error) {
1384
+ this.throwError(`Failed to get stream length ${key}`, key, error);
1385
+ }
1386
+ }
1387
+ };
1388
+
1389
+ // src/streams/traits/stream-read-trait.ts
1390
+ var StreamReadTrait = class extends StreamCrudTrait {
1391
+ async xread(streams, options) {
1392
+ try {
1393
+ const args = [];
1394
+ if (options?.count) {
1395
+ args.push("COUNT", options.count);
1396
+ }
1397
+ if (options?.block !== void 0) {
1398
+ args.push("BLOCK", options.block);
1399
+ }
1400
+ args.push("STREAMS");
1401
+ const keys = Object.keys(streams);
1402
+ const ids = Object.values(streams);
1403
+ args.push(...keys, ...ids);
1404
+ const result = await this.client.xread(...args);
1405
+ if (!result) {
1406
+ return [];
1407
+ }
1408
+ return this.parseStreamResults(result);
1409
+ } catch (error) {
1410
+ this.throwError("Failed to read from streams", void 0, error);
1411
+ }
1412
+ }
1413
+ async xrange(key, start = "-", end = "+", count) {
1414
+ try {
1415
+ const args = [key, start, end];
1416
+ if (count) {
1417
+ args.push("COUNT", count);
1418
+ }
1419
+ const result = count ? await this.client.xrange(key, start, end, "COUNT", count) : await this.client.xrange(key, start, end);
1420
+ return this.parseEntries(result);
1421
+ } catch (error) {
1422
+ this.throwError(`Failed to read range from stream ${key}`, key, error);
1423
+ }
1424
+ }
1425
+ async xrevrange(key, end = "+", start = "-", count) {
1426
+ try {
1427
+ const args = [key, end, start];
1428
+ if (count) {
1429
+ args.push("COUNT", count);
1430
+ }
1431
+ const result = count ? await this.client.xrevrange(key, end, start, "COUNT", count) : await this.client.xrevrange(key, end, start);
1432
+ return this.parseEntries(result);
1433
+ } catch (error) {
1434
+ this.throwError(`Failed to read reverse range from stream ${key}`, key, error);
1435
+ }
1436
+ }
1437
+ };
1438
+
1439
+ // src/streams/traits/stream-consumer-trait.ts
1440
+ var StreamConsumerTrait = class extends StreamReadTrait {
1441
+ async xgroupCreate(key, groupName, id = "$", mkstream = false) {
1442
+ try {
1443
+ const args = [key, groupName, id];
1444
+ if (mkstream) {
1445
+ args.push("MKSTREAM");
1446
+ }
1447
+ if (mkstream) {
1448
+ await this.client.xgroup("CREATE", key, groupName, id, "MKSTREAM");
1449
+ } else {
1450
+ await this.client.xgroup("CREATE", key, groupName, id);
1451
+ }
1452
+ } catch (error) {
1453
+ if (!error.message?.includes("BUSYGROUP")) {
1454
+ this.throwError(`Failed to create consumer group ${groupName}`, key, error);
1455
+ }
1456
+ }
1457
+ }
1458
+ async xgroupDestroy(key, groupName) {
1459
+ try {
1460
+ const result = await this.client.xgroup("DESTROY", key, groupName);
1461
+ return result === 1;
1462
+ } catch (error) {
1463
+ this.throwError(`Failed to destroy consumer group ${groupName}`, key, error);
1464
+ }
1465
+ }
1466
+ async xgroupSetId(key, groupName, id) {
1467
+ try {
1468
+ await this.client.xgroup("SETID", key, groupName, id);
1469
+ } catch (error) {
1470
+ this.throwError(`Failed to set ID for consumer group ${groupName}`, key, error);
1471
+ }
1472
+ }
1473
+ async xreadgroup(groupName, consumerName, streams, options) {
1474
+ try {
1475
+ const args = ["GROUP", groupName, consumerName];
1476
+ if (options?.count) {
1477
+ args.push("COUNT", options.count);
1478
+ }
1479
+ if (options?.block !== void 0) {
1480
+ args.push("BLOCK", options.block);
1481
+ }
1482
+ if (options?.noack) {
1483
+ args.push("NOACK");
1484
+ }
1485
+ args.push("STREAMS");
1486
+ const keys = Object.keys(streams);
1487
+ const ids = Object.values(streams);
1488
+ args.push(...keys, ...ids);
1489
+ const result = await this.client.xreadgroup(...args);
1490
+ if (!result) {
1491
+ return [];
1492
+ }
1493
+ return this.parseStreamResults(result);
1494
+ } catch (error) {
1495
+ this.throwError("Failed to read from consumer group", void 0, error);
1496
+ }
1497
+ }
1498
+ async xack(key, groupName, ...ids) {
1499
+ try {
1500
+ return await this.client.xack(key, groupName, ...ids);
1501
+ } catch (error) {
1502
+ this.throwError(`Failed to acknowledge messages in group ${groupName}`, key, error);
1503
+ }
1504
+ }
1505
+ async xpending(key, groupName, options) {
1506
+ try {
1507
+ const args = [key, groupName];
1508
+ if (options?.start && options?.end) {
1509
+ args.push(options.start, options.end, options.count || 10);
1510
+ if (options.consumer) {
1511
+ args.push(options.consumer);
1512
+ }
1513
+ }
1514
+ return await this.client.xpending(...args);
1515
+ } catch (error) {
1516
+ this.throwError(`Failed to get pending messages for group ${groupName}`, key, error);
1517
+ }
1518
+ }
1519
+ async xclaim(key, groupName, consumerName, minIdleTime, ids, options) {
1520
+ try {
1521
+ const args = [key, groupName, consumerName, minIdleTime, ...ids];
1522
+ if (options?.idle) {
1523
+ args.push("IDLE", options.idle);
1524
+ }
1525
+ if (options?.time) {
1526
+ args.push("TIME", options.time);
1527
+ }
1528
+ if (options?.retrycount) {
1529
+ args.push("RETRYCOUNT", options.retrycount);
1530
+ }
1531
+ if (options?.force) {
1532
+ args.push("FORCE");
1533
+ }
1534
+ if (options?.justid) {
1535
+ args.push("JUSTID");
1536
+ }
1537
+ const result = await this.client.xclaim(...args);
1538
+ if (options?.justid) {
1539
+ return result;
1540
+ }
1541
+ return this.parseEntries(result);
1542
+ } catch (error) {
1543
+ this.throwError(`Failed to claim messages for consumer ${consumerName}`, key, error);
1544
+ }
1545
+ }
1546
+ };
1547
+
1548
+ // src/streams/traits/stream-info-trait.ts
1549
+ var StreamInfoTrait = class extends StreamConsumerTrait {
1550
+ async xinfo(subcommand, key, groupName) {
1551
+ try {
1552
+ const args = [subcommand, key];
1553
+ if (groupName && subcommand === "CONSUMERS") {
1554
+ args.push(groupName);
1555
+ }
1556
+ const result = await this.client.xinfo(...args);
1557
+ if (subcommand === "STREAM") {
1558
+ return this.parseStreamInfo(result);
1559
+ } else if (subcommand === "GROUPS") {
1560
+ return this.parseGroupsInfo(result);
1561
+ } else {
1562
+ return result;
1563
+ }
1564
+ } catch (error) {
1565
+ this.throwError(`Failed to get info for stream ${key}`, key, error);
1566
+ }
1567
+ }
1568
+ parseStreamInfo(raw) {
1569
+ const info = {};
1570
+ for (let i = 0; i < raw.length; i += 2) {
1571
+ const key = raw[i];
1572
+ const value = raw[i + 1];
1573
+ switch (key) {
1574
+ case "length":
1575
+ case "radix-tree-keys":
1576
+ case "radix-tree-nodes":
1577
+ case "groups": {
1578
+ info[this.camelCase(key)] = value;
1579
+ break;
1580
+ }
1581
+ case "last-generated-id": {
1582
+ info.lastGeneratedId = value;
1583
+ break;
1584
+ }
1585
+ case "first-entry":
1586
+ case "last-entry": {
1587
+ if (value) {
1588
+ info[this.camelCase(key)] = {
1589
+ id: value[0],
1590
+ fields: this.parseFields(value[1])
1591
+ };
1592
+ }
1593
+ break;
1594
+ }
1595
+ }
1596
+ }
1597
+ return info;
1598
+ }
1599
+ parseGroupsInfo(raw) {
1600
+ return raw.map((group) => {
1601
+ const info = {};
1602
+ for (let i = 0; i < group.length; i += 2) {
1603
+ const key = group[i];
1604
+ const value = group[i + 1];
1605
+ switch (key) {
1606
+ case "name":
1607
+ case "consumers":
1608
+ case "pending": {
1609
+ info[key] = value;
1610
+ break;
1611
+ }
1612
+ case "last-delivered-id": {
1613
+ info.lastDeliveredId = value;
1614
+ break;
1615
+ }
1616
+ }
1617
+ }
1618
+ return info;
1619
+ });
1620
+ }
1621
+ };
1622
+
1623
+ // src/streams/modular-stream-manager.ts
1624
+ var ModularRedisStreamManager = class extends StreamInfoTrait {
1625
+ constructor(client) {
1626
+ super(client);
1627
+ }
1628
+ // Additional high-level methods can be added here
1629
+ async createStreamWithGroup(key, groupName, options) {
1630
+ await this.xadd(key, "*", { init: "true" }, options);
1631
+ await this.xgroupCreate(key, groupName, "0");
1632
+ const entries = await this.xrange(key, "-", "+", 1);
1633
+ if (entries.length > 0 && entries[0]?.fields["init"] === "true") {
1634
+ await this.xdel(key, entries[0].id);
1635
+ }
1636
+ }
1637
+ async getStreamStats(key) {
1638
+ const length = await this.xlen(key);
1639
+ const info = await this.xinfo("STREAM", key);
1640
+ let groups;
1641
+ try {
1642
+ const groupsInfo = await this.xinfo("GROUPS", key);
1643
+ groups = Array.isArray(groupsInfo) ? groupsInfo : void 0;
1644
+ } catch {
1645
+ }
1646
+ return { length, info, groups };
1647
+ }
1648
+ async consumeStream(groupName, consumerName, keys, options) {
1649
+ const streams = {};
1650
+ keys.forEach((key) => {
1651
+ streams[key] = ">";
1652
+ });
1653
+ const messages = await this.xreadgroup(groupName, consumerName, streams, {
1654
+ count: options?.count,
1655
+ block: options?.block,
1656
+ noack: options?.autoAck
1657
+ });
1658
+ let processedCount = 0;
1659
+ for (const [streamKey, entries] of messages) {
1660
+ for (const entry of entries) {
1661
+ if (options?.processMessage) {
1662
+ await options.processMessage(streamKey, entry);
1663
+ }
1664
+ if (!options?.autoAck) {
1665
+ await this.xack(streamKey, groupName, entry.id);
1666
+ }
1667
+ processedCount++;
1668
+ }
1669
+ }
1670
+ return processedCount;
1671
+ }
1672
+ };
1673
+
1674
+ export { ModularRedisAdapter, ModularRedisStreamManager, RedisAdapter, RedisCacheAdapter, RedisCommands, createDatabaseAdapterWithCache };
1675
+ //# sourceMappingURL=index.js.map
1676
+ //# sourceMappingURL=index.js.map