@qwickapps/server 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. package/dist/index.d.ts +2 -2
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +12 -2
  4. package/dist/index.js.map +1 -1
  5. package/dist/plugins/bans/bans-plugin.d.ts.map +1 -1
  6. package/dist/plugins/bans/bans-plugin.js +12 -3
  7. package/dist/plugins/bans/bans-plugin.js.map +1 -1
  8. package/dist/plugins/devices/__tests__/devices-plugin.test.d.ts +11 -0
  9. package/dist/plugins/devices/__tests__/devices-plugin.test.d.ts.map +1 -0
  10. package/dist/plugins/devices/__tests__/devices-plugin.test.js +410 -0
  11. package/dist/plugins/devices/__tests__/devices-plugin.test.js.map +1 -0
  12. package/dist/plugins/devices/__tests__/token-utils.test.d.ts +7 -0
  13. package/dist/plugins/devices/__tests__/token-utils.test.d.ts.map +1 -0
  14. package/dist/plugins/devices/__tests__/token-utils.test.js +197 -0
  15. package/dist/plugins/devices/__tests__/token-utils.test.js.map +1 -0
  16. package/dist/plugins/devices/adapters/compute-adapter.d.ts +36 -0
  17. package/dist/plugins/devices/adapters/compute-adapter.d.ts.map +1 -0
  18. package/dist/plugins/devices/adapters/compute-adapter.js +100 -0
  19. package/dist/plugins/devices/adapters/compute-adapter.js.map +1 -0
  20. package/dist/plugins/devices/adapters/index.d.ts +12 -0
  21. package/dist/plugins/devices/adapters/index.d.ts.map +1 -0
  22. package/dist/plugins/devices/adapters/index.js +10 -0
  23. package/dist/plugins/devices/adapters/index.js.map +1 -0
  24. package/dist/plugins/devices/adapters/mobile-adapter.d.ts +41 -0
  25. package/dist/plugins/devices/adapters/mobile-adapter.d.ts.map +1 -0
  26. package/dist/plugins/devices/adapters/mobile-adapter.js +131 -0
  27. package/dist/plugins/devices/adapters/mobile-adapter.js.map +1 -0
  28. package/dist/plugins/devices/devices-plugin.d.ts +70 -0
  29. package/dist/plugins/devices/devices-plugin.d.ts.map +1 -0
  30. package/dist/plugins/devices/devices-plugin.js +453 -0
  31. package/dist/plugins/devices/devices-plugin.js.map +1 -0
  32. package/dist/plugins/devices/index.d.ts +18 -0
  33. package/dist/plugins/devices/index.d.ts.map +1 -0
  34. package/dist/plugins/devices/index.js +18 -0
  35. package/dist/plugins/devices/index.js.map +1 -0
  36. package/dist/plugins/devices/stores/index.d.ts +9 -0
  37. package/dist/plugins/devices/stores/index.d.ts.map +1 -0
  38. package/dist/plugins/devices/stores/index.js +9 -0
  39. package/dist/plugins/devices/stores/index.js.map +1 -0
  40. package/dist/plugins/devices/stores/postgres-store.d.ts +26 -0
  41. package/dist/plugins/devices/stores/postgres-store.d.ts.map +1 -0
  42. package/dist/plugins/devices/stores/postgres-store.js +199 -0
  43. package/dist/plugins/devices/stores/postgres-store.js.map +1 -0
  44. package/dist/plugins/devices/token-utils.d.ts +100 -0
  45. package/dist/plugins/devices/token-utils.d.ts.map +1 -0
  46. package/dist/plugins/devices/token-utils.js +162 -0
  47. package/dist/plugins/devices/token-utils.js.map +1 -0
  48. package/dist/plugins/devices/types.d.ts +307 -0
  49. package/dist/plugins/devices/types.d.ts.map +1 -0
  50. package/dist/plugins/devices/types.js +10 -0
  51. package/dist/plugins/devices/types.js.map +1 -0
  52. package/dist/plugins/index.d.ts +14 -2
  53. package/dist/plugins/index.d.ts.map +1 -1
  54. package/dist/plugins/index.js +13 -1
  55. package/dist/plugins/index.js.map +1 -1
  56. package/dist/plugins/notifications/__tests__/notifications-manager.test.d.ts +5 -0
  57. package/dist/plugins/notifications/__tests__/notifications-manager.test.d.ts.map +1 -0
  58. package/dist/plugins/notifications/__tests__/notifications-manager.test.js +470 -0
  59. package/dist/plugins/notifications/__tests__/notifications-manager.test.js.map +1 -0
  60. package/dist/plugins/notifications/index.d.ts +71 -0
  61. package/dist/plugins/notifications/index.d.ts.map +1 -0
  62. package/dist/plugins/notifications/index.js +72 -0
  63. package/dist/plugins/notifications/index.js.map +1 -0
  64. package/dist/plugins/notifications/notifications-manager.d.ts +182 -0
  65. package/dist/plugins/notifications/notifications-manager.d.ts.map +1 -0
  66. package/dist/plugins/notifications/notifications-manager.js +610 -0
  67. package/dist/plugins/notifications/notifications-manager.js.map +1 -0
  68. package/dist/plugins/notifications/notifications-plugin.d.ts +83 -0
  69. package/dist/plugins/notifications/notifications-plugin.d.ts.map +1 -0
  70. package/dist/plugins/notifications/notifications-plugin.js +337 -0
  71. package/dist/plugins/notifications/notifications-plugin.js.map +1 -0
  72. package/dist/plugins/notifications/types.d.ts +164 -0
  73. package/dist/plugins/notifications/types.d.ts.map +1 -0
  74. package/dist/plugins/notifications/types.js +9 -0
  75. package/dist/plugins/notifications/types.js.map +1 -0
  76. package/dist/plugins/parental/__tests__/parental-plugin.test.d.ts +12 -0
  77. package/dist/plugins/parental/__tests__/parental-plugin.test.d.ts.map +1 -0
  78. package/dist/plugins/parental/__tests__/parental-plugin.test.js +349 -0
  79. package/dist/plugins/parental/__tests__/parental-plugin.test.js.map +1 -0
  80. package/dist/plugins/parental/adapters/index.d.ts +8 -0
  81. package/dist/plugins/parental/adapters/index.d.ts.map +1 -0
  82. package/dist/plugins/parental/adapters/index.js +7 -0
  83. package/dist/plugins/parental/adapters/index.js.map +1 -0
  84. package/dist/plugins/parental/adapters/kids-adapter.d.ts +24 -0
  85. package/dist/plugins/parental/adapters/kids-adapter.d.ts.map +1 -0
  86. package/dist/plugins/parental/adapters/kids-adapter.js +174 -0
  87. package/dist/plugins/parental/adapters/kids-adapter.js.map +1 -0
  88. package/dist/plugins/parental/index.d.ts +14 -0
  89. package/dist/plugins/parental/index.d.ts.map +1 -0
  90. package/dist/plugins/parental/index.js +15 -0
  91. package/dist/plugins/parental/index.js.map +1 -0
  92. package/dist/plugins/parental/parental-plugin.d.ts +88 -0
  93. package/dist/plugins/parental/parental-plugin.d.ts.map +1 -0
  94. package/dist/plugins/parental/parental-plugin.js +666 -0
  95. package/dist/plugins/parental/parental-plugin.js.map +1 -0
  96. package/dist/plugins/parental/stores/index.d.ts +7 -0
  97. package/dist/plugins/parental/stores/index.d.ts.map +1 -0
  98. package/dist/plugins/parental/stores/index.js +7 -0
  99. package/dist/plugins/parental/stores/index.js.map +1 -0
  100. package/dist/plugins/parental/stores/postgres-store.d.ts +10 -0
  101. package/dist/plugins/parental/stores/postgres-store.d.ts.map +1 -0
  102. package/dist/plugins/parental/stores/postgres-store.js +209 -0
  103. package/dist/plugins/parental/stores/postgres-store.js.map +1 -0
  104. package/dist/plugins/parental/types.d.ts +154 -0
  105. package/dist/plugins/parental/types.d.ts.map +1 -0
  106. package/dist/plugins/parental/types.js +10 -0
  107. package/dist/plugins/parental/types.js.map +1 -0
  108. package/dist/plugins/profiles/__tests__/profiles-plugin.test.d.ts +11 -0
  109. package/dist/plugins/profiles/__tests__/profiles-plugin.test.d.ts.map +1 -0
  110. package/dist/plugins/profiles/__tests__/profiles-plugin.test.js +243 -0
  111. package/dist/plugins/profiles/__tests__/profiles-plugin.test.js.map +1 -0
  112. package/dist/plugins/profiles/index.d.ts +12 -0
  113. package/dist/plugins/profiles/index.d.ts.map +1 -0
  114. package/dist/plugins/profiles/index.js +13 -0
  115. package/dist/plugins/profiles/index.js.map +1 -0
  116. package/dist/plugins/profiles/profiles-plugin.d.ts +71 -0
  117. package/dist/plugins/profiles/profiles-plugin.d.ts.map +1 -0
  118. package/dist/plugins/profiles/profiles-plugin.js +481 -0
  119. package/dist/plugins/profiles/profiles-plugin.js.map +1 -0
  120. package/dist/plugins/profiles/stores/index.d.ts +9 -0
  121. package/dist/plugins/profiles/stores/index.d.ts.map +1 -0
  122. package/dist/plugins/profiles/stores/index.js +9 -0
  123. package/dist/plugins/profiles/stores/index.js.map +1 -0
  124. package/dist/plugins/profiles/stores/postgres-store.d.ts +18 -0
  125. package/dist/plugins/profiles/stores/postgres-store.d.ts.map +1 -0
  126. package/dist/plugins/profiles/stores/postgres-store.js +310 -0
  127. package/dist/plugins/profiles/stores/postgres-store.js.map +1 -0
  128. package/dist/plugins/profiles/types.d.ts +289 -0
  129. package/dist/plugins/profiles/types.d.ts.map +1 -0
  130. package/dist/plugins/profiles/types.js +10 -0
  131. package/dist/plugins/profiles/types.js.map +1 -0
  132. package/dist/plugins/subscriptions/__tests__/subscriptions-plugin.test.d.ts +11 -0
  133. package/dist/plugins/subscriptions/__tests__/subscriptions-plugin.test.d.ts.map +1 -0
  134. package/dist/plugins/subscriptions/__tests__/subscriptions-plugin.test.js +305 -0
  135. package/dist/plugins/subscriptions/__tests__/subscriptions-plugin.test.js.map +1 -0
  136. package/dist/plugins/subscriptions/index.d.ts +12 -0
  137. package/dist/plugins/subscriptions/index.d.ts.map +1 -0
  138. package/dist/plugins/subscriptions/index.js +13 -0
  139. package/dist/plugins/subscriptions/index.js.map +1 -0
  140. package/dist/plugins/subscriptions/stores/index.d.ts +9 -0
  141. package/dist/plugins/subscriptions/stores/index.d.ts.map +1 -0
  142. package/dist/plugins/subscriptions/stores/index.js +9 -0
  143. package/dist/plugins/subscriptions/stores/index.js.map +1 -0
  144. package/dist/plugins/subscriptions/stores/postgres-store.d.ts +14 -0
  145. package/dist/plugins/subscriptions/stores/postgres-store.d.ts.map +1 -0
  146. package/dist/plugins/subscriptions/stores/postgres-store.js +359 -0
  147. package/dist/plugins/subscriptions/stores/postgres-store.js.map +1 -0
  148. package/dist/plugins/subscriptions/subscriptions-plugin.d.ts +82 -0
  149. package/dist/plugins/subscriptions/subscriptions-plugin.d.ts.map +1 -0
  150. package/dist/plugins/subscriptions/subscriptions-plugin.js +449 -0
  151. package/dist/plugins/subscriptions/subscriptions-plugin.js.map +1 -0
  152. package/dist/plugins/subscriptions/types.d.ts +308 -0
  153. package/dist/plugins/subscriptions/types.d.ts.map +1 -0
  154. package/dist/plugins/subscriptions/types.js +10 -0
  155. package/dist/plugins/subscriptions/types.js.map +1 -0
  156. package/dist/plugins/usage/__tests__/usage-plugin.test.d.ts +11 -0
  157. package/dist/plugins/usage/__tests__/usage-plugin.test.d.ts.map +1 -0
  158. package/dist/plugins/usage/__tests__/usage-plugin.test.js +218 -0
  159. package/dist/plugins/usage/__tests__/usage-plugin.test.js.map +1 -0
  160. package/dist/plugins/usage/index.d.ts +12 -0
  161. package/dist/plugins/usage/index.d.ts.map +1 -0
  162. package/dist/plugins/usage/index.js +13 -0
  163. package/dist/plugins/usage/index.js.map +1 -0
  164. package/dist/plugins/usage/stores/index.d.ts +9 -0
  165. package/dist/plugins/usage/stores/index.d.ts.map +1 -0
  166. package/dist/plugins/usage/stores/index.js +9 -0
  167. package/dist/plugins/usage/stores/index.js.map +1 -0
  168. package/dist/plugins/usage/stores/postgres-store.d.ts +14 -0
  169. package/dist/plugins/usage/stores/postgres-store.d.ts.map +1 -0
  170. package/dist/plugins/usage/stores/postgres-store.js +146 -0
  171. package/dist/plugins/usage/stores/postgres-store.js.map +1 -0
  172. package/dist/plugins/usage/types.d.ts +195 -0
  173. package/dist/plugins/usage/types.d.ts.map +1 -0
  174. package/dist/plugins/usage/types.js +10 -0
  175. package/dist/plugins/usage/types.js.map +1 -0
  176. package/dist/plugins/usage/usage-plugin.d.ts +51 -0
  177. package/dist/plugins/usage/usage-plugin.d.ts.map +1 -0
  178. package/dist/plugins/usage/usage-plugin.js +412 -0
  179. package/dist/plugins/usage/usage-plugin.js.map +1 -0
  180. package/dist/plugins/users/__tests__/postgres-store.test.d.ts +10 -0
  181. package/dist/plugins/users/__tests__/postgres-store.test.d.ts.map +1 -0
  182. package/dist/plugins/users/__tests__/postgres-store.test.js +229 -0
  183. package/dist/plugins/users/__tests__/postgres-store.test.js.map +1 -0
  184. package/dist/plugins/users/__tests__/users-plugin.test.js +3 -0
  185. package/dist/plugins/users/__tests__/users-plugin.test.js.map +1 -1
  186. package/dist/plugins/users/index.d.ts +2 -2
  187. package/dist/plugins/users/index.d.ts.map +1 -1
  188. package/dist/plugins/users/index.js +1 -1
  189. package/dist/plugins/users/index.js.map +1 -1
  190. package/dist/plugins/users/stores/postgres-store.d.ts.map +1 -1
  191. package/dist/plugins/users/stores/postgres-store.js +76 -0
  192. package/dist/plugins/users/stores/postgres-store.js.map +1 -1
  193. package/dist/plugins/users/types.d.ts +74 -6
  194. package/dist/plugins/users/types.d.ts.map +1 -1
  195. package/dist/plugins/users/users-plugin.d.ts +15 -1
  196. package/dist/plugins/users/users-plugin.d.ts.map +1 -1
  197. package/dist/plugins/users/users-plugin.js +29 -0
  198. package/dist/plugins/users/users-plugin.js.map +1 -1
  199. package/dist-ui/assets/index-CynOqPkb.js +469 -0
  200. package/dist-ui/assets/index-CynOqPkb.js.map +1 -0
  201. package/dist-ui/index.html +1 -1
  202. package/dist-ui-lib/api/controlPanelApi.d.ts +46 -0
  203. package/dist-ui-lib/components/StatCard.d.ts +16 -0
  204. package/dist-ui-lib/dashboard/widgets/NotificationsStatsWidget.d.ts +12 -0
  205. package/dist-ui-lib/dashboard/widgets/index.d.ts +1 -0
  206. package/dist-ui-lib/index.js +1822 -1611
  207. package/dist-ui-lib/index.js.map +1 -1
  208. package/dist-ui-lib/pages/NotificationsPage.d.ts +9 -0
  209. package/dist-ui-lib/utils/formatters.d.ts +19 -0
  210. package/package.json +1 -1
  211. package/src/index.ts +178 -0
  212. package/src/plugins/bans/bans-plugin.ts +15 -3
  213. package/src/plugins/devices/__tests__/devices-plugin.test.ts +551 -0
  214. package/src/plugins/devices/__tests__/token-utils.test.ts +264 -0
  215. package/src/plugins/devices/adapters/compute-adapter.ts +139 -0
  216. package/src/plugins/devices/adapters/index.ts +13 -0
  217. package/src/plugins/devices/adapters/mobile-adapter.ts +179 -0
  218. package/src/plugins/devices/devices-plugin.ts +538 -0
  219. package/src/plugins/devices/index.ts +69 -0
  220. package/src/plugins/devices/stores/index.ts +9 -0
  221. package/src/plugins/devices/stores/postgres-store.ts +304 -0
  222. package/src/plugins/devices/token-utils.ts +213 -0
  223. package/src/plugins/devices/types.ts +351 -0
  224. package/src/plugins/index.ts +218 -0
  225. package/src/plugins/notifications/__tests__/notifications-manager.test.ts +637 -0
  226. package/src/plugins/notifications/index.ts +91 -0
  227. package/src/plugins/notifications/notifications-manager.ts +773 -0
  228. package/src/plugins/notifications/notifications-plugin.ts +398 -0
  229. package/src/plugins/notifications/types.ts +207 -0
  230. package/src/plugins/parental/__tests__/parental-plugin.test.ts +465 -0
  231. package/src/plugins/parental/adapters/index.ts +8 -0
  232. package/src/plugins/parental/adapters/kids-adapter.ts +206 -0
  233. package/src/plugins/parental/index.ts +55 -0
  234. package/src/plugins/parental/parental-plugin.ts +759 -0
  235. package/src/plugins/parental/stores/index.ts +7 -0
  236. package/src/plugins/parental/stores/postgres-store.ts +304 -0
  237. package/src/plugins/parental/types.ts +180 -0
  238. package/src/plugins/profiles/__tests__/profiles-plugin.test.ts +321 -0
  239. package/src/plugins/profiles/index.ts +49 -0
  240. package/src/plugins/profiles/profiles-plugin.ts +546 -0
  241. package/src/plugins/profiles/stores/index.ts +9 -0
  242. package/src/plugins/profiles/stores/postgres-store.ts +439 -0
  243. package/src/plugins/profiles/types.ts +338 -0
  244. package/src/plugins/subscriptions/__tests__/subscriptions-plugin.test.ts +404 -0
  245. package/src/plugins/subscriptions/index.ts +51 -0
  246. package/src/plugins/subscriptions/stores/index.ts +9 -0
  247. package/src/plugins/subscriptions/stores/postgres-store.ts +482 -0
  248. package/src/plugins/subscriptions/subscriptions-plugin.ts +530 -0
  249. package/src/plugins/subscriptions/types.ts +355 -0
  250. package/src/plugins/usage/__tests__/usage-plugin.test.ts +288 -0
  251. package/src/plugins/usage/index.ts +39 -0
  252. package/src/plugins/usage/stores/index.ts +9 -0
  253. package/src/plugins/usage/stores/postgres-store.ts +213 -0
  254. package/src/plugins/usage/types.ts +222 -0
  255. package/src/plugins/usage/usage-plugin.ts +484 -0
  256. package/src/plugins/users/__tests__/postgres-store.test.ts +326 -0
  257. package/src/plugins/users/__tests__/users-plugin.test.ts +3 -0
  258. package/src/plugins/users/index.ts +6 -0
  259. package/src/plugins/users/stores/postgres-store.ts +104 -0
  260. package/src/plugins/users/types.ts +82 -6
  261. package/src/plugins/users/users-plugin.ts +37 -0
  262. package/ui/src/App.tsx +5 -1
  263. package/ui/src/api/controlPanelApi.ts +103 -6
  264. package/ui/src/components/StatCard.tsx +58 -0
  265. package/ui/src/dashboard/builtInWidgets.tsx +3 -1
  266. package/ui/src/dashboard/widgets/NotificationsStatsWidget.tsx +167 -0
  267. package/ui/src/dashboard/widgets/index.ts +1 -0
  268. package/ui/src/pages/NotificationsPage.tsx +417 -0
  269. package/ui/src/utils/formatters.ts +33 -0
  270. package/dist-ui/assets/index-D7DoZ9rL.js +0 -478
  271. package/dist-ui/assets/index-D7DoZ9rL.js.map +0 -1
@@ -0,0 +1,610 @@
1
+ /**
2
+ * Notifications Manager
3
+ *
4
+ * Core service that manages PostgreSQL LISTEN/NOTIFY and SSE client connections.
5
+ * Provides realtime event routing from database to connected clients.
6
+ *
7
+ * Architecture:
8
+ * - Single dedicated PostgreSQL connection for LISTEN (not from pool)
9
+ * - In-memory Map of SSE clients
10
+ * - Event routing based on device_id/user_id filters
11
+ * - Automatic reconnection with exponential backoff
12
+ * - Heartbeat system for connection health
13
+ *
14
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
15
+ */
16
+ import pg from 'pg';
17
+ const { Client } = pg;
18
+ // Default configuration values
19
+ const DEFAULT_HEARTBEAT_INTERVAL = 60000; // 60 seconds
20
+ const DEFAULT_RECONNECT_MAX_ATTEMPTS = 10;
21
+ const DEFAULT_RECONNECT_BASE_DELAY = 1000; // 1 second
22
+ const DEFAULT_RECONNECT_MAX_DELAY = 60000; // 60 seconds
23
+ const CONNECTION_HEALTH_TIMEOUT = 30 * 60 * 1000; // 30 minutes (increased for low-traffic systems)
24
+ const DEFAULT_MAX_CLIENTS = 10000; // Maximum concurrent SSE clients
25
+ /**
26
+ * NotificationsManager - Singleton service for realtime notifications
27
+ */
28
+ export class NotificationsManager {
29
+ constructor(connectionString, channels, config, logger) {
30
+ this.client = null;
31
+ this.clients = new Map();
32
+ // Connection state
33
+ this.initialized = false;
34
+ this.isReconnecting = false;
35
+ this.isShuttingDown = false;
36
+ this.reconnectAttempts = 0;
37
+ // Statistics
38
+ this.stats = {
39
+ totalConnections: 0,
40
+ currentConnections: 0,
41
+ eventsProcessed: 0,
42
+ eventsRouted: 0,
43
+ eventsParseFailed: 0,
44
+ eventsDroppedNoClients: 0,
45
+ reconnectionAttempts: 0,
46
+ lastReconnectionAt: undefined,
47
+ };
48
+ // Health tracking
49
+ this.lastEventReceivedAt = Date.now();
50
+ this.connectionString = connectionString;
51
+ this.channels = channels;
52
+ this.logger = logger;
53
+ // Apply configuration with defaults
54
+ this.heartbeatInterval = config.heartbeat?.interval ?? DEFAULT_HEARTBEAT_INTERVAL;
55
+ this.heartbeatIncludeStatus = config.heartbeat?.includeStatus !== false;
56
+ this.reconnectMaxAttempts = config.reconnect?.maxAttempts ?? DEFAULT_RECONNECT_MAX_ATTEMPTS;
57
+ this.reconnectBaseDelay = config.reconnect?.baseDelay ?? DEFAULT_RECONNECT_BASE_DELAY;
58
+ this.reconnectMaxDelay = config.reconnect?.maxDelay ?? DEFAULT_RECONNECT_MAX_DELAY;
59
+ this.maxClients = DEFAULT_MAX_CLIENTS;
60
+ }
61
+ /**
62
+ * Helper to safely truncate IDs for logging
63
+ */
64
+ truncateId(id) {
65
+ return id ? id.substring(0, 8) : 'unknown';
66
+ }
67
+ /**
68
+ * Initialize the manager - connect to PostgreSQL and start LISTEN
69
+ */
70
+ async initialize() {
71
+ if (this.initialized) {
72
+ return;
73
+ }
74
+ await this.connect();
75
+ }
76
+ /**
77
+ * Connect to PostgreSQL and set up LISTEN
78
+ */
79
+ async connect() {
80
+ if (this.isShuttingDown) {
81
+ this.logger.debug('Skip connection attempt - shutting down');
82
+ return;
83
+ }
84
+ try {
85
+ // Clean up existing connection if any
86
+ await this.cleanupConnection();
87
+ // Create new client
88
+ this.client = new Client({
89
+ connectionString: this.connectionString,
90
+ });
91
+ // Set up error handler before connecting
92
+ this.client.on('error', (err) => {
93
+ this.logger.error('PostgreSQL LISTEN connection error', { error: err.message });
94
+ this.handleConnectionError();
95
+ });
96
+ // Set up notification handler
97
+ this.client.on('notification', (msg) => {
98
+ this.handleNotification(msg);
99
+ });
100
+ // Connect
101
+ await this.client.connect();
102
+ // Subscribe to channels
103
+ for (const channel of this.channels) {
104
+ await this.client.query(`LISTEN ${this.sanitizeChannelName(channel)}`);
105
+ this.logger.debug(`Listening on channel: ${channel}`);
106
+ }
107
+ // Success
108
+ this.initialized = true;
109
+ this.reconnectAttempts = 0;
110
+ this.isReconnecting = false;
111
+ const clientMsg = this.clients.size > 0
112
+ ? ` - ${this.clients.size} client${this.clients.size !== 1 ? 's' : ''} connected`
113
+ : '';
114
+ this.logger.info(`Notifications service ready (${this.channels.length} channels)${clientMsg}`);
115
+ }
116
+ catch (error) {
117
+ this.initialized = false;
118
+ const errorMsg = error instanceof Error ? error.message : String(error);
119
+ this.logger.error('Failed to connect to PostgreSQL for LISTEN', { error: errorMsg });
120
+ this.scheduleReconnect();
121
+ }
122
+ }
123
+ /**
124
+ * Handle PostgreSQL connection error
125
+ */
126
+ handleConnectionError() {
127
+ this.initialized = false;
128
+ if (!this.isReconnecting && !this.isShuttingDown) {
129
+ this.scheduleReconnect();
130
+ }
131
+ }
132
+ /**
133
+ * Handle incoming notification from PostgreSQL
134
+ */
135
+ handleNotification(msg) {
136
+ this.stats.eventsProcessed++;
137
+ this.lastEventReceivedAt = Date.now();
138
+ const channel = msg.channel;
139
+ const payloadStr = msg.payload;
140
+ if (!payloadStr) {
141
+ this.logger.debug('Received empty notification payload', { channel });
142
+ return;
143
+ }
144
+ let payload;
145
+ try {
146
+ payload = JSON.parse(payloadStr);
147
+ }
148
+ catch {
149
+ this.stats.eventsParseFailed++;
150
+ this.logger.warn('Failed to parse notification payload as JSON', {
151
+ channel,
152
+ payload: payloadStr.substring(0, 100),
153
+ totalParseFailed: this.stats.eventsParseFailed,
154
+ });
155
+ return;
156
+ }
157
+ this.logger.debug('Received notification', {
158
+ channel,
159
+ deviceId: this.truncateId(payload.deviceId),
160
+ userId: this.truncateId(payload.userId),
161
+ eventType: payload.eventType,
162
+ });
163
+ // Route to matching clients
164
+ this.routeEvent(channel, payload);
165
+ }
166
+ /**
167
+ * Route event to matching SSE clients
168
+ */
169
+ routeEvent(channel, payload) {
170
+ const eventType = payload.eventType || channel;
171
+ const deviceId = payload.deviceId;
172
+ const userId = payload.userId;
173
+ const matchingClients = this.filterClients(deviceId, userId);
174
+ if (matchingClients.length === 0) {
175
+ this.stats.eventsDroppedNoClients++;
176
+ this.logger.debug('No SSE clients to receive event', {
177
+ channel,
178
+ eventType,
179
+ deviceId: this.truncateId(deviceId),
180
+ userId: this.truncateId(userId),
181
+ totalClients: this.clients.size,
182
+ });
183
+ return;
184
+ }
185
+ this.logger.debug(`Broadcasting ${eventType} to ${matchingClients.length} client(s)`);
186
+ for (const client of matchingClients) {
187
+ this.sendEvent(client, eventType, payload);
188
+ this.stats.eventsRouted++;
189
+ }
190
+ }
191
+ /**
192
+ * Filter clients based on device_id or user_id
193
+ */
194
+ filterClients(deviceId, userId) {
195
+ const matching = [];
196
+ for (const client of this.clients.values()) {
197
+ // Device-specific client matches device
198
+ if (client.deviceId && deviceId && client.deviceId === deviceId) {
199
+ matching.push(client);
200
+ }
201
+ // User-wide client matches user
202
+ else if (client.userId && userId && client.userId === userId) {
203
+ matching.push(client);
204
+ }
205
+ }
206
+ return matching;
207
+ }
208
+ /**
209
+ * Send SSE event to a client
210
+ */
211
+ sendEvent(client, eventType, data) {
212
+ try {
213
+ const eventData = JSON.stringify({ eventType, payload: data });
214
+ client.response.write(`event: ${eventType}\n`);
215
+ client.response.write(`data: ${eventData}\n\n`);
216
+ }
217
+ catch {
218
+ // Client disconnected - will be cleaned up by close handler
219
+ this.logger.debug('Event send failed - client disconnected', {
220
+ clientId: client.id.substring(0, 8),
221
+ eventType,
222
+ });
223
+ }
224
+ }
225
+ /**
226
+ * Schedule reconnection with exponential backoff
227
+ */
228
+ scheduleReconnect() {
229
+ if (this.isShuttingDown) {
230
+ this.isReconnecting = false;
231
+ return;
232
+ }
233
+ if (this.isReconnecting) {
234
+ this.logger.debug('Reconnection already in progress, skipping');
235
+ return;
236
+ }
237
+ if (this.reconnectAttempts >= this.reconnectMaxAttempts) {
238
+ this.logger.error(`PostgreSQL LISTEN connection failed after ${this.reconnectMaxAttempts} attempts. ` +
239
+ 'Call forceReconnect() to retry.');
240
+ this.initialized = false;
241
+ this.isReconnecting = false;
242
+ return;
243
+ }
244
+ this.isReconnecting = true;
245
+ this.reconnectAttempts++;
246
+ this.stats.reconnectionAttempts++;
247
+ // Calculate delay with exponential backoff
248
+ const delay = Math.min(this.reconnectBaseDelay * Math.pow(2, this.reconnectAttempts - 1), this.reconnectMaxDelay);
249
+ this.logger.info(`Reconnecting to PostgreSQL in ${Math.round(delay / 1000)}s ` +
250
+ `(attempt ${this.reconnectAttempts}/${this.reconnectMaxAttempts})`);
251
+ this.reconnectTimer = setTimeout(() => {
252
+ this.stats.lastReconnectionAt = new Date();
253
+ this.connect();
254
+ }, delay);
255
+ }
256
+ /**
257
+ * Clean up existing PostgreSQL connection
258
+ */
259
+ async cleanupConnection() {
260
+ if (!this.client) {
261
+ return;
262
+ }
263
+ try {
264
+ // Unlisten all channels
265
+ for (const channel of this.channels) {
266
+ try {
267
+ await this.client.query(`UNLISTEN ${this.sanitizeChannelName(channel)}`);
268
+ }
269
+ catch {
270
+ // Ignore cleanup errors
271
+ }
272
+ }
273
+ await this.client.end();
274
+ }
275
+ catch {
276
+ // Ignore cleanup errors
277
+ }
278
+ this.client = null;
279
+ }
280
+ /**
281
+ * Sanitize channel name to prevent SQL injection
282
+ */
283
+ sanitizeChannelName(channel) {
284
+ // Only allow alphanumeric and underscore
285
+ return channel.replace(/[^a-zA-Z0-9_]/g, '_');
286
+ }
287
+ // ===========================================================================
288
+ // Public API
289
+ // ===========================================================================
290
+ /**
291
+ * Register a new SSE client
292
+ * @returns true if registered, false if at capacity
293
+ */
294
+ registerClient(id, deviceId, userId, response) {
295
+ // Check capacity
296
+ if (this.clients.size >= this.maxClients) {
297
+ this.logger.warn('Max SSE clients reached, rejecting connection', {
298
+ maxClients: this.maxClients,
299
+ currentClients: this.clients.size,
300
+ });
301
+ return false;
302
+ }
303
+ const client = {
304
+ id,
305
+ deviceId,
306
+ userId,
307
+ response,
308
+ connectedAt: new Date(),
309
+ };
310
+ this.clients.set(id, client);
311
+ this.stats.totalConnections++;
312
+ this.stats.currentConnections++;
313
+ // Log connection
314
+ const identifier = deviceId
315
+ ? `Device ${this.truncateId(deviceId)}`
316
+ : userId
317
+ ? `User ${this.truncateId(userId)}`
318
+ : 'Unknown client';
319
+ this.logger.info(`${identifier} connected (${this.clients.size} active)`);
320
+ // Send initial connection event
321
+ this.sendEvent(client, 'connected', {
322
+ message: 'Connected to notifications service',
323
+ clientId: id,
324
+ timestamp: new Date().toISOString(),
325
+ });
326
+ // Set up cleanup on disconnect
327
+ response.on('close', () => {
328
+ this.unregisterClient(id);
329
+ });
330
+ // Start heartbeat if this is the first client
331
+ if (this.clients.size === 1 && !this.heartbeatTimer) {
332
+ this.startHeartbeat();
333
+ }
334
+ return true;
335
+ }
336
+ /**
337
+ * Unregister a client
338
+ */
339
+ unregisterClient(id) {
340
+ const client = this.clients.get(id);
341
+ if (!client)
342
+ return;
343
+ this.clients.delete(id);
344
+ this.stats.currentConnections--;
345
+ const identifier = client.deviceId
346
+ ? `Device ${this.truncateId(client.deviceId)}`
347
+ : client.userId
348
+ ? `User ${this.truncateId(client.userId)}`
349
+ : 'Unknown client';
350
+ const durationMs = Date.now() - client.connectedAt.getTime();
351
+ const durationMin = Math.round(durationMs / 60000);
352
+ const durationDisplay = durationMin > 0 ? `${durationMin}m` : '<1m';
353
+ this.logger.info(`${identifier} disconnected after ${durationDisplay} (${this.clients.size} active)`);
354
+ // Stop heartbeat if no clients remain
355
+ if (this.clients.size === 0) {
356
+ this.stopHeartbeat();
357
+ }
358
+ }
359
+ /**
360
+ * Broadcast event to a specific device
361
+ */
362
+ broadcastToDevice(deviceId, eventType, payload) {
363
+ let count = 0;
364
+ for (const client of this.clients.values()) {
365
+ if (client.deviceId === deviceId) {
366
+ this.sendEvent(client, eventType, payload);
367
+ count++;
368
+ }
369
+ }
370
+ return count;
371
+ }
372
+ /**
373
+ * Broadcast event to all devices for a user
374
+ */
375
+ broadcastToUser(userId, eventType, payload) {
376
+ let count = 0;
377
+ for (const client of this.clients.values()) {
378
+ if (client.userId === userId) {
379
+ this.sendEvent(client, eventType, payload);
380
+ count++;
381
+ }
382
+ }
383
+ return count;
384
+ }
385
+ /**
386
+ * Broadcast to all connected clients
387
+ */
388
+ broadcastToAll(eventType, payload) {
389
+ let count = 0;
390
+ for (const client of this.clients.values()) {
391
+ this.sendEvent(client, eventType, payload);
392
+ count++;
393
+ }
394
+ return count;
395
+ }
396
+ // ===========================================================================
397
+ // Heartbeat System
398
+ // ===========================================================================
399
+ /**
400
+ * Start heartbeat system
401
+ */
402
+ startHeartbeat() {
403
+ this.logger.debug(`Starting heartbeat (${this.heartbeatInterval / 1000}s interval)`);
404
+ this.heartbeatTimer = setInterval(() => {
405
+ if (this.clients.size === 0) {
406
+ return;
407
+ }
408
+ const heartbeatData = {
409
+ timestamp: new Date().toISOString(),
410
+ };
411
+ if (this.heartbeatIncludeStatus) {
412
+ heartbeatData.server = {
413
+ status: this.initialized ? 'healthy' : 'degraded',
414
+ uptime: Math.round(process.uptime()),
415
+ clients: this.clients.size,
416
+ };
417
+ }
418
+ this.logger.debug(`Broadcasting heartbeat to ${this.clients.size} clients`);
419
+ for (const client of this.clients.values()) {
420
+ this.sendEvent(client, 'heartbeat', heartbeatData);
421
+ }
422
+ }, this.heartbeatInterval);
423
+ }
424
+ /**
425
+ * Stop heartbeat system
426
+ */
427
+ stopHeartbeat() {
428
+ if (this.heartbeatTimer) {
429
+ clearInterval(this.heartbeatTimer);
430
+ this.heartbeatTimer = undefined;
431
+ this.logger.debug('Stopped heartbeat');
432
+ }
433
+ }
434
+ // ===========================================================================
435
+ // Client Management
436
+ // ===========================================================================
437
+ /**
438
+ * Get list of connected clients
439
+ */
440
+ getClients() {
441
+ const now = Date.now();
442
+ return Array.from(this.clients.values()).map((client) => ({
443
+ id: client.id,
444
+ deviceId: client.deviceId,
445
+ userId: client.userId,
446
+ connectedAt: client.connectedAt.toISOString(),
447
+ durationMs: now - client.connectedAt.getTime(),
448
+ }));
449
+ }
450
+ /**
451
+ * Disconnect a specific client by ID
452
+ * @param clientId - The client ID to disconnect
453
+ * @param disconnectedBy - Optional info about who initiated the disconnect (for audit logging)
454
+ * @returns true if client was found and disconnected, false otherwise
455
+ */
456
+ disconnectClient(clientId, disconnectedBy) {
457
+ const client = this.clients.get(clientId);
458
+ if (!client) {
459
+ return false;
460
+ }
461
+ // Audit log with details about who disconnected the client
462
+ const disconnectInfo = disconnectedBy
463
+ ? ` by ${disconnectedBy.email || disconnectedBy.userId || disconnectedBy.ip || 'admin'}`
464
+ : '';
465
+ this.logger.info(`Force disconnecting client ${this.truncateId(clientId)}${disconnectInfo}` +
466
+ (client.deviceId ? ` (device: ${this.truncateId(client.deviceId)})` : '') +
467
+ (client.userId ? ` (user: ${this.truncateId(client.userId)})` : ''));
468
+ // Send disconnect event before closing
469
+ try {
470
+ this.sendEvent(client, 'disconnected', {
471
+ reason: 'Disconnected by administrator',
472
+ timestamp: new Date().toISOString(),
473
+ });
474
+ client.response.end();
475
+ }
476
+ catch {
477
+ // Ignore errors - client may have already disconnected
478
+ }
479
+ // The unregisterClient will be called by the 'close' event handler
480
+ return true;
481
+ }
482
+ // ===========================================================================
483
+ // Statistics & Health
484
+ // ===========================================================================
485
+ /**
486
+ * Get current statistics
487
+ */
488
+ getStats() {
489
+ return {
490
+ ...this.stats,
491
+ clientsByType: {
492
+ device: Array.from(this.clients.values()).filter((c) => c.deviceId).length,
493
+ user: Array.from(this.clients.values()).filter((c) => c.userId && !c.deviceId).length,
494
+ },
495
+ connectionHealth: this.getConnectionHealth(),
496
+ };
497
+ }
498
+ /**
499
+ * Get connection health status
500
+ */
501
+ getConnectionHealth() {
502
+ const now = Date.now();
503
+ const timeSinceLastEvent = now - this.lastEventReceivedAt;
504
+ const isHealthy = this.initialized && timeSinceLastEvent < CONNECTION_HEALTH_TIMEOUT;
505
+ return {
506
+ isConnected: this.initialized,
507
+ isHealthy,
508
+ lastEventAt: this.lastEventReceivedAt ? new Date(this.lastEventReceivedAt) : null,
509
+ timeSinceLastEvent,
510
+ channelCount: this.channels.length,
511
+ isReconnecting: this.isReconnecting,
512
+ reconnectAttempts: this.reconnectAttempts,
513
+ };
514
+ }
515
+ /**
516
+ * Force reconnection - useful for recovery
517
+ */
518
+ async forceReconnect() {
519
+ this.logger.info('Force reconnection requested');
520
+ this.reconnectAttempts = 0;
521
+ this.isReconnecting = false;
522
+ if (this.reconnectTimer) {
523
+ clearTimeout(this.reconnectTimer);
524
+ this.reconnectTimer = undefined;
525
+ }
526
+ await this.cleanupConnection();
527
+ await this.connect();
528
+ }
529
+ /**
530
+ * Shutdown the manager
531
+ */
532
+ async shutdown() {
533
+ this.isShuttingDown = true;
534
+ // Stop heartbeat
535
+ this.stopHeartbeat();
536
+ // Clear reconnect timer
537
+ if (this.reconnectTimer) {
538
+ clearTimeout(this.reconnectTimer);
539
+ this.reconnectTimer = undefined;
540
+ }
541
+ if (this.clients.size > 0) {
542
+ this.logger.info(`Shutting down notifications service (${this.clients.size} active connections)`);
543
+ }
544
+ // Close all SSE connections
545
+ for (const client of this.clients.values()) {
546
+ try {
547
+ client.response.end();
548
+ }
549
+ catch {
550
+ // Ignore errors during shutdown
551
+ }
552
+ }
553
+ this.clients.clear();
554
+ // Clean up PostgreSQL connection
555
+ await this.cleanupConnection();
556
+ this.initialized = false;
557
+ this.logger.info('Notifications service stopped');
558
+ }
559
+ }
560
+ // =============================================================================
561
+ // Singleton Management
562
+ // =============================================================================
563
+ let managerInstance = null;
564
+ /**
565
+ * Set the notifications manager singleton
566
+ */
567
+ export function setNotificationsManager(manager) {
568
+ managerInstance = manager;
569
+ }
570
+ /**
571
+ * Get the notifications manager singleton
572
+ * @throws Error if manager is not initialized
573
+ */
574
+ export function getNotificationsManager() {
575
+ if (!managerInstance) {
576
+ throw new Error('NotificationsManager not initialized. Did you register the notifications plugin?');
577
+ }
578
+ return managerInstance;
579
+ }
580
+ /**
581
+ * Check if notifications manager is available
582
+ */
583
+ export function hasNotificationsManager() {
584
+ return managerInstance !== null;
585
+ }
586
+ // =============================================================================
587
+ // Helper Functions
588
+ // =============================================================================
589
+ /**
590
+ * Broadcast event to a specific device
591
+ * @returns Number of clients the event was sent to
592
+ */
593
+ export function broadcastToDevice(deviceId, eventType, payload) {
594
+ return getNotificationsManager().broadcastToDevice(deviceId, eventType, payload);
595
+ }
596
+ /**
597
+ * Broadcast event to all devices for a user
598
+ * @returns Number of clients the event was sent to
599
+ */
600
+ export function broadcastToUser(userId, eventType, payload) {
601
+ return getNotificationsManager().broadcastToUser(userId, eventType, payload);
602
+ }
603
+ /**
604
+ * Broadcast event to all connected clients
605
+ * @returns Number of clients the event was sent to
606
+ */
607
+ export function broadcastToAll(eventType, payload) {
608
+ return getNotificationsManager().broadcastToAll(eventType, payload);
609
+ }
610
+ //# sourceMappingURL=notifications-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications-manager.js","sourceRoot":"","sources":["../../../src/plugins/notifications/notifications-manager.ts"],"names":[],"mappings":"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"}