@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.
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/dist/plugins/bans/bans-plugin.d.ts.map +1 -1
- package/dist/plugins/bans/bans-plugin.js +12 -3
- package/dist/plugins/bans/bans-plugin.js.map +1 -1
- package/dist/plugins/devices/__tests__/devices-plugin.test.d.ts +11 -0
- package/dist/plugins/devices/__tests__/devices-plugin.test.d.ts.map +1 -0
- package/dist/plugins/devices/__tests__/devices-plugin.test.js +410 -0
- package/dist/plugins/devices/__tests__/devices-plugin.test.js.map +1 -0
- package/dist/plugins/devices/__tests__/token-utils.test.d.ts +7 -0
- package/dist/plugins/devices/__tests__/token-utils.test.d.ts.map +1 -0
- package/dist/plugins/devices/__tests__/token-utils.test.js +197 -0
- package/dist/plugins/devices/__tests__/token-utils.test.js.map +1 -0
- package/dist/plugins/devices/adapters/compute-adapter.d.ts +36 -0
- package/dist/plugins/devices/adapters/compute-adapter.d.ts.map +1 -0
- package/dist/plugins/devices/adapters/compute-adapter.js +100 -0
- package/dist/plugins/devices/adapters/compute-adapter.js.map +1 -0
- package/dist/plugins/devices/adapters/index.d.ts +12 -0
- package/dist/plugins/devices/adapters/index.d.ts.map +1 -0
- package/dist/plugins/devices/adapters/index.js +10 -0
- package/dist/plugins/devices/adapters/index.js.map +1 -0
- package/dist/plugins/devices/adapters/mobile-adapter.d.ts +41 -0
- package/dist/plugins/devices/adapters/mobile-adapter.d.ts.map +1 -0
- package/dist/plugins/devices/adapters/mobile-adapter.js +131 -0
- package/dist/plugins/devices/adapters/mobile-adapter.js.map +1 -0
- package/dist/plugins/devices/devices-plugin.d.ts +70 -0
- package/dist/plugins/devices/devices-plugin.d.ts.map +1 -0
- package/dist/plugins/devices/devices-plugin.js +453 -0
- package/dist/plugins/devices/devices-plugin.js.map +1 -0
- package/dist/plugins/devices/index.d.ts +18 -0
- package/dist/plugins/devices/index.d.ts.map +1 -0
- package/dist/plugins/devices/index.js +18 -0
- package/dist/plugins/devices/index.js.map +1 -0
- package/dist/plugins/devices/stores/index.d.ts +9 -0
- package/dist/plugins/devices/stores/index.d.ts.map +1 -0
- package/dist/plugins/devices/stores/index.js +9 -0
- package/dist/plugins/devices/stores/index.js.map +1 -0
- package/dist/plugins/devices/stores/postgres-store.d.ts +26 -0
- package/dist/plugins/devices/stores/postgres-store.d.ts.map +1 -0
- package/dist/plugins/devices/stores/postgres-store.js +199 -0
- package/dist/plugins/devices/stores/postgres-store.js.map +1 -0
- package/dist/plugins/devices/token-utils.d.ts +100 -0
- package/dist/plugins/devices/token-utils.d.ts.map +1 -0
- package/dist/plugins/devices/token-utils.js +162 -0
- package/dist/plugins/devices/token-utils.js.map +1 -0
- package/dist/plugins/devices/types.d.ts +307 -0
- package/dist/plugins/devices/types.d.ts.map +1 -0
- package/dist/plugins/devices/types.js +10 -0
- package/dist/plugins/devices/types.js.map +1 -0
- package/dist/plugins/index.d.ts +14 -2
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js +13 -1
- package/dist/plugins/index.js.map +1 -1
- package/dist/plugins/notifications/__tests__/notifications-manager.test.d.ts +5 -0
- package/dist/plugins/notifications/__tests__/notifications-manager.test.d.ts.map +1 -0
- package/dist/plugins/notifications/__tests__/notifications-manager.test.js +470 -0
- package/dist/plugins/notifications/__tests__/notifications-manager.test.js.map +1 -0
- package/dist/plugins/notifications/index.d.ts +71 -0
- package/dist/plugins/notifications/index.d.ts.map +1 -0
- package/dist/plugins/notifications/index.js +72 -0
- package/dist/plugins/notifications/index.js.map +1 -0
- package/dist/plugins/notifications/notifications-manager.d.ts +182 -0
- package/dist/plugins/notifications/notifications-manager.d.ts.map +1 -0
- package/dist/plugins/notifications/notifications-manager.js +610 -0
- package/dist/plugins/notifications/notifications-manager.js.map +1 -0
- package/dist/plugins/notifications/notifications-plugin.d.ts +83 -0
- package/dist/plugins/notifications/notifications-plugin.d.ts.map +1 -0
- package/dist/plugins/notifications/notifications-plugin.js +337 -0
- package/dist/plugins/notifications/notifications-plugin.js.map +1 -0
- package/dist/plugins/notifications/types.d.ts +164 -0
- package/dist/plugins/notifications/types.d.ts.map +1 -0
- package/dist/plugins/notifications/types.js +9 -0
- package/dist/plugins/notifications/types.js.map +1 -0
- package/dist/plugins/parental/__tests__/parental-plugin.test.d.ts +12 -0
- package/dist/plugins/parental/__tests__/parental-plugin.test.d.ts.map +1 -0
- package/dist/plugins/parental/__tests__/parental-plugin.test.js +349 -0
- package/dist/plugins/parental/__tests__/parental-plugin.test.js.map +1 -0
- package/dist/plugins/parental/adapters/index.d.ts +8 -0
- package/dist/plugins/parental/adapters/index.d.ts.map +1 -0
- package/dist/plugins/parental/adapters/index.js +7 -0
- package/dist/plugins/parental/adapters/index.js.map +1 -0
- package/dist/plugins/parental/adapters/kids-adapter.d.ts +24 -0
- package/dist/plugins/parental/adapters/kids-adapter.d.ts.map +1 -0
- package/dist/plugins/parental/adapters/kids-adapter.js +174 -0
- package/dist/plugins/parental/adapters/kids-adapter.js.map +1 -0
- package/dist/plugins/parental/index.d.ts +14 -0
- package/dist/plugins/parental/index.d.ts.map +1 -0
- package/dist/plugins/parental/index.js +15 -0
- package/dist/plugins/parental/index.js.map +1 -0
- package/dist/plugins/parental/parental-plugin.d.ts +88 -0
- package/dist/plugins/parental/parental-plugin.d.ts.map +1 -0
- package/dist/plugins/parental/parental-plugin.js +666 -0
- package/dist/plugins/parental/parental-plugin.js.map +1 -0
- package/dist/plugins/parental/stores/index.d.ts +7 -0
- package/dist/plugins/parental/stores/index.d.ts.map +1 -0
- package/dist/plugins/parental/stores/index.js +7 -0
- package/dist/plugins/parental/stores/index.js.map +1 -0
- package/dist/plugins/parental/stores/postgres-store.d.ts +10 -0
- package/dist/plugins/parental/stores/postgres-store.d.ts.map +1 -0
- package/dist/plugins/parental/stores/postgres-store.js +209 -0
- package/dist/plugins/parental/stores/postgres-store.js.map +1 -0
- package/dist/plugins/parental/types.d.ts +154 -0
- package/dist/plugins/parental/types.d.ts.map +1 -0
- package/dist/plugins/parental/types.js +10 -0
- package/dist/plugins/parental/types.js.map +1 -0
- package/dist/plugins/profiles/__tests__/profiles-plugin.test.d.ts +11 -0
- package/dist/plugins/profiles/__tests__/profiles-plugin.test.d.ts.map +1 -0
- package/dist/plugins/profiles/__tests__/profiles-plugin.test.js +243 -0
- package/dist/plugins/profiles/__tests__/profiles-plugin.test.js.map +1 -0
- package/dist/plugins/profiles/index.d.ts +12 -0
- package/dist/plugins/profiles/index.d.ts.map +1 -0
- package/dist/plugins/profiles/index.js +13 -0
- package/dist/plugins/profiles/index.js.map +1 -0
- package/dist/plugins/profiles/profiles-plugin.d.ts +71 -0
- package/dist/plugins/profiles/profiles-plugin.d.ts.map +1 -0
- package/dist/plugins/profiles/profiles-plugin.js +481 -0
- package/dist/plugins/profiles/profiles-plugin.js.map +1 -0
- package/dist/plugins/profiles/stores/index.d.ts +9 -0
- package/dist/plugins/profiles/stores/index.d.ts.map +1 -0
- package/dist/plugins/profiles/stores/index.js +9 -0
- package/dist/plugins/profiles/stores/index.js.map +1 -0
- package/dist/plugins/profiles/stores/postgres-store.d.ts +18 -0
- package/dist/plugins/profiles/stores/postgres-store.d.ts.map +1 -0
- package/dist/plugins/profiles/stores/postgres-store.js +310 -0
- package/dist/plugins/profiles/stores/postgres-store.js.map +1 -0
- package/dist/plugins/profiles/types.d.ts +289 -0
- package/dist/plugins/profiles/types.d.ts.map +1 -0
- package/dist/plugins/profiles/types.js +10 -0
- package/dist/plugins/profiles/types.js.map +1 -0
- package/dist/plugins/subscriptions/__tests__/subscriptions-plugin.test.d.ts +11 -0
- package/dist/plugins/subscriptions/__tests__/subscriptions-plugin.test.d.ts.map +1 -0
- package/dist/plugins/subscriptions/__tests__/subscriptions-plugin.test.js +305 -0
- package/dist/plugins/subscriptions/__tests__/subscriptions-plugin.test.js.map +1 -0
- package/dist/plugins/subscriptions/index.d.ts +12 -0
- package/dist/plugins/subscriptions/index.d.ts.map +1 -0
- package/dist/plugins/subscriptions/index.js +13 -0
- package/dist/plugins/subscriptions/index.js.map +1 -0
- package/dist/plugins/subscriptions/stores/index.d.ts +9 -0
- package/dist/plugins/subscriptions/stores/index.d.ts.map +1 -0
- package/dist/plugins/subscriptions/stores/index.js +9 -0
- package/dist/plugins/subscriptions/stores/index.js.map +1 -0
- package/dist/plugins/subscriptions/stores/postgres-store.d.ts +14 -0
- package/dist/plugins/subscriptions/stores/postgres-store.d.ts.map +1 -0
- package/dist/plugins/subscriptions/stores/postgres-store.js +359 -0
- package/dist/plugins/subscriptions/stores/postgres-store.js.map +1 -0
- package/dist/plugins/subscriptions/subscriptions-plugin.d.ts +82 -0
- package/dist/plugins/subscriptions/subscriptions-plugin.d.ts.map +1 -0
- package/dist/plugins/subscriptions/subscriptions-plugin.js +449 -0
- package/dist/plugins/subscriptions/subscriptions-plugin.js.map +1 -0
- package/dist/plugins/subscriptions/types.d.ts +308 -0
- package/dist/plugins/subscriptions/types.d.ts.map +1 -0
- package/dist/plugins/subscriptions/types.js +10 -0
- package/dist/plugins/subscriptions/types.js.map +1 -0
- package/dist/plugins/usage/__tests__/usage-plugin.test.d.ts +11 -0
- package/dist/plugins/usage/__tests__/usage-plugin.test.d.ts.map +1 -0
- package/dist/plugins/usage/__tests__/usage-plugin.test.js +218 -0
- package/dist/plugins/usage/__tests__/usage-plugin.test.js.map +1 -0
- package/dist/plugins/usage/index.d.ts +12 -0
- package/dist/plugins/usage/index.d.ts.map +1 -0
- package/dist/plugins/usage/index.js +13 -0
- package/dist/plugins/usage/index.js.map +1 -0
- package/dist/plugins/usage/stores/index.d.ts +9 -0
- package/dist/plugins/usage/stores/index.d.ts.map +1 -0
- package/dist/plugins/usage/stores/index.js +9 -0
- package/dist/plugins/usage/stores/index.js.map +1 -0
- package/dist/plugins/usage/stores/postgres-store.d.ts +14 -0
- package/dist/plugins/usage/stores/postgres-store.d.ts.map +1 -0
- package/dist/plugins/usage/stores/postgres-store.js +146 -0
- package/dist/plugins/usage/stores/postgres-store.js.map +1 -0
- package/dist/plugins/usage/types.d.ts +195 -0
- package/dist/plugins/usage/types.d.ts.map +1 -0
- package/dist/plugins/usage/types.js +10 -0
- package/dist/plugins/usage/types.js.map +1 -0
- package/dist/plugins/usage/usage-plugin.d.ts +51 -0
- package/dist/plugins/usage/usage-plugin.d.ts.map +1 -0
- package/dist/plugins/usage/usage-plugin.js +412 -0
- package/dist/plugins/usage/usage-plugin.js.map +1 -0
- package/dist/plugins/users/__tests__/postgres-store.test.d.ts +10 -0
- package/dist/plugins/users/__tests__/postgres-store.test.d.ts.map +1 -0
- package/dist/plugins/users/__tests__/postgres-store.test.js +229 -0
- package/dist/plugins/users/__tests__/postgres-store.test.js.map +1 -0
- package/dist/plugins/users/__tests__/users-plugin.test.js +3 -0
- package/dist/plugins/users/__tests__/users-plugin.test.js.map +1 -1
- package/dist/plugins/users/index.d.ts +2 -2
- package/dist/plugins/users/index.d.ts.map +1 -1
- package/dist/plugins/users/index.js +1 -1
- package/dist/plugins/users/index.js.map +1 -1
- package/dist/plugins/users/stores/postgres-store.d.ts.map +1 -1
- package/dist/plugins/users/stores/postgres-store.js +76 -0
- package/dist/plugins/users/stores/postgres-store.js.map +1 -1
- package/dist/plugins/users/types.d.ts +74 -6
- package/dist/plugins/users/types.d.ts.map +1 -1
- package/dist/plugins/users/users-plugin.d.ts +15 -1
- package/dist/plugins/users/users-plugin.d.ts.map +1 -1
- package/dist/plugins/users/users-plugin.js +29 -0
- package/dist/plugins/users/users-plugin.js.map +1 -1
- package/dist-ui/assets/index-CynOqPkb.js +469 -0
- package/dist-ui/assets/index-CynOqPkb.js.map +1 -0
- package/dist-ui/index.html +1 -1
- package/dist-ui-lib/api/controlPanelApi.d.ts +46 -0
- package/dist-ui-lib/components/StatCard.d.ts +16 -0
- package/dist-ui-lib/dashboard/widgets/NotificationsStatsWidget.d.ts +12 -0
- package/dist-ui-lib/dashboard/widgets/index.d.ts +1 -0
- package/dist-ui-lib/index.js +1822 -1611
- package/dist-ui-lib/index.js.map +1 -1
- package/dist-ui-lib/pages/NotificationsPage.d.ts +9 -0
- package/dist-ui-lib/utils/formatters.d.ts +19 -0
- package/package.json +1 -1
- package/src/index.ts +178 -0
- package/src/plugins/bans/bans-plugin.ts +15 -3
- package/src/plugins/devices/__tests__/devices-plugin.test.ts +551 -0
- package/src/plugins/devices/__tests__/token-utils.test.ts +264 -0
- package/src/plugins/devices/adapters/compute-adapter.ts +139 -0
- package/src/plugins/devices/adapters/index.ts +13 -0
- package/src/plugins/devices/adapters/mobile-adapter.ts +179 -0
- package/src/plugins/devices/devices-plugin.ts +538 -0
- package/src/plugins/devices/index.ts +69 -0
- package/src/plugins/devices/stores/index.ts +9 -0
- package/src/plugins/devices/stores/postgres-store.ts +304 -0
- package/src/plugins/devices/token-utils.ts +213 -0
- package/src/plugins/devices/types.ts +351 -0
- package/src/plugins/index.ts +218 -0
- package/src/plugins/notifications/__tests__/notifications-manager.test.ts +637 -0
- package/src/plugins/notifications/index.ts +91 -0
- package/src/plugins/notifications/notifications-manager.ts +773 -0
- package/src/plugins/notifications/notifications-plugin.ts +398 -0
- package/src/plugins/notifications/types.ts +207 -0
- package/src/plugins/parental/__tests__/parental-plugin.test.ts +465 -0
- package/src/plugins/parental/adapters/index.ts +8 -0
- package/src/plugins/parental/adapters/kids-adapter.ts +206 -0
- package/src/plugins/parental/index.ts +55 -0
- package/src/plugins/parental/parental-plugin.ts +759 -0
- package/src/plugins/parental/stores/index.ts +7 -0
- package/src/plugins/parental/stores/postgres-store.ts +304 -0
- package/src/plugins/parental/types.ts +180 -0
- package/src/plugins/profiles/__tests__/profiles-plugin.test.ts +321 -0
- package/src/plugins/profiles/index.ts +49 -0
- package/src/plugins/profiles/profiles-plugin.ts +546 -0
- package/src/plugins/profiles/stores/index.ts +9 -0
- package/src/plugins/profiles/stores/postgres-store.ts +439 -0
- package/src/plugins/profiles/types.ts +338 -0
- package/src/plugins/subscriptions/__tests__/subscriptions-plugin.test.ts +404 -0
- package/src/plugins/subscriptions/index.ts +51 -0
- package/src/plugins/subscriptions/stores/index.ts +9 -0
- package/src/plugins/subscriptions/stores/postgres-store.ts +482 -0
- package/src/plugins/subscriptions/subscriptions-plugin.ts +530 -0
- package/src/plugins/subscriptions/types.ts +355 -0
- package/src/plugins/usage/__tests__/usage-plugin.test.ts +288 -0
- package/src/plugins/usage/index.ts +39 -0
- package/src/plugins/usage/stores/index.ts +9 -0
- package/src/plugins/usage/stores/postgres-store.ts +213 -0
- package/src/plugins/usage/types.ts +222 -0
- package/src/plugins/usage/usage-plugin.ts +484 -0
- package/src/plugins/users/__tests__/postgres-store.test.ts +326 -0
- package/src/plugins/users/__tests__/users-plugin.test.ts +3 -0
- package/src/plugins/users/index.ts +6 -0
- package/src/plugins/users/stores/postgres-store.ts +104 -0
- package/src/plugins/users/types.ts +82 -6
- package/src/plugins/users/users-plugin.ts +37 -0
- package/ui/src/App.tsx +5 -1
- package/ui/src/api/controlPanelApi.ts +103 -6
- package/ui/src/components/StatCard.tsx +58 -0
- package/ui/src/dashboard/builtInWidgets.tsx +3 -1
- package/ui/src/dashboard/widgets/NotificationsStatsWidget.tsx +167 -0
- package/ui/src/dashboard/widgets/index.ts +1 -0
- package/ui/src/pages/NotificationsPage.tsx +417 -0
- package/ui/src/utils/formatters.ts +33 -0
- package/dist-ui/assets/index-D7DoZ9rL.js +0 -478
- 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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"}
|