@memberjunction/core-entities 3.3.0 → 3.4.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.
@@ -0,0 +1,149 @@
1
+ /**
2
+ * @fileoverview MCP Engine for caching MCP server, connection, and tool data
3
+ *
4
+ * Provides centralized caching for MCP (Model Context Protocol) entities.
5
+ * Execution logs are NOT cached here - they should be loaded on-demand via RunView.
6
+ *
7
+ * @module @memberjunction/core-entities/MCPEngine
8
+ */
9
+ import { BaseEngine, IMetadataProvider, UserInfo } from "@memberjunction/core";
10
+ import { MCPServerEntity, MCPServerConnectionEntity, MCPServerToolEntity } from "../generated/entity_subclasses";
11
+ /**
12
+ * MCPEngine provides centralized caching for MCP-related entities.
13
+ *
14
+ * Cached entities:
15
+ * - MCP Servers: Server definitions with transport, auth, and rate limit config
16
+ * - MCP Server Connections: Connection instances for each server
17
+ * - MCP Server Tools: Tools discovered from MCP servers
18
+ *
19
+ * NOT cached (load on-demand):
20
+ * - MCP Tool Execution Logs: Historical data that should be queried as needed
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * // Initialize the engine
25
+ * await MCPEngine.Instance.Config(false, contextUser);
26
+ *
27
+ * // Access cached data
28
+ * const servers = MCPEngine.Instance.Servers;
29
+ * const connections = MCPEngine.Instance.Connections;
30
+ * const tools = MCPEngine.Instance.Tools;
31
+ *
32
+ * // Get tools for a specific server
33
+ * const serverTools = MCPEngine.Instance.GetToolsByServer(serverId);
34
+ *
35
+ * // Force refresh
36
+ * await MCPEngine.Instance.Config(true, contextUser);
37
+ * ```
38
+ */
39
+ export declare class MCPEngine extends BaseEngine<MCPEngine> {
40
+ /**
41
+ * Configures and loads the MCP engine data.
42
+ *
43
+ * @param forceRefresh - If true, forces a refresh of cached data
44
+ * @param contextUser - User context for data loading (required for server-side)
45
+ * @param provider - Optional metadata provider
46
+ */
47
+ Config(forceRefresh?: boolean, contextUser?: UserInfo, provider?: IMetadataProvider): Promise<void>;
48
+ /**
49
+ * Gets the singleton instance of MCPEngine
50
+ */
51
+ static get Instance(): MCPEngine;
52
+ private _Servers;
53
+ private _Connections;
54
+ private _Tools;
55
+ /**
56
+ * Gets all cached MCP servers
57
+ */
58
+ get Servers(): MCPServerEntity[];
59
+ /**
60
+ * Gets all cached MCP server connections
61
+ */
62
+ get Connections(): MCPServerConnectionEntity[];
63
+ /**
64
+ * Gets all cached MCP server tools
65
+ */
66
+ get Tools(): MCPServerToolEntity[];
67
+ /**
68
+ * Gets a server by ID
69
+ *
70
+ * @param serverId - The server ID
71
+ * @returns The server entity or undefined if not found
72
+ */
73
+ GetServerById(serverId: string): MCPServerEntity | undefined;
74
+ /**
75
+ * Gets a connection by ID
76
+ *
77
+ * @param connectionId - The connection ID
78
+ * @returns The connection entity or undefined if not found
79
+ */
80
+ GetConnectionById(connectionId: string): MCPServerConnectionEntity | undefined;
81
+ /**
82
+ * Gets a tool by ID
83
+ *
84
+ * @param toolId - The tool ID
85
+ * @returns The tool entity or undefined if not found
86
+ */
87
+ GetToolById(toolId: string): MCPServerToolEntity | undefined;
88
+ /**
89
+ * Gets all connections for a specific server
90
+ *
91
+ * @param serverId - The server ID
92
+ * @returns Array of connections for the server
93
+ */
94
+ GetConnectionsByServer(serverId: string): MCPServerConnectionEntity[];
95
+ /**
96
+ * Gets all tools for a specific server
97
+ *
98
+ * @param serverId - The server ID
99
+ * @returns Array of tools for the server
100
+ */
101
+ GetToolsByServer(serverId: string): MCPServerToolEntity[];
102
+ /**
103
+ * Gets active servers only
104
+ *
105
+ * @returns Array of servers with Status = 'Active'
106
+ */
107
+ get ActiveServers(): MCPServerEntity[];
108
+ /**
109
+ * Gets active connections only
110
+ *
111
+ * @returns Array of connections with Status = 'Active'
112
+ */
113
+ get ActiveConnections(): MCPServerConnectionEntity[];
114
+ /**
115
+ * Gets active tools only
116
+ *
117
+ * @returns Array of tools with Status = 'Active'
118
+ */
119
+ get ActiveTools(): MCPServerToolEntity[];
120
+ /**
121
+ * Gets active connections for a specific server
122
+ *
123
+ * @param serverId - The server ID
124
+ * @returns Array of active connections for the server
125
+ */
126
+ GetActiveConnectionsByServer(serverId: string): MCPServerConnectionEntity[];
127
+ /**
128
+ * Gets active tools for a specific server
129
+ *
130
+ * @param serverId - The server ID
131
+ * @returns Array of active tools for the server
132
+ */
133
+ GetActiveToolsByServer(serverId: string): MCPServerToolEntity[];
134
+ /**
135
+ * Gets the server name for a given server ID
136
+ *
137
+ * @param serverId - The server ID
138
+ * @returns The server name or 'Unknown' if not found
139
+ */
140
+ GetServerName(serverId: string): string;
141
+ /**
142
+ * Gets the connection name for a given connection ID
143
+ *
144
+ * @param connectionId - The connection ID
145
+ * @returns The connection name or 'Unknown' if not found
146
+ */
147
+ GetConnectionName(connectionId: string): string;
148
+ }
149
+ //# sourceMappingURL=MCPEngine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MCPEngine.d.ts","sourceRoot":"","sources":["../../src/engines/MCPEngine.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAA4B,iBAAiB,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACzG,OAAO,EACH,eAAe,EACf,yBAAyB,EACzB,mBAAmB,EACtB,MAAM,gCAAgC,CAAC;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,SAAU,SAAQ,UAAU,CAAC,SAAS,CAAC;IAChD;;;;;;OAMG;IACU,MAAM,CAAC,YAAY,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBhH;;OAEG;IACH,WAAkB,QAAQ,IAAI,SAAS,CAEtC;IAMD,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,YAAY,CAAmC;IACvD,OAAO,CAAC,MAAM,CAA6B;IAM3C;;OAEG;IACH,IAAW,OAAO,IAAI,eAAe,EAAE,CAEtC;IAED;;OAEG;IACH,IAAW,WAAW,IAAI,yBAAyB,EAAE,CAEpD;IAED;;OAEG;IACH,IAAW,KAAK,IAAI,mBAAmB,EAAE,CAExC;IAMD;;;;;OAKG;IACI,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAInE;;;;;OAKG;IACI,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,yBAAyB,GAAG,SAAS;IAIrF;;;;;OAKG;IACI,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAInE;;;;;OAKG;IACI,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,yBAAyB,EAAE;IAI5E;;;;;OAKG;IACI,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,mBAAmB,EAAE;IAIhE;;;;OAIG;IACH,IAAW,aAAa,IAAI,eAAe,EAAE,CAE5C;IAED;;;;OAIG;IACH,IAAW,iBAAiB,IAAI,yBAAyB,EAAE,CAE1D;IAED;;;;OAIG;IACH,IAAW,WAAW,IAAI,mBAAmB,EAAE,CAE9C;IAED;;;;;OAKG;IACI,4BAA4B,CAAC,QAAQ,EAAE,MAAM,GAAG,yBAAyB,EAAE;IAIlF;;;;;OAKG;IACI,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,mBAAmB,EAAE;IAItE;;;;;OAKG;IACI,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAK9C;;;;;OAKG;IACI,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;CAIzD"}
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ /**
3
+ * @fileoverview MCP Engine for caching MCP server, connection, and tool data
4
+ *
5
+ * Provides centralized caching for MCP (Model Context Protocol) entities.
6
+ * Execution logs are NOT cached here - they should be loaded on-demand via RunView.
7
+ *
8
+ * @module @memberjunction/core-entities/MCPEngine
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.MCPEngine = void 0;
12
+ const core_1 = require("@memberjunction/core");
13
+ /**
14
+ * MCPEngine provides centralized caching for MCP-related entities.
15
+ *
16
+ * Cached entities:
17
+ * - MCP Servers: Server definitions with transport, auth, and rate limit config
18
+ * - MCP Server Connections: Connection instances for each server
19
+ * - MCP Server Tools: Tools discovered from MCP servers
20
+ *
21
+ * NOT cached (load on-demand):
22
+ * - MCP Tool Execution Logs: Historical data that should be queried as needed
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * // Initialize the engine
27
+ * await MCPEngine.Instance.Config(false, contextUser);
28
+ *
29
+ * // Access cached data
30
+ * const servers = MCPEngine.Instance.Servers;
31
+ * const connections = MCPEngine.Instance.Connections;
32
+ * const tools = MCPEngine.Instance.Tools;
33
+ *
34
+ * // Get tools for a specific server
35
+ * const serverTools = MCPEngine.Instance.GetToolsByServer(serverId);
36
+ *
37
+ * // Force refresh
38
+ * await MCPEngine.Instance.Config(true, contextUser);
39
+ * ```
40
+ */
41
+ class MCPEngine extends core_1.BaseEngine {
42
+ constructor() {
43
+ super(...arguments);
44
+ // ========================================
45
+ // Private Storage
46
+ // ========================================
47
+ this._Servers = [];
48
+ this._Connections = [];
49
+ this._Tools = [];
50
+ }
51
+ /**
52
+ * Configures and loads the MCP engine data.
53
+ *
54
+ * @param forceRefresh - If true, forces a refresh of cached data
55
+ * @param contextUser - User context for data loading (required for server-side)
56
+ * @param provider - Optional metadata provider
57
+ */
58
+ async Config(forceRefresh, contextUser, provider) {
59
+ const configs = [
60
+ {
61
+ Type: 'entity',
62
+ EntityName: 'MJ: MCP Servers',
63
+ PropertyName: '_Servers',
64
+ CacheLocal: true
65
+ },
66
+ {
67
+ Type: 'entity',
68
+ EntityName: 'MJ: MCP Server Connections',
69
+ PropertyName: '_Connections',
70
+ CacheLocal: true
71
+ },
72
+ {
73
+ Type: 'entity',
74
+ EntityName: 'MJ: MCP Server Tools',
75
+ PropertyName: '_Tools',
76
+ CacheLocal: true
77
+ }
78
+ ];
79
+ await this.Load(configs, provider, forceRefresh, contextUser);
80
+ }
81
+ /**
82
+ * Gets the singleton instance of MCPEngine
83
+ */
84
+ static get Instance() {
85
+ return super.getInstance();
86
+ }
87
+ // ========================================
88
+ // Public Getters
89
+ // ========================================
90
+ /**
91
+ * Gets all cached MCP servers
92
+ */
93
+ get Servers() {
94
+ return this._Servers;
95
+ }
96
+ /**
97
+ * Gets all cached MCP server connections
98
+ */
99
+ get Connections() {
100
+ return this._Connections;
101
+ }
102
+ /**
103
+ * Gets all cached MCP server tools
104
+ */
105
+ get Tools() {
106
+ return this._Tools;
107
+ }
108
+ // ========================================
109
+ // Helper Methods
110
+ // ========================================
111
+ /**
112
+ * Gets a server by ID
113
+ *
114
+ * @param serverId - The server ID
115
+ * @returns The server entity or undefined if not found
116
+ */
117
+ GetServerById(serverId) {
118
+ return this._Servers.find(s => s.ID === serverId);
119
+ }
120
+ /**
121
+ * Gets a connection by ID
122
+ *
123
+ * @param connectionId - The connection ID
124
+ * @returns The connection entity or undefined if not found
125
+ */
126
+ GetConnectionById(connectionId) {
127
+ return this._Connections.find(c => c.ID === connectionId);
128
+ }
129
+ /**
130
+ * Gets a tool by ID
131
+ *
132
+ * @param toolId - The tool ID
133
+ * @returns The tool entity or undefined if not found
134
+ */
135
+ GetToolById(toolId) {
136
+ return this._Tools.find(t => t.ID === toolId);
137
+ }
138
+ /**
139
+ * Gets all connections for a specific server
140
+ *
141
+ * @param serverId - The server ID
142
+ * @returns Array of connections for the server
143
+ */
144
+ GetConnectionsByServer(serverId) {
145
+ return this._Connections.filter(c => c.MCPServerID === serverId);
146
+ }
147
+ /**
148
+ * Gets all tools for a specific server
149
+ *
150
+ * @param serverId - The server ID
151
+ * @returns Array of tools for the server
152
+ */
153
+ GetToolsByServer(serverId) {
154
+ return this._Tools.filter(t => t.MCPServerID === serverId);
155
+ }
156
+ /**
157
+ * Gets active servers only
158
+ *
159
+ * @returns Array of servers with Status = 'Active'
160
+ */
161
+ get ActiveServers() {
162
+ return this._Servers.filter(s => s.Status === 'Active');
163
+ }
164
+ /**
165
+ * Gets active connections only
166
+ *
167
+ * @returns Array of connections with Status = 'Active'
168
+ */
169
+ get ActiveConnections() {
170
+ return this._Connections.filter(c => c.Status === 'Active');
171
+ }
172
+ /**
173
+ * Gets active tools only
174
+ *
175
+ * @returns Array of tools with Status = 'Active'
176
+ */
177
+ get ActiveTools() {
178
+ return this._Tools.filter(t => t.Status === 'Active');
179
+ }
180
+ /**
181
+ * Gets active connections for a specific server
182
+ *
183
+ * @param serverId - The server ID
184
+ * @returns Array of active connections for the server
185
+ */
186
+ GetActiveConnectionsByServer(serverId) {
187
+ return this._Connections.filter(c => c.MCPServerID === serverId && c.Status === 'Active');
188
+ }
189
+ /**
190
+ * Gets active tools for a specific server
191
+ *
192
+ * @param serverId - The server ID
193
+ * @returns Array of active tools for the server
194
+ */
195
+ GetActiveToolsByServer(serverId) {
196
+ return this._Tools.filter(t => t.MCPServerID === serverId && t.Status === 'Active');
197
+ }
198
+ /**
199
+ * Gets the server name for a given server ID
200
+ *
201
+ * @param serverId - The server ID
202
+ * @returns The server name or 'Unknown' if not found
203
+ */
204
+ GetServerName(serverId) {
205
+ const server = this.GetServerById(serverId);
206
+ return server?.Name ?? 'Unknown';
207
+ }
208
+ /**
209
+ * Gets the connection name for a given connection ID
210
+ *
211
+ * @param connectionId - The connection ID
212
+ * @returns The connection name or 'Unknown' if not found
213
+ */
214
+ GetConnectionName(connectionId) {
215
+ const connection = this.GetConnectionById(connectionId);
216
+ return connection?.Name ?? 'Unknown';
217
+ }
218
+ }
219
+ exports.MCPEngine = MCPEngine;
220
+ //# sourceMappingURL=MCPEngine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MCPEngine.js","sourceRoot":"","sources":["../../src/engines/MCPEngine.ts"],"names":[],"mappings":"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"}
@@ -44,6 +44,25 @@ export declare class UserInfoEngine extends BaseEngine<UserInfoEngine> {
44
44
  private _UserNotificationPreferences;
45
45
  private _loadedForUserId;
46
46
  private _createDefaultAppsPromise;
47
+ /**
48
+ * Debounce time in milliseconds for SetSettingDebounced calls.
49
+ * Default is 500ms. Change via the SettingsDebounceMs setter.
50
+ */
51
+ private _settingsDebounceMs;
52
+ /**
53
+ * Map of pending setting updates: key -> { value, contextUser, timestamp }
54
+ * These are queued and flushed after the debounce period of inactivity.
55
+ */
56
+ private _pendingSettings;
57
+ /**
58
+ * Timer handle for the debounce flush
59
+ */
60
+ private _settingsDebounceTimer;
61
+ /**
62
+ * Promise that resolves when the current flush operation completes.
63
+ * Used to prevent concurrent flush operations.
64
+ */
65
+ private _flushPromise;
47
66
  /**
48
67
  * Configures the engine by loading user-specific metadata from the database.
49
68
  * All entities are filtered by the current user's ID and cached locally for performance.
@@ -87,6 +106,50 @@ export declare class UserInfoEngine extends BaseEngine<UserInfoEngine> {
87
106
  * @returns true if successful (or setting didn't exist), false on error
88
107
  */
89
108
  DeleteSetting(settingKey: string): Promise<boolean>;
109
+ /**
110
+ * Get the current debounce time in milliseconds for SetSettingDebounced calls.
111
+ */
112
+ get SettingsDebounceMs(): number;
113
+ /**
114
+ * Set the debounce time in milliseconds for SetSettingDebounced calls.
115
+ * When changed, any pending settings are flushed first before the new debounce time takes effect.
116
+ * @param value - The debounce time in milliseconds (minimum 100ms, maximum 10000ms)
117
+ */
118
+ set SettingsDebounceMs(value: number);
119
+ /**
120
+ * Queue a setting update with debouncing. Multiple calls within the debounce period
121
+ * are batched together, with only the last value for each key being saved.
122
+ * The actual database save occurs after the debounce period of inactivity.
123
+ *
124
+ * This is the preferred method for UI components that may update settings frequently
125
+ * (e.g., on every resize, scroll, or input change).
126
+ *
127
+ * @param settingKey - The setting key (e.g., "AI_DASHBOARD_ROOT/ai-models")
128
+ * @param value - The setting value (string, typically JSON for complex data)
129
+ * @param contextUser - Optional user context for server-side use
130
+ */
131
+ SetSettingDebounced(settingKey: string, value: string, contextUser?: UserInfo): void;
132
+ /**
133
+ * Immediately flush all pending debounced settings to the database.
134
+ * Call this when you need to ensure settings are saved (e.g., before navigation).
135
+ * Safe to call multiple times - concurrent calls will wait for the current flush to complete.
136
+ *
137
+ * @returns Promise that resolves when all pending settings have been saved
138
+ */
139
+ FlushPendingSettings(): Promise<void>;
140
+ /**
141
+ * Internal method to perform the actual flush of settings.
142
+ * @param settingsToSave - Map of settings to save
143
+ */
144
+ private doFlushSettings;
145
+ /**
146
+ * Check if there are any pending debounced settings waiting to be saved.
147
+ */
148
+ get HasPendingSettings(): boolean;
149
+ /**
150
+ * Get the number of pending debounced settings.
151
+ */
152
+ get PendingSettingsCount(): number;
90
153
  /**
91
154
  * Get unread notifications for the current user
92
155
  */
@@ -1 +1 @@
1
- {"version":3,"file":"UserInfoEngine.d.ts","sourceRoot":"","sources":["../../src/engines/UserInfoEngine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"UserInfoEngine.d.ts","sourceRoot":"","sources":["../../src/engines/UserInfoEngine.ts"],"names":[],"mappings":"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"}
@@ -47,6 +47,28 @@ let UserInfoEngine = class UserInfoEngine extends core_1.BaseEngine {
47
47
  this._loadedForUserId = null;
48
48
  // Track in-progress CreateDefaultApplications call to prevent duplicate execution
49
49
  this._createDefaultAppsPromise = null;
50
+ // ========================================================================
51
+ // DEBOUNCED SETTINGS SUPPORT
52
+ // ========================================================================
53
+ /**
54
+ * Debounce time in milliseconds for SetSettingDebounced calls.
55
+ * Default is 500ms. Change via the SettingsDebounceMs setter.
56
+ */
57
+ this._settingsDebounceMs = 500;
58
+ /**
59
+ * Map of pending setting updates: key -> { value, contextUser, timestamp }
60
+ * These are queued and flushed after the debounce period of inactivity.
61
+ */
62
+ this._pendingSettings = new Map();
63
+ /**
64
+ * Timer handle for the debounce flush
65
+ */
66
+ this._settingsDebounceTimer = null;
67
+ /**
68
+ * Promise that resolves when the current flush operation completes.
69
+ * Used to prevent concurrent flush operations.
70
+ */
71
+ this._flushPromise = null;
50
72
  }
51
73
  /**
52
74
  * Returns the global instance of the class. This is a singleton class, so there is only one instance of it in the application.
@@ -248,6 +270,120 @@ let UserInfoEngine = class UserInfoEngine extends core_1.BaseEngine {
248
270
  return false;
249
271
  }
250
272
  }
273
+ // ========================================================================
274
+ // DEBOUNCED SETTINGS METHODS
275
+ // ========================================================================
276
+ /**
277
+ * Get the current debounce time in milliseconds for SetSettingDebounced calls.
278
+ */
279
+ get SettingsDebounceMs() {
280
+ return this._settingsDebounceMs;
281
+ }
282
+ /**
283
+ * Set the debounce time in milliseconds for SetSettingDebounced calls.
284
+ * When changed, any pending settings are flushed first before the new debounce time takes effect.
285
+ * @param value - The debounce time in milliseconds (minimum 100ms, maximum 10000ms)
286
+ */
287
+ set SettingsDebounceMs(value) {
288
+ const clampedValue = Math.max(100, Math.min(10000, value));
289
+ if (clampedValue !== this._settingsDebounceMs) {
290
+ // Flush any pending settings before changing the debounce time
291
+ this.FlushPendingSettings();
292
+ this._settingsDebounceMs = clampedValue;
293
+ }
294
+ }
295
+ /**
296
+ * Queue a setting update with debouncing. Multiple calls within the debounce period
297
+ * are batched together, with only the last value for each key being saved.
298
+ * The actual database save occurs after the debounce period of inactivity.
299
+ *
300
+ * This is the preferred method for UI components that may update settings frequently
301
+ * (e.g., on every resize, scroll, or input change).
302
+ *
303
+ * @param settingKey - The setting key (e.g., "AI_DASHBOARD_ROOT/ai-models")
304
+ * @param value - The setting value (string, typically JSON for complex data)
305
+ * @param contextUser - Optional user context for server-side use
306
+ */
307
+ SetSettingDebounced(settingKey, value, contextUser) {
308
+ // Queue the setting update
309
+ this._pendingSettings.set(settingKey, {
310
+ value,
311
+ contextUser,
312
+ timestamp: Date.now(),
313
+ });
314
+ // Reset the debounce timer
315
+ if (this._settingsDebounceTimer) {
316
+ clearTimeout(this._settingsDebounceTimer);
317
+ }
318
+ this._settingsDebounceTimer = setTimeout(() => {
319
+ this.FlushPendingSettings();
320
+ }, this._settingsDebounceMs);
321
+ }
322
+ /**
323
+ * Immediately flush all pending debounced settings to the database.
324
+ * Call this when you need to ensure settings are saved (e.g., before navigation).
325
+ * Safe to call multiple times - concurrent calls will wait for the current flush to complete.
326
+ *
327
+ * @returns Promise that resolves when all pending settings have been saved
328
+ */
329
+ async FlushPendingSettings() {
330
+ // Clear the timer since we're flushing now
331
+ if (this._settingsDebounceTimer) {
332
+ clearTimeout(this._settingsDebounceTimer);
333
+ this._settingsDebounceTimer = null;
334
+ }
335
+ // If nothing pending, return immediately
336
+ if (this._pendingSettings.size === 0) {
337
+ return;
338
+ }
339
+ // If a flush is already in progress, wait for it and then check again
340
+ if (this._flushPromise) {
341
+ await this._flushPromise;
342
+ // After waiting, there might be new pending settings, so recurse
343
+ if (this._pendingSettings.size > 0) {
344
+ return this.FlushPendingSettings();
345
+ }
346
+ return;
347
+ }
348
+ // Take a snapshot of pending settings and clear the queue
349
+ const settingsToSave = new Map(this._pendingSettings);
350
+ this._pendingSettings.clear();
351
+ // Create the flush promise
352
+ this._flushPromise = this.doFlushSettings(settingsToSave);
353
+ try {
354
+ await this._flushPromise;
355
+ }
356
+ finally {
357
+ this._flushPromise = null;
358
+ }
359
+ }
360
+ /**
361
+ * Internal method to perform the actual flush of settings.
362
+ * @param settingsToSave - Map of settings to save
363
+ */
364
+ async doFlushSettings(settingsToSave) {
365
+ const savePromises = [];
366
+ for (const [key, { value, contextUser }] of settingsToSave) {
367
+ savePromises.push(this.SetSetting(key, value, contextUser));
368
+ }
369
+ const results = await Promise.all(savePromises);
370
+ const failedCount = results.filter((r) => !r).length;
371
+ if (failedCount > 0) {
372
+ console.warn(`UserInfoEngine.FlushPendingSettings: ${failedCount} of ${results.length} settings failed to save`);
373
+ }
374
+ }
375
+ /**
376
+ * Check if there are any pending debounced settings waiting to be saved.
377
+ */
378
+ get HasPendingSettings() {
379
+ return this._pendingSettings.size > 0;
380
+ }
381
+ /**
382
+ * Get the number of pending debounced settings.
383
+ */
384
+ get PendingSettingsCount() {
385
+ return this._pendingSettings.size;
386
+ }
251
387
  /**
252
388
  * Get unread notifications for the current user
253
389
  */