@enyo-energy/energy-app-sdk 0.0.37 → 0.0.39

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 (47) hide show
  1. package/dist/cjs/implementations/appliances/appliance-manager.cjs +399 -0
  2. package/dist/cjs/implementations/appliances/appliance-manager.d.cts +191 -0
  3. package/dist/cjs/implementations/appliances/identifier-strategies.cjs +180 -0
  4. package/dist/cjs/implementations/appliances/identifier-strategies.d.cts +140 -0
  5. package/dist/cjs/implementations/appliances/in-memory-appliance-manager.cjs +281 -0
  6. package/dist/cjs/implementations/appliances/in-memory-appliance-manager.d.cts +119 -0
  7. package/dist/cjs/implementations/data-bus/demo-data-bus.cjs +246 -0
  8. package/dist/cjs/implementations/data-bus/demo-data-bus.d.cts +111 -0
  9. package/dist/cjs/implementations/modbus/EnergyAppModbusDataTypeConverter.d.cts +2 -2
  10. package/dist/cjs/implementations/modbus/EnergyAppModbusFaultTolerantReader.cjs +76 -0
  11. package/dist/cjs/implementations/modbus/EnergyAppModbusFaultTolerantReader.d.cts +31 -1
  12. package/dist/cjs/implementations/modbus/EnergyAppModbusRegisterMapper.d.cts +2 -2
  13. package/dist/cjs/implementations/modbus/interfaces.d.cts +7 -93
  14. package/dist/cjs/implementations/modbus/sunspec/sunspec-devices.cjs +342 -0
  15. package/dist/cjs/implementations/modbus/sunspec/sunspec-devices.d.cts +95 -0
  16. package/dist/cjs/implementations/modbus/sunspec/sunspec-modbus-client.cjs +433 -0
  17. package/dist/cjs/implementations/modbus/sunspec/sunspec-modbus-client.d.cts +171 -0
  18. package/dist/cjs/index.cjs +2 -3
  19. package/dist/cjs/index.d.cts +2 -3
  20. package/dist/cjs/types/enyo-data-bus-value.d.cts +2 -1
  21. package/dist/cjs/version.cjs +1 -1
  22. package/dist/cjs/version.d.cts +1 -1
  23. package/dist/implementations/appliances/appliance-manager.d.ts +191 -0
  24. package/dist/implementations/appliances/appliance-manager.js +395 -0
  25. package/dist/implementations/appliances/demo-appliance-manager.d.ts +118 -0
  26. package/dist/implementations/appliances/demo-appliance-manager.js +277 -0
  27. package/dist/implementations/appliances/identifier-strategies.d.ts +140 -0
  28. package/dist/implementations/appliances/identifier-strategies.js +171 -0
  29. package/dist/implementations/appliances/in-memory-appliance-manager.d.ts +119 -0
  30. package/dist/implementations/appliances/in-memory-appliance-manager.js +277 -0
  31. package/dist/implementations/data-bus/demo-data-bus.d.ts +111 -0
  32. package/dist/implementations/data-bus/demo-data-bus.js +242 -0
  33. package/dist/implementations/modbus/EnergyAppModbusDataTypeConverter.d.ts +2 -2
  34. package/dist/implementations/modbus/EnergyAppModbusFaultTolerantReader.d.ts +31 -1
  35. package/dist/implementations/modbus/EnergyAppModbusFaultTolerantReader.js +76 -0
  36. package/dist/implementations/modbus/EnergyAppModbusRegisterMapper.d.ts +2 -2
  37. package/dist/implementations/modbus/interfaces.d.ts +7 -93
  38. package/dist/implementations/modbus/sunspec/sunspec-devices.d.ts +95 -0
  39. package/dist/implementations/modbus/sunspec/sunspec-devices.js +335 -0
  40. package/dist/implementations/modbus/sunspec/sunspec-modbus-client.d.ts +171 -0
  41. package/dist/implementations/modbus/sunspec/sunspec-modbus-client.js +429 -0
  42. package/dist/index.d.ts +2 -3
  43. package/dist/index.js +2 -3
  44. package/dist/types/enyo-data-bus-value.d.ts +2 -1
  45. package/dist/version.d.ts +1 -1
  46. package/dist/version.js +1 -1
  47. package/package.json +1 -1
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IdentifierStrategyFactory = exports.FallbackIdentifierStrategy = exports.CompositeIdentifierStrategy = exports.CustomMetadataStrategy = exports.SerialNumberStrategy = exports.NetworkDeviceIdStrategy = void 0;
4
+ /**
5
+ * Strategy that uses the network device ID as the identifier.
6
+ * This is the default strategy for most appliances.
7
+ */
8
+ class NetworkDeviceIdStrategy {
9
+ name = 'networkDeviceId';
10
+ /**
11
+ * Extracts the network device ID.
12
+ * @param appliance The appliance (not used in this strategy)
13
+ * @param networkDevice The network device to get the ID from
14
+ * @returns The network device ID or undefined
15
+ */
16
+ extract(appliance, networkDevice) {
17
+ return networkDevice?.id;
18
+ }
19
+ }
20
+ exports.NetworkDeviceIdStrategy = NetworkDeviceIdStrategy;
21
+ /**
22
+ * Strategy that uses the appliance's serial number as the identifier.
23
+ * Useful when appliances can move between network devices.
24
+ */
25
+ class SerialNumberStrategy {
26
+ name = 'serialNumber';
27
+ /**
28
+ * Extracts the serial number from the appliance metadata.
29
+ * @param appliance The appliance to extract the serial number from
30
+ * @returns The serial number or undefined
31
+ */
32
+ extract(appliance) {
33
+ return appliance.metadata?.serialNumber;
34
+ }
35
+ }
36
+ exports.SerialNumberStrategy = SerialNumberStrategy;
37
+ /**
38
+ * Strategy that uses a custom metadata field as the identifier.
39
+ * Allows using any field from the appliance metadata.
40
+ */
41
+ class CustomMetadataStrategy {
42
+ fieldName;
43
+ name;
44
+ /**
45
+ * Creates a strategy that uses a custom metadata field.
46
+ * @param fieldName The name of the metadata field to use as identifier
47
+ */
48
+ constructor(fieldName) {
49
+ this.fieldName = fieldName;
50
+ this.name = `metadata.${String(fieldName)}`;
51
+ }
52
+ /**
53
+ * Extracts the custom field value from the appliance metadata.
54
+ * @param appliance The appliance to extract the field from
55
+ * @returns The field value or undefined
56
+ */
57
+ extract(appliance) {
58
+ const value = appliance.metadata?.[this.fieldName];
59
+ return value !== undefined ? String(value) : undefined;
60
+ }
61
+ }
62
+ exports.CustomMetadataStrategy = CustomMetadataStrategy;
63
+ /**
64
+ * Strategy that combines multiple identifiers to create a composite key.
65
+ * Useful when a single identifier is not unique enough.
66
+ */
67
+ class CompositeIdentifierStrategy {
68
+ strategies;
69
+ separator;
70
+ name;
71
+ /**
72
+ * Creates a strategy that combines multiple strategies.
73
+ * @param strategies The strategies to combine
74
+ * @param separator The separator to use between identifier parts
75
+ */
76
+ constructor(strategies, separator = ':') {
77
+ this.strategies = strategies;
78
+ this.separator = separator;
79
+ this.name = `composite(${strategies.map(s => s.name).join('+')})`;
80
+ }
81
+ /**
82
+ * Extracts and combines identifiers from multiple strategies.
83
+ * @param appliance The appliance to extract identifiers from
84
+ * @param networkDevice The network device if available
85
+ * @returns The combined identifier or undefined if any part is missing
86
+ */
87
+ extract(appliance, networkDevice) {
88
+ const parts = [];
89
+ for (const strategy of this.strategies) {
90
+ const value = strategy.extract(appliance, networkDevice);
91
+ if (!value) {
92
+ return undefined; // All parts must be present
93
+ }
94
+ parts.push(value);
95
+ }
96
+ return parts.join(this.separator);
97
+ }
98
+ }
99
+ exports.CompositeIdentifierStrategy = CompositeIdentifierStrategy;
100
+ /**
101
+ * Strategy that tries multiple strategies in order and uses the first available identifier.
102
+ * Useful for fallback scenarios.
103
+ */
104
+ class FallbackIdentifierStrategy {
105
+ strategies;
106
+ name;
107
+ /**
108
+ * Creates a strategy that tries multiple strategies in order.
109
+ * @param strategies The strategies to try in order
110
+ */
111
+ constructor(strategies) {
112
+ this.strategies = strategies;
113
+ this.name = `fallback(${strategies.map(s => s.name).join('|')})`;
114
+ }
115
+ /**
116
+ * Tries strategies in order and returns the first available identifier.
117
+ * @param appliance The appliance to extract identifiers from
118
+ * @param networkDevice The network device if available
119
+ * @returns The first available identifier or undefined
120
+ */
121
+ extract(appliance, networkDevice) {
122
+ for (const strategy of this.strategies) {
123
+ const value = strategy.extract(appliance, networkDevice);
124
+ if (value) {
125
+ return value;
126
+ }
127
+ }
128
+ return undefined;
129
+ }
130
+ }
131
+ exports.FallbackIdentifierStrategy = FallbackIdentifierStrategy;
132
+ /**
133
+ * Factory class for creating common identifier strategies.
134
+ */
135
+ class IdentifierStrategyFactory {
136
+ /**
137
+ * Creates the default network device ID strategy.
138
+ */
139
+ static networkDeviceId() {
140
+ return new NetworkDeviceIdStrategy();
141
+ }
142
+ /**
143
+ * Creates a serial number strategy.
144
+ */
145
+ static serialNumber() {
146
+ return new SerialNumberStrategy();
147
+ }
148
+ /**
149
+ * Creates a custom metadata field strategy.
150
+ * @param fieldName The metadata field to use
151
+ */
152
+ static customMetadata(fieldName) {
153
+ return new CustomMetadataStrategy(fieldName);
154
+ }
155
+ /**
156
+ * Creates a composite strategy that combines multiple identifiers.
157
+ * @param strategies The strategies to combine
158
+ * @param separator The separator between parts
159
+ */
160
+ static composite(strategies, separator) {
161
+ return new CompositeIdentifierStrategy(strategies, separator);
162
+ }
163
+ /**
164
+ * Creates a fallback strategy that tries multiple strategies in order.
165
+ * @param strategies The strategies to try
166
+ */
167
+ static fallback(strategies) {
168
+ return new FallbackIdentifierStrategy(strategies);
169
+ }
170
+ /**
171
+ * Creates a strategy that prefers serial number but falls back to network device ID.
172
+ */
173
+ static serialNumberOrDeviceId() {
174
+ return new FallbackIdentifierStrategy([
175
+ new SerialNumberStrategy(),
176
+ new NetworkDeviceIdStrategy()
177
+ ]);
178
+ }
179
+ }
180
+ exports.IdentifierStrategyFactory = IdentifierStrategyFactory;
@@ -0,0 +1,140 @@
1
+ import type { EnyoAppliance } from "../../types/enyo-appliance.cjs";
2
+ import type { EnyoNetworkDevice } from "../../types/enyo-network-device.cjs";
3
+ /**
4
+ * Strategy interface for extracting unique identifiers from appliances.
5
+ * Allows flexible identification of appliances based on different criteria.
6
+ */
7
+ export interface IdentifierStrategy {
8
+ /**
9
+ * Extract the unique identifier from an appliance or its associated data.
10
+ * @param appliance The appliance to extract the identifier from
11
+ * @param networkDevice Optional network device associated with the appliance
12
+ * @returns The extracted identifier string, or undefined if not available
13
+ */
14
+ extract(appliance: Partial<EnyoAppliance>, networkDevice?: EnyoNetworkDevice): string | undefined;
15
+ /**
16
+ * Name of the strategy for logging and debugging purposes.
17
+ */
18
+ name: string;
19
+ }
20
+ /**
21
+ * Strategy that uses the network device ID as the identifier.
22
+ * This is the default strategy for most appliances.
23
+ */
24
+ export declare class NetworkDeviceIdStrategy implements IdentifierStrategy {
25
+ name: string;
26
+ /**
27
+ * Extracts the network device ID.
28
+ * @param appliance The appliance (not used in this strategy)
29
+ * @param networkDevice The network device to get the ID from
30
+ * @returns The network device ID or undefined
31
+ */
32
+ extract(appliance: Partial<EnyoAppliance>, networkDevice?: EnyoNetworkDevice): string | undefined;
33
+ }
34
+ /**
35
+ * Strategy that uses the appliance's serial number as the identifier.
36
+ * Useful when appliances can move between network devices.
37
+ */
38
+ export declare class SerialNumberStrategy implements IdentifierStrategy {
39
+ name: string;
40
+ /**
41
+ * Extracts the serial number from the appliance metadata.
42
+ * @param appliance The appliance to extract the serial number from
43
+ * @returns The serial number or undefined
44
+ */
45
+ extract(appliance: Partial<EnyoAppliance>): string | undefined;
46
+ }
47
+ /**
48
+ * Strategy that uses a custom metadata field as the identifier.
49
+ * Allows using any field from the appliance metadata.
50
+ */
51
+ export declare class CustomMetadataStrategy implements IdentifierStrategy {
52
+ private fieldName;
53
+ name: string;
54
+ /**
55
+ * Creates a strategy that uses a custom metadata field.
56
+ * @param fieldName The name of the metadata field to use as identifier
57
+ */
58
+ constructor(fieldName: keyof NonNullable<EnyoAppliance['metadata']>);
59
+ /**
60
+ * Extracts the custom field value from the appliance metadata.
61
+ * @param appliance The appliance to extract the field from
62
+ * @returns The field value or undefined
63
+ */
64
+ extract(appliance: Partial<EnyoAppliance>): string | undefined;
65
+ }
66
+ /**
67
+ * Strategy that combines multiple identifiers to create a composite key.
68
+ * Useful when a single identifier is not unique enough.
69
+ */
70
+ export declare class CompositeIdentifierStrategy implements IdentifierStrategy {
71
+ private strategies;
72
+ private separator;
73
+ name: string;
74
+ /**
75
+ * Creates a strategy that combines multiple strategies.
76
+ * @param strategies The strategies to combine
77
+ * @param separator The separator to use between identifier parts
78
+ */
79
+ constructor(strategies: IdentifierStrategy[], separator?: string);
80
+ /**
81
+ * Extracts and combines identifiers from multiple strategies.
82
+ * @param appliance The appliance to extract identifiers from
83
+ * @param networkDevice The network device if available
84
+ * @returns The combined identifier or undefined if any part is missing
85
+ */
86
+ extract(appliance: Partial<EnyoAppliance>, networkDevice?: EnyoNetworkDevice): string | undefined;
87
+ }
88
+ /**
89
+ * Strategy that tries multiple strategies in order and uses the first available identifier.
90
+ * Useful for fallback scenarios.
91
+ */
92
+ export declare class FallbackIdentifierStrategy implements IdentifierStrategy {
93
+ private strategies;
94
+ name: string;
95
+ /**
96
+ * Creates a strategy that tries multiple strategies in order.
97
+ * @param strategies The strategies to try in order
98
+ */
99
+ constructor(strategies: IdentifierStrategy[]);
100
+ /**
101
+ * Tries strategies in order and returns the first available identifier.
102
+ * @param appliance The appliance to extract identifiers from
103
+ * @param networkDevice The network device if available
104
+ * @returns The first available identifier or undefined
105
+ */
106
+ extract(appliance: Partial<EnyoAppliance>, networkDevice?: EnyoNetworkDevice): string | undefined;
107
+ }
108
+ /**
109
+ * Factory class for creating common identifier strategies.
110
+ */
111
+ export declare class IdentifierStrategyFactory {
112
+ /**
113
+ * Creates the default network device ID strategy.
114
+ */
115
+ static networkDeviceId(): NetworkDeviceIdStrategy;
116
+ /**
117
+ * Creates a serial number strategy.
118
+ */
119
+ static serialNumber(): SerialNumberStrategy;
120
+ /**
121
+ * Creates a custom metadata field strategy.
122
+ * @param fieldName The metadata field to use
123
+ */
124
+ static customMetadata(fieldName: keyof NonNullable<EnyoAppliance['metadata']>): CustomMetadataStrategy;
125
+ /**
126
+ * Creates a composite strategy that combines multiple identifiers.
127
+ * @param strategies The strategies to combine
128
+ * @param separator The separator between parts
129
+ */
130
+ static composite(strategies: IdentifierStrategy[], separator?: string): CompositeIdentifierStrategy;
131
+ /**
132
+ * Creates a fallback strategy that tries multiple strategies in order.
133
+ * @param strategies The strategies to try
134
+ */
135
+ static fallback(strategies: IdentifierStrategy[]): FallbackIdentifierStrategy;
136
+ /**
137
+ * Creates a strategy that prefers serial number but falls back to network device ID.
138
+ */
139
+ static serialNumberOrDeviceId(): FallbackIdentifierStrategy;
140
+ }
@@ -0,0 +1,281 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InMemoryApplianceManager = void 0;
4
+ const enyo_appliance_js_1 = require("../../types/enyo-appliance.cjs");
5
+ const appliance_manager_js_1 = require("./appliance-manager.cjs");
6
+ /**
7
+ * Demo implementation of ApplianceManager that stores all data in memory.
8
+ * This class provides the same interface as ApplianceManager but doesn't
9
+ * use energyApp.useAppliances() for persistence.
10
+ */
11
+ class InMemoryApplianceManager extends appliance_manager_js_1.ApplianceManager {
12
+ memoryStore = new Map();
13
+ nextId = 1;
14
+ networkDevicesStore = new Map();
15
+ /**
16
+ * Creates a new DemoApplianceManager instance.
17
+ * @param energyApp The EnergyApp instance (not used for persistence in demo)
18
+ * @param config Configuration options for the manager
19
+ */
20
+ constructor(energyApp, config) {
21
+ super(energyApp, config);
22
+ }
23
+ /**
24
+ * Creates or updates an appliance in memory.
25
+ * @param config The appliance configuration
26
+ * @param existingApplianceId Optional ID of an existing appliance to update
27
+ * @returns The ID of the created or updated appliance
28
+ */
29
+ async createOrUpdateAppliance(config, existingApplianceId) {
30
+ const applianceId = existingApplianceId || `appliance_${this.nextId++}`;
31
+ // Build network device IDs list
32
+ const networkDeviceIds = config.networkDevices?.map(d => d.id) ?? [];
33
+ // Get existing metadata if updating
34
+ const existingAppliance = existingApplianceId ? this.memoryStore.get(existingApplianceId) : null;
35
+ // Merge metadata with defaults and existing values
36
+ const metadata = {
37
+ connectionType: config.metadata?.connectionType ||
38
+ existingAppliance?.metadata?.connectionType ||
39
+ enyo_appliance_js_1.EnyoApplianceConnectionType.Connector,
40
+ state: config.metadata?.state ||
41
+ existingAppliance?.metadata?.state ||
42
+ enyo_appliance_js_1.EnyoApplianceStateEnum.Connected,
43
+ ...config.metadata
44
+ };
45
+ // Build appliance data
46
+ const applianceData = {
47
+ id: applianceId,
48
+ name: config.name,
49
+ type: config.type,
50
+ networkDeviceIds,
51
+ metadata,
52
+ ...(config.topology && { topology: config.topology })
53
+ };
54
+ // Add type-specific metadata
55
+ if (config.typeMetadata) {
56
+ Object.assign(applianceData, config.typeMetadata);
57
+ }
58
+ // Save to memory store
59
+ this.memoryStore.set(applianceId, applianceData);
60
+ // Store network devices if provided
61
+ if (config.networkDevices) {
62
+ this.networkDevicesStore.set(applianceId, config.networkDevices);
63
+ }
64
+ // Update cache
65
+ this.updateCache(applianceData, config.networkDevices?.[0]);
66
+ console.log(`[DEMO] ${existingApplianceId ? 'Updated' : 'Created'} appliance ${applianceId} of type ${config.type}`);
67
+ return applianceId;
68
+ }
69
+ /**
70
+ * Gets an appliance by ID from memory.
71
+ * @param applianceId The ID of the appliance
72
+ * @returns The appliance or null if not found
73
+ */
74
+ async getApplianceById(applianceId) {
75
+ return this.memoryStore.get(applianceId) || null;
76
+ }
77
+ /**
78
+ * Gets all appliances from memory.
79
+ * @returns Array of all appliances
80
+ */
81
+ async getAllAppliances() {
82
+ return Array.from(this.memoryStore.values());
83
+ }
84
+ /**
85
+ * Gets network devices associated with an appliance.
86
+ * @param appliance The appliance
87
+ * @returns Array of network devices
88
+ */
89
+ async getNetworkDevicesForApplianceDemo(appliance) {
90
+ return this.networkDevicesStore.get(appliance.id) || [];
91
+ }
92
+ /**
93
+ * Finds appliances by their identifier using the configured strategy.
94
+ * @param identifier The identifier to search for
95
+ * @returns Array of matching appliances
96
+ */
97
+ async findByIdentifier(identifier) {
98
+ const matches = [];
99
+ const strategy = this.getIdentifierStrategy();
100
+ for (const appliance of this.memoryStore.values()) {
101
+ const networkDevices = await this.getNetworkDevicesForApplianceDemo(appliance);
102
+ const extractedId = strategy.extract(appliance, networkDevices[0]);
103
+ if (extractedId === identifier) {
104
+ matches.push(appliance);
105
+ this.updateCache(appliance, networkDevices[0]);
106
+ }
107
+ }
108
+ return matches;
109
+ }
110
+ /**
111
+ * Finds an appliance using multiple strategies.
112
+ * @param searchValue The value to search for
113
+ * @param strategies Array of strategies to try
114
+ * @returns The first matching result or undefined
115
+ */
116
+ async findWithStrategies(searchValue, strategies) {
117
+ for (const strategy of strategies) {
118
+ for (const appliance of this.memoryStore.values()) {
119
+ const networkDevices = await this.getNetworkDevicesForApplianceDemo(appliance);
120
+ const identifier = strategy.extract(appliance, networkDevices[0]);
121
+ if (identifier === searchValue) {
122
+ return {
123
+ appliance,
124
+ identifier,
125
+ strategy: strategy.name
126
+ };
127
+ }
128
+ }
129
+ }
130
+ return undefined;
131
+ }
132
+ /**
133
+ * Gets all appliances of a specific type.
134
+ * @param type The appliance type to filter by
135
+ * @returns Array of appliances of the specified type
136
+ */
137
+ async getAppliancesByType(type) {
138
+ return Array.from(this.memoryStore.values()).filter(a => a.type === type);
139
+ }
140
+ /**
141
+ * Updates the state of an appliance in memory.
142
+ * @param applianceId The ID of the appliance to update
143
+ * @param connectionType The new connection type
144
+ * @param state The new state
145
+ */
146
+ async updateApplianceState(applianceId, connectionType, state) {
147
+ const appliance = this.memoryStore.get(applianceId);
148
+ if (appliance) {
149
+ appliance.metadata = {
150
+ ...appliance.metadata,
151
+ connectionType,
152
+ state
153
+ };
154
+ this.memoryStore.set(applianceId, appliance);
155
+ this.updateCache(appliance);
156
+ console.log(`[DEMO] Updated appliance ${applianceId} state to ${state}`);
157
+ }
158
+ else {
159
+ throw new Error(`Appliance ${applianceId} not found`);
160
+ }
161
+ }
162
+ /**
163
+ * Updates metadata for an appliance in memory.
164
+ * @param applianceId The ID of the appliance
165
+ * @param metadata The metadata to update
166
+ */
167
+ async updateApplianceMetadata(applianceId, metadata) {
168
+ const appliance = this.memoryStore.get(applianceId);
169
+ if (appliance) {
170
+ appliance.metadata = {
171
+ ...appliance.metadata,
172
+ ...metadata
173
+ };
174
+ this.memoryStore.set(applianceId, appliance);
175
+ this.updateCache(appliance);
176
+ console.log(`[DEMO] Updated metadata for appliance ${applianceId}`);
177
+ }
178
+ else {
179
+ throw new Error(`Appliance ${applianceId} not found`);
180
+ }
181
+ }
182
+ /**
183
+ * Removes an appliance from memory.
184
+ * @param applianceId The ID of the appliance to remove
185
+ */
186
+ async removeAppliance(applianceId) {
187
+ if (this.memoryStore.has(applianceId)) {
188
+ this.memoryStore.delete(applianceId);
189
+ this.networkDevicesStore.delete(applianceId);
190
+ // Clean up cache (from parent class)
191
+ this.clearCache();
192
+ console.log(`[DEMO] Removed appliance ${applianceId}`);
193
+ }
194
+ else {
195
+ throw new Error(`Appliance ${applianceId} not found`);
196
+ }
197
+ }
198
+ /**
199
+ * Performs a bulk update on multiple appliances in memory.
200
+ * @param updates Array of updates to perform
201
+ * @returns Results of the bulk update operation
202
+ */
203
+ async bulkUpdate(updates) {
204
+ const succeeded = [];
205
+ const failed = [];
206
+ for (const update of updates) {
207
+ try {
208
+ const appliance = this.memoryStore.get(update.applianceId);
209
+ if (appliance) {
210
+ const updatedAppliance = {
211
+ ...appliance,
212
+ ...update.data,
213
+ id: appliance.id // Ensure ID is preserved
214
+ };
215
+ this.memoryStore.set(update.applianceId, updatedAppliance);
216
+ this.updateCache(updatedAppliance);
217
+ succeeded.push(update.applianceId);
218
+ }
219
+ else {
220
+ failed.push(update.applianceId);
221
+ }
222
+ }
223
+ catch (error) {
224
+ console.error(`[DEMO] Bulk update failed for ${update.applianceId}: ${error}`);
225
+ failed.push(update.applianceId);
226
+ }
227
+ }
228
+ console.log(`[DEMO] Bulk update completed: ${succeeded.length} succeeded, ${failed.length} failed`);
229
+ return { succeeded, failed };
230
+ }
231
+ /**
232
+ * Gets statistics about the managed appliances in memory.
233
+ * @returns Statistics object
234
+ */
235
+ async getStatistics() {
236
+ const appliances = Array.from(this.memoryStore.values());
237
+ const byType = {};
238
+ const byState = {};
239
+ for (const appliance of appliances) {
240
+ // Count by type
241
+ byType[appliance.type] = (byType[appliance.type] ?? 0) + 1;
242
+ // Count by state
243
+ const state = appliance.metadata?.state ?? 'unknown';
244
+ byState[state] = (byState[state] ?? 0) + 1;
245
+ }
246
+ return {
247
+ total: appliances.length,
248
+ byType,
249
+ byState,
250
+ cached: this.memoryStore.size
251
+ };
252
+ }
253
+ /**
254
+ * Refreshes the cache with all appliances from memory.
255
+ */
256
+ async refreshCache() {
257
+ this.clearCache();
258
+ for (const appliance of this.memoryStore.values()) {
259
+ const networkDevices = await this.getNetworkDevicesForApplianceDemo(appliance);
260
+ this.updateCache(appliance, networkDevices[0]);
261
+ }
262
+ }
263
+ /**
264
+ * Clears all data from memory (for testing purposes).
265
+ */
266
+ clearAllData() {
267
+ this.memoryStore.clear();
268
+ this.networkDevicesStore.clear();
269
+ this.clearCache();
270
+ this.nextId = 1;
271
+ console.log('[DEMO] All data cleared from memory');
272
+ }
273
+ /**
274
+ * Gets the current size of the memory store.
275
+ * @returns The number of appliances in memory
276
+ */
277
+ getMemoryStoreSize() {
278
+ return this.memoryStore.size;
279
+ }
280
+ }
281
+ exports.InMemoryApplianceManager = InMemoryApplianceManager;