@lyxa.ai/core 1.2.22 → 1.2.24

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.
@@ -18,7 +18,10 @@ async function subscribeToSocketEvent() {
18
18
  channel.ack(msg);
19
19
  }
20
20
  catch (e) {
21
- console.error('Failed to handle socket event:', e);
21
+ console.error('[Socket] Failed to handle socket event:', {
22
+ error: e instanceof Error ? e.message : e,
23
+ queue: queueName,
24
+ });
22
25
  channel.nack(msg, false, false);
23
26
  }
24
27
  });
@@ -1 +1 @@
1
- {"version":3,"file":"socket-event-consumer.js","sourceRoot":"/","sources":["libraries/socket/core/socket-event-consumer.ts"],"names":[],"mappings":";;AAIA,wDAoBC;AAxBD,sEAAkE;AAClE,uCAAwD;AACxD,+EAA0D;AAEnD,KAAK,UAAU,sBAAsB;IAC3C,MAAM,OAAO,GAAG,IAAA,kBAAU,GAAE,CAAC;IAC7B,MAAM,SAAS,GAAG,iBAAiB,IAAA,8BAAa,GAAE,EAAE,CAAC;IAErD,MAAM,OAAO,CAAC,WAAW,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,MAAM,OAAO,CAAC,SAAS,CAAC,SAAS,EAAE,qBAAa,EAAE,YAAY,IAAA,8BAAa,GAAE,EAAE,CAAC,CAAC;IAEjF,MAAM,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE;QACtC,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,IAAI,CAAC;YACJ,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;YAClF,uCAAS,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;YAC7C,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACZ,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,CAAC,CAAC,CAAC;YACnD,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QACjC,CAAC;IACF,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,yCAAyC,SAAS,GAAG,CAAC,CAAC;AACpE,CAAC","sourcesContent":["import { getInstanceId } from '../../../utilities/instance.utils';\nimport { EXCHANGE_NAME, getChannel } from '../../event';\nimport { LocalSubs } from './local-subscription-registry';\n\nexport async function subscribeToSocketEvent() {\n\tconst channel = getChannel();\n\tconst queueName = `socket-events-${getInstanceId()}`;\n\n\tawait channel.assertQueue(queueName, { durable: true });\n\tawait channel.bindQueue(queueName, EXCHANGE_NAME, `instance.${getInstanceId()}`);\n\n\tawait channel.consume(queueName, msg => {\n\t\tif (!msg) return;\n\t\ttry {\n\t\t\tconst { localKey, payload, recipient } = JSON.parse(msg.content.toString('utf8'));\n\t\t\tLocalSubs.emit(recipient, localKey, payload);\n\t\t\tchannel.ack(msg);\n\t\t} catch (e) {\n\t\t\tconsole.error('Failed to handle socket event:', e);\n\t\t\tchannel.nack(msg, false, false);\n\t\t}\n\t});\n\n\tconsole.log(`Subscribed to socket events on queue [${queueName}]`);\n}\n"]}
1
+ {"version":3,"file":"socket-event-consumer.js","sourceRoot":"/","sources":["libraries/socket/core/socket-event-consumer.ts"],"names":[],"mappings":";;AAIA,wDAuBC;AA3BD,sEAAkE;AAClE,uCAAwD;AACxD,+EAA0D;AAEnD,KAAK,UAAU,sBAAsB;IAC3C,MAAM,OAAO,GAAG,IAAA,kBAAU,GAAE,CAAC;IAC7B,MAAM,SAAS,GAAG,iBAAiB,IAAA,8BAAa,GAAE,EAAE,CAAC;IAErD,MAAM,OAAO,CAAC,WAAW,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,MAAM,OAAO,CAAC,SAAS,CAAC,SAAS,EAAE,qBAAa,EAAE,YAAY,IAAA,8BAAa,GAAE,EAAE,CAAC,CAAC;IAEjF,MAAM,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE;QACtC,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,IAAI,CAAC;YACJ,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;YAClF,uCAAS,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;YAC7C,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACZ,OAAO,CAAC,KAAK,CAAC,yCAAyC,EAAE;gBACxD,KAAK,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBACzC,KAAK,EAAE,SAAS;aAChB,CAAC,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QACjC,CAAC;IACF,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,yCAAyC,SAAS,GAAG,CAAC,CAAC;AACpE,CAAC","sourcesContent":["import { getInstanceId } from '../../../utilities/instance.utils';\nimport { EXCHANGE_NAME, getChannel } from '../../event';\nimport { LocalSubs } from './local-subscription-registry';\n\nexport async function subscribeToSocketEvent() {\n\tconst channel = getChannel();\n\tconst queueName = `socket-events-${getInstanceId()}`;\n\n\tawait channel.assertQueue(queueName, { durable: true });\n\tawait channel.bindQueue(queueName, EXCHANGE_NAME, `instance.${getInstanceId()}`);\n\n\tawait channel.consume(queueName, msg => {\n\t\tif (!msg) return;\n\t\ttry {\n\t\t\tconst { localKey, payload, recipient } = JSON.parse(msg.content.toString('utf8'));\n\t\t\tLocalSubs.emit(recipient, localKey, payload);\n\t\t\tchannel.ack(msg);\n\t\t} catch (e) {\n\t\t\tconsole.error('[Socket] Failed to handle socket event:', {\n\t\t\t\terror: e instanceof Error ? e.message : e,\n\t\t\t\tqueue: queueName,\n\t\t\t});\n\t\t\tchannel.nack(msg, false, false); // Don't requeue malformed messages\n\t\t}\n\t});\n\n\tconsole.log(`Subscribed to socket events on queue [${queueName}]`);\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { BaseSocketEvent } from '../BaseSocketEvent';
2
2
  import { EntitySubscription } from './socket-redis-connections';
3
- import { NotificationSocketEvent } from '../events/notification.socket.event';
3
+ import { NotificationSocketEvent } from '../events';
4
4
  export declare function publishSocketEvent(event: BaseSocketEvent<any, any>, recipients: EntitySubscription[]): Promise<void>;
5
5
  export declare function publishNotificationSocketEvent(event: NotificationSocketEvent, recipients: EntitySubscription[]): Promise<void>;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.publishSocketEvent = publishSocketEvent;
4
4
  exports.publishNotificationSocketEvent = publishNotificationSocketEvent;
5
+ const __1 = require("../../..");
5
6
  const socket_redis_connections_1 = require("./socket-redis-connections");
6
7
  const event_1 = require("../../event");
7
8
  const PushNotificationEvent_1 = require("../PushNotificationEvent");
@@ -34,22 +35,32 @@ async function getActiveSubscribedRecipients(recipients, localKey) {
34
35
  if (recipients.length === 0) {
35
36
  return { subscribed: [], unsubscribed: [] };
36
37
  }
37
- const batchInput = recipients.map(recipient => ({ entity: recipient, eventKey: localKey }));
38
- const resultsMap = await (0, socket_redis_connections_1.getEntitySubscriptionInfoBatch)(batchInput);
38
+ const redis = (0, __1.getLibraries)().getRedisService();
39
39
  const subscribed = [];
40
40
  const unsubscribed = [];
41
- for (let i = 0; i < recipients.length; i++) {
42
- const recipient = recipients[i];
43
- const entityKeyStr = `${recipient.type ?? 'default'}:${recipient.id}`;
44
- const cacheKey = `${entityKeyStr}:${localKey}`;
45
- const info = resultsMap.get(cacheKey);
46
- if (info && info.isSubscribed && info.instances.length > 0) {
47
- subscribed.push({ recipient, instances: info.instances });
41
+ await Promise.all(recipients.map(async (recipient) => {
42
+ const sockets = await redis.getSetMembers((0, socket_redis_connections_1.getEntityEventSocketsKey)(recipient, localKey));
43
+ if (sockets.length > 0) {
44
+ const instanceSet = new Set();
45
+ for (let i = 0; i < sockets.length; i++) {
46
+ try {
47
+ const socketInfo = JSON.parse(sockets[i]);
48
+ instanceSet.add(socketInfo.instanceId);
49
+ }
50
+ catch {
51
+ }
52
+ }
53
+ if (instanceSet.size > 0) {
54
+ subscribed.push({ recipient, instances: Array.from(instanceSet) });
55
+ }
56
+ else {
57
+ unsubscribed.push(recipient);
58
+ }
48
59
  }
49
60
  else {
50
61
  unsubscribed.push(recipient);
51
62
  }
52
- }
63
+ }));
53
64
  return { subscribed, unsubscribed };
54
65
  }
55
66
  async function publishSocketEvent(event, recipients) {
@@ -76,18 +87,25 @@ async function publishNotificationSocketEvent(event, recipients) {
76
87
  if (recipients.length === 0)
77
88
  return;
78
89
  const eventKey = event.getSubscriptionKey();
79
- const batchInput = recipients.map(recipient => ({ entity: recipient, eventKey }));
80
- const resultsMap = await (0, socket_redis_connections_1.getEntitySubscriptionInfoBatch)(batchInput);
90
+ const redis = (0, __1.getLibraries)().getRedisService();
81
91
  const validInstances = [];
82
- for (let i = 0; i < recipients.length; i++) {
83
- const recipient = recipients[i];
84
- const entityKeyStr = `${recipient.type ?? 'default'}:${recipient.id}`;
85
- const cacheKey = `${entityKeyStr}:${eventKey}`;
86
- const info = resultsMap.get(cacheKey);
87
- if (info && info.instances.length > 0) {
88
- validInstances.push({ recipient, instances: info.instances });
92
+ await Promise.all(recipients.map(async (recipient) => {
93
+ const sockets = await redis.getSetMembers((0, socket_redis_connections_1.getEntityEventSocketsKey)(recipient, eventKey));
94
+ if (sockets.length > 0) {
95
+ const instanceSet = new Set();
96
+ for (let i = 0; i < sockets.length; i++) {
97
+ try {
98
+ const socketInfo = JSON.parse(sockets[i]);
99
+ instanceSet.add(socketInfo.instanceId);
100
+ }
101
+ catch {
102
+ }
103
+ }
104
+ if (instanceSet.size > 0) {
105
+ validInstances.push({ recipient, instances: Array.from(instanceSet) });
106
+ }
89
107
  }
90
- }
108
+ }));
91
109
  if (validInstances.length > 0) {
92
110
  publishToInstances(validInstances, eventKey, event.payload());
93
111
  }
@@ -1 +1 @@
1
- {"version":3,"file":"socket-event-publisher.js","sourceRoot":"/","sources":["libraries/socket/core/socket-event-publisher.ts"],"names":[],"mappings":"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","sourcesContent":["import { getLibraries } from '../../..';\nimport { BaseSocketEvent } from '../BaseSocketEvent';\nimport { EntitySubscription, getEntitySubscriptionInfo, getEntitySubscriptionInfoBatch } from './socket-redis-connections';\nimport { NotificationSocketEvent } from '../events/notification.socket.event';\nimport { EXCHANGE_NAME, getChannel, INSTANCE_ROUTE_PREFIX, publishEvent } from '../../event';\nimport { PushNotificationEvent } from '../PushNotificationEvent';\nimport { PushNotificationEventType } from '../../../utilities/enum';\n\n// Reusable publish options\nconst PUBLISH_OPTIONS = {\n\tcontentType: 'application/json',\n\tpersistent: true,\n} as const;\n\n// Zero-overhead publishing - minimal allocations\nfunction publishToInstances(\n\trecipientsWithInstances: Array<{ recipient: EntitySubscription; instances: string[] }>,\n\tlocalKey: string,\n\tpayload: any\n): void {\n\tif (recipientsWithInstances.length === 0) return;\n\n\tconst channel = getChannel();\n\n\t// Pre-serialize message once\n\tconst message = { localKey, payload, recipient: null as any };\n\t\n\t// Fire-and-forget with minimal overhead\n\tfor (let i = 0; i < recipientsWithInstances.length; i++) {\n\t\tconst { recipient, instances } = recipientsWithInstances[i];\n\t\tmessage.recipient = recipient;\n\t\tconst messageStr = JSON.stringify(message);\n\n\t\tfor (let j = 0; j < instances.length; j++) {\n\t\t\tconst routingKey = `${INSTANCE_ROUTE_PREFIX}.${instances[j]}`;\n\t\t\t\n\t\t\ttry {\n\t\t\t\t// Direct publish - Buffer.from creates minimal overhead\n\t\t\t\tchannel.publish(EXCHANGE_NAME, routingKey, Buffer.from(messageStr, 'utf8'), PUBLISH_OPTIONS);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(`[Socket] Publish failed: ${routingKey}`, error);\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Zero-allocation recipient filtering\nasync function getActiveSubscribedRecipients(\n\trecipients: EntitySubscription[],\n\tlocalKey: string\n): Promise<{\n\tsubscribed: Array<{ recipient: EntitySubscription; instances: string[] }>;\n\tunsubscribed: EntitySubscription[];\n}> {\n\tif (recipients.length === 0) {\n\t\treturn { subscribed: [], unsubscribed: [] };\n\t}\n\n\t// Use batch API\n\tconst batchInput = recipients.map(recipient => ({ entity: recipient, eventKey: localKey }));\n\tconst resultsMap = await getEntitySubscriptionInfoBatch(batchInput);\n\n\t// Pre-allocate arrays\n\tconst subscribed: Array<{ recipient: EntitySubscription; instances: string[] }> = [];\n\tconst unsubscribed: EntitySubscription[] = [];\n\n\t// Single pass with minimal allocations\n\tfor (let i = 0; i < recipients.length; i++) {\n\t\tconst recipient = recipients[i];\n\t\tconst entityKeyStr = `${recipient.type ?? 'default'}:${recipient.id}`;\n\t\tconst cacheKey = `${entityKeyStr}:${localKey}`;\n\t\tconst info = resultsMap.get(cacheKey);\n\n\t\tif (info && info.isSubscribed && info.instances.length > 0) {\n\t\t\tsubscribed.push({ recipient, instances: info.instances });\n\t\t} else {\n\t\t\tunsubscribed.push(recipient);\n\t\t}\n\t}\n\n\treturn { subscribed, unsubscribed };\n}\n\n// Minimal overhead publish - early returns, lazy evaluation\nexport async function publishSocketEvent(\n\tevent: BaseSocketEvent<any, any>,\n\trecipients: EntitySubscription[]\n): Promise<void> {\n\tif (recipients.length === 0) return;\n\n\tconst localKey = event.getSubscriptionKey();\n\tconst payload = event.payload();\n\n\tconst { subscribed, unsubscribed } = await getActiveSubscribedRecipients(recipients, localKey);\n\n\t// Fire-and-forget: zero blocking\n\tif (subscribed.length > 0) {\n\t\tpublishToInstances(subscribed, localKey, payload);\n\t}\n\n\t// Lazy fallback evaluation - only if needed\n\tif (unsubscribed.length > 0) {\n\t\tconst notificationEvent = event.notification?.();\n\t\tconst pushNotificationEvent = event.pushNotification?.();\n\n\t\t// Fire without awaiting - true fire-and-forget\n\t\tif (pushNotificationEvent) {\n\t\t\tpublishEvent(new PushNotificationEvent(PushNotificationEventType.CHATROOM_MESSAGE_SEND, payload)).catch(\n\t\t\t\terr => console.error('[Socket] Push failed:', err)\n\t\t\t);\n\t\t}\n\n\t\tif (notificationEvent) {\n\t\t\tpublishNotificationSocketEvent(notificationEvent, unsubscribed).catch(err =>\n\t\t\t\tconsole.error('[Socket] Notification failed:', err)\n\t\t\t);\n\t\t}\n\t}\n}\n\n// Zero-overhead notification publish\nexport async function publishNotificationSocketEvent(\n\tevent: NotificationSocketEvent,\n\trecipients: EntitySubscription[]\n): Promise<void> {\n\tif (recipients.length === 0) return;\n\n\tconst eventKey = event.getSubscriptionKey();\n\tconst batchInput = recipients.map(recipient => ({ entity: recipient, eventKey }));\n\tconst resultsMap = await getEntitySubscriptionInfoBatch(batchInput);\n\n\t// Pre-allocate for valid instances\n\tconst validInstances: Array<{ recipient: EntitySubscription; instances: string[] }> = [];\n\n\tfor (let i = 0; i < recipients.length; i++) {\n\t\tconst recipient = recipients[i];\n\t\tconst entityKeyStr = `${recipient.type ?? 'default'}:${recipient.id}`;\n\t\tconst cacheKey = `${entityKeyStr}:${eventKey}`;\n\t\tconst info = resultsMap.get(cacheKey);\n\n\t\tif (info && info.instances.length > 0) {\n\t\t\tvalidInstances.push({ recipient, instances: info.instances });\n\t\t}\n\t}\n\n\tif (validInstances.length > 0) {\n\t\tpublishToInstances(validInstances, eventKey, event.payload());\n\t}\n}\n"]}
1
+ {"version":3,"file":"socket-event-publisher.js","sourceRoot":"/","sources":["libraries/socket/core/socket-event-publisher.ts"],"names":[],"mappings":"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","sourcesContent":["import { getLibraries } from '../../..';\nimport { BaseSocketEvent } from '../BaseSocketEvent';\nimport { EntitySubscription, getEntityEventSocketsKey } from './socket-redis-connections';\nimport { NotificationSocketEvent } from '../events';\nimport { EXCHANGE_NAME, getChannel, INSTANCE_ROUTE_PREFIX, publishEvent } from '../../event';\nimport { PushNotificationEvent } from '../PushNotificationEvent';\nimport { PushNotificationEventType } from '../../../utilities/enum';\n\n// Reusable publish options\nconst PUBLISH_OPTIONS = {\n\tcontentType: 'application/json',\n\tpersistent: true,\n} as const;\n\n// Zero-overhead publishing - minimal allocations\nfunction publishToInstances(\n\trecipientsWithInstances: Array<{ recipient: EntitySubscription; instances: string[] }>,\n\tlocalKey: string,\n\tpayload: any\n): void {\n\tif (recipientsWithInstances.length === 0) return;\n\n\tconst channel = getChannel();\n\n\t// Pre-serialize message once\n\tconst message = { localKey, payload, recipient: null as any };\n\t\n\t// Fire-and-forget with minimal overhead\n\tfor (let i = 0; i < recipientsWithInstances.length; i++) {\n\t\tconst { recipient, instances } = recipientsWithInstances[i];\n\t\tmessage.recipient = recipient;\n\t\tconst messageStr = JSON.stringify(message);\n\n\t\tfor (let j = 0; j < instances.length; j++) {\n\t\t\tconst routingKey = `${INSTANCE_ROUTE_PREFIX}.${instances[j]}`;\n\t\t\t\n\t\t\ttry {\n\t\t\t\t// Direct publish - Buffer.from creates minimal overhead\n\t\t\t\tchannel.publish(EXCHANGE_NAME, routingKey, Buffer.from(messageStr, 'utf8'), PUBLISH_OPTIONS);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(`[Socket] Publish failed: ${routingKey}`, error);\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Ultra-simple: Direct Redis lookups, no batch/cache/parsing!\nasync function getActiveSubscribedRecipients(\n\trecipients: EntitySubscription[],\n\tlocalKey: string\n): Promise<{\n\tsubscribed: Array<{ recipient: EntitySubscription; instances: string[] }>;\n\tunsubscribed: EntitySubscription[];\n}> {\n\tif (recipients.length === 0) {\n\t\treturn { subscribed: [], unsubscribed: [] };\n\t}\n\n\tconst redis = getLibraries().getRedisService();\n\tconst subscribed: Array<{ recipient: EntitySubscription; instances: string[] }> = [];\n\tconst unsubscribed: EntitySubscription[] = [];\n\n\t// Parallel lookups - one key per recipient\n\tawait Promise.all(\n\t\trecipients.map(async (recipient) => {\n\t\t\tconst sockets = await redis.getSetMembers(getEntityEventSocketsKey(recipient, localKey));\n\t\t\t\n\t\t\tif (sockets.length > 0) {\n\t\t\t\t// Extract instances\n\t\t\t\tconst instanceSet = new Set<string>();\n\t\t\t\tfor (let i = 0; i < sockets.length; i++) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst socketInfo = JSON.parse(sockets[i]);\n\t\t\t\t\t\tinstanceSet.add(socketInfo.instanceId);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Skip malformed socket data\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (instanceSet.size > 0) {\n\t\t\t\t\tsubscribed.push({ recipient, instances: Array.from(instanceSet) });\n\t\t\t\t} else {\n\t\t\t\t\tunsubscribed.push(recipient);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tunsubscribed.push(recipient);\n\t\t\t}\n\t\t})\n\t);\n\n\treturn { subscribed, unsubscribed };\n}\n\n// Minimal overhead publish - early returns, lazy evaluation\nexport async function publishSocketEvent(\n\tevent: BaseSocketEvent<any, any>,\n\trecipients: EntitySubscription[]\n): Promise<void> {\n\tif (recipients.length === 0) return;\n\n\tconst localKey = event.getSubscriptionKey();\n\tconst payload = event.payload();\n\n\tconst { subscribed, unsubscribed } = await getActiveSubscribedRecipients(recipients, localKey);\n\n\t// Fire-and-forget: zero blocking\n\tif (subscribed.length > 0) {\n\t\tpublishToInstances(subscribed, localKey, payload);\n\t}\n\n\t// Lazy fallback evaluation - only if needed\n\tif (unsubscribed.length > 0) {\n\t\tconst notificationEvent = event.notification?.();\n\t\tconst pushNotificationEvent = event.pushNotification?.();\n\n\t\t// Fire without awaiting - true fire-and-forget\n\t\tif (pushNotificationEvent) {\n\t\t\tpublishEvent(new PushNotificationEvent(PushNotificationEventType.CHATROOM_MESSAGE_SEND, payload)).catch(\n\t\t\t\terr => console.error('[Socket] Push failed:', err)\n\t\t\t);\n\t\t}\n\n\t\tif (notificationEvent) {\n\t\t\tpublishNotificationSocketEvent(notificationEvent, unsubscribed).catch(err =>\n\t\t\t\tconsole.error('[Socket] Notification failed:', err)\n\t\t\t);\n\t\t}\n\t}\n}\n\n// Ultra-simple notification publish: Direct lookups!\nexport async function publishNotificationSocketEvent(\n\tevent: NotificationSocketEvent,\n\trecipients: EntitySubscription[]\n): Promise<void> {\n\tif (recipients.length === 0) return;\n\n\tconst eventKey = event.getSubscriptionKey();\n\tconst redis = getLibraries().getRedisService();\n\tconst validInstances: Array<{ recipient: EntitySubscription; instances: string[] }> = [];\n\n\t// Parallel direct lookups\n\tawait Promise.all(\n\t\trecipients.map(async (recipient) => {\n\t\t\tconst sockets = await redis.getSetMembers(getEntityEventSocketsKey(recipient, eventKey));\n\t\t\t\n\t\t\tif (sockets.length > 0) {\n\t\t\t\tconst instanceSet = new Set<string>();\n\t\t\t\tfor (let i = 0; i < sockets.length; i++) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst socketInfo = JSON.parse(sockets[i]);\n\t\t\t\t\t\tinstanceSet.add(socketInfo.instanceId);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Skip malformed socket data\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (instanceSet.size > 0) {\n\t\t\t\t\tvalidInstances.push({ recipient, instances: Array.from(instanceSet) });\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t);\n\n\tif (validInstances.length > 0) {\n\t\tpublishToInstances(validInstances, eventKey, event.payload());\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"socket-event-registry.map.js","sourceRoot":"/","sources":["libraries/socket/core/socket-event-registry.map.ts"],"names":[],"mappings":";;;AAAA,kDAA0D;AAC1D,sCAA2F;AAC3F,qFAAyE;AACzE,yFAA6E;AAE7E,mFAA8E;AAC9E,qFAA+E;AAC/E,qGAA8F;AAGjF,QAAA,QAAQ,GAAG;IACvB,CAAC,sBAAe,CAAC,qBAAqB,CAAC,EAAE;QACxC,IAAI,EAAE,uCAA8B;QACpC,OAAO,EAAE,uCAA8B,CAAC,OAAO;QAC/C,UAAU,EAAE,uCAA8B,CAAC,UAAU;KACrD;IACD,CAAC,sBAAe,CAAC,yBAAyB,CAAC,EAAE;QAC5C,IAAI,EAAE,uCAA8B;QACpC,OAAO,EAAE,uCAA8B,CAAC,OAAO;KAC/C;IACD,CAAC,sBAAe,CAAC,aAAa,CAAC,EAAE;QAChC,IAAI,EAAE,8CAAiB;QACvB,OAAO,EAAE,8CAAiB,CAAC,OAAO;KAClC;IACD,CAAC,sBAAe,CAAC,eAAe,CAAC,EAAE;QAClC,IAAI,EAAE,kDAAmB;QACzB,OAAO,EAAE,kDAAmB,CAAC,OAAO;QACpC,UAAU,EAAE,kDAAmB,CAAC,UAAU;KAC1C;IACD,CAAC,sBAAe,CAAC,YAAY,CAAC,EAAE;QAC/B,IAAI,EAAE,mDAAuB;QAC7B,OAAO,EAAE,mDAAuB,CAAC,OAAO;KACxC;IACD,CAAC,sBAAe,CAAC,aAAa,CAAC,EAAE;QAChC,IAAI,EAAE,oDAAuB;QAC7B,OAAO,EAAE,oDAAuB,CAAC,OAAO;KACxC;IACD,CAAC,sBAAe,CAAC,qBAAqB,CAAC,EAAE;QACxC,IAAI,EAAE,mEAA8B;QACpC,OAAO,EAAE,mEAA8B,CAAC,OAAO;QAC/C,UAAU,EAAE,mEAA8B,CAAC,UAAU;KACrD;CACQ,CAAC","sourcesContent":["import { SocketEventType } from '../../../utilities/enum';\nimport { ChatlistMessageSendSocketEvent, ChatroomMessageSendSocketEvent } from '../events';\nimport { TicketAssignEvent } from '../events/ticket-assign.socket.event';\nimport { TicketUnassignEvent } from '../events/ticket-unassign.socket.event';\nimport { EventRegistration } from './index';\nimport { NotificationSocketEvent } from '../events/notification.socket.event';\nimport { RiderConnectSocketEvent } from '../events/rider-connect.socket.event';\nimport { RiderLocationUpdateSocketEvent } from '../events/rider-location-update.socket.event';\nimport { scheduler } from 'timers/promises';\n\nexport const REGISTRY = {\n\t[SocketEventType.CHATROOM_MESSAGE_SEND]: {\n\t\tctor: ChatroomMessageSendSocketEvent,\n\t\tschemas: ChatroomMessageSendSocketEvent.schemas,\n\t\tidentifier: ChatroomMessageSendSocketEvent.identifier,\n\t},\n\t[SocketEventType.CHATLIST_MESSAGE_RECEIVED]: {\n\t\tctor: ChatlistMessageSendSocketEvent,\n\t\tschemas: ChatlistMessageSendSocketEvent.schemas,\n\t},\n\t[SocketEventType.TICKET_ASSIGN]: {\n\t\tctor: TicketAssignEvent,\n\t\tschemas: TicketAssignEvent.schemas,\n\t},\n\t[SocketEventType.TICKET_UNASSIGN]: {\n\t\tctor: TicketUnassignEvent,\n\t\tschemas: TicketUnassignEvent.schemas,\n\t\tidentifier: TicketUnassignEvent.identifier,\n\t},\n\t[SocketEventType.NOTIFICATION]: {\n\t\tctor: NotificationSocketEvent,\n\t\tschemas: NotificationSocketEvent.schemas,\n\t},\n\t[SocketEventType.RIDER_CONNECT]: {\n\t\tctor: RiderConnectSocketEvent,\n\t\tschemas: RiderConnectSocketEvent.schemas,\n\t},\n\t[SocketEventType.RIDER_LOCATION_UPDATE]: {\n\t\tctor: RiderLocationUpdateSocketEvent,\n\t\tschemas: RiderLocationUpdateSocketEvent.schemas,\n\t\tidentifier: RiderLocationUpdateSocketEvent.identifier,\n\t},\n} as const;\n\nexport type Registry = {\n\t[K in keyof typeof REGISTRY]: (typeof REGISTRY)[K] extends EventRegistration<any>\n\t\t? (typeof REGISTRY)[K]\n\t\t: never;\n};\n"]}
1
+ {"version":3,"file":"socket-event-registry.map.js","sourceRoot":"/","sources":["libraries/socket/core/socket-event-registry.map.ts"],"names":[],"mappings":";;;AAAA,kDAA0D;AAC1D,sCAA2F;AAC3F,qFAAyE;AACzE,yFAA6E;AAE7E,mFAA8E;AAC9E,qFAA+E;AAC/E,qGAA8F;AAEjF,QAAA,QAAQ,GAAG;IACvB,CAAC,sBAAe,CAAC,qBAAqB,CAAC,EAAE;QACxC,IAAI,EAAE,uCAA8B;QACpC,OAAO,EAAE,uCAA8B,CAAC,OAAO;QAC/C,UAAU,EAAE,uCAA8B,CAAC,UAAU;KACrD;IACD,CAAC,sBAAe,CAAC,yBAAyB,CAAC,EAAE;QAC5C,IAAI,EAAE,uCAA8B;QACpC,OAAO,EAAE,uCAA8B,CAAC,OAAO;KAC/C;IACD,CAAC,sBAAe,CAAC,aAAa,CAAC,EAAE;QAChC,IAAI,EAAE,8CAAiB;QACvB,OAAO,EAAE,8CAAiB,CAAC,OAAO;KAClC;IACD,CAAC,sBAAe,CAAC,eAAe,CAAC,EAAE;QAClC,IAAI,EAAE,kDAAmB;QACzB,OAAO,EAAE,kDAAmB,CAAC,OAAO;QACpC,UAAU,EAAE,kDAAmB,CAAC,UAAU;KAC1C;IACD,CAAC,sBAAe,CAAC,YAAY,CAAC,EAAE;QAC/B,IAAI,EAAE,mDAAuB;QAC7B,OAAO,EAAE,mDAAuB,CAAC,OAAO;KACxC;IACD,CAAC,sBAAe,CAAC,aAAa,CAAC,EAAE;QAChC,IAAI,EAAE,oDAAuB;QAC7B,OAAO,EAAE,oDAAuB,CAAC,OAAO;KACxC;IACD,CAAC,sBAAe,CAAC,qBAAqB,CAAC,EAAE;QACxC,IAAI,EAAE,mEAA8B;QACpC,OAAO,EAAE,mEAA8B,CAAC,OAAO;QAC/C,UAAU,EAAE,mEAA8B,CAAC,UAAU;KACrD;CACQ,CAAC","sourcesContent":["import { SocketEventType } from '../../../utilities/enum';\nimport { ChatlistMessageSendSocketEvent, ChatroomMessageSendSocketEvent } from '../events';\nimport { TicketAssignEvent } from '../events/ticket-assign.socket.event';\nimport { TicketUnassignEvent } from '../events/ticket-unassign.socket.event';\nimport { EventRegistration } from './index';\nimport { NotificationSocketEvent } from '../events/notification.socket.event';\nimport { RiderConnectSocketEvent } from '../events/rider-connect.socket.event';\nimport { RiderLocationUpdateSocketEvent } from '../events/rider-location-update.socket.event';\n\nexport const REGISTRY = {\n\t[SocketEventType.CHATROOM_MESSAGE_SEND]: {\n\t\tctor: ChatroomMessageSendSocketEvent,\n\t\tschemas: ChatroomMessageSendSocketEvent.schemas,\n\t\tidentifier: ChatroomMessageSendSocketEvent.identifier,\n\t},\n\t[SocketEventType.CHATLIST_MESSAGE_RECEIVED]: {\n\t\tctor: ChatlistMessageSendSocketEvent,\n\t\tschemas: ChatlistMessageSendSocketEvent.schemas,\n\t},\n\t[SocketEventType.TICKET_ASSIGN]: {\n\t\tctor: TicketAssignEvent,\n\t\tschemas: TicketAssignEvent.schemas,\n\t},\n\t[SocketEventType.TICKET_UNASSIGN]: {\n\t\tctor: TicketUnassignEvent,\n\t\tschemas: TicketUnassignEvent.schemas,\n\t\tidentifier: TicketUnassignEvent.identifier,\n\t},\n\t[SocketEventType.NOTIFICATION]: {\n\t\tctor: NotificationSocketEvent,\n\t\tschemas: NotificationSocketEvent.schemas,\n\t},\n\t[SocketEventType.RIDER_CONNECT]: {\n\t\tctor: RiderConnectSocketEvent,\n\t\tschemas: RiderConnectSocketEvent.schemas,\n\t},\n\t[SocketEventType.RIDER_LOCATION_UPDATE]: {\n\t\tctor: RiderLocationUpdateSocketEvent,\n\t\tschemas: RiderLocationUpdateSocketEvent.schemas,\n\t\tidentifier: RiderLocationUpdateSocketEvent.identifier,\n\t},\n} as const;\n\nexport type Registry = {\n\t[K in keyof typeof REGISTRY]: (typeof REGISTRY)[K] extends EventRegistration<any>\n\t\t? (typeof REGISTRY)[K]\n\t\t: never;\n};\n"]}
@@ -8,6 +8,8 @@ export interface SocketRedisEventInformation {
8
8
  instanceId: string;
9
9
  socketId: string;
10
10
  }
11
+ export declare const entityKey: (entity: EntitySubscription) => string;
12
+ export declare const getEntityEventSocketsKey: (entity: EntitySubscription, eventKey: string) => string;
11
13
  export declare function connectEntityToSocketEvent(entity: EntitySubscription, socketRedisEventInformation: SocketRedisEventInformation): Promise<void>;
12
14
  export declare function getConnectedEntityByType(type: AuthEntityType): Promise<string[]>;
13
15
  export declare function disconnectEntityFromSocketEvent(entity: EntitySubscription, socketRedisEventInformation: SocketRedisEventInformation): Promise<void>;
@@ -22,7 +24,7 @@ export declare function getEntitySubscriptionInfoBatch(entities: Array<{
22
24
  isSubscribed: boolean;
23
25
  instances: string[];
24
26
  }>>;
25
- export declare function isEntityConnected(entity: EntitySubscription): Promise<boolean>;
27
+ export declare function isEntityConnected(entity: EntitySubscription, eventKey: string): Promise<boolean>;
26
28
  export declare function disconnectAllEntitiesFromInstance(entityType?: AuthEntityType): Promise<void>;
27
29
  export declare function getEventSubscribers(eventKey: string): Promise<EntitySubscription[]>;
28
30
  export declare function getEventSubscribersBatch(eventKeys: string[]): Promise<Map<string, EntitySubscription[]>>;
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getEntityEventSocketsKey = exports.entityKey = void 0;
3
4
  exports.connectEntityToSocketEvent = connectEntityToSocketEvent;
4
5
  exports.getConnectedEntityByType = getConnectedEntityByType;
5
6
  exports.disconnectEntityFromSocketEvent = disconnectEntityFromSocketEvent;
@@ -23,10 +24,10 @@ const entityKey = (entity) => {
23
24
  }
24
25
  return key;
25
26
  };
26
- const kEntityEvents = (entity) => `socket:events:${entityKey(entity)}`;
27
- const kEntityInstances = (entity) => `socket:instances:${entityKey(entity)}`;
28
- const kEntityConnection = (entityType) => `socket:conn:${entityType ?? 'all'}`;
29
- const kEventSubscribers = (eventKey) => `socket:event_subs:${eventKey}`;
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;
30
31
  class LRUCache {
31
32
  cache = new Map();
32
33
  maxSize;
@@ -63,13 +64,19 @@ const eventSubscribersCache = new LRUCache(5000);
63
64
  const CACHE_TTL = 5000;
64
65
  async function connectEntityToSocketEvent(entity, socketRedisEventInformation) {
65
66
  const redis = (0, __1.getLibraries)().getRedisService();
66
- const entityKeyStr = entityKey(entity);
67
- const eventData = JSON.stringify(socketRedisEventInformation);
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
+ });
68
77
  await Promise.all([
69
- redis.addToSet(kEntityEvents(entity), eventData),
70
- redis.addToSet(kEntityInstances(entity), socketRedisEventInformation.instanceId),
71
- redis.addToSet(kEntityConnection(entity.type), entity.id),
72
- redis.addToSet(kEventSubscribers(socketRedisEventInformation.eventKey), entityKeyStr),
78
+ redis.addToSet(kEntityEventSockets(entity, socketRedisEventInformation.eventKey), socketData),
79
+ redis.addToSet(kEventSubscribers(socketRedisEventInformation.eventKey), subscriberData),
73
80
  ]);
74
81
  const cacheKey = `${entityKeyStr}:${socketRedisEventInformation.eventKey}`;
75
82
  subscriptionCache.delete(cacheKey);
@@ -77,26 +84,39 @@ async function connectEntityToSocketEvent(entity, socketRedisEventInformation) {
77
84
  }
78
85
  async function getConnectedEntityByType(type) {
79
86
  const redis = (0, __1.getLibraries)().getRedisService();
80
- return redis.getSetMembers(kEntityConnection(type));
87
+ const pattern = `socket:entity:${type}:*`;
88
+ const keys = await redis.redisClient.keys(pattern);
89
+ const idSet = new Set();
90
+ for (const key of keys) {
91
+ const parts = key.split(':');
92
+ idSet.add(parts[3]);
93
+ }
94
+ return Array.from(idSet);
81
95
  }
82
96
  async function disconnectEntityFromSocketEvent(entity, socketRedisEventInformation) {
83
97
  const redis = (0, __1.getLibraries)().getRedisService();
84
- const eventData = JSON.stringify(socketRedisEventInformation);
85
- const entityKeyStr = entityKey(entity);
86
- await redis.removeFromSet(kEntityEvents(entity), eventData);
87
- const remainingEvents = (await redis.getSetMembers(kEntityEvents(entity))).map(r => JSON.parse(r));
88
- const hasInstanceEvents = remainingEvents.some(e => e.instanceId === socketRedisEventInformation.instanceId);
89
- const hasAnyEvents = remainingEvents.length > 0;
90
- const stillSubscribedToEvent = remainingEvents.some(e => e.eventKey === socketRedisEventInformation.eventKey);
98
+ const entityKeyStr = (0, exports.entityKey)(entity);
99
+ const socketData = JSON.stringify({
100
+ instanceId: socketRedisEventInformation.instanceId,
101
+ socketId: socketRedisEventInformation.socketId,
102
+ });
103
+ const entityEventKey = kEntityEventSockets(entity, socketRedisEventInformation.eventKey);
104
+ const eventKey = kEventSubscribers(socketRedisEventInformation.eventKey);
105
+ const [, eventSubscribers] = await Promise.all([
106
+ redis.removeFromSet(entityEventKey, socketData),
107
+ redis.getSetMembers(eventKey),
108
+ ]);
109
+ const remainingSockets = await redis.getSetMembers(entityEventKey);
110
+ const toRemove = eventSubscribers.find(s => {
111
+ const parsed = JSON.parse(s);
112
+ return parsed.entity === entityKeyStr && parsed.socketId === socketRedisEventInformation.socketId;
113
+ });
91
114
  const cleanupOps = [];
92
- if (!hasInstanceEvents) {
93
- cleanupOps.push(redis.removeFromSet(kEntityInstances(entity), socketRedisEventInformation.instanceId));
94
- }
95
- if (!hasAnyEvents) {
96
- cleanupOps.push(redis.removeFromSet(kEntityConnection(entity.type), entity.id));
115
+ if (toRemove) {
116
+ cleanupOps.push(redis.removeFromSet(eventKey, toRemove));
97
117
  }
98
- if (!stillSubscribedToEvent) {
99
- cleanupOps.push(redis.removeFromSet(kEventSubscribers(socketRedisEventInformation.eventKey), entityKeyStr));
118
+ if (remainingSockets.length === 0) {
119
+ cleanupOps.push(redis.deleteCachedObject(entityEventKey));
100
120
  }
101
121
  if (cleanupOps.length > 0) {
102
122
  await Promise.all(cleanupOps);
@@ -106,7 +126,7 @@ async function disconnectEntityFromSocketEvent(entity, socketRedisEventInformati
106
126
  eventSubscribersCache.delete(socketRedisEventInformation.eventKey);
107
127
  }
108
128
  async function getEntitySubscriptionInfo(entity, eventKey) {
109
- const entityKeyStr = entityKey(entity);
129
+ const entityKeyStr = (0, exports.entityKey)(entity);
110
130
  const cacheKey = `${entityKeyStr}:${eventKey}`;
111
131
  const cached = subscriptionCache.get(cacheKey);
112
132
  if (cached) {
@@ -116,17 +136,14 @@ async function getEntitySubscriptionInfo(entity, eventKey) {
116
136
  }
117
137
  }
118
138
  const redis = (0, __1.getLibraries)().getRedisService();
119
- const [events, instances] = await Promise.all([
120
- redis.getSetMembers(kEntityEvents(entity)),
121
- redis.getSetMembers(kEntityInstances(entity)),
122
- ]);
123
- let isSubscribed = false;
124
- for (let i = 0; i < events.length; i++) {
125
- if (events[i].includes(eventKey)) {
126
- isSubscribed = true;
127
- break;
128
- }
139
+ const sockets = await redis.getSetMembers(kEntityEventSockets(entity, eventKey));
140
+ const isSubscribed = sockets.length > 0;
141
+ const instanceSet = new Set();
142
+ for (let i = 0; i < sockets.length; i++) {
143
+ const socketInfo = JSON.parse(sockets[i]);
144
+ instanceSet.add(socketInfo.instanceId);
129
145
  }
146
+ const instances = Array.from(instanceSet);
130
147
  const result = { isSubscribed, instances };
131
148
  subscriptionCache.set(cacheKey, { ...result, timestamp: Date.now() });
132
149
  return result;
@@ -140,7 +157,7 @@ async function getEntitySubscriptionInfoBatch(entities) {
140
157
  const uncached = [];
141
158
  for (let i = 0; i < entities.length; i++) {
142
159
  const { entity, eventKey } = entities[i];
143
- const cacheKey = `${entityKey(entity)}:${eventKey}`;
160
+ const cacheKey = `${(0, exports.entityKey)(entity)}:${eventKey}`;
144
161
  const cached = subscriptionCache.get(cacheKey);
145
162
  if (cached && now - cached.timestamp < CACHE_TTL) {
146
163
  results.set(cacheKey, { isSubscribed: cached.isSubscribed, instances: cached.instances });
@@ -152,69 +169,88 @@ async function getEntitySubscriptionInfoBatch(entities) {
152
169
  if (uncached.length === 0)
153
170
  return results;
154
171
  await Promise.all(uncached.map(async ({ entity, eventKey }) => {
155
- const [events, instances] = await Promise.all([
156
- redis.getSetMembers(kEntityEvents(entity)),
157
- redis.getSetMembers(kEntityInstances(entity)),
158
- ]);
159
- let isSubscribed = false;
160
- for (let i = 0; i < events.length; i++) {
161
- if (events[i].includes(eventKey)) {
162
- isSubscribed = true;
163
- break;
164
- }
172
+ const sockets = await redis.getSetMembers(kEntityEventSockets(entity, eventKey));
173
+ const isSubscribed = sockets.length > 0;
174
+ const instanceSet = new Set();
175
+ for (let i = 0; i < sockets.length; i++) {
176
+ const socketInfo = JSON.parse(sockets[i]);
177
+ instanceSet.add(socketInfo.instanceId);
165
178
  }
166
- const cacheKey = `${entityKey(entity)}:${eventKey}`;
167
- const result = { isSubscribed, instances };
179
+ const cacheKey = `${(0, exports.entityKey)(entity)}:${eventKey}`;
180
+ const result = { isSubscribed, instances: Array.from(instanceSet) };
168
181
  subscriptionCache.set(cacheKey, { ...result, timestamp: now });
169
182
  results.set(cacheKey, result);
170
183
  }));
171
184
  return results;
172
185
  }
173
- async function isEntityConnected(entity) {
186
+ async function isEntityConnected(entity, eventKey) {
174
187
  const redis = (0, __1.getLibraries)().getRedisService();
175
- return redis.isMemberOfSet(kEntityConnection(entity.type), entity.id);
188
+ const sockets = await redis.getSetMembers(kEntityEventSockets(entity, eventKey));
189
+ return sockets.length > 0;
176
190
  }
177
191
  async function disconnectAllEntitiesFromInstance(entityType) {
178
192
  const instanceId = (0, instance_utils_1.getInstanceId)();
179
193
  const redis = (0, __1.getLibraries)().getRedisService();
180
- const connectedEntities = await redis.getSetMembers(kEntityConnection(entityType));
181
- if (!connectedEntities.length)
194
+ const pattern = entityType ? `socket:entity:${entityType}:*` : 'socket:entity:*';
195
+ const entityEventKeys = await redis.redisClient.keys(pattern);
196
+ if (!entityEventKeys.length)
182
197
  return;
183
198
  const affectedEvents = new Set();
184
- await Promise.all(connectedEntities.map(async (entityId) => {
185
- const entity = { id: entityId, type: entityType };
186
- const allEvents = await redis.getSetMembers(kEntityEvents(entity));
187
- if (!allEvents.length)
199
+ const results = await Promise.allSettled(entityEventKeys.map(async (keyPath) => {
200
+ const sockets = await redis.getSetMembers(keyPath);
201
+ if (!sockets.length)
188
202
  return;
189
- const parsedEvents = allEvents.map(e => ({
190
- raw: e,
191
- parsed: JSON.parse(e),
192
- }));
193
- const eventsToRemove = parsedEvents.filter(e => e.parsed.instanceId === instanceId);
194
- if (!eventsToRemove.length)
203
+ const keyParts = keyPath.split(':');
204
+ const eventKey = keyParts.slice(4).join(':');
205
+ const entityKeyStr = `${keyParts[2]}:${keyParts[3]}`;
206
+ const socketsToRemove = sockets.filter(s => {
207
+ try {
208
+ const parsed = JSON.parse(s);
209
+ return parsed.instanceId === instanceId;
210
+ }
211
+ catch {
212
+ return false;
213
+ }
214
+ });
215
+ if (!socketsToRemove.length)
195
216
  return;
196
- eventsToRemove.forEach(e => affectedEvents.add(e.parsed.eventKey));
197
- await Promise.all(eventsToRemove.map(e => redis.removeFromSet(kEntityEvents(entity), e.raw)));
198
- const remainingEvents = parsedEvents.filter(e => !eventsToRemove.includes(e));
199
- const cleanupOps = [];
200
- if (!remainingEvents.some(e => e.parsed.instanceId === instanceId)) {
201
- cleanupOps.push(redis.removeFromSet(kEntityInstances(entity), instanceId));
217
+ affectedEvents.add(eventKey);
218
+ await Promise.all(socketsToRemove.map(s => redis.removeFromSet(keyPath, s)));
219
+ const eventCleanup = [];
220
+ for (const socketStr of socketsToRemove) {
221
+ try {
222
+ const parsed = JSON.parse(socketStr);
223
+ const eventSubs = await redis.getSetMembers(kEventSubscribers(eventKey));
224
+ const toRemove = eventSubs.find(s => {
225
+ try {
226
+ const sub = JSON.parse(s);
227
+ return sub.entity === entityKeyStr && sub.socketId === parsed.socketId;
228
+ }
229
+ catch {
230
+ return false;
231
+ }
232
+ });
233
+ if (toRemove) {
234
+ eventCleanup.push(redis.removeFromSet(kEventSubscribers(eventKey), toRemove));
235
+ }
236
+ }
237
+ catch (err) {
238
+ console.error(`[Socket] Failed to cleanup subscriber for ${eventKey}:`, err);
239
+ }
202
240
  }
203
- if (remainingEvents.length === 0) {
204
- cleanupOps.push(redis.removeFromSet(kEntityConnection(entityType), entityId));
241
+ const remainingSockets = sockets.length - socketsToRemove.length;
242
+ if (remainingSockets === 0) {
243
+ eventCleanup.push(redis.deleteCachedObject(keyPath));
205
244
  }
206
- const remainingEventKeys = new Set(remainingEvents.map(e => e.parsed.eventKey));
207
- const removedEventKeys = eventsToRemove
208
- .map(e => e.parsed.eventKey)
209
- .filter(key => !remainingEventKeys.has(key));
210
- removedEventKeys.forEach(eventKey => {
211
- cleanupOps.push(redis.removeFromSet(kEventSubscribers(eventKey), entityKey(entity)));
212
- });
213
- if (cleanupOps.length > 0) {
214
- await Promise.all(cleanupOps);
245
+ if (eventCleanup.length > 0) {
246
+ await Promise.all(eventCleanup);
215
247
  }
216
- subscriptionCache.delete(entityKey(entity));
248
+ subscriptionCache.delete(`${entityKeyStr}:${eventKey}`);
217
249
  }));
250
+ const failures = results.filter(r => r.status === 'rejected');
251
+ if (failures.length > 0) {
252
+ console.error(`[Socket] ${failures.length} cleanup operations failed during instance disconnect`);
253
+ }
218
254
  affectedEvents.forEach(eventKey => eventSubscribersCache.delete(eventKey));
219
255
  }
220
256
  async function getEventSubscribers(eventKey) {
@@ -224,32 +260,38 @@ async function getEventSubscribers(eventKey) {
224
260
  return cached.subscribers;
225
261
  }
226
262
  const redis = (0, __1.getLibraries)().getRedisService();
227
- const entityKeys = await redis.getSetMembers(kEventSubscribers(eventKey));
228
- if (entityKeys.length === 0) {
263
+ const subscriberData = await redis.getSetMembers(kEventSubscribers(eventKey));
264
+ if (subscriberData.length === 0) {
229
265
  const empty = [];
230
266
  eventSubscribersCache.set(eventKey, { subscribers: empty, timestamp: now });
231
267
  return empty;
232
268
  }
233
- const subscribers = new Array(entityKeys.length);
234
- for (let i = 0; i < entityKeys.length; i++) {
235
- const colonIndex = entityKeys[i].indexOf(':');
236
- const type = entityKeys[i].substring(0, colonIndex);
237
- const id = entityKeys[i].substring(colonIndex + 1);
238
- subscribers[i] = {
239
- id,
240
- type: type === 'default' ? undefined : type,
241
- };
269
+ const entityMap = new Map();
270
+ for (let i = 0; i < subscriberData.length; i++) {
271
+ const sub = JSON.parse(subscriberData[i]);
272
+ const entityKeyStr = sub.entity;
273
+ if (!entityMap.has(entityKeyStr)) {
274
+ const colonIndex = entityKeyStr.indexOf(':');
275
+ const type = entityKeyStr.substring(0, colonIndex);
276
+ const id = entityKeyStr.substring(colonIndex + 1);
277
+ entityMap.set(entityKeyStr, {
278
+ id,
279
+ type: type === 'default' ? undefined : type,
280
+ });
281
+ }
242
282
  }
283
+ const subscribers = Array.from(entityMap.values());
243
284
  eventSubscribersCache.set(eventKey, { subscribers, timestamp: now });
244
285
  return subscribers;
245
286
  }
246
287
  async function getEventSubscribersBatch(eventKeys) {
247
288
  const redis = (0, __1.getLibraries)().getRedisService();
248
289
  const results = new Map();
290
+ const now = Date.now();
249
291
  const uncached = [];
250
292
  for (const eventKey of eventKeys) {
251
293
  const cached = eventSubscribersCache.get(eventKey);
252
- if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
294
+ if (cached && now - cached.timestamp < CACHE_TTL) {
253
295
  results.set(eventKey, cached.subscribers);
254
296
  }
255
297
  else {
@@ -258,15 +300,23 @@ async function getEventSubscribersBatch(eventKeys) {
258
300
  }
259
301
  if (uncached.length > 0) {
260
302
  await Promise.all(uncached.map(async (eventKey) => {
261
- const entityKeys = await redis.getSetMembers(kEventSubscribers(eventKey));
262
- const subscribers = entityKeys.map(key => {
263
- const [type, id] = key.split(':');
264
- return {
265
- id,
266
- type: type === 'default' ? undefined : type,
267
- };
268
- });
269
- eventSubscribersCache.set(eventKey, { subscribers, timestamp: Date.now() });
303
+ const subscriberData = await redis.getSetMembers(kEventSubscribers(eventKey));
304
+ const entityMap = new Map();
305
+ for (let i = 0; i < subscriberData.length; i++) {
306
+ const sub = JSON.parse(subscriberData[i]);
307
+ const entityKeyStr = sub.entity;
308
+ if (!entityMap.has(entityKeyStr)) {
309
+ const colonIndex = entityKeyStr.indexOf(':');
310
+ const type = entityKeyStr.substring(0, colonIndex);
311
+ const id = entityKeyStr.substring(colonIndex + 1);
312
+ entityMap.set(entityKeyStr, {
313
+ id,
314
+ type: type === 'default' ? undefined : type,
315
+ });
316
+ }
317
+ }
318
+ const subscribers = Array.from(entityMap.values());
319
+ eventSubscribersCache.set(eventKey, { subscribers, timestamp: now });
270
320
  results.set(eventKey, subscribers);
271
321
  }));
272
322
  }
@@ -285,24 +335,28 @@ async function getEventSubscribersByType(eventKey, entityType) {
285
335
  return filtered;
286
336
  }
287
337
  const redis = (0, __1.getLibraries)().getRedisService();
288
- const entityKeys = await redis.getSetMembers(kEventSubscribers(eventKey));
338
+ const subscriberData = await redis.getSetMembers(kEventSubscribers(eventKey));
289
339
  const typePrefix = `${entityType}:`;
290
340
  const filtered = [];
291
- const all = [];
292
- for (let i = 0; i < entityKeys.length; i++) {
293
- const key = entityKeys[i];
294
- const colonIndex = key.indexOf(':');
295
- const type = key.substring(0, colonIndex);
296
- const id = key.substring(colonIndex + 1);
297
- const sub = {
298
- id,
299
- type: type === 'default' ? undefined : type,
300
- };
301
- all.push(sub);
302
- if (key.startsWith(typePrefix)) {
303
- filtered.push(sub);
341
+ const entityMap = new Map();
342
+ for (let i = 0; i < subscriberData.length; i++) {
343
+ const sub = JSON.parse(subscriberData[i]);
344
+ const entityKeyStr = sub.entity;
345
+ if (!entityMap.has(entityKeyStr)) {
346
+ const colonIndex = entityKeyStr.indexOf(':');
347
+ const type = entityKeyStr.substring(0, colonIndex);
348
+ const id = entityKeyStr.substring(colonIndex + 1);
349
+ const entity = {
350
+ id,
351
+ type: type === 'default' ? undefined : type,
352
+ };
353
+ entityMap.set(entityKeyStr, entity);
354
+ if (entityKeyStr.startsWith(typePrefix)) {
355
+ filtered.push(entity);
356
+ }
304
357
  }
305
358
  }
359
+ const all = Array.from(entityMap.values());
306
360
  eventSubscribersCache.set(eventKey, { subscribers: all, timestamp: now });
307
361
  return filtered;
308
362
  }
@@ -1 +1 @@
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';\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\nconst 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// Pre-built key patterns (avoid string concatenation overhead)\nconst kEntityEvents = (entity: EntitySubscription) => `socket:events:${entityKey(entity)}`;\nconst kEntityInstances = (entity: EntitySubscription) => `socket:instances:${entityKey(entity)}`;\nconst kEntityConnection = (entityType?: AuthEntityType) => `socket:conn:${entityType ?? 'all'}`;\nconst kEventSubscribers = (eventKey: string) => `socket:event_subs:${eventKey}`;\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<string, { isSubscribed: boolean; instances: string[]; timestamp: number }>(\n\t10000\n);\n\n// Cache event subscribers (who's listening to what event)\nconst eventSubscribersCache = new LRUCache<string, { subscribers: EntitySubscription[]; timestamp: number }>(5000);\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\tconst eventData = JSON.stringify(socketRedisEventInformation);\n\n\t// Single Redis pipeline - all ops in one round-trip\n\tawait Promise.all([\n\t\tredis.addToSet(kEntityEvents(entity), eventData),\n\t\tredis.addToSet(kEntityInstances(entity), socketRedisEventInformation.instanceId),\n\t\tredis.addToSet(kEntityConnection(entity.type), entity.id),\n\t\tredis.addToSet(kEventSubscribers(socketRedisEventInformation.eventKey), entityKeyStr),\n\t]);\n\n\t// Lazy cache invalidation (only if cached)\n\tconst cacheKey = `${entityKeyStr}:${socketRedisEventInformation.eventKey}`;\n\tsubscriptionCache.delete(cacheKey);\n\teventSubscribersCache.delete(socketRedisEventInformation.eventKey);\n}\n\nexport async function getConnectedEntityByType(type: AuthEntityType): Promise<string[]> {\n\tconst redis = getLibraries().getRedisService();\n\treturn redis.getSetMembers(kEntityConnection(type));\n}\n\nexport async function disconnectEntityFromSocketEvent(\n\tentity: EntitySubscription,\n\tsocketRedisEventInformation: SocketRedisEventInformation\n) {\n\tconst redis = getLibraries().getRedisService();\n\tconst eventData = JSON.stringify(socketRedisEventInformation);\n\tconst entityKeyStr = entityKey(entity);\n\n\tawait redis.removeFromSet(kEntityEvents(entity), eventData);\n\n\t// Check remaining events in parallel with removal\n\tconst remainingEvents = (await redis.getSetMembers(kEntityEvents(entity))).map(\n\t\tr => JSON.parse(r) as SocketRedisEventInformation\n\t);\n\n\tconst hasInstanceEvents = remainingEvents.some(e => e.instanceId === socketRedisEventInformation.instanceId);\n\tconst hasAnyEvents = remainingEvents.length > 0;\n\t\n\t// Check if entity still subscribed to this specific event\n\tconst stillSubscribedToEvent = remainingEvents.some(e => e.eventKey === socketRedisEventInformation.eventKey);\n\n\t// Batch cleanup operations\n\tconst cleanupOps = [];\n\tif (!hasInstanceEvents) {\n\t\tcleanupOps.push(redis.removeFromSet(kEntityInstances(entity), socketRedisEventInformation.instanceId));\n\t}\n\tif (!hasAnyEvents) {\n\t\tcleanupOps.push(redis.removeFromSet(kEntityConnection(entity.type), entity.id));\n\t}\n\t// Remove from reverse index if no longer subscribed to this event\n\tif (!stillSubscribedToEvent) {\n\t\tcleanupOps.push(redis.removeFromSet(kEventSubscribers(socketRedisEventInformation.eventKey), entityKeyStr));\n\t}\n\n\tif (cleanupOps.length > 0) {\n\t\tawait Promise.all(cleanupOps);\n\t}\n\n\t// Invalidate caches on disconnection\n\tconst cacheKey = `${entityKeyStr}:${socketRedisEventInformation.eventKey}`;\n\tsubscriptionCache.delete(cacheKey);\n\teventSubscribersCache.delete(socketRedisEventInformation.eventKey);\n}\n\n// Zero-overhead hot path with inline cache check\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 (avoid function call overhead)\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// Single parallel fetch\n\tconst [events, instances] = await Promise.all([\n\t\tredis.getSetMembers(kEntityEvents(entity)),\n\t\tredis.getSetMembers(kEntityInstances(entity)),\n\t]);\n\n\t// Optimized check - early return on first match\n\tlet isSubscribed = false;\n\tfor (let i = 0; i < events.length; i++) {\n\t\tif (events[i].includes(eventKey)) {\n\t\t\tisSubscribed = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Cache for next time\n\tconst result = { isSubscribed, instances };\n\tsubscriptionCache.set(cacheKey, { ...result, timestamp: Date.now() });\n\n\treturn result;\n}\n\n// Ultra-optimized batch with minimal allocations\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\t\n\t// Pre-allocate uncached array\n\tconst uncached: typeof entities = [];\n\t\n\t// Single pass: check cache and separate\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\t// Early return if all cached\n\tif (uncached.length === 0) return results;\n\n\t// Fetch all uncached in parallel\n\tawait Promise.all(\n\t\tuncached.map(async ({ entity, eventKey }) => {\n\t\t\tconst [events, instances] = await Promise.all([\n\t\t\t\tredis.getSetMembers(kEntityEvents(entity)),\n\t\t\t\tredis.getSetMembers(kEntityInstances(entity)),\n\t\t\t]);\n\n\t\t\t// Fast string search instead of JSON parse\n\t\t\tlet isSubscribed = false;\n\t\t\tfor (let i = 0; i < events.length; i++) {\n\t\t\t\tif (events[i].includes(eventKey)) {\n\t\t\t\t\tisSubscribed = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst cacheKey = `${entityKey(entity)}:${eventKey}`;\n\t\t\tconst result = { isSubscribed, instances };\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): Promise<boolean> {\n\tconst redis = getLibraries().getRedisService();\n\treturn redis.isMemberOfSet(kEntityConnection(entity.type), entity.id);\n}\n\nexport async function disconnectAllEntitiesFromInstance(entityType?: AuthEntityType) {\n\tconst instanceId = getInstanceId();\n\tconst redis = getLibraries().getRedisService();\n\n\tconst connectedEntities = await redis.getSetMembers(kEntityConnection(entityType));\n\tif (!connectedEntities.length) return;\n\n\tconst affectedEvents = new Set<string>();\n\n\t// Process all entities in parallel\n\tawait Promise.all(\n\t\tconnectedEntities.map(async entityId => {\n\t\t\tconst entity: EntitySubscription = { id: entityId, type: entityType };\n\t\t\tconst allEvents = await redis.getSetMembers(kEntityEvents(entity));\n\t\t\tif (!allEvents.length) return;\n\n\t\t\t// Parse once, use many times\n\t\t\tconst parsedEvents = allEvents.map(e => ({\n\t\t\t\traw: e,\n\t\t\t\tparsed: JSON.parse(e) as SocketRedisEventInformation,\n\t\t\t}));\n\n\t\t\tconst eventsToRemove = parsedEvents.filter(e => e.parsed.instanceId === instanceId);\n\t\t\tif (!eventsToRemove.length) return;\n\n\t\t\t// Track events that will be affected\n\t\t\teventsToRemove.forEach(e => affectedEvents.add(e.parsed.eventKey));\n\n\t\t\t// Batch remove events\n\t\t\tawait Promise.all(eventsToRemove.map(e => redis.removeFromSet(kEntityEvents(entity), e.raw)));\n\n\t\t\t// Check if cleanup needed (reuse parsed data)\n\t\t\tconst remainingEvents = parsedEvents.filter(e => !eventsToRemove.includes(e));\n\t\t\tconst cleanupOps = [];\n\n\t\t\tif (!remainingEvents.some(e => e.parsed.instanceId === instanceId)) {\n\t\t\t\tcleanupOps.push(redis.removeFromSet(kEntityInstances(entity), instanceId));\n\t\t\t}\n\n\t\t\tif (remainingEvents.length === 0) {\n\t\t\t\tcleanupOps.push(redis.removeFromSet(kEntityConnection(entityType), entityId));\n\t\t\t}\n\n\t\t\t// Check which events this entity is no longer subscribed to\n\t\t\tconst remainingEventKeys = new Set(remainingEvents.map(e => e.parsed.eventKey));\n\t\t\tconst removedEventKeys = eventsToRemove\n\t\t\t\t.map(e => e.parsed.eventKey)\n\t\t\t\t.filter(key => !remainingEventKeys.has(key));\n\n\t\t\t// Remove from reverse index for events no longer subscribed\n\t\t\tremovedEventKeys.forEach(eventKey => {\n\t\t\t\tcleanupOps.push(redis.removeFromSet(kEventSubscribers(eventKey), entityKey(entity)));\n\t\t\t});\n\n\t\t\tif (cleanupOps.length > 0) {\n\t\t\t\tawait Promise.all(cleanupOps);\n\t\t\t}\n\n\t\t\t// Clear cache for this entity\n\t\t\tsubscriptionCache.delete(entityKey(entity));\n\t\t})\n\t);\n\n\t// Invalidate event subscriber caches for affected events\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\t\n\tif (cached && now - cached.timestamp < CACHE_TTL) {\n\t\treturn cached.subscribers;\n\t}\n\n\tconst redis = getLibraries().getRedisService();\n\tconst entityKeys = await redis.getSetMembers(kEventSubscribers(eventKey));\n\n\tif (entityKeys.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// Optimized parsing - single pass, no intermediate arrays\n\tconst subscribers: EntitySubscription[] = new Array(entityKeys.length);\n\tfor (let i = 0; i < entityKeys.length; i++) {\n\t\tconst colonIndex = entityKeys[i].indexOf(':');\n\t\tconst type = entityKeys[i].substring(0, colonIndex);\n\t\tconst id = entityKeys[i].substring(colonIndex + 1);\n\t\t\n\t\tsubscribers[i] = {\n\t\t\tid,\n\t\t\ttype: type === 'default' ? undefined : (type as AuthEntityType),\n\t\t};\n\t}\n\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\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 && Date.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 entityKeys = await redis.getSetMembers(kEventSubscribers(eventKey));\n\n\t\t\t\tconst subscribers: EntitySubscription[] = entityKeys.map(key => {\n\t\t\t\t\tconst [type, id] = key.split(':');\n\t\t\t\t\treturn {\n\t\t\t\t\t\tid,\n\t\t\t\t\t\ttype: type === 'default' ? undefined : (type as AuthEntityType),\n\t\t\t\t\t};\n\t\t\t\t});\n\n\t\t\t\teventSubscribersCache.set(eventKey, { subscribers, timestamp: Date.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\t\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 entityKeys = await redis.getSetMembers(kEventSubscribers(eventKey));\n\tconst typePrefix = `${entityType}:`;\n\t\n\tconst filtered: EntitySubscription[] = [];\n\tconst all: EntitySubscription[] = [];\n\t\n\tfor (let i = 0; i < entityKeys.length; i++) {\n\t\tconst key = entityKeys[i];\n\t\tconst colonIndex = key.indexOf(':');\n\t\tconst type = key.substring(0, colonIndex);\n\t\tconst id = key.substring(colonIndex + 1);\n\t\t\n\t\tconst sub: EntitySubscription = {\n\t\t\tid,\n\t\t\ttype: type === 'default' ? undefined : (type as AuthEntityType),\n\t\t};\n\t\t\n\t\tall.push(sub);\n\t\tif (key.startsWith(typePrefix)) {\n\t\t\tfiltered.push(sub);\n\t\t}\n\t}\n\n\t// Cache all subscribers for future calls\n\teventSubscribersCache.set(eventKey, { subscribers: all, timestamp: now });\n\t\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"]}
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';\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\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\tconst keys = await redis.redisClient.keys(pattern);\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\tidSet.add(parts[3]); // Extract ID from socket:entity:type:id:eventKey\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\n\tconst socketData = JSON.stringify({\n\t\tinstanceId: socketRedisEventInformation.instanceId,\n\t\tsocketId: socketRedisEventInformation.socketId,\n\t});\n\n\tconst entityEventKey = kEntityEventSockets(entity, socketRedisEventInformation.eventKey);\n\tconst eventKey = kEventSubscribers(socketRedisEventInformation.eventKey);\n\n\t// Parallel operations for speed\n\tconst [, eventSubscribers] = await Promise.all([\n\t\tredis.removeFromSet(entityEventKey, socketData),\n\t\tredis.getSetMembers(eventKey),\n\t]);\n\n\t// Check remaining sockets AFTER removal (atomic check)\n\tconst remainingSockets = await redis.getSetMembers(entityEventKey);\n\n\t// Remove from event subscribers\n\tconst toRemove = eventSubscribers.find(s => {\n\t\tconst parsed = JSON.parse(s);\n\t\treturn parsed.entity === entityKeyStr && parsed.socketId === socketRedisEventInformation.socketId;\n\t});\n\n\tconst cleanupOps = [];\n\tif (toRemove) {\n\t\tcleanupOps.push(redis.removeFromSet(eventKey, toRemove));\n\t}\n\n\t// If no more sockets for this event, delete the key (safe after atomic check)\n\tif (remainingSockets.length === 0) {\n\t\tcleanupOps.push(redis.deleteCachedObject(entityEventKey));\n\t}\n\n\tif (cleanupOps.length > 0) {\n\t\tawait Promise.all(cleanupOps);\n\t}\n\n\t// Invalidate caches\n\tconst cacheKey = `${entityKeyStr}:${socketRedisEventInformation.eventKey}`;\n\tsubscriptionCache.delete(cacheKey);\n\teventSubscribersCache.delete(socketRedisEventInformation.eventKey);\n}\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 redis.redisClient.keys(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"]}
@@ -22,7 +22,7 @@ Perfect for sharing types between frontend and backend applications.
22
22
 
23
23
  ## Version
24
24
 
25
- Version: 1.2.22
25
+ Version: 1.2.24
26
26
 
27
27
  ## Dependencies
28
28
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lyxa.ai/types",
3
- "version": "1.2.22",
3
+ "version": "1.2.24",
4
4
  "description": "Lyxa type definitions and validation schemas for both frontend and backend",
5
5
  "author": "elie <42282499+Internalizable@users.noreply.github.com>",
6
6
  "license": "MIT",
@@ -64,7 +64,7 @@ export declare function createPaginatorObject<T extends AnyParamConstructor<any>
64
64
  };
65
65
  items: any[];
66
66
  }>;
67
- export declare function paginateAggregation(model: any, pipeline: any[], page?: number, size?: number, sort?: any): Promise<{
67
+ export declare function paginateAggregation(model: any, pipeline: any[], page?: number, size?: number, sort?: any, populateOptions?: any): Promise<{
68
68
  metadata: {
69
69
  page: number;
70
70
  size: number;
@@ -59,7 +59,7 @@ function createPaginatorObject(model, itemSchema, transformFn) {
59
59
  return PaginatedSchema.parse(paginatedResult);
60
60
  };
61
61
  }
62
- async function paginateAggregation(model, pipeline, page = 1, size = 10, sort = { createdAt: -1 }) {
62
+ async function paginateAggregation(model, pipeline, page = 1, size = 10, sort = { createdAt: -1 }, populateOptions) {
63
63
  const skip = (page - 1) * size;
64
64
  const limit = size;
65
65
  const pipelineWithCount = [...pipeline];
@@ -72,6 +72,7 @@ async function paginateAggregation(model, pipeline, page = 1, size = 10, sort =
72
72
  paginatedPipeline.push({ $skip: skip });
73
73
  paginatedPipeline.push({ $limit: limit });
74
74
  const data = await model.aggregate(paginatedPipeline).exec();
75
+ const populatedData = populateOptions ? await model.populate(data, populateOptions) : data;
75
76
  return {
76
77
  metadata: {
77
78
  page,
@@ -79,7 +80,7 @@ async function paginateAggregation(model, pipeline, page = 1, size = 10, sort =
79
80
  totalElements,
80
81
  totalPages,
81
82
  },
82
- documents: data,
83
+ documents: populatedData,
83
84
  };
84
85
  }
85
86
  //# sourceMappingURL=pagination.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pagination.js","sourceRoot":"/","sources":["utilities/pagination.ts"],"names":[],"mappings":"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","sourcesContent":["import { DocumentType, ReturnModelType } from '@typegoose/typegoose';\nimport { FilterQuery, PopulateOptions } from 'mongoose';\nimport { z } from 'zod';\nimport { AnyParamConstructor } from '@typegoose/typegoose/lib/types';\nimport { FilterDTO, PaginatedResponse } from './validation';\n\n/**\n * A helper to create a paginated Zod schema for an item type.\n */\nexport function createPaginatedSchema<ItemType extends z.ZodTypeAny>(itemSchema: ItemType) {\n\treturn z.object({\n\t\tmetadata: z.object({\n\t\t\tpage: z.number(),\n\t\t\tsize: z.number(),\n\t\t\ttotalElements: z.number(),\n\t\t\ttotalPages: z.number(),\n\t\t}),\n\t\titems: z.array(itemSchema),\n\t});\n}\n\nexport interface RawPaginatedResult<T extends AnyParamConstructor<any>> {\n\tmetadata: {\n\t\tpage: number;\n\t\tsize: number;\n\t\ttotalElements: number;\n\t\ttotalPages: number;\n\t};\n\tdocuments: DocumentType<T>[];\n}\n\n/**\n * The common pagination options.\n */\nexport interface PaginatorOptions<TClass extends AnyParamConstructor<any>> {\n\tquery?: FilterQuery<DocumentType<TClass>>;\n\tpage?: number;\n\tsize?: number;\n\tsort?: Record<string, 1 | -1>;\n\tselect?: Record<string, 0 | 1>;\n\tpopulate?: PopulateOptions | (PopulateOptions | string)[];\n}\n\n/**\n * This internal function wraps the common query logic:\n * - filter, page, size, sort, populate\n * - fetch documents, count documents\n * - compute totalPages\n * Returns a standard object with `metadata` & `documents`.\n */\nasync function _basePaginate<T extends AnyParamConstructor<any>>(\n\tmodel: ReturnModelType<T>,\n\toptions: PaginatorOptions<T>\n): Promise<RawPaginatedResult<T>> {\n\tconst { query = {}, page = 1, size = 10, sort = {}, select, populate } = options;\n\n\tconst skip = (page - 1) * size;\n\n\tlet result = model.find(query).sort(sort).skip(skip).limit(size);\n\n\tif (select) {\n\t\tresult = result.select(select) as any;\n\t}\n\tif (populate) {\n\t\tresult = result.populate(populate);\n\t}\n\n\tconst [documents, totalElements] = await Promise.all([result.exec(), model.countDocuments(query)]);\n\n\tconst totalPages = Math.ceil(totalElements / size);\n\n\treturn {\n\t\tmetadata: {\n\t\t\tpage,\n\t\t\tsize,\n\t\t\ttotalElements,\n\t\t\ttotalPages,\n\t\t},\n\t\tdocuments: documents as unknown as DocumentType<T>[],\n\t};\n}\n\n/**\n * Creates a paginator returning raw documents.\n *\n * @param model The Typegoose model\n * @returns A function that, when passed `PaginatorOptions`, returns raw docs + metadata.\n */\nexport function createRawDocumentPaginatorObject<T extends AnyParamConstructor<any>>(\n\tmodel: ReturnModelType<T>\n) {\n\treturn async function paginate(options: PaginatorOptions<T>): Promise<RawPaginatedResult<T>> {\n\t\tconst { metadata, documents } = await _basePaginate(model, options);\n\n\t\treturn {\n\t\t\tmetadata,\n\t\t\tdocuments,\n\t\t};\n\t};\n}\n\n/**\n * Creates a paginator that returns Zod-validated items.\n *\n * @param model The Typegoose model\n * @param itemSchema A Zod schema describing the shape of each item\n * @param transformFn Optional transform function to convert raw doc -> item\n */\nexport function createPaginatorObject<T extends AnyParamConstructor<any>>(\n\tmodel: ReturnModelType<T>,\n\titemSchema: z.ZodTypeAny,\n\ttransformFn?: (doc: DocumentType<T>) => z.infer<typeof itemSchema>\n) {\n\tconst PaginatedSchema = createPaginatedSchema(itemSchema);\n\n\treturn async function paginate(options: PaginatorOptions<T>) {\n\t\tconst { metadata, documents } = await _basePaginate(model, options);\n\n\t\tconst items = transformFn ? documents.map(transformFn) : documents;\n\n\t\tconst paginatedResult = {\n\t\t\tmetadata,\n\t\t\titems,\n\t\t};\n\n\t\treturn PaginatedSchema.parse(paginatedResult);\n\t};\n}\nexport async function paginateAggregation(\n\tmodel: any,\n\tpipeline: any[],\n\tpage: number = 1,\n\tsize: number = 10,\n\tsort: any = { createdAt: -1 }\n) {\n\t// Calculate skip and limit based on the page and size\n\tconst skip = (page - 1) * size;\n\tconst limit = size;\n\n\t// Copy the pipeline to avoid mutation\n\tconst pipelineWithCount = [...pipeline];\n\n\t// Step 1: Calculate total count\n\tpipelineWithCount.push({ $count: 'totalCount' });\n\n\t// Step 2: Execute to get total count\n\tconst totalCountResult = await model.aggregate(pipelineWithCount).exec();\n\tconst totalElements = totalCountResult?.[0]?.totalCount || 0;\n\tconst totalPages = Math.ceil(totalElements / size);\n\n\t// Step 3: Apply pagination to the original pipeline\n\tconst paginatedPipeline = [...pipeline];\n\tpaginatedPipeline.push({ $sort: sort });\n\tpaginatedPipeline.push({ $skip: skip });\n\tpaginatedPipeline.push({ $limit: limit });\n\n\t// Step 4: Execute the paginated pipeline\n\tconst data = await model.aggregate(paginatedPipeline).exec();\n\n\t// Return the paginated data with metadata\n\treturn {\n\t\tmetadata: {\n\t\t\tpage,\n\t\t\tsize,\n\t\t\ttotalElements,\n\t\t\ttotalPages,\n\t\t},\n\t\tdocuments: data,\n\t};\n}\n"]}
1
+ {"version":3,"file":"pagination.js","sourceRoot":"/","sources":["utilities/pagination.ts"],"names":[],"mappings":"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","sourcesContent":["import { DocumentType, ReturnModelType } from '@typegoose/typegoose';\nimport { FilterQuery, PopulateOptions } from 'mongoose';\nimport { z } from 'zod';\nimport { AnyParamConstructor } from '@typegoose/typegoose/lib/types';\nimport { FilterDTO, PaginatedResponse } from './validation';\n\n/**\n * A helper to create a paginated Zod schema for an item type.\n */\nexport function createPaginatedSchema<ItemType extends z.ZodTypeAny>(itemSchema: ItemType) {\n\treturn z.object({\n\t\tmetadata: z.object({\n\t\t\tpage: z.number(),\n\t\t\tsize: z.number(),\n\t\t\ttotalElements: z.number(),\n\t\t\ttotalPages: z.number(),\n\t\t}),\n\t\titems: z.array(itemSchema),\n\t});\n}\n\nexport interface RawPaginatedResult<T extends AnyParamConstructor<any>> {\n\tmetadata: {\n\t\tpage: number;\n\t\tsize: number;\n\t\ttotalElements: number;\n\t\ttotalPages: number;\n\t};\n\tdocuments: DocumentType<T>[];\n}\n\n/**\n * The common pagination options.\n */\nexport interface PaginatorOptions<TClass extends AnyParamConstructor<any>> {\n\tquery?: FilterQuery<DocumentType<TClass>>;\n\tpage?: number;\n\tsize?: number;\n\tsort?: Record<string, 1 | -1>;\n\tselect?: Record<string, 0 | 1>;\n\tpopulate?: PopulateOptions | (PopulateOptions | string)[];\n}\n\n/**\n * This internal function wraps the common query logic:\n * - filter, page, size, sort, populate\n * - fetch documents, count documents\n * - compute totalPages\n * Returns a standard object with `metadata` & `documents`.\n */\nasync function _basePaginate<T extends AnyParamConstructor<any>>(\n\tmodel: ReturnModelType<T>,\n\toptions: PaginatorOptions<T>\n): Promise<RawPaginatedResult<T>> {\n\tconst { query = {}, page = 1, size = 10, sort = {}, select, populate } = options;\n\n\tconst skip = (page - 1) * size;\n\n\tlet result = model.find(query).sort(sort).skip(skip).limit(size);\n\n\tif (select) {\n\t\tresult = result.select(select) as any;\n\t}\n\tif (populate) {\n\t\tresult = result.populate(populate);\n\t}\n\n\tconst [documents, totalElements] = await Promise.all([result.exec(), model.countDocuments(query)]);\n\n\tconst totalPages = Math.ceil(totalElements / size);\n\n\treturn {\n\t\tmetadata: {\n\t\t\tpage,\n\t\t\tsize,\n\t\t\ttotalElements,\n\t\t\ttotalPages,\n\t\t},\n\t\tdocuments: documents as unknown as DocumentType<T>[],\n\t};\n}\n\n/**\n * Creates a paginator returning raw documents.\n *\n * @param model The Typegoose model\n * @returns A function that, when passed `PaginatorOptions`, returns raw docs + metadata.\n */\nexport function createRawDocumentPaginatorObject<T extends AnyParamConstructor<any>>(\n\tmodel: ReturnModelType<T>\n) {\n\treturn async function paginate(options: PaginatorOptions<T>): Promise<RawPaginatedResult<T>> {\n\t\tconst { metadata, documents } = await _basePaginate(model, options);\n\n\t\treturn {\n\t\t\tmetadata,\n\t\t\tdocuments,\n\t\t};\n\t};\n}\n\n/**\n * Creates a paginator that returns Zod-validated items.\n *\n * @param model The Typegoose model\n * @param itemSchema A Zod schema describing the shape of each item\n * @param transformFn Optional transform function to convert raw doc -> item\n */\nexport function createPaginatorObject<T extends AnyParamConstructor<any>>(\n\tmodel: ReturnModelType<T>,\n\titemSchema: z.ZodTypeAny,\n\ttransformFn?: (doc: DocumentType<T>) => z.infer<typeof itemSchema>\n) {\n\tconst PaginatedSchema = createPaginatedSchema(itemSchema);\n\n\treturn async function paginate(options: PaginatorOptions<T>) {\n\t\tconst { metadata, documents } = await _basePaginate(model, options);\n\n\t\tconst items = transformFn ? documents.map(transformFn) : documents;\n\n\t\tconst paginatedResult = {\n\t\t\tmetadata,\n\t\t\titems,\n\t\t};\n\n\t\treturn PaginatedSchema.parse(paginatedResult);\n\t};\n}\nexport async function paginateAggregation(\n\tmodel: any,\n\tpipeline: any[],\n\tpage: number = 1,\n\tsize: number = 10,\n\tsort: any = { createdAt: -1 },\n\tpopulateOptions?: any\n) {\n\t// Calculate skip and limit based on the page and size\n\tconst skip = (page - 1) * size;\n\tconst limit = size;\n\n\t// Copy the pipeline to avoid mutation\n\tconst pipelineWithCount = [...pipeline];\n\n\t// Step 1: Calculate total count\n\tpipelineWithCount.push({ $count: 'totalCount' });\n\n\t// Step 2: Execute to get total count\n\tconst totalCountResult = await model.aggregate(pipelineWithCount).exec();\n\tconst totalElements = totalCountResult?.[0]?.totalCount || 0;\n\tconst totalPages = Math.ceil(totalElements / size);\n\n\t// Step 3: Apply pagination to the original pipeline\n\tconst paginatedPipeline = [...pipeline];\n\tpaginatedPipeline.push({ $sort: sort });\n\tpaginatedPipeline.push({ $skip: skip });\n\tpaginatedPipeline.push({ $limit: limit });\n\n\t// Step 4: Execute the paginated pipeline\n\tconst data = await model.aggregate(paginatedPipeline).exec();\n\n\t// Step 5: Optional populate\n\tconst populatedData = populateOptions ? await model.populate(data, populateOptions) : data;\n\n\t// Return the paginated data with metadata\n\treturn {\n\t\tmetadata: {\n\t\t\tpage,\n\t\t\tsize,\n\t\t\ttotalElements,\n\t\t\ttotalPages,\n\t\t},\n\t\tdocuments: populatedData,\n\t};\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lyxa.ai/core",
3
- "version": "1.2.22",
3
+ "version": "1.2.24",
4
4
  "description": "The Core system of the Lyxa services.",
5
5
  "author": "elie <42282499+Internalizable@users.noreply.github.com>",
6
6
  "license": "MIT",