@lyxa.ai/core 1.3.76 → 1.3.79

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/index.js +2 -2
  2. package/dist/index.js.map +1 -1
  3. package/dist/libraries/socket/PushNotificationEvent.d.ts +1 -1
  4. package/dist/libraries/socket/PushNotificationEvent.js.map +1 -1
  5. package/dist/libraries/socket/adapters/socket-subscription.js +3 -2
  6. package/dist/libraries/socket/adapters/socket-subscription.js.map +1 -1
  7. package/dist/libraries/socket/connections/batch.d.ts +12 -0
  8. package/dist/libraries/socket/connections/batch.js +58 -0
  9. package/dist/libraries/socket/connections/batch.js.map +1 -0
  10. package/dist/libraries/socket/connections/cache.d.ts +9 -0
  11. package/dist/libraries/socket/connections/cache.js +36 -0
  12. package/dist/libraries/socket/connections/cache.js.map +1 -0
  13. package/dist/libraries/socket/connections/constants.d.ts +2 -0
  14. package/dist/libraries/socket/connections/constants.js +6 -0
  15. package/dist/libraries/socket/connections/constants.js.map +1 -0
  16. package/dist/libraries/socket/connections/event-subscribers.d.ts +5 -0
  17. package/dist/libraries/socket/connections/event-subscribers.js +60 -0
  18. package/dist/libraries/socket/connections/event-subscribers.js.map +1 -0
  19. package/dist/libraries/socket/connections/index.d.ts +7 -0
  20. package/dist/libraries/socket/connections/index.js +24 -0
  21. package/dist/libraries/socket/connections/index.js.map +1 -0
  22. package/dist/libraries/socket/connections/instance-disconnect.d.ts +2 -0
  23. package/dist/libraries/socket/connections/instance-disconnect.js +43 -0
  24. package/dist/libraries/socket/connections/instance-disconnect.js.map +1 -0
  25. package/dist/libraries/socket/connections/keys.d.ts +10 -0
  26. package/dist/libraries/socket/connections/keys.js +23 -0
  27. package/dist/libraries/socket/connections/keys.js.map +1 -0
  28. package/dist/libraries/socket/connections/presence.d.ts +4 -0
  29. package/dist/libraries/socket/connections/presence.js +23 -0
  30. package/dist/libraries/socket/connections/presence.js.map +1 -0
  31. package/dist/libraries/socket/connections/redis-helpers.d.ts +2 -0
  32. package/dist/libraries/socket/connections/redis-helpers.js +14 -0
  33. package/dist/libraries/socket/connections/redis-helpers.js.map +1 -0
  34. package/dist/libraries/socket/connections/subscription.d.ts +13 -0
  35. package/dist/libraries/socket/connections/subscription.js +73 -0
  36. package/dist/libraries/socket/connections/subscription.js.map +1 -0
  37. package/dist/libraries/socket/core/index.d.ts +0 -1
  38. package/dist/libraries/socket/core/index.js +0 -1
  39. package/dist/libraries/socket/core/index.js.map +1 -1
  40. package/dist/libraries/socket/core/local-subscription-registry.d.ts +1 -1
  41. package/dist/libraries/socket/core/local-subscription-registry.js.map +1 -1
  42. package/dist/libraries/socket/core/socket-event-publisher.d.ts +1 -1
  43. package/dist/libraries/socket/core/socket-event-publisher.js +9 -15
  44. package/dist/libraries/socket/core/socket-event-publisher.js.map +1 -1
  45. package/dist/types/README.md +1 -1
  46. package/dist/types/package.json +1 -1
  47. package/dist/types/utilities/enum.d.ts +0 -1
  48. package/dist/types/utilities/enum.js +0 -1
  49. package/dist/types/utilities/enum.js.map +1 -1
  50. package/dist/utilities/enum.d.ts +0 -1
  51. package/dist/utilities/enum.js +0 -1
  52. package/dist/utilities/enum.js.map +1 -1
  53. package/package.json +1 -1
  54. package/dist/libraries/socket/core/socket-redis-connections.d.ts +0 -36
  55. package/dist/libraries/socket/core/socket-redis-connections.js +0 -412
  56. package/dist/libraries/socket/core/socket-redis-connections.js.map +0 -1
@@ -1,412 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getEntityEventSocketsKey = exports.entityKey = void 0;
4
- exports.connectEntityToSocketEvent = connectEntityToSocketEvent;
5
- exports.getConnectedEntityByType = getConnectedEntityByType;
6
- exports.disconnectEntityFromSocketEvent = disconnectEntityFromSocketEvent;
7
- exports.getEntitySubscriptionInfo = getEntitySubscriptionInfo;
8
- exports.getEntitySubscriptionInfoBatch = getEntitySubscriptionInfoBatch;
9
- exports.isEntityConnected = isEntityConnected;
10
- exports.disconnectAllEntitiesFromInstance = disconnectAllEntitiesFromInstance;
11
- exports.getEventSubscribers = getEventSubscribers;
12
- exports.getEventSubscribersBatch = getEventSubscribersBatch;
13
- exports.getEventSubscribersByType = getEventSubscribersByType;
14
- exports.getEventSubscriberCount = getEventSubscriberCount;
15
- const __1 = require("../../..");
16
- const instance_utils_1 = require("../../../utilities/instance.utils");
17
- const keyCache = new Map();
18
- const entityKey = (entity) => {
19
- const cacheKey = `${entity.type}:${entity.id}`;
20
- let key = keyCache.get(cacheKey);
21
- if (!key) {
22
- key = `${entity.type ?? 'default'}:${entity.id}`;
23
- keyCache.set(cacheKey, key);
24
- }
25
- return key;
26
- };
27
- exports.entityKey = entityKey;
28
- const kEntityEventSockets = (entity, eventKey) => `socket:entity:${(0, exports.entityKey)(entity)}:${eventKey}`;
29
- const kEventSubscribers = (eventKey) => `socket:event:${eventKey}`;
30
- exports.getEntityEventSocketsKey = kEntityEventSockets;
31
- class LRUCache {
32
- cache = new Map();
33
- maxSize;
34
- constructor(maxSize = 10000) {
35
- this.maxSize = maxSize;
36
- }
37
- get(key) {
38
- const value = this.cache.get(key);
39
- if (value !== undefined) {
40
- this.cache.delete(key);
41
- this.cache.set(key, value);
42
- }
43
- return value;
44
- }
45
- set(key, value) {
46
- this.cache.delete(key);
47
- if (this.cache.size >= this.maxSize) {
48
- const firstKey = this.cache.keys().next().value;
49
- if (firstKey !== undefined) {
50
- this.cache.delete(firstKey);
51
- }
52
- }
53
- this.cache.set(key, value);
54
- }
55
- delete(key) {
56
- this.cache.delete(key);
57
- }
58
- clear() {
59
- this.cache.clear();
60
- }
61
- }
62
- const subscriptionCache = new LRUCache(10000);
63
- const eventSubscribersCache = new LRUCache(5000);
64
- const CACHE_TTL = 5000;
65
- async function connectEntityToSocketEvent(entity, socketRedisEventInformation) {
66
- const redis = (0, __1.getLibraries)().getRedisService();
67
- const entityKeyStr = (0, exports.entityKey)(entity);
68
- const socketData = JSON.stringify({
69
- instanceId: socketRedisEventInformation.instanceId,
70
- socketId: socketRedisEventInformation.socketId,
71
- });
72
- const subscriberData = JSON.stringify({
73
- entity: entityKeyStr,
74
- socketId: socketRedisEventInformation.socketId,
75
- instanceId: socketRedisEventInformation.instanceId,
76
- });
77
- await Promise.all([
78
- redis.addToSet(kEntityEventSockets(entity, socketRedisEventInformation.eventKey), socketData),
79
- redis.addToSet(kEventSubscribers(socketRedisEventInformation.eventKey), subscriberData),
80
- ]);
81
- const cacheKey = `${entityKeyStr}:${socketRedisEventInformation.eventKey}`;
82
- subscriptionCache.delete(cacheKey);
83
- eventSubscribersCache.delete(socketRedisEventInformation.eventKey);
84
- }
85
- async function scanKeys(redis, pattern) {
86
- const keys = [];
87
- let cursor = '0';
88
- do {
89
- const [newCursor, foundKeys] = await redis.scan(cursor, 'MATCH', pattern, 'COUNT', 100);
90
- cursor = newCursor;
91
- if (foundKeys.length > 0) {
92
- keys.push(...foundKeys);
93
- }
94
- } while (cursor !== '0');
95
- return keys;
96
- }
97
- async function getConnectedEntityByType(type) {
98
- const redis = (0, __1.getLibraries)().getRedisService();
99
- const pattern = `socket:entity:${type}:*`;
100
- const keys = await scanKeys(redis.redisClient, pattern);
101
- const idSet = new Set();
102
- for (const key of keys) {
103
- const parts = key.split(':');
104
- if (parts.length >= 4) {
105
- idSet.add(parts[3]);
106
- }
107
- }
108
- return Array.from(idSet);
109
- }
110
- async function disconnectEntityFromSocketEvent(entity, socketRedisEventInformation) {
111
- const redis = (0, __1.getLibraries)().getRedisService();
112
- const entityKeyStr = (0, exports.entityKey)(entity);
113
- const { instanceId, socketId, eventKey } = socketRedisEventInformation;
114
- const entityEventKey = kEntityEventSockets(entity, eventKey);
115
- const eventSubsKey = kEventSubscribers(eventKey);
116
- try {
117
- const [entitySockets, eventSubs] = await Promise.all([
118
- redis.getSetMembers(entityEventKey),
119
- redis.getSetMembers(eventSubsKey),
120
- ]);
121
- const cleanupOps = [];
122
- const socketsToRemove = entitySockets.filter(s => {
123
- try {
124
- const parsed = JSON.parse(s);
125
- return parsed.socketId === socketId && parsed.instanceId === instanceId;
126
- }
127
- catch {
128
- return false;
129
- }
130
- });
131
- if (socketsToRemove.length > 0) {
132
- cleanupOps.push(...socketsToRemove.map(s => redis.removeFromSet(entityEventKey, s)));
133
- }
134
- const subscribersToRemove = eventSubs.filter(sub => {
135
- try {
136
- const parsed = JSON.parse(sub);
137
- return (parsed.socketId === socketId && parsed.instanceId === instanceId && parsed.entity === entityKeyStr);
138
- }
139
- catch {
140
- return false;
141
- }
142
- });
143
- if (subscribersToRemove.length > 0) {
144
- cleanupOps.push(...subscribersToRemove.map(s => redis.removeFromSet(eventSubsKey, s)));
145
- }
146
- if (cleanupOps.length > 0) {
147
- await Promise.all(cleanupOps);
148
- }
149
- const remainingSockets = entitySockets.length - socketsToRemove.length;
150
- if (remainingSockets === 0) {
151
- await redis.deleteCachedObject(entityEventKey);
152
- }
153
- const cacheKey = `${entityKeyStr}:${eventKey}`;
154
- subscriptionCache.delete(cacheKey);
155
- eventSubscribersCache.delete(eventKey);
156
- console.log(`Disconnected socket ${socketId} from event ${eventKey} of entity ${entity.id}`);
157
- return {
158
- removed: socketsToRemove.length > 0 || subscribersToRemove.length > 0,
159
- socketsRemoved: socketsToRemove.length,
160
- subscribersRemoved: subscribersToRemove.length,
161
- };
162
- }
163
- catch (error) {
164
- console.error(`Failed to disconnect socket ${socketId} from entity ${entity.id}:`, error);
165
- throw error;
166
- }
167
- }
168
- async function getEntitySubscriptionInfo(entity, eventKey) {
169
- const entityKeyStr = (0, exports.entityKey)(entity);
170
- const cacheKey = `${entityKeyStr}:${eventKey}`;
171
- const cached = subscriptionCache.get(cacheKey);
172
- if (cached) {
173
- const age = Date.now() - cached.timestamp;
174
- if (age < CACHE_TTL) {
175
- return { isSubscribed: cached.isSubscribed, instances: cached.instances };
176
- }
177
- }
178
- const redis = (0, __1.getLibraries)().getRedisService();
179
- const sockets = await redis.getSetMembers(kEntityEventSockets(entity, eventKey));
180
- const isSubscribed = sockets.length > 0;
181
- const instanceSet = new Set();
182
- for (let i = 0; i < sockets.length; i++) {
183
- const socketInfo = JSON.parse(sockets[i]);
184
- instanceSet.add(socketInfo.instanceId);
185
- }
186
- const instances = Array.from(instanceSet);
187
- const result = { isSubscribed, instances };
188
- subscriptionCache.set(cacheKey, { ...result, timestamp: Date.now() });
189
- return result;
190
- }
191
- async function getEntitySubscriptionInfoBatch(entities) {
192
- if (entities.length === 0)
193
- return new Map();
194
- const redis = (0, __1.getLibraries)().getRedisService();
195
- const results = new Map();
196
- const now = Date.now();
197
- const uncached = [];
198
- for (let i = 0; i < entities.length; i++) {
199
- const { entity, eventKey } = entities[i];
200
- const cacheKey = `${(0, exports.entityKey)(entity)}:${eventKey}`;
201
- const cached = subscriptionCache.get(cacheKey);
202
- if (cached && now - cached.timestamp < CACHE_TTL) {
203
- results.set(cacheKey, { isSubscribed: cached.isSubscribed, instances: cached.instances });
204
- }
205
- else {
206
- uncached.push(entities[i]);
207
- }
208
- }
209
- if (uncached.length === 0)
210
- return results;
211
- await Promise.all(uncached.map(async ({ entity, eventKey }) => {
212
- const sockets = await redis.getSetMembers(kEntityEventSockets(entity, eventKey));
213
- const isSubscribed = sockets.length > 0;
214
- const instanceSet = new Set();
215
- for (let i = 0; i < sockets.length; i++) {
216
- const socketInfo = JSON.parse(sockets[i]);
217
- instanceSet.add(socketInfo.instanceId);
218
- }
219
- const cacheKey = `${(0, exports.entityKey)(entity)}:${eventKey}`;
220
- const result = { isSubscribed, instances: Array.from(instanceSet) };
221
- subscriptionCache.set(cacheKey, { ...result, timestamp: now });
222
- results.set(cacheKey, result);
223
- }));
224
- return results;
225
- }
226
- async function isEntityConnected(entity, eventKey) {
227
- const redis = (0, __1.getLibraries)().getRedisService();
228
- const sockets = await redis.getSetMembers(kEntityEventSockets(entity, eventKey));
229
- return sockets.length > 0;
230
- }
231
- async function disconnectAllEntitiesFromInstance(entityType) {
232
- const instanceId = (0, instance_utils_1.getInstanceId)();
233
- const redis = (0, __1.getLibraries)().getRedisService();
234
- const pattern = entityType ? `socket:entity:${entityType}:*` : 'socket:entity:*';
235
- const entityEventKeys = await scanKeys(redis.redisClient, pattern);
236
- if (!entityEventKeys.length)
237
- return;
238
- const affectedEvents = new Set();
239
- const results = await Promise.allSettled(entityEventKeys.map(async (keyPath) => {
240
- const sockets = await redis.getSetMembers(keyPath);
241
- if (!sockets.length)
242
- return;
243
- const keyParts = keyPath.split(':');
244
- const eventKey = keyParts.slice(4).join(':');
245
- const entityKeyStr = `${keyParts[2]}:${keyParts[3]}`;
246
- const socketsToRemove = sockets.filter(s => {
247
- try {
248
- const parsed = JSON.parse(s);
249
- return parsed.instanceId === instanceId;
250
- }
251
- catch {
252
- return false;
253
- }
254
- });
255
- if (!socketsToRemove.length)
256
- return;
257
- affectedEvents.add(eventKey);
258
- await Promise.all(socketsToRemove.map(s => redis.removeFromSet(keyPath, s)));
259
- const eventCleanup = [];
260
- for (const socketStr of socketsToRemove) {
261
- try {
262
- const parsed = JSON.parse(socketStr);
263
- const eventSubs = await redis.getSetMembers(kEventSubscribers(eventKey));
264
- const toRemove = eventSubs.find(s => {
265
- try {
266
- const sub = JSON.parse(s);
267
- return sub.entity === entityKeyStr && sub.socketId === parsed.socketId;
268
- }
269
- catch {
270
- return false;
271
- }
272
- });
273
- if (toRemove) {
274
- eventCleanup.push(redis.removeFromSet(kEventSubscribers(eventKey), toRemove));
275
- }
276
- }
277
- catch (err) {
278
- console.error(`[Socket] Failed to cleanup subscriber for ${eventKey}:`, err);
279
- }
280
- }
281
- const remainingSockets = sockets.length - socketsToRemove.length;
282
- if (remainingSockets === 0) {
283
- eventCleanup.push(redis.deleteCachedObject(keyPath));
284
- }
285
- if (eventCleanup.length > 0) {
286
- await Promise.all(eventCleanup);
287
- }
288
- subscriptionCache.delete(`${entityKeyStr}:${eventKey}`);
289
- }));
290
- const failures = results.filter(r => r.status === 'rejected');
291
- if (failures.length > 0) {
292
- console.error(`[Socket] ${failures.length} cleanup operations failed during instance disconnect`);
293
- }
294
- affectedEvents.forEach(eventKey => eventSubscribersCache.delete(eventKey));
295
- }
296
- async function getEventSubscribers(eventKey) {
297
- const cached = eventSubscribersCache.get(eventKey);
298
- const now = Date.now();
299
- if (cached && now - cached.timestamp < CACHE_TTL) {
300
- return cached.subscribers;
301
- }
302
- const redis = (0, __1.getLibraries)().getRedisService();
303
- const subscriberData = await redis.getSetMembers(kEventSubscribers(eventKey));
304
- if (subscriberData.length === 0) {
305
- const empty = [];
306
- eventSubscribersCache.set(eventKey, { subscribers: empty, timestamp: now });
307
- return empty;
308
- }
309
- const entityMap = new Map();
310
- for (let i = 0; i < subscriberData.length; i++) {
311
- const sub = JSON.parse(subscriberData[i]);
312
- const entityKeyStr = sub.entity;
313
- if (!entityMap.has(entityKeyStr)) {
314
- const colonIndex = entityKeyStr.indexOf(':');
315
- const type = entityKeyStr.substring(0, colonIndex);
316
- const id = entityKeyStr.substring(colonIndex + 1);
317
- entityMap.set(entityKeyStr, {
318
- id,
319
- type: type === 'default' ? undefined : type,
320
- });
321
- }
322
- }
323
- const subscribers = Array.from(entityMap.values());
324
- eventSubscribersCache.set(eventKey, { subscribers, timestamp: now });
325
- return subscribers;
326
- }
327
- async function getEventSubscribersBatch(eventKeys) {
328
- const redis = (0, __1.getLibraries)().getRedisService();
329
- const results = new Map();
330
- const now = Date.now();
331
- const uncached = [];
332
- for (const eventKey of eventKeys) {
333
- const cached = eventSubscribersCache.get(eventKey);
334
- if (cached && now - cached.timestamp < CACHE_TTL) {
335
- results.set(eventKey, cached.subscribers);
336
- }
337
- else {
338
- uncached.push(eventKey);
339
- }
340
- }
341
- if (uncached.length > 0) {
342
- await Promise.all(uncached.map(async (eventKey) => {
343
- const subscriberData = await redis.getSetMembers(kEventSubscribers(eventKey));
344
- const entityMap = new Map();
345
- for (let i = 0; i < subscriberData.length; i++) {
346
- const sub = JSON.parse(subscriberData[i]);
347
- const entityKeyStr = sub.entity;
348
- if (!entityMap.has(entityKeyStr)) {
349
- const colonIndex = entityKeyStr.indexOf(':');
350
- const type = entityKeyStr.substring(0, colonIndex);
351
- const id = entityKeyStr.substring(colonIndex + 1);
352
- entityMap.set(entityKeyStr, {
353
- id,
354
- type: type === 'default' ? undefined : type,
355
- });
356
- }
357
- }
358
- const subscribers = Array.from(entityMap.values());
359
- eventSubscribersCache.set(eventKey, { subscribers, timestamp: now });
360
- results.set(eventKey, subscribers);
361
- }));
362
- }
363
- return results;
364
- }
365
- async function getEventSubscribersByType(eventKey, entityType) {
366
- const cached = eventSubscribersCache.get(eventKey);
367
- const now = Date.now();
368
- if (cached && now - cached.timestamp < CACHE_TTL) {
369
- const filtered = [];
370
- for (let i = 0; i < cached.subscribers.length; i++) {
371
- if (cached.subscribers[i].type === entityType) {
372
- filtered.push(cached.subscribers[i]);
373
- }
374
- }
375
- return filtered;
376
- }
377
- const redis = (0, __1.getLibraries)().getRedisService();
378
- const subscriberData = await redis.getSetMembers(kEventSubscribers(eventKey));
379
- const typePrefix = `${entityType}:`;
380
- const filtered = [];
381
- const entityMap = new Map();
382
- for (let i = 0; i < subscriberData.length; i++) {
383
- const sub = JSON.parse(subscriberData[i]);
384
- const entityKeyStr = sub.entity;
385
- if (!entityMap.has(entityKeyStr)) {
386
- const colonIndex = entityKeyStr.indexOf(':');
387
- const type = entityKeyStr.substring(0, colonIndex);
388
- const id = entityKeyStr.substring(colonIndex + 1);
389
- const entity = {
390
- id,
391
- type: type === 'default' ? undefined : type,
392
- };
393
- entityMap.set(entityKeyStr, entity);
394
- if (entityKeyStr.startsWith(typePrefix)) {
395
- filtered.push(entity);
396
- }
397
- }
398
- }
399
- const all = Array.from(entityMap.values());
400
- eventSubscribersCache.set(eventKey, { subscribers: all, timestamp: now });
401
- return filtered;
402
- }
403
- async function getEventSubscriberCount(eventKey) {
404
- const cached = eventSubscribersCache.get(eventKey);
405
- if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
406
- return cached.subscribers.length;
407
- }
408
- const redis = (0, __1.getLibraries)().getRedisService();
409
- const members = await redis.getSetMembers(kEventSubscribers(eventKey));
410
- return members.length;
411
- }
412
- //# sourceMappingURL=socket-redis-connections.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"socket-redis-connections.js","sourceRoot":"/","sources":["libraries/socket/core/socket-redis-connections.ts"],"names":[],"mappings":"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","sourcesContent":["import { getLibraries } from '../../..';\nimport { getInstanceId } from '../../../utilities/instance.utils';\nimport { AuthEntityType } from '../../auth';\nimport type { Redis } from 'ioredis';\n\nexport type EntitySubscription = {\n\tid: string;\n\ttype?: AuthEntityType;\n};\n\nexport interface SocketRedisEventInformation {\n\teventKey: string;\n\tinstanceId: string;\n\tsocketId: string;\n}\n\n// Zero-overhead key generation with memoization\nconst keyCache = new Map<string, string>();\n\nexport const entityKey = (entity: EntitySubscription): string => {\n\tconst cacheKey = `${entity.type}:${entity.id}`;\n\tlet key = keyCache.get(cacheKey);\n\tif (!key) {\n\t\tkey = `${entity.type ?? 'default'}:${entity.id}`;\n\t\tkeyCache.set(cacheKey, key);\n\t}\n\treturn key;\n};\n\n// Ultra-simplified structure: Direct event lookup, no parsing!\nconst kEntityEventSockets = (entity: EntitySubscription, eventKey: string) =>\n\t`socket:entity:${entityKey(entity)}:${eventKey}`;\nconst kEventSubscribers = (eventKey: string) => `socket:event:${eventKey}`;\n\n// Export for use in publisher (avoid duplication)\nexport const getEntityEventSocketsKey = kEntityEventSockets;\n\n// LRU Cache for hot entities (reduces Redis load by 80-90%)\nclass LRUCache<K, V> {\n\tprivate cache = new Map<K, V>();\n\tprivate maxSize: number;\n\n\tconstructor(maxSize = 10000) {\n\t\tthis.maxSize = maxSize;\n\t}\n\n\tget(key: K): V | undefined {\n\t\tconst value = this.cache.get(key);\n\t\tif (value !== undefined) {\n\t\t\t// Move to end (most recently used)\n\t\t\tthis.cache.delete(key);\n\t\t\tthis.cache.set(key, value);\n\t\t}\n\t\treturn value;\n\t}\n\n\tset(key: K, value: V): void {\n\t\t// Remove if exists (will re-add at end)\n\t\tthis.cache.delete(key);\n\n\t\t// Evict oldest if at capacity\n\t\tif (this.cache.size >= this.maxSize) {\n\t\t\tconst firstKey = this.cache.keys().next().value;\n\t\t\tif (firstKey !== undefined) {\n\t\t\t\tthis.cache.delete(firstKey);\n\t\t\t}\n\t\t}\n\n\t\tthis.cache.set(key, value);\n\t}\n\n\tdelete(key: K): void {\n\t\tthis.cache.delete(key);\n\t}\n\n\tclear(): void {\n\t\tthis.cache.clear();\n\t}\n}\n\n// Cache subscription info for 5 seconds (hot path optimization)\nconst subscriptionCache = new LRUCache<\n\tstring,\n\t{ isSubscribed: boolean; instances: string[]; timestamp: number }\n>(10000);\n\n// Cache event subscribers (who's listening to what event)\nconst eventSubscribersCache = new LRUCache<string, { subscribers: EntitySubscription[]; timestamp: number }>(\n\t5000\n);\n\nconst CACHE_TTL = 5000; // 5 seconds\n\nexport async function connectEntityToSocketEvent(\n\tentity: EntitySubscription,\n\tsocketRedisEventInformation: SocketRedisEventInformation\n) {\n\tconst redis = getLibraries().getRedisService();\n\tconst entityKeyStr = entityKey(entity);\n\n\t// Simple: just store instanceId and socketId\n\tconst socketData = JSON.stringify({\n\t\tinstanceId: socketRedisEventInformation.instanceId,\n\t\tsocketId: socketRedisEventInformation.socketId,\n\t});\n\n\tconst subscriberData = JSON.stringify({\n\t\tentity: entityKeyStr,\n\t\tsocketId: socketRedisEventInformation.socketId,\n\t\tinstanceId: socketRedisEventInformation.instanceId,\n\t});\n\n\t// 2 Redis operations with event-specific key\n\tawait Promise.all([\n\t\tredis.addToSet(kEntityEventSockets(entity, socketRedisEventInformation.eventKey), socketData),\n\t\tredis.addToSet(kEventSubscribers(socketRedisEventInformation.eventKey), subscriberData),\n\t]);\n\n\t// Lazy cache invalidation\n\tconst cacheKey = `${entityKeyStr}:${socketRedisEventInformation.eventKey}`;\n\tsubscriptionCache.delete(cacheKey);\n\teventSubscribersCache.delete(socketRedisEventInformation.eventKey);\n}\n\n// Helper for non-blocking key scanning\nasync function scanKeys(redis: Redis, pattern: string): Promise<string[]> {\n\tconst keys: string[] = [];\n\tlet cursor = '0';\n\tdo {\n\t\t// Scan with count 100 to avoid blocking\n\t\tconst [newCursor, foundKeys] = await redis.scan(cursor, 'MATCH', pattern, 'COUNT', 100);\n\t\tcursor = newCursor;\n\t\tif (foundKeys.length > 0) {\n\t\t\tkeys.push(...foundKeys);\n\t\t}\n\t} while (cursor !== '0');\n\treturn keys;\n}\n\nexport async function getConnectedEntityByType(type: AuthEntityType): Promise<string[]> {\n\tconst redis = getLibraries().getRedisService();\n\t// Use pattern matching via ioredis directly\n\tconst pattern = `socket:entity:${type}:*`;\n\n\t// Use non-blocking scan instead of keys\n\tconst keys = await scanKeys(redis.redisClient, pattern);\n\n\t// Extract entity IDs from keys: socket:entity:type:id:eventKey\n\t// Get unique IDs (since one entity can have multiple event subscriptions)\n\tconst idSet = new Set<string>();\n\tfor (const key of keys) {\n\t\tconst parts = key.split(':');\n\t\tif (parts.length >= 4) {\n\t\t\tidSet.add(parts[3]); // Extract ID from socket:entity:type:id:eventKey\n\t\t}\n\t}\n\treturn Array.from(idSet);\n}\n\nexport async function disconnectEntityFromSocketEvent(\n\tentity: EntitySubscription,\n\tsocketRedisEventInformation: SocketRedisEventInformation\n) {\n\tconst redis = getLibraries().getRedisService();\n\tconst entityKeyStr = entityKey(entity);\n\tconst { instanceId, socketId, eventKey } = socketRedisEventInformation;\n\n\t// Build the exact keys we need (no pattern matching!)\n\tconst entityEventKey = kEntityEventSockets(entity, eventKey);\n\tconst eventSubsKey = kEventSubscribers(eventKey);\n\n\ttry {\n\t\t// Fetch both sets in parallel\n\t\tconst [entitySockets, eventSubs] = await Promise.all([\n\t\t\tredis.getSetMembers(entityEventKey),\n\t\t\tredis.getSetMembers(eventSubsKey),\n\t\t]);\n\n\t\tconst cleanupOps: Promise<any>[] = [];\n\n\t\t// Find and remove matching sockets from entity-event key\n\t\tconst socketsToRemove = entitySockets.filter(s => {\n\t\t\ttry {\n\t\t\t\tconst parsed = JSON.parse(s);\n\t\t\t\treturn parsed.socketId === socketId && parsed.instanceId === instanceId;\n\t\t\t} catch {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\n\t\tif (socketsToRemove.length > 0) {\n\t\t\t// Remove all matching sockets in parallel\n\t\t\tcleanupOps.push(...socketsToRemove.map(s => redis.removeFromSet(entityEventKey, s)));\n\t\t}\n\n\t\t// Find and remove matching subscribers from event subscribers key\n\t\tconst subscribersToRemove = eventSubs.filter(sub => {\n\t\t\ttry {\n\t\t\t\tconst parsed = JSON.parse(sub);\n\t\t\t\treturn (\n\t\t\t\t\tparsed.socketId === socketId && parsed.instanceId === instanceId && parsed.entity === entityKeyStr\n\t\t\t\t);\n\t\t\t} catch {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\n\t\tif (subscribersToRemove.length > 0) {\n\t\t\tcleanupOps.push(...subscribersToRemove.map(s => redis.removeFromSet(eventSubsKey, s)));\n\t\t}\n\n\t\t// Execute all removals in parallel\n\t\tif (cleanupOps.length > 0) {\n\t\t\tawait Promise.all(cleanupOps);\n\t\t}\n\n\t\t// Check if entity-event key is now empty and delete if so\n\t\tconst remainingSockets = entitySockets.length - socketsToRemove.length;\n\t\tif (remainingSockets === 0) {\n\t\t\tawait redis.deleteCachedObject(entityEventKey);\n\t\t}\n\n\t\t// Invalidate caches\n\t\tconst cacheKey = `${entityKeyStr}:${eventKey}`;\n\t\tsubscriptionCache.delete(cacheKey);\n\t\teventSubscribersCache.delete(eventKey);\n\n\t\tconsole.log(`Disconnected socket ${socketId} from event ${eventKey} of entity ${entity.id}`);\n\n\t\treturn {\n\t\t\tremoved: socketsToRemove.length > 0 || subscribersToRemove.length > 0,\n\t\t\tsocketsRemoved: socketsToRemove.length,\n\t\t\tsubscribersRemoved: subscribersToRemove.length,\n\t\t};\n\t} catch (error) {\n\t\tconsole.error(`Failed to disconnect socket ${socketId} from entity ${entity.id}:`, error);\n\t\tthrow error;\n\t}\n}\n// Ultra-simple: Direct key lookup, no parsing!\nexport async function getEntitySubscriptionInfo(\n\tentity: EntitySubscription,\n\teventKey: string\n): Promise<{ isSubscribed: boolean; instances: string[] }> {\n\tconst entityKeyStr = entityKey(entity);\n\tconst cacheKey = `${entityKeyStr}:${eventKey}`;\n\n\t// Inline cache check\n\tconst cached = subscriptionCache.get(cacheKey);\n\tif (cached) {\n\t\tconst age = Date.now() - cached.timestamp;\n\t\tif (age < CACHE_TTL) {\n\t\t\treturn { isSubscribed: cached.isSubscribed, instances: cached.instances };\n\t\t}\n\t}\n\n\tconst redis = getLibraries().getRedisService();\n\n\t// Direct lookup - event-specific key!\n\tconst sockets = await redis.getSetMembers(kEntityEventSockets(entity, eventKey));\n\n\tconst isSubscribed = sockets.length > 0;\n\tconst instanceSet = new Set<string>();\n\n\t// Extract instances (no filtering needed!)\n\tfor (let i = 0; i < sockets.length; i++) {\n\t\tconst socketInfo = JSON.parse(sockets[i]);\n\t\tinstanceSet.add(socketInfo.instanceId);\n\t}\n\n\tconst instances = Array.from(instanceSet);\n\tconst result = { isSubscribed, instances };\n\tsubscriptionCache.set(cacheKey, { ...result, timestamp: Date.now() });\n\n\treturn result;\n}\n\n// Batch lookup - parallel direct lookups, no parsing/filtering!\nexport async function getEntitySubscriptionInfoBatch(\n\tentities: Array<{ entity: EntitySubscription; eventKey: string }>\n): Promise<Map<string, { isSubscribed: boolean; instances: string[] }>> {\n\tif (entities.length === 0) return new Map();\n\n\tconst redis = getLibraries().getRedisService();\n\tconst results = new Map<string, { isSubscribed: boolean; instances: string[] }>();\n\tconst now = Date.now();\n\tconst uncached: typeof entities = [];\n\n\t// Check cache first\n\tfor (let i = 0; i < entities.length; i++) {\n\t\tconst { entity, eventKey } = entities[i];\n\t\tconst cacheKey = `${entityKey(entity)}:${eventKey}`;\n\t\tconst cached = subscriptionCache.get(cacheKey);\n\n\t\tif (cached && now - cached.timestamp < CACHE_TTL) {\n\t\t\tresults.set(cacheKey, { isSubscribed: cached.isSubscribed, instances: cached.instances });\n\t\t} else {\n\t\t\tuncached.push(entities[i]);\n\t\t}\n\t}\n\n\tif (uncached.length === 0) return results;\n\n\t// Fetch all uncached in parallel - direct event-specific lookups!\n\tawait Promise.all(\n\t\tuncached.map(async ({ entity, eventKey }) => {\n\t\t\tconst sockets = await redis.getSetMembers(kEntityEventSockets(entity, eventKey));\n\n\t\t\tconst isSubscribed = sockets.length > 0;\n\t\t\tconst instanceSet = new Set<string>();\n\n\t\t\t// Just extract instances, no filtering!\n\t\t\tfor (let i = 0; i < sockets.length; i++) {\n\t\t\t\tconst socketInfo = JSON.parse(sockets[i]);\n\t\t\t\tinstanceSet.add(socketInfo.instanceId);\n\t\t\t}\n\n\t\t\tconst cacheKey = `${entityKey(entity)}:${eventKey}`;\n\t\t\tconst result = { isSubscribed, instances: Array.from(instanceSet) };\n\n\t\t\tsubscriptionCache.set(cacheKey, { ...result, timestamp: now });\n\t\t\tresults.set(cacheKey, result);\n\t\t})\n\t);\n\n\treturn results;\n}\n\nexport async function isEntityConnected(entity: EntitySubscription, eventKey: string): Promise<boolean> {\n\tconst redis = getLibraries().getRedisService();\n\tconst sockets = await redis.getSetMembers(kEntityEventSockets(entity, eventKey));\n\treturn sockets.length > 0;\n}\n\nexport async function disconnectAllEntitiesFromInstance(entityType?: AuthEntityType) {\n\tconst instanceId = getInstanceId();\n\tconst redis = getLibraries().getRedisService();\n\n\t// Find all entity-event keys matching the pattern\n\tconst pattern = entityType ? `socket:entity:${entityType}:*` : 'socket:entity:*';\n\tconst entityEventKeys = await scanKeys(redis.redisClient, pattern);\n\tif (!entityEventKeys.length) return;\n\n\tconst affectedEvents = new Set<string>();\n\n\t// Use allSettled for resilience - don't fail all if one fails\n\tconst results = await Promise.allSettled(\n\t\tentityEventKeys.map(async (keyPath: string) => {\n\t\t\tconst sockets = await redis.getSetMembers(keyPath);\n\t\t\tif (!sockets.length) return;\n\n\t\t\t// Extract event from key: socket:entity:type:id:eventKey\n\t\t\tconst keyParts = keyPath.split(':');\n\t\t\tconst eventKey = keyParts.slice(4).join(':'); // Handle eventKeys with colons\n\t\t\tconst entityKeyStr = `${keyParts[2]}:${keyParts[3]}`;\n\n\t\t\t// Find sockets from this instance\n\t\t\tconst socketsToRemove = sockets.filter(s => {\n\t\t\t\ttry {\n\t\t\t\t\tconst parsed = JSON.parse(s);\n\t\t\t\t\treturn parsed.instanceId === instanceId;\n\t\t\t\t} catch {\n\t\t\t\t\treturn false; // Skip malformed data\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tif (!socketsToRemove.length) return;\n\n\t\t\taffectedEvents.add(eventKey);\n\n\t\t\t// Remove from entity-event key\n\t\t\tawait Promise.all(socketsToRemove.map(s => redis.removeFromSet(keyPath, s)));\n\n\t\t\t// Remove from event subscribers\n\t\t\tconst eventCleanup = [];\n\t\t\tfor (const socketStr of socketsToRemove) {\n\t\t\t\ttry {\n\t\t\t\t\tconst parsed = JSON.parse(socketStr);\n\t\t\t\t\tconst eventSubs = await redis.getSetMembers(kEventSubscribers(eventKey));\n\t\t\t\t\tconst toRemove = eventSubs.find(s => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst sub = JSON.parse(s);\n\t\t\t\t\t\t\treturn sub.entity === entityKeyStr && sub.socketId === parsed.socketId;\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tif (toRemove) {\n\t\t\t\t\t\teventCleanup.push(redis.removeFromSet(kEventSubscribers(eventKey), toRemove));\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconsole.error(`[Socket] Failed to cleanup subscriber for ${eventKey}:`, err);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check if this entity-event has any sockets left\n\t\t\tconst remainingSockets = sockets.length - socketsToRemove.length;\n\t\t\tif (remainingSockets === 0) {\n\t\t\t\teventCleanup.push(redis.deleteCachedObject(keyPath));\n\t\t\t}\n\n\t\t\tif (eventCleanup.length > 0) {\n\t\t\t\tawait Promise.all(eventCleanup);\n\t\t\t}\n\n\t\t\t// Clear cache\n\t\t\tsubscriptionCache.delete(`${entityKeyStr}:${eventKey}`);\n\t\t})\n\t);\n\n\t// Log any failures\n\tconst failures = results.filter(r => r.status === 'rejected');\n\tif (failures.length > 0) {\n\t\tconsole.error(`[Socket] ${failures.length} cleanup operations failed during instance disconnect`);\n\t}\n\n\t// Invalidate affected event caches\n\taffectedEvents.forEach(eventKey => eventSubscribersCache.delete(eventKey));\n}\n\n// Zero-allocation hot path for event subscribers\nexport async function getEventSubscribers(eventKey: string): Promise<EntitySubscription[]> {\n\tconst cached = eventSubscribersCache.get(eventKey);\n\tconst now = Date.now();\n\n\tif (cached && now - cached.timestamp < CACHE_TTL) {\n\t\treturn cached.subscribers;\n\t}\n\n\tconst redis = getLibraries().getRedisService();\n\tconst subscriberData = await redis.getSetMembers(kEventSubscribers(eventKey));\n\n\tif (subscriberData.length === 0) {\n\t\tconst empty: EntitySubscription[] = [];\n\t\teventSubscribersCache.set(eventKey, { subscribers: empty, timestamp: now });\n\t\treturn empty;\n\t}\n\n\t// Parse subscriber data and extract unique entities\n\tconst entityMap = new Map<string, EntitySubscription>();\n\tfor (let i = 0; i < subscriberData.length; i++) {\n\t\tconst sub = JSON.parse(subscriberData[i]);\n\t\tconst entityKeyStr = sub.entity;\n\n\t\tif (!entityMap.has(entityKeyStr)) {\n\t\t\tconst colonIndex = entityKeyStr.indexOf(':');\n\t\t\tconst type = entityKeyStr.substring(0, colonIndex);\n\t\t\tconst id = entityKeyStr.substring(colonIndex + 1);\n\n\t\t\tentityMap.set(entityKeyStr, {\n\t\t\t\tid,\n\t\t\t\ttype: type === 'default' ? undefined : (type as AuthEntityType),\n\t\t\t});\n\t\t}\n\t}\n\n\tconst subscribers = Array.from(entityMap.values());\n\teventSubscribersCache.set(eventKey, { subscribers, timestamp: now });\n\treturn subscribers;\n}\n\n// ⚡ Batch variant: Get subscribers for multiple events at once\nexport async function getEventSubscribersBatch(\n\teventKeys: string[]\n): Promise<Map<string, EntitySubscription[]>> {\n\tconst redis = getLibraries().getRedisService();\n\tconst results = new Map<string, EntitySubscription[]>();\n\tconst now = Date.now();\n\n\t// Separate cached vs uncached\n\tconst uncached: string[] = [];\n\tfor (const eventKey of eventKeys) {\n\t\tconst cached = eventSubscribersCache.get(eventKey);\n\t\tif (cached && now - cached.timestamp < CACHE_TTL) {\n\t\t\tresults.set(eventKey, cached.subscribers);\n\t\t} else {\n\t\t\tuncached.push(eventKey);\n\t\t}\n\t}\n\n\t// Fetch uncached in parallel\n\tif (uncached.length > 0) {\n\t\tawait Promise.all(\n\t\t\tuncached.map(async eventKey => {\n\t\t\t\tconst subscriberData = await redis.getSetMembers(kEventSubscribers(eventKey));\n\n\t\t\t\tconst entityMap = new Map<string, EntitySubscription>();\n\t\t\t\tfor (let i = 0; i < subscriberData.length; i++) {\n\t\t\t\t\tconst sub = JSON.parse(subscriberData[i]);\n\t\t\t\t\tconst entityKeyStr = sub.entity;\n\n\t\t\t\t\tif (!entityMap.has(entityKeyStr)) {\n\t\t\t\t\t\tconst colonIndex = entityKeyStr.indexOf(':');\n\t\t\t\t\t\tconst type = entityKeyStr.substring(0, colonIndex);\n\t\t\t\t\t\tconst id = entityKeyStr.substring(colonIndex + 1);\n\n\t\t\t\t\t\tentityMap.set(entityKeyStr, {\n\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\ttype: type === 'default' ? undefined : (type as AuthEntityType),\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst subscribers = Array.from(entityMap.values());\n\t\t\t\teventSubscribersCache.set(eventKey, { subscribers, timestamp: now });\n\t\t\t\tresults.set(eventKey, subscribers);\n\t\t\t})\n\t\t);\n\t}\n\n\treturn results;\n}\n\n// Zero-copy filtered query - inline filtering to avoid double allocation\nexport async function getEventSubscribersByType(\n\teventKey: string,\n\tentityType: AuthEntityType\n): Promise<EntitySubscription[]> {\n\tconst cached = eventSubscribersCache.get(eventKey);\n\tconst now = Date.now();\n\n\tif (cached && now - cached.timestamp < CACHE_TTL) {\n\t\t// Fast filter on cached data\n\t\tconst filtered: EntitySubscription[] = [];\n\t\tfor (let i = 0; i < cached.subscribers.length; i++) {\n\t\t\tif (cached.subscribers[i].type === entityType) {\n\t\t\t\tfiltered.push(cached.subscribers[i]);\n\t\t\t}\n\t\t}\n\t\treturn filtered;\n\t}\n\n\t// Fetch and filter in one pass\n\tconst redis = getLibraries().getRedisService();\n\tconst subscriberData = await redis.getSetMembers(kEventSubscribers(eventKey));\n\tconst typePrefix = `${entityType}:`;\n\n\tconst filtered: EntitySubscription[] = [];\n\tconst entityMap = new Map<string, EntitySubscription>();\n\n\tfor (let i = 0; i < subscriberData.length; i++) {\n\t\tconst sub = JSON.parse(subscriberData[i]);\n\t\tconst entityKeyStr = sub.entity;\n\n\t\tif (!entityMap.has(entityKeyStr)) {\n\t\t\tconst colonIndex = entityKeyStr.indexOf(':');\n\t\t\tconst type = entityKeyStr.substring(0, colonIndex);\n\t\t\tconst id = entityKeyStr.substring(colonIndex + 1);\n\n\t\t\tconst entity: EntitySubscription = {\n\t\t\t\tid,\n\t\t\t\ttype: type === 'default' ? undefined : (type as AuthEntityType),\n\t\t\t};\n\n\t\t\tentityMap.set(entityKeyStr, entity);\n\n\t\t\tif (entityKeyStr.startsWith(typePrefix)) {\n\t\t\t\tfiltered.push(entity);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Cache all unique subscribers for future calls\n\tconst all = Array.from(entityMap.values());\n\teventSubscribersCache.set(eventKey, { subscribers: all, timestamp: now });\n\n\treturn filtered;\n}\n\n// ⚡ Get subscriber count (fast, check cache or count)\nexport async function getEventSubscriberCount(eventKey: string): Promise<number> {\n\t// Check cache first\n\tconst cached = eventSubscribersCache.get(eventKey);\n\tif (cached && Date.now() - cached.timestamp < CACHE_TTL) {\n\t\treturn cached.subscribers.length;\n\t}\n\n\t// Otherwise fetch and count\n\tconst redis = getLibraries().getRedisService();\n\tconst members = await redis.getSetMembers(kEventSubscribers(eventKey));\n\treturn members.length;\n}\n"]}