ocpp-ws-io 2.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,423 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/adapters/redis/index.ts
21
+ var redis_exports = {};
22
+ __export(redis_exports, {
23
+ RedisAdapter: () => RedisAdapter
24
+ });
25
+ module.exports = __toCommonJS(redis_exports);
26
+
27
+ // src/adapters/redis/helpers.ts
28
+ var IoRedisDriver = class {
29
+ constructor(pub, sub, blocking) {
30
+ this.pub = pub;
31
+ this.sub = sub;
32
+ this.blocking = blocking;
33
+ if (this.sub.on) {
34
+ this.sub.on("message", (channel, message) => {
35
+ const handler = this._handlers.get(channel);
36
+ if (handler) handler(message);
37
+ });
38
+ }
39
+ }
40
+ _handlers = /* @__PURE__ */ new Map();
41
+ async publish(channel, message) {
42
+ await this.pub.publish(channel, message);
43
+ }
44
+ async subscribe(channel, handler) {
45
+ this._handlers.set(channel, handler);
46
+ await this.sub.subscribe(channel);
47
+ }
48
+ async unsubscribe(channel) {
49
+ await this.sub.unsubscribe(channel);
50
+ this._handlers.delete(channel);
51
+ }
52
+ async set(key, value, ttlSeconds) {
53
+ if (ttlSeconds) {
54
+ await this.pub.set(key, value, "EX", ttlSeconds);
55
+ } else {
56
+ await this.pub.set(key, value);
57
+ }
58
+ }
59
+ async get(key) {
60
+ return await this.pub.get(key) || null;
61
+ }
62
+ async mget(keys) {
63
+ if (keys.length === 0) return [];
64
+ return await this.pub.mget(...keys);
65
+ }
66
+ async del(key) {
67
+ await this.pub.del(key);
68
+ }
69
+ async xadd(stream, args, maxLen) {
70
+ const flatArgs = [];
71
+ if (maxLen) {
72
+ flatArgs.push("MAXLEN", "~", maxLen.toString());
73
+ }
74
+ flatArgs.push("*");
75
+ for (const [k, v] of Object.entries(args)) {
76
+ flatArgs.push(k, v);
77
+ }
78
+ return await this.pub.xadd(stream, ...flatArgs);
79
+ }
80
+ async xaddBatch(messages, maxLen) {
81
+ if (messages.length === 0) return;
82
+ const pipeline = this.pub.pipeline();
83
+ for (const msg of messages) {
84
+ const flatArgs = [];
85
+ if (maxLen) {
86
+ flatArgs.push("MAXLEN", "~", maxLen.toString());
87
+ }
88
+ flatArgs.push("*");
89
+ for (const [k, v] of Object.entries(msg.args)) {
90
+ flatArgs.push(k, v);
91
+ }
92
+ pipeline.xadd(msg.stream, ...flatArgs);
93
+ }
94
+ await pipeline.exec();
95
+ }
96
+ async xread(streams, count, block) {
97
+ const args = [];
98
+ if (count) {
99
+ args.push("COUNT", count);
100
+ }
101
+ if (typeof block === "number") {
102
+ args.push("BLOCK", block);
103
+ }
104
+ args.push("STREAMS");
105
+ streams.forEach((s) => {
106
+ args.push(s.key);
107
+ });
108
+ streams.forEach((s) => {
109
+ args.push(s.id);
110
+ });
111
+ const client = block && this.blocking ? this.blocking : this.pub;
112
+ const result = await client.xread(...args);
113
+ if (!result) return null;
114
+ return result.map(([stream, messages]) => ({
115
+ stream,
116
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
117
+ messages: messages.map(([id, fields]) => {
118
+ const data = {};
119
+ for (let i = 0; i < fields.length; i += 2) {
120
+ data[fields[i]] = fields[i + 1];
121
+ }
122
+ return { id, data };
123
+ })
124
+ }));
125
+ }
126
+ async xlen(stream) {
127
+ return await this.pub.xlen(stream);
128
+ }
129
+ async disconnect() {
130
+ this._handlers.clear();
131
+ const close = async (c) => {
132
+ if (c.quit) await c.quit();
133
+ else if (c.disconnect) await c.disconnect();
134
+ };
135
+ await Promise.all([close(this.pub), close(this.sub)]);
136
+ }
137
+ };
138
+ var NodeRedisDriver = class {
139
+ constructor(pub, sub, blocking) {
140
+ this.pub = pub;
141
+ this.sub = sub;
142
+ this.blocking = blocking;
143
+ }
144
+ async publish(channel, message) {
145
+ await this.pub.publish(channel, message);
146
+ }
147
+ async subscribe(channel, handler) {
148
+ await this.sub.subscribe(channel, handler);
149
+ }
150
+ async unsubscribe(channel) {
151
+ await this.sub.unsubscribe(channel);
152
+ }
153
+ async set(key, value, ttlSeconds) {
154
+ if (ttlSeconds) {
155
+ await this.pub.set(key, value, { EX: ttlSeconds });
156
+ } else {
157
+ await this.pub.set(key, value);
158
+ }
159
+ }
160
+ async get(key) {
161
+ return await this.pub.get(key) || null;
162
+ }
163
+ async mget(keys) {
164
+ if (keys.length === 0) return [];
165
+ return await this.pub.mGet(keys);
166
+ }
167
+ async del(key) {
168
+ await this.pub.del(key);
169
+ }
170
+ async xadd(stream, args, maxLen) {
171
+ const options = {};
172
+ if (maxLen) {
173
+ options.MKSTREAM = true;
174
+ }
175
+ return await this.pub.xAdd(stream, "*", args, {
176
+ TRIM: maxLen ? {
177
+ strategy: "MAXLEN",
178
+ strategyModifier: "~",
179
+ threshold: maxLen
180
+ } : void 0
181
+ });
182
+ }
183
+ async xaddBatch(messages, maxLen) {
184
+ if (messages.length === 0) return;
185
+ const multi = this.pub.multi();
186
+ for (const msg of messages) {
187
+ multi.xAdd(msg.stream, "*", msg.args, {
188
+ TRIM: maxLen ? {
189
+ strategy: "MAXLEN",
190
+ strategyModifier: "~",
191
+ threshold: maxLen
192
+ } : void 0
193
+ });
194
+ }
195
+ await multi.exec();
196
+ }
197
+ async xread(streams, count, block) {
198
+ const options = {};
199
+ if (count) options.COUNT = count;
200
+ if (typeof block === "number") options.BLOCK = block;
201
+ const streamsParam = streams.map((s) => ({
202
+ key: s.key,
203
+ id: s.id
204
+ }));
205
+ const client = block && this.blocking ? this.blocking : this.pub;
206
+ const result = await client.xRead(streamsParam, options);
207
+ if (!result || result.length === 0) return null;
208
+ return result.map((entry) => ({
209
+ stream: entry.name,
210
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
211
+ messages: entry.messages.map((msg) => ({
212
+ id: msg.id,
213
+ data: msg.message
214
+ }))
215
+ }));
216
+ }
217
+ async xlen(stream) {
218
+ return await this.pub.xLen(stream);
219
+ }
220
+ async disconnect() {
221
+ await Promise.all([this.pub.disconnect(), this.sub.disconnect()]);
222
+ }
223
+ };
224
+ function createDriver(pub, sub, blocking) {
225
+ if (sub.isOpen !== void 0 && typeof sub.subscribe === "function") {
226
+ return new NodeRedisDriver(pub, sub, blocking);
227
+ }
228
+ return new IoRedisDriver(pub, sub, blocking);
229
+ }
230
+
231
+ // src/adapters/redis/index.ts
232
+ var RedisAdapter = class {
233
+ _driver;
234
+ _prefix;
235
+ _streamMaxLen;
236
+ _handlers = /* @__PURE__ */ new Map();
237
+ _streamOffsets = /* @__PURE__ */ new Map();
238
+ // streamKey -> lastId
239
+ _streams = /* @__PURE__ */ new Set();
240
+ // Active streams to poll
241
+ _polling = false;
242
+ _closed = false;
243
+ constructor(options) {
244
+ this._prefix = options.prefix ?? "ocpp-ws-io:";
245
+ this._streamMaxLen = options.streamMaxLen ?? 1e3;
246
+ this._driver = createDriver(
247
+ options.pubClient,
248
+ options.subClient,
249
+ options.blockingClient
250
+ );
251
+ }
252
+ async publish(channel, data) {
253
+ const prefixedChannel = this._prefix + channel;
254
+ const message = JSON.stringify(data);
255
+ if (channel.startsWith("ocpp:node:")) {
256
+ await this._driver.xadd(prefixedChannel, { message }, this._streamMaxLen);
257
+ } else {
258
+ await this._driver.publish(prefixedChannel, message);
259
+ }
260
+ }
261
+ async publishBatch(messages) {
262
+ const streamMessages = [];
263
+ const broadcastMessages = [];
264
+ for (const msg of messages) {
265
+ const prefixedChannel = this._prefix + msg.channel;
266
+ const message = JSON.stringify(msg.data);
267
+ if (msg.channel.startsWith("ocpp:node:")) {
268
+ streamMessages.push({ stream: prefixedChannel, args: { message } });
269
+ } else {
270
+ broadcastMessages.push({ channel: prefixedChannel, message });
271
+ }
272
+ }
273
+ const promises = [];
274
+ if (streamMessages.length > 0) {
275
+ promises.push(this._driver.xaddBatch(streamMessages, this._streamMaxLen));
276
+ }
277
+ if (broadcastMessages.length > 0) {
278
+ promises.push(
279
+ Promise.all(
280
+ broadcastMessages.map(
281
+ (bm) => this._driver.publish(bm.channel, bm.message)
282
+ )
283
+ ).then(() => {
284
+ })
285
+ // Map `Promise<void[]>` to `Promise<void>`
286
+ );
287
+ }
288
+ await Promise.all(promises);
289
+ }
290
+ async subscribe(channel, handler) {
291
+ if (!this._handlers.has(channel)) {
292
+ this._handlers.set(channel, /* @__PURE__ */ new Set());
293
+ const prefixedChannel = this._prefix + channel;
294
+ if (channel.startsWith("ocpp:node:")) {
295
+ if (!this._streams.has(prefixedChannel)) {
296
+ this._streams.add(prefixedChannel);
297
+ this._streamOffsets.set(prefixedChannel, "0");
298
+ this._ensurePolling();
299
+ }
300
+ } else {
301
+ await this._driver.subscribe(prefixedChannel, (message) => {
302
+ this._handleMessage(channel, message);
303
+ });
304
+ }
305
+ }
306
+ this._handlers.get(channel)?.add(handler);
307
+ }
308
+ async unsubscribe(channel) {
309
+ const prefixedChannel = this._prefix + channel;
310
+ if (this._streams.has(prefixedChannel)) {
311
+ this._streams.delete(prefixedChannel);
312
+ this._streamOffsets.delete(prefixedChannel);
313
+ } else {
314
+ await this._driver.unsubscribe(prefixedChannel);
315
+ }
316
+ this._handlers.delete(channel);
317
+ }
318
+ async disconnect() {
319
+ this._closed = true;
320
+ this._handlers.clear();
321
+ this._streams.clear();
322
+ await this._driver.disconnect();
323
+ }
324
+ _handleMessage(channel, message) {
325
+ const handlers = this._handlers.get(channel);
326
+ if (!handlers) return;
327
+ let data;
328
+ try {
329
+ data = JSON.parse(message);
330
+ } catch {
331
+ data = message;
332
+ }
333
+ for (const handler of handlers) {
334
+ try {
335
+ handler(data);
336
+ } catch {
337
+ }
338
+ }
339
+ }
340
+ // ─── Stream Polling ───────────────────────────────────────────────
341
+ _ensurePolling() {
342
+ if (this._polling || this._closed) return;
343
+ this._polling = true;
344
+ this._pollLoop().catch(() => {
345
+ this._polling = false;
346
+ });
347
+ }
348
+ async _pollLoop() {
349
+ while (!this._closed) {
350
+ if (this._streams.size === 0) {
351
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
352
+ continue;
353
+ }
354
+ const streamsArg = Array.from(this._streams).map((key) => ({
355
+ key,
356
+ id: this._streamOffsets.get(key) || "$"
357
+ }));
358
+ try {
359
+ const entries = await this._driver.xread(streamsArg, void 0, 1e3);
360
+ if (entries) {
361
+ for (const entry of entries) {
362
+ const channel = entry.stream.replace(this._prefix, "");
363
+ for (const msg of entry.messages) {
364
+ this._streamOffsets.set(entry.stream, msg.id);
365
+ const messageContent = msg.data.message;
366
+ if (messageContent) {
367
+ this._handleMessage(channel, messageContent);
368
+ }
369
+ }
370
+ }
371
+ }
372
+ } catch (_err) {
373
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
374
+ }
375
+ }
376
+ this._polling = false;
377
+ }
378
+ // ─── Presence Registry ─────────────────────────────────────────────
379
+ async setPresence(identity, nodeId, ttl) {
380
+ const key = `${this._prefix}presence:${identity}`;
381
+ await this._driver.set(key, nodeId, ttl);
382
+ }
383
+ async getPresence(identity) {
384
+ const key = `${this._prefix}presence:${identity}`;
385
+ return await this._driver.get(key);
386
+ }
387
+ async getPresenceBatch(identities) {
388
+ if (identities.length === 0) return [];
389
+ const keys = identities.map((id) => `${this._prefix}presence:${id}`);
390
+ if (this._driver.mget) {
391
+ return await this._driver.mget(keys);
392
+ }
393
+ return await Promise.all(keys.map((k) => this._driver.get(k)));
394
+ }
395
+ async removePresence(identity) {
396
+ const key = `${this._prefix}presence:${identity}`;
397
+ await this._driver.del(key);
398
+ }
399
+ // ─── Observability Pipeline ────────────────────────────────────────
400
+ async metrics() {
401
+ let pendingMessages = 0;
402
+ const streamDetails = {};
403
+ for (const streamKey of this._streams) {
404
+ try {
405
+ const length = await this._driver.xlen(streamKey);
406
+ pendingMessages += length;
407
+ streamDetails[streamKey] = length;
408
+ } catch {
409
+ streamDetails[streamKey] = -1;
410
+ }
411
+ }
412
+ return {
413
+ pendingMessages,
414
+ activeStreams: this._streams.size,
415
+ streamDetails
416
+ };
417
+ }
418
+ };
419
+ // Annotate the CommonJS export names for ESM import in node:
420
+ 0 && (module.exports = {
421
+ RedisAdapter
422
+ });
423
+ //# sourceMappingURL=redis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/adapters/redis/index.ts","../../src/adapters/redis/helpers.ts"],"sourcesContent":["import type { EventAdapterInterface } from \"../../types.js\";\nimport {\n createDriver,\n type RedisLikeClient,\n type RedisPubSubDriver,\n} from \"./helpers.js\";\n\nexport interface RedisAdapterOptions {\n /** Redis client for publishing */\n pubClient: RedisLikeClient;\n /** Redis client for subscribing (must be a separate connection) */\n subClient: RedisLikeClient;\n /** Redis client for blocking stream operations (recommended for reliability) */\n blockingClient?: RedisLikeClient;\n /** Optional key prefix for channels (default: 'ocpp-ws-io:') */\n prefix?: string;\n /** StreamMaxLen for trimming (default: 1000) */\n streamMaxLen?: number;\n}\n\n/**\n * Redis adapter for cross-process event distribution.\n *\n * Supports `ioredis` and `node-redis` (v4+).\n * Uses Redis Streams for reliable unicast (node-to-node) and Pub/Sub for broadcast.\n */\nexport class RedisAdapter implements EventAdapterInterface {\n private _driver: RedisPubSubDriver;\n private _prefix: string;\n private _streamMaxLen: number;\n private _handlers = new Map<string, Set<(data: unknown) => void>>();\n private _streamOffsets = new Map<string, string>(); // streamKey -> lastId\n private _streams = new Set<string>(); // Active streams to poll\n private _polling = false;\n private _closed = false;\n\n constructor(options: RedisAdapterOptions) {\n this._prefix = options.prefix ?? \"ocpp-ws-io:\";\n this._streamMaxLen = options.streamMaxLen ?? 1000;\n this._driver = createDriver(\n options.pubClient,\n options.subClient,\n options.blockingClient,\n );\n }\n\n async publish(channel: string, data: unknown): Promise<void> {\n const prefixedChannel = this._prefix + channel;\n const message = JSON.stringify(data);\n\n // Unicast (Node-to-Node) -> Use Streams\n if (channel.startsWith(\"ocpp:node:\")) {\n await this._driver.xadd(prefixedChannel, { message }, this._streamMaxLen);\n } else {\n // Broadcast -> Use Pub/Sub\n await this._driver.publish(prefixedChannel, message);\n }\n }\n\n async publishBatch(\n messages: { channel: string; data: unknown }[],\n ): Promise<void> {\n const streamMessages: { stream: string; args: Record<string, string> }[] =\n [];\n const broadcastMessages: { channel: string; message: string }[] = [];\n\n for (const msg of messages) {\n const prefixedChannel = this._prefix + msg.channel;\n const message = JSON.stringify(msg.data);\n\n if (msg.channel.startsWith(\"ocpp:node:\")) {\n streamMessages.push({ stream: prefixedChannel, args: { message } });\n } else {\n broadcastMessages.push({ channel: prefixedChannel, message });\n }\n }\n\n const promises: Promise<void>[] = [];\n\n if (streamMessages.length > 0) {\n promises.push(this._driver.xaddBatch(streamMessages, this._streamMaxLen));\n }\n\n if (broadcastMessages.length > 0) {\n promises.push(\n Promise.all(\n broadcastMessages.map((bm) =>\n this._driver.publish(bm.channel, bm.message),\n ),\n ).then(() => {}), // Map `Promise<void[]>` to `Promise<void>`\n );\n }\n\n await Promise.all(promises);\n }\n\n async subscribe(\n channel: string,\n handler: (data: unknown) => void,\n ): Promise<void> {\n if (!this._handlers.has(channel)) {\n this._handlers.set(channel, new Set());\n const prefixedChannel = this._prefix + channel;\n\n if (channel.startsWith(\"ocpp:node:\")) {\n // Stream subscription\n // Start from '0' (beginning) to pick up missed messages during downtime (persistence).\n // Since we trim the stream (MAXLEN), this will only replay recent pending messages.\n if (!this._streams.has(prefixedChannel)) {\n this._streams.add(prefixedChannel);\n this._streamOffsets.set(prefixedChannel, \"0\");\n this._ensurePolling();\n }\n } else {\n // Pub/Sub subscription\n await this._driver.subscribe(prefixedChannel, (message) => {\n this._handleMessage(channel, message);\n });\n }\n }\n this._handlers.get(channel)?.add(handler);\n }\n\n async unsubscribe(channel: string): Promise<void> {\n const prefixedChannel = this._prefix + channel;\n\n if (this._streams.has(prefixedChannel)) {\n this._streams.delete(prefixedChannel);\n this._streamOffsets.delete(prefixedChannel); // Cleanup offset\n } else {\n await this._driver.unsubscribe(prefixedChannel);\n }\n\n this._handlers.delete(channel);\n }\n\n async disconnect(): Promise<void> {\n this._closed = true;\n this._handlers.clear();\n this._streams.clear();\n await this._driver.disconnect();\n }\n\n private _handleMessage(channel: string, message: string): void {\n const handlers = this._handlers.get(channel);\n if (!handlers) return;\n\n let data: unknown;\n try {\n data = JSON.parse(message);\n } catch {\n data = message;\n }\n\n for (const handler of handlers) {\n try {\n handler(data);\n } catch {\n // Swallow handler errors\n }\n }\n }\n\n // ─── Stream Polling ───────────────────────────────────────────────\n\n private _ensurePolling() {\n if (this._polling || this._closed) return;\n this._polling = true;\n this._pollLoop().catch(() => {\n this._polling = false;\n });\n }\n\n private async _pollLoop() {\n while (!this._closed) {\n if (this._streams.size === 0) {\n await new Promise((resolve) => setTimeout(resolve, 1000));\n continue;\n }\n\n const streamsArg = Array.from(this._streams).map((key) => ({\n key,\n id: this._streamOffsets.get(key) || \"$\",\n }));\n\n try {\n // Block for 1s. This allows picking up new subscriptions reasonably fast.\n const entries = await this._driver.xread(streamsArg, undefined, 1000);\n\n if (entries) {\n for (const entry of entries) {\n const channel = entry.stream.replace(this._prefix, \"\"); // remove prefix to find handler key\n\n for (const msg of entry.messages) {\n // Update offset\n this._streamOffsets.set(entry.stream, msg.id);\n\n const messageContent = msg.data.message;\n if (messageContent) {\n this._handleMessage(channel, messageContent);\n }\n }\n }\n }\n } catch (_err) {\n // Log error? For now swallow to keep loop alive\n // Avoid tight loop on error\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n }\n this._polling = false;\n }\n\n // ─── Presence Registry ─────────────────────────────────────────────\n\n async setPresence(\n identity: string,\n nodeId: string,\n ttl: number,\n ): Promise<void> {\n const key = `${this._prefix}presence:${identity}`;\n await this._driver.set(key, nodeId, ttl);\n }\n\n async getPresence(identity: string): Promise<string | null> {\n const key = `${this._prefix}presence:${identity}`;\n return await this._driver.get(key);\n }\n\n async getPresenceBatch(identities: string[]): Promise<(string | null)[]> {\n if (identities.length === 0) return [];\n const keys = identities.map((id) => `${this._prefix}presence:${id}`);\n if (this._driver.mget) {\n return await this._driver.mget(keys);\n }\n // Fallback if mget not available\n return await Promise.all(keys.map((k) => this._driver.get(k)));\n }\n\n async removePresence(identity: string): Promise<void> {\n const key = `${this._prefix}presence:${identity}`;\n await this._driver.del(key);\n }\n\n // ─── Observability Pipeline ────────────────────────────────────────\n\n async metrics(): Promise<Record<string, unknown>> {\n let pendingMessages = 0;\n const streamDetails: Record<string, number> = {};\n\n // Calculate \"consumer lag\" by checking the length of all active streams\n // Since we use MAXLEN for trimming, XLEN directly equals pending unread messages\n for (const streamKey of this._streams) {\n try {\n const length = await this._driver.xlen(streamKey);\n pendingMessages += length;\n streamDetails[streamKey] = length;\n } catch {\n // Ignore failures for individual stream stats\n streamDetails[streamKey] = -1;\n }\n }\n\n return {\n pendingMessages,\n activeStreams: this._streams.size,\n streamDetails,\n };\n }\n}\n","export interface RedisLikeClient {\n publish(\n channel: string,\n message: string,\n ): Promise<number | unknown | undefined>;\n subscribe(channel: string, ...args: unknown[]): Promise<unknown | undefined>;\n unsubscribe(\n channel: string,\n ...args: unknown[]\n ): Promise<unknown | undefined>;\n on?(\n event: \"message\",\n callback: (channel: string, message: string) => void,\n ): unknown;\n disconnect?(): Promise<void> | void;\n quit?(): Promise<unknown> | undefined;\n // Node Redis v4 specific\n isOpen?: boolean;\n}\n\n// ─── Stream Types ───────────────────────────────────────────────\n\nexport interface StreamMessage {\n id: string;\n data: Record<string, string>;\n}\n\nexport interface StreamEntry {\n stream: string;\n messages: StreamMessage[];\n}\n\n// ─── Extended Redis Driver ──────────────────────────────────────\n\nexport interface RedisPubSubDriver {\n publish(channel: string, message: string): Promise<void>;\n subscribe(channel: string, handler: (message: string) => void): Promise<void>;\n unsubscribe(channel: string): Promise<void>;\n disconnect(): Promise<void>;\n\n // Key-Value Store for Presence\n set(key: string, value: string, ttlSeconds?: number): Promise<void>;\n get(key: string): Promise<string | null>;\n mget(keys: string[]): Promise<(string | null)[]>;\n del(key: string): Promise<void>;\n\n // Streams\n xadd(\n stream: string,\n args: Record<string, string>,\n maxLen?: number,\n ): Promise<string>;\n xaddBatch(\n messages: { stream: string; args: Record<string, string> }[],\n maxLen?: number,\n ): Promise<void>;\n xread(\n streams: { key: string; id: string }[],\n count?: number,\n block?: number,\n ): Promise<StreamEntry[] | null>;\n xlen(stream: string): Promise<number>;\n}\n\nexport class IoRedisDriver implements RedisPubSubDriver {\n private _handlers = new Map<string, (msg: string) => void>();\n\n constructor(\n private pub: any,\n private sub: any,\n private blocking?: any,\n ) {\n if (this.sub.on) {\n this.sub.on(\"message\", (channel: string, message: string) => {\n const handler = this._handlers.get(channel);\n if (handler) handler(message);\n });\n }\n }\n\n async publish(channel: string, message: string): Promise<void> {\n await this.pub.publish(channel, message);\n }\n\n async subscribe(\n channel: string,\n handler: (message: string) => void,\n ): Promise<void> {\n this._handlers.set(channel, handler);\n await this.sub.subscribe(channel);\n }\n\n async unsubscribe(channel: string): Promise<void> {\n await this.sub.unsubscribe(channel);\n this._handlers.delete(channel);\n }\n\n async set(key: string, value: string, ttlSeconds?: number): Promise<void> {\n if (ttlSeconds) {\n await this.pub.set(key, value, \"EX\", ttlSeconds);\n } else {\n await this.pub.set(key, value);\n }\n }\n\n async get(key: string): Promise<string | null> {\n return (await this.pub.get(key)) || null;\n }\n\n async mget(keys: string[]): Promise<(string | null)[]> {\n if (keys.length === 0) return [];\n return await this.pub.mget(...keys);\n }\n\n async del(key: string): Promise<void> {\n await this.pub.del(key);\n }\n\n async xadd(\n stream: string,\n args: Record<string, string>,\n maxLen?: number,\n ): Promise<string> {\n const flatArgs: string[] = [];\n if (maxLen) {\n flatArgs.push(\"MAXLEN\", \"~\", maxLen.toString());\n }\n flatArgs.push(\"*\"); // ID = auto\n for (const [k, v] of Object.entries(args)) {\n flatArgs.push(k, v);\n }\n return (await this.pub.xadd(stream, ...flatArgs)) as string;\n }\n\n async xaddBatch(\n messages: { stream: string; args: Record<string, string> }[],\n maxLen?: number,\n ): Promise<void> {\n if (messages.length === 0) return;\n const pipeline = this.pub.pipeline();\n for (const msg of messages) {\n const flatArgs: string[] = [];\n if (maxLen) {\n flatArgs.push(\"MAXLEN\", \"~\", maxLen.toString());\n }\n flatArgs.push(\"*\");\n for (const [k, v] of Object.entries(msg.args)) {\n flatArgs.push(k, v);\n }\n pipeline.xadd(msg.stream, ...flatArgs);\n }\n await pipeline.exec();\n }\n\n async xread(\n streams: { key: string; id: string }[],\n count?: number,\n block?: number,\n ): Promise<StreamEntry[] | null> {\n const args: (string | number)[] = [];\n if (count) {\n args.push(\"COUNT\", count);\n }\n if (typeof block === \"number\") {\n args.push(\"BLOCK\", block);\n }\n args.push(\"STREAMS\");\n streams.forEach((s) => {\n args.push(s.key);\n });\n streams.forEach((s) => {\n args.push(s.id);\n });\n\n // Use blocking client if available and blocking is requested\n const client = block && this.blocking ? this.blocking : this.pub;\n\n // ioredis returns [[key, [[id, [k,v,k,v]]]]]\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = (await client.xread(...args)) as any;\n\n if (!result) return null;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return result.map(([stream, messages]: any) => ({\n stream,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n messages: messages.map(([id, fields]: any) => {\n const data: Record<string, string> = {};\n for (let i = 0; i < fields.length; i += 2) {\n data[fields[i]] = fields[i + 1];\n }\n return { id, data };\n }),\n }));\n }\n\n async xlen(stream: string): Promise<number> {\n return (await this.pub.xlen(stream)) as number;\n }\n\n async disconnect(): Promise<void> {\n this._handlers.clear();\n const close = async (c: any) => {\n if (c.quit) await c.quit();\n else if (c.disconnect) await c.disconnect();\n };\n await Promise.all([close(this.pub), close(this.sub)]);\n }\n}\n\nexport class NodeRedisDriver implements RedisPubSubDriver {\n constructor(\n private pub: any,\n private sub: any,\n private blocking?: any,\n ) {}\n\n async publish(channel: string, message: string): Promise<void> {\n await this.pub.publish(channel, message);\n }\n\n async subscribe(\n channel: string,\n handler: (message: string) => void,\n ): Promise<void> {\n await this.sub.subscribe(channel, handler);\n }\n\n async unsubscribe(channel: string): Promise<void> {\n await this.sub.unsubscribe(channel);\n }\n\n async set(key: string, value: string, ttlSeconds?: number): Promise<void> {\n if (ttlSeconds) {\n await this.pub.set(key, value, { EX: ttlSeconds });\n } else {\n await this.pub.set(key, value);\n }\n }\n\n async get(key: string): Promise<string | null> {\n return (await this.pub.get(key)) || null;\n }\n\n async mget(keys: string[]): Promise<(string | null)[]> {\n if (keys.length === 0) return [];\n return await this.pub.mGet(keys);\n }\n\n async del(key: string): Promise<void> {\n await this.pub.del(key);\n }\n\n async xadd(\n stream: string,\n args: Record<string, string>,\n maxLen?: number,\n ): Promise<string> {\n const options: any = {};\n if (maxLen) {\n options.MKSTREAM = true; // Make sure stream exists\n // node-redis specific options for MAXLEN\n // But basic xadd signature is (key, id, message, options?)\n }\n // Node Redis v4 xAdd: (key, id, message)\n // For trimming, it might be in options.\n // Let's assume standard usage for now.\n // Actually Node Redis v4: .xAdd(key, id, message, options)\n\n // Construct message object\n return await this.pub.xAdd(stream, \"*\", args, {\n TRIM: maxLen\n ? {\n strategy: \"MAXLEN\",\n strategyModifier: \"~\",\n threshold: maxLen,\n }\n : undefined,\n });\n }\n\n async xaddBatch(\n messages: { stream: string; args: Record<string, string> }[],\n maxLen?: number,\n ): Promise<void> {\n if (messages.length === 0) return;\n const multi = this.pub.multi();\n for (const msg of messages) {\n multi.xAdd(msg.stream, \"*\", msg.args, {\n TRIM: maxLen\n ? {\n strategy: \"MAXLEN\",\n strategyModifier: \"~\",\n threshold: maxLen,\n }\n : undefined,\n });\n }\n await multi.exec();\n }\n\n async xread(\n streams: { key: string; id: string }[],\n count?: number,\n block?: number,\n ): Promise<StreamEntry[] | null> {\n // Node Redis v4 .xRead(streams, options)\n const options: any = {};\n if (count) options.COUNT = count;\n if (typeof block === \"number\") options.BLOCK = block;\n\n const streamsParam = streams.map((s) => ({\n key: s.key,\n id: s.id,\n }));\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const client = block && this.blocking ? this.blocking : this.pub;\n const result = (await client.xRead(streamsParam, options)) as any;\n\n if (!result || result.length === 0) return null;\n\n // Node Redis v4 returns: { name: string, messages: { id: string, message: Record<string,string> }[] }[]\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return result.map((entry: any) => ({\n stream: entry.name,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n messages: entry.messages.map((msg: any) => ({\n id: msg.id,\n data: msg.message,\n })),\n }));\n }\n\n async xlen(stream: string): Promise<number> {\n return (await this.pub.xLen(stream)) as number;\n }\n\n async disconnect(): Promise<void> {\n await Promise.all([this.pub.disconnect(), this.sub.disconnect()]);\n }\n}\n\nexport function createDriver(\n pub: any,\n sub: any,\n blocking?: any,\n): RedisPubSubDriver {\n // Simple heuristic: Node Redis v4 clients usually have 'isOpen' boolean\n if (sub.isOpen !== undefined && typeof sub.subscribe === \"function\") {\n return new NodeRedisDriver(pub, sub, blocking);\n }\n // Default to IoRedis / Generic\n return new IoRedisDriver(pub, sub, blocking);\n}\n"],"mappings":"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","names":[]}