@ecobridge.xyz/devicemanager 3.0.2

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 (137) hide show
  1. package/.gitea/workflows/default_nottags.yaml +66 -0
  2. package/.gitea/workflows/default_tags.yaml +124 -0
  3. package/.vscode/launch.json +11 -0
  4. package/.vscode/settings.json +26 -0
  5. package/changelog.md +91 -0
  6. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  7. package/dist_ts/00_commitinfo_data.js +9 -0
  8. package/dist_ts/device/device.classes.device.d.ts +205 -0
  9. package/dist_ts/device/device.classes.device.js +344 -0
  10. package/dist_ts/devicemanager.classes.devicemanager.d.ts +210 -0
  11. package/dist_ts/devicemanager.classes.devicemanager.js +835 -0
  12. package/dist_ts/discovery/discovery.classes.homeassistant.d.ts +101 -0
  13. package/dist_ts/discovery/discovery.classes.homeassistant.js +313 -0
  14. package/dist_ts/discovery/discovery.classes.mdns.d.ts +90 -0
  15. package/dist_ts/discovery/discovery.classes.mdns.js +291 -0
  16. package/dist_ts/discovery/discovery.classes.networkscanner.d.ts +64 -0
  17. package/dist_ts/discovery/discovery.classes.networkscanner.js +535 -0
  18. package/dist_ts/discovery/discovery.classes.ssdp.d.ts +112 -0
  19. package/dist_ts/discovery/discovery.classes.ssdp.js +255 -0
  20. package/dist_ts/factories/index.d.ts +190 -0
  21. package/dist_ts/factories/index.js +350 -0
  22. package/dist_ts/features/feature.abstract.d.ts +118 -0
  23. package/dist_ts/features/feature.abstract.js +172 -0
  24. package/dist_ts/features/feature.camera.d.ts +95 -0
  25. package/dist_ts/features/feature.camera.js +162 -0
  26. package/dist_ts/features/feature.climate.d.ts +174 -0
  27. package/dist_ts/features/feature.climate.js +328 -0
  28. package/dist_ts/features/feature.cover.d.ts +121 -0
  29. package/dist_ts/features/feature.cover.js +217 -0
  30. package/dist_ts/features/feature.fan.d.ts +127 -0
  31. package/dist_ts/features/feature.fan.js +235 -0
  32. package/dist_ts/features/feature.light.d.ts +156 -0
  33. package/dist_ts/features/feature.light.js +296 -0
  34. package/dist_ts/features/feature.lock.d.ts +103 -0
  35. package/dist_ts/features/feature.lock.js +170 -0
  36. package/dist_ts/features/feature.playback.d.ts +98 -0
  37. package/dist_ts/features/feature.playback.js +191 -0
  38. package/dist_ts/features/feature.power.d.ts +79 -0
  39. package/dist_ts/features/feature.power.js +173 -0
  40. package/dist_ts/features/feature.print.d.ts +78 -0
  41. package/dist_ts/features/feature.print.js +226 -0
  42. package/dist_ts/features/feature.scan.d.ts +79 -0
  43. package/dist_ts/features/feature.scan.js +315 -0
  44. package/dist_ts/features/feature.sensor.d.ts +95 -0
  45. package/dist_ts/features/feature.sensor.js +147 -0
  46. package/dist_ts/features/feature.snmp.d.ts +88 -0
  47. package/dist_ts/features/feature.snmp.js +175 -0
  48. package/dist_ts/features/feature.switch.d.ts +75 -0
  49. package/dist_ts/features/feature.switch.js +126 -0
  50. package/dist_ts/features/feature.volume.d.ts +104 -0
  51. package/dist_ts/features/feature.volume.js +186 -0
  52. package/dist_ts/features/index.d.ts +19 -0
  53. package/dist_ts/features/index.js +23 -0
  54. package/dist_ts/helpers/helpers.iprange.d.ts +35 -0
  55. package/dist_ts/helpers/helpers.iprange.js +151 -0
  56. package/dist_ts/helpers/helpers.retry.d.ts +25 -0
  57. package/dist_ts/helpers/helpers.retry.js +69 -0
  58. package/dist_ts/index.d.ts +15 -0
  59. package/dist_ts/index.js +40 -0
  60. package/dist_ts/interfaces/feature.interfaces.d.ts +255 -0
  61. package/dist_ts/interfaces/feature.interfaces.js +6 -0
  62. package/dist_ts/interfaces/homeassistant.interfaces.d.ts +550 -0
  63. package/dist_ts/interfaces/homeassistant.interfaces.js +111 -0
  64. package/dist_ts/interfaces/index.d.ts +330 -0
  65. package/dist_ts/interfaces/index.js +16 -0
  66. package/dist_ts/interfaces/smarthome.interfaces.d.ts +282 -0
  67. package/dist_ts/interfaces/smarthome.interfaces.js +7 -0
  68. package/dist_ts/paths.d.ts +1 -0
  69. package/dist_ts/paths.js +3 -0
  70. package/dist_ts/plugins.d.ts +23 -0
  71. package/dist_ts/plugins.js +30 -0
  72. package/dist_ts/protocols/index.d.ts +12 -0
  73. package/dist_ts/protocols/index.js +21 -0
  74. package/dist_ts/protocols/protocol.escl.d.ts +58 -0
  75. package/dist_ts/protocols/protocol.escl.js +364 -0
  76. package/dist_ts/protocols/protocol.homeassistant.d.ts +248 -0
  77. package/dist_ts/protocols/protocol.homeassistant.js +611 -0
  78. package/dist_ts/protocols/protocol.ipp.d.ts +45 -0
  79. package/dist_ts/protocols/protocol.ipp.js +284 -0
  80. package/dist_ts/protocols/protocol.nut.d.ts +160 -0
  81. package/dist_ts/protocols/protocol.nut.js +364 -0
  82. package/dist_ts/protocols/protocol.sane.d.ts +104 -0
  83. package/dist_ts/protocols/protocol.sane.js +597 -0
  84. package/dist_ts/protocols/protocol.snmp.d.ts +133 -0
  85. package/dist_ts/protocols/protocol.snmp.js +333 -0
  86. package/dist_ts/protocols/protocol.upnp.d.ts +207 -0
  87. package/dist_ts/protocols/protocol.upnp.js +442 -0
  88. package/dist_ts/protocols/protocol.upssnmp.d.ts +160 -0
  89. package/dist_ts/protocols/protocol.upssnmp.js +263 -0
  90. package/npmextra.json +24 -0
  91. package/package.json +39 -0
  92. package/readme.hints.md +115 -0
  93. package/readme.md +624 -0
  94. package/test/test.ts +261 -0
  95. package/ts/00_commitinfo_data.ts +8 -0
  96. package/ts/device/device.classes.device.ts +454 -0
  97. package/ts/devicemanager.classes.devicemanager.ts +1219 -0
  98. package/ts/discovery/discovery.classes.homeassistant.ts +376 -0
  99. package/ts/discovery/discovery.classes.mdns.ts +347 -0
  100. package/ts/discovery/discovery.classes.networkscanner.ts +648 -0
  101. package/ts/discovery/discovery.classes.ssdp.ts +357 -0
  102. package/ts/factories/index.ts +696 -0
  103. package/ts/features/feature.abstract.ts +251 -0
  104. package/ts/features/feature.camera.ts +214 -0
  105. package/ts/features/feature.climate.ts +407 -0
  106. package/ts/features/feature.cover.ts +278 -0
  107. package/ts/features/feature.fan.ts +296 -0
  108. package/ts/features/feature.light.ts +369 -0
  109. package/ts/features/feature.lock.ts +223 -0
  110. package/ts/features/feature.playback.ts +246 -0
  111. package/ts/features/feature.power.ts +231 -0
  112. package/ts/features/feature.print.ts +297 -0
  113. package/ts/features/feature.scan.ts +370 -0
  114. package/ts/features/feature.sensor.ts +202 -0
  115. package/ts/features/feature.snmp.ts +235 -0
  116. package/ts/features/feature.switch.ts +170 -0
  117. package/ts/features/feature.volume.ts +256 -0
  118. package/ts/features/index.ts +25 -0
  119. package/ts/helpers/helpers.iprange.ts +172 -0
  120. package/ts/helpers/helpers.retry.ts +100 -0
  121. package/ts/index.ts +165 -0
  122. package/ts/interfaces/feature.interfaces.ts +359 -0
  123. package/ts/interfaces/homeassistant.interfaces.ts +666 -0
  124. package/ts/interfaces/index.ts +421 -0
  125. package/ts/interfaces/smarthome.interfaces.ts +421 -0
  126. package/ts/paths.ts +5 -0
  127. package/ts/plugins.ts +41 -0
  128. package/ts/protocols/index.ts +59 -0
  129. package/ts/protocols/protocol.escl.ts +439 -0
  130. package/ts/protocols/protocol.homeassistant.ts +737 -0
  131. package/ts/protocols/protocol.ipp.ts +329 -0
  132. package/ts/protocols/protocol.nut.ts +471 -0
  133. package/ts/protocols/protocol.sane.ts +694 -0
  134. package/ts/protocols/protocol.snmp.ts +439 -0
  135. package/ts/protocols/protocol.upnp.ts +627 -0
  136. package/ts/protocols/protocol.upssnmp.ts +377 -0
  137. package/tsconfig.json +12 -0
@@ -0,0 +1,350 @@
1
+ /**
2
+ * Device Factory Functions
3
+ * Create UniversalDevice instances with appropriate features
4
+ */
5
+ import { UniversalDevice } from '../device/device.classes.device.js';
6
+ import { ScanFeature } from '../features/feature.scan.js';
7
+ import { PrintFeature } from '../features/feature.print.js';
8
+ import { PlaybackFeature } from '../features/feature.playback.js';
9
+ import { VolumeFeature } from '../features/feature.volume.js';
10
+ import { PowerFeature } from '../features/feature.power.js';
11
+ import { SnmpFeature } from '../features/feature.snmp.js';
12
+ /**
13
+ * Create a scanner device (UniversalDevice with ScanFeature)
14
+ */
15
+ export function createScanner(info, retryOptions) {
16
+ const protocol = info.protocol === 'ipp' ? 'escl' : info.protocol;
17
+ const isSecure = info.txtRecords['TLS'] === '1' || (protocol === 'escl' && info.port === 443);
18
+ // Parse capabilities from TXT records
19
+ const formats = parseScanFormats(info.txtRecords);
20
+ const resolutions = parseScanResolutions(info.txtRecords);
21
+ const colorModes = parseScanColorModes(info.txtRecords);
22
+ const sources = parseScanSources(info.txtRecords);
23
+ const device = new UniversalDevice(info.address, info.port, {
24
+ name: info.name,
25
+ manufacturer: info.txtRecords['usb_MFG'] || info.txtRecords['mfg'],
26
+ model: info.txtRecords['usb_MDL'] || info.txtRecords['mdl'] || info.txtRecords['ty'],
27
+ retryOptions,
28
+ });
29
+ // Override the generated ID with discovery ID
30
+ device.id = info.id;
31
+ // Add scan feature
32
+ const scanFeature = new ScanFeature(device.getDeviceReference(), info.port, {
33
+ protocol: protocol,
34
+ secure: isSecure,
35
+ supportedFormats: formats,
36
+ supportedResolutions: resolutions,
37
+ supportedColorModes: colorModes,
38
+ supportedSources: sources,
39
+ hasAdf: sources.includes('adf') || sources.includes('adf-duplex'),
40
+ hasDuplex: sources.includes('adf-duplex'),
41
+ });
42
+ device.addFeature(scanFeature);
43
+ return device;
44
+ }
45
+ /**
46
+ * Create a printer device (UniversalDevice with PrintFeature)
47
+ */
48
+ export function createPrinter(info, retryOptions) {
49
+ const ippPath = info.txtRecords['rp'] || info.txtRecords['rfo'] || '/ipp/print';
50
+ const uri = `ipp://${info.address}:${info.port}${ippPath.startsWith('/') ? '' : '/'}${ippPath}`;
51
+ const device = new UniversalDevice(info.address, info.port, {
52
+ name: info.name,
53
+ manufacturer: info.txtRecords['usb_MFG'] || info.txtRecords['mfg'],
54
+ model: info.txtRecords['usb_MDL'] || info.txtRecords['mdl'] || info.txtRecords['ty'],
55
+ retryOptions,
56
+ });
57
+ // Override the generated ID with discovery ID
58
+ device.id = info.id;
59
+ // Add print feature
60
+ const printFeature = new PrintFeature(device.getDeviceReference(), info.port, {
61
+ protocol: 'ipp',
62
+ uri,
63
+ supportsColor: info.txtRecords['Color'] === 'T' || info.txtRecords['color'] === 'true',
64
+ supportsDuplex: info.txtRecords['Duplex'] === 'T' || info.txtRecords['duplex'] === 'true',
65
+ });
66
+ device.addFeature(printFeature);
67
+ return device;
68
+ }
69
+ /**
70
+ * Create an SNMP device (UniversalDevice with SnmpFeature)
71
+ */
72
+ export function createSnmpDevice(info, retryOptions) {
73
+ const device = new UniversalDevice(info.address, info.port, {
74
+ name: info.name,
75
+ retryOptions,
76
+ });
77
+ // Override the generated ID with discovery ID
78
+ device.id = info.id;
79
+ // Add SNMP feature
80
+ const snmpFeature = new SnmpFeature(device.getDeviceReference(), info.port, {
81
+ community: info.community ?? 'public',
82
+ });
83
+ device.addFeature(snmpFeature);
84
+ return device;
85
+ }
86
+ /**
87
+ * Create a UPS device (UniversalDevice with PowerFeature)
88
+ */
89
+ export function createUpsDevice(info, retryOptions) {
90
+ const device = new UniversalDevice(info.address, info.port, {
91
+ name: info.name,
92
+ retryOptions,
93
+ });
94
+ // Override the generated ID with discovery ID
95
+ device.id = info.id;
96
+ // Add power feature
97
+ const powerFeature = new PowerFeature(device.getDeviceReference(), info.port, {
98
+ protocol: info.protocol,
99
+ upsName: info.upsName,
100
+ community: info.community,
101
+ });
102
+ device.addFeature(powerFeature);
103
+ return device;
104
+ }
105
+ /**
106
+ * Create a speaker device (UniversalDevice with PlaybackFeature and VolumeFeature)
107
+ */
108
+ export function createSpeaker(info, retryOptions) {
109
+ const device = new UniversalDevice(info.address, info.port, {
110
+ name: info.name,
111
+ model: info.modelName,
112
+ retryOptions,
113
+ });
114
+ // Override the generated ID with discovery ID
115
+ device.id = info.id;
116
+ // Add playback feature
117
+ const playbackFeature = new PlaybackFeature(device.getDeviceReference(), info.port, {
118
+ protocol: info.protocol,
119
+ supportsQueue: info.protocol === 'sonos',
120
+ supportsSeek: info.protocol !== 'airplay',
121
+ });
122
+ device.addFeature(playbackFeature);
123
+ // Add volume feature
124
+ const volumeFeature = new VolumeFeature(device.getDeviceReference(), info.port, {
125
+ volumeProtocol: info.protocol,
126
+ minVolume: 0,
127
+ maxVolume: 100,
128
+ supportsMute: true,
129
+ });
130
+ device.addFeature(volumeFeature);
131
+ return device;
132
+ }
133
+ /**
134
+ * Create a DLNA renderer device (UniversalDevice with PlaybackFeature)
135
+ */
136
+ export function createDlnaRenderer(info, retryOptions) {
137
+ const device = new UniversalDevice(info.address, info.port, {
138
+ name: info.friendlyName || info.name,
139
+ manufacturer: info.manufacturer,
140
+ model: info.modelName,
141
+ retryOptions,
142
+ });
143
+ // Override the generated ID with discovery ID
144
+ device.id = info.id;
145
+ // Add playback feature for DLNA
146
+ const playbackFeature = new PlaybackFeature(device.getDeviceReference(), info.port, {
147
+ protocol: 'dlna',
148
+ supportsQueue: false,
149
+ supportsSeek: true,
150
+ });
151
+ device.addFeature(playbackFeature);
152
+ // Add volume feature
153
+ const volumeFeature = new VolumeFeature(device.getDeviceReference(), info.port, {
154
+ volumeProtocol: 'dlna',
155
+ minVolume: 0,
156
+ maxVolume: 100,
157
+ supportsMute: true,
158
+ });
159
+ device.addFeature(volumeFeature);
160
+ return device;
161
+ }
162
+ // ============================================================================
163
+ // Parsing Helpers
164
+ // ============================================================================
165
+ function parseScanFormats(txtRecords) {
166
+ const formats = [];
167
+ const pdl = txtRecords['pdl'] || txtRecords['DocumentFormat'] || '';
168
+ if (pdl.includes('jpeg') || pdl.includes('jpg'))
169
+ formats.push('jpeg');
170
+ if (pdl.includes('png'))
171
+ formats.push('png');
172
+ if (pdl.includes('pdf'))
173
+ formats.push('pdf');
174
+ if (pdl.includes('tiff'))
175
+ formats.push('tiff');
176
+ return formats.length > 0 ? formats : ['jpeg', 'png'];
177
+ }
178
+ function parseScanResolutions(txtRecords) {
179
+ const rs = txtRecords['rs'] || '';
180
+ const parts = rs.split(',').map((s) => parseInt(s.trim())).filter((n) => !isNaN(n) && n > 0);
181
+ return parts.length > 0 ? parts : [75, 150, 300, 600];
182
+ }
183
+ function parseScanColorModes(txtRecords) {
184
+ const cs = txtRecords['cs'] || txtRecords['ColorSpace'] || '';
185
+ const modes = [];
186
+ if (cs.includes('color') || cs.includes('RGB'))
187
+ modes.push('color');
188
+ if (cs.includes('gray') || cs.includes('grayscale'))
189
+ modes.push('grayscale');
190
+ if (cs.includes('binary') || cs.includes('bw'))
191
+ modes.push('blackwhite');
192
+ return modes.length > 0 ? modes : ['color', 'grayscale'];
193
+ }
194
+ function parseScanSources(txtRecords) {
195
+ const is = txtRecords['is'] || txtRecords['InputSource'] || '';
196
+ const sources = [];
197
+ if (is.includes('platen') || is.includes('flatbed') || is === '') {
198
+ sources.push('flatbed');
199
+ }
200
+ if (is.includes('adf') || is.includes('feeder')) {
201
+ sources.push('adf');
202
+ }
203
+ if (is.includes('duplex')) {
204
+ sources.push('adf-duplex');
205
+ }
206
+ return sources.length > 0 ? sources : ['flatbed'];
207
+ }
208
+ // ============================================================================
209
+ // Smart Home Factories
210
+ // ============================================================================
211
+ import { SwitchFeature } from '../features/feature.switch.js';
212
+ import { SensorFeature } from '../features/feature.sensor.js';
213
+ import { LightFeature } from '../features/feature.light.js';
214
+ import { CoverFeature } from '../features/feature.cover.js';
215
+ import { LockFeature } from '../features/feature.lock.js';
216
+ import { FanFeature } from '../features/feature.fan.js';
217
+ import { ClimateFeature } from '../features/feature.climate.js';
218
+ import { CameraFeature } from '../features/feature.camera.js';
219
+ export function createSmartSwitch(info, retryOptions) {
220
+ const device = new UniversalDevice(info.address, info.port, {
221
+ name: info.name,
222
+ retryOptions,
223
+ });
224
+ device.id = info.id;
225
+ const switchFeature = new SwitchFeature(device.getDeviceReference(), info.port, {
226
+ protocol: info.protocol,
227
+ entityId: info.entityId,
228
+ protocolClient: info.protocolClient,
229
+ deviceClass: info.deviceClass,
230
+ });
231
+ device.addFeature(switchFeature);
232
+ return device;
233
+ }
234
+ export function createSmartSensor(info, retryOptions) {
235
+ const device = new UniversalDevice(info.address, info.port, {
236
+ name: info.name,
237
+ retryOptions,
238
+ });
239
+ device.id = info.id;
240
+ const sensorFeature = new SensorFeature(device.getDeviceReference(), info.port, {
241
+ protocol: info.protocol,
242
+ entityId: info.entityId,
243
+ protocolClient: info.protocolClient,
244
+ deviceClass: info.deviceClass,
245
+ stateClass: info.stateClass,
246
+ unit: info.unit,
247
+ });
248
+ device.addFeature(sensorFeature);
249
+ return device;
250
+ }
251
+ export function createSmartLight(info, retryOptions) {
252
+ const device = new UniversalDevice(info.address, info.port, {
253
+ name: info.name,
254
+ retryOptions,
255
+ });
256
+ device.id = info.id;
257
+ const lightFeature = new LightFeature(device.getDeviceReference(), info.port, {
258
+ protocol: info.protocol,
259
+ entityId: info.entityId,
260
+ protocolClient: info.protocolClient,
261
+ capabilities: info.capabilities,
262
+ });
263
+ device.addFeature(lightFeature);
264
+ return device;
265
+ }
266
+ export function createSmartCover(info, retryOptions) {
267
+ const device = new UniversalDevice(info.address, info.port, {
268
+ name: info.name,
269
+ retryOptions,
270
+ });
271
+ device.id = info.id;
272
+ const coverFeature = new CoverFeature(device.getDeviceReference(), info.port, {
273
+ protocol: info.protocol,
274
+ entityId: info.entityId,
275
+ protocolClient: info.protocolClient,
276
+ deviceClass: info.deviceClass,
277
+ capabilities: info.capabilities,
278
+ });
279
+ device.addFeature(coverFeature);
280
+ return device;
281
+ }
282
+ export function createSmartLock(info, retryOptions) {
283
+ const device = new UniversalDevice(info.address, info.port, {
284
+ name: info.name,
285
+ retryOptions,
286
+ });
287
+ device.id = info.id;
288
+ const lockFeature = new LockFeature(device.getDeviceReference(), info.port, {
289
+ protocol: info.protocol,
290
+ entityId: info.entityId,
291
+ protocolClient: info.protocolClient,
292
+ supportsOpen: info.supportsOpen,
293
+ });
294
+ device.addFeature(lockFeature);
295
+ return device;
296
+ }
297
+ export function createSmartFan(info, retryOptions) {
298
+ const device = new UniversalDevice(info.address, info.port, {
299
+ name: info.name,
300
+ retryOptions,
301
+ });
302
+ device.id = info.id;
303
+ const fanFeature = new FanFeature(device.getDeviceReference(), info.port, {
304
+ protocol: info.protocol,
305
+ entityId: info.entityId,
306
+ protocolClient: info.protocolClient,
307
+ capabilities: info.capabilities,
308
+ });
309
+ device.addFeature(fanFeature);
310
+ return device;
311
+ }
312
+ export function createSmartClimate(info, retryOptions) {
313
+ const device = new UniversalDevice(info.address, info.port, {
314
+ name: info.name,
315
+ retryOptions,
316
+ });
317
+ device.id = info.id;
318
+ const climateFeature = new ClimateFeature(device.getDeviceReference(), info.port, {
319
+ protocol: info.protocol,
320
+ entityId: info.entityId,
321
+ protocolClient: info.protocolClient,
322
+ capabilities: info.capabilities,
323
+ });
324
+ device.addFeature(climateFeature);
325
+ return device;
326
+ }
327
+ export function createSmartCamera(info, retryOptions) {
328
+ const device = new UniversalDevice(info.address, info.port, {
329
+ name: info.name,
330
+ retryOptions,
331
+ });
332
+ device.id = info.id;
333
+ const cameraFeature = new CameraFeature(device.getDeviceReference(), info.port, {
334
+ protocol: info.protocol,
335
+ entityId: info.entityId,
336
+ protocolClient: info.protocolClient,
337
+ capabilities: info.capabilities,
338
+ });
339
+ device.addFeature(cameraFeature);
340
+ return device;
341
+ }
342
+ // ============================================================================
343
+ // Exports
344
+ // ============================================================================
345
+ export {
346
+ // Re-export device and feature types for convenience
347
+ UniversalDevice, ScanFeature, PrintFeature, PlaybackFeature, VolumeFeature, PowerFeature, SnmpFeature,
348
+ // Smart home features
349
+ SwitchFeature, SensorFeature, LightFeature, CoverFeature, LockFeature, FanFeature, ClimateFeature, CameraFeature, };
350
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9mYWN0b3JpZXMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBRUgsT0FBTyxFQUFFLGVBQWUsRUFBNkIsTUFBTSxvQ0FBb0MsQ0FBQztBQUNoRyxPQUFPLEVBQUUsV0FBVyxFQUE0QixNQUFNLDZCQUE2QixDQUFDO0FBQ3BGLE9BQU8sRUFBRSxZQUFZLEVBQTZCLE1BQU0sOEJBQThCLENBQUM7QUFDdkYsT0FBTyxFQUFFLGVBQWUsRUFBZ0MsTUFBTSxpQ0FBaUMsQ0FBQztBQUNoRyxPQUFPLEVBQUUsYUFBYSxFQUE4QixNQUFNLCtCQUErQixDQUFDO0FBQzFGLE9BQU8sRUFBRSxZQUFZLEVBQTZCLE1BQU0sOEJBQThCLENBQUM7QUFDdkYsT0FBTyxFQUFFLFdBQVcsRUFBNEIsTUFBTSw2QkFBNkIsQ0FBQztBQXVCcEY7O0dBRUc7QUFDSCxNQUFNLFVBQVUsYUFBYSxDQUMzQixJQUEyQixFQUMzQixZQUE0QjtJQUU1QixNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsUUFBUSxLQUFLLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDO0lBQ2xFLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsUUFBUSxLQUFLLE1BQU0sSUFBSSxJQUFJLENBQUMsSUFBSSxLQUFLLEdBQUcsQ0FBQyxDQUFDO0lBRTlGLHNDQUFzQztJQUN0QyxNQUFNLE9BQU8sR0FBRyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDbEQsTUFBTSxXQUFXLEdBQUcsb0JBQW9CLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQzFELE1BQU0sVUFBVSxHQUFHLG1CQUFtQixDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FB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
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Abstract Feature base class
3
+ * Features are composable capabilities that can be attached to devices
4
+ */
5
+ import * as plugins from '../plugins.js';
6
+ import type { TFeatureType, TFeatureState, IFeature, IFeatureInfo, IFeatureOptions } from '../interfaces/feature.interfaces.js';
7
+ import type { IRetryOptions } from '../interfaces/index.js';
8
+ /**
9
+ * Forward reference to Device to avoid circular dependency
10
+ * The actual Device class will set this reference
11
+ */
12
+ export type TDeviceReference = {
13
+ id: string;
14
+ name: string;
15
+ address: string;
16
+ port: number;
17
+ };
18
+ /**
19
+ * Abstract base class for all features
20
+ * Provides common functionality for connection management, state tracking, and retry logic
21
+ */
22
+ export declare abstract class Feature extends plugins.events.EventEmitter implements IFeature {
23
+ /**
24
+ * The feature type identifier
25
+ */
26
+ abstract readonly type: TFeatureType;
27
+ /**
28
+ * The protocol used by this feature
29
+ */
30
+ abstract readonly protocol: string;
31
+ /**
32
+ * The port used by this feature
33
+ */
34
+ protected _port: number;
35
+ /**
36
+ * Current feature state
37
+ */
38
+ protected _state: TFeatureState;
39
+ /**
40
+ * Last error encountered
41
+ */
42
+ protected _lastError?: Error;
43
+ /**
44
+ * Reference to the parent device
45
+ */
46
+ protected _device: TDeviceReference;
47
+ /**
48
+ * Retry configuration
49
+ */
50
+ protected _retryConfig: Required<IRetryOptions>;
51
+ /**
52
+ * Additional metadata from discovery
53
+ */
54
+ protected _metadata: Record<string, unknown>;
55
+ constructor(device: TDeviceReference, port: number, options?: IFeatureOptions);
56
+ /**
57
+ * Get the feature port
58
+ */
59
+ get port(): number;
60
+ /**
61
+ * Get the current feature state
62
+ */
63
+ get state(): TFeatureState;
64
+ /**
65
+ * Check if the feature is connected
66
+ */
67
+ get isConnected(): boolean;
68
+ /**
69
+ * Get the last error
70
+ */
71
+ get lastError(): Error | undefined;
72
+ /**
73
+ * Get the device address
74
+ */
75
+ get address(): string;
76
+ /**
77
+ * Get the device ID
78
+ */
79
+ get deviceId(): string;
80
+ /**
81
+ * Connect to the feature endpoint
82
+ */
83
+ connect(): Promise<void>;
84
+ /**
85
+ * Disconnect from the feature endpoint
86
+ */
87
+ disconnect(): Promise<void>;
88
+ /**
89
+ * Perform the actual connection logic
90
+ * Implemented by each feature subclass
91
+ */
92
+ protected abstract doConnect(): Promise<void>;
93
+ /**
94
+ * Perform the actual disconnection logic
95
+ * Implemented by each feature subclass
96
+ */
97
+ protected abstract doDisconnect(): Promise<void>;
98
+ /**
99
+ * Get feature-specific info for serialization
100
+ */
101
+ abstract getFeatureInfo(): IFeatureInfo;
102
+ /**
103
+ * Set the feature state and emit change event
104
+ */
105
+ protected setState(state: TFeatureState): void;
106
+ /**
107
+ * Execute an operation with retry logic
108
+ */
109
+ protected withRetry<T>(operation: () => Promise<T>): Promise<T>;
110
+ /**
111
+ * Get base feature info
112
+ */
113
+ protected getBaseFeatureInfo(): IFeatureInfo;
114
+ /**
115
+ * Clear error state
116
+ */
117
+ clearError(): void;
118
+ }
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Abstract Feature base class
3
+ * Features are composable capabilities that can be attached to devices
4
+ */
5
+ import * as plugins from '../plugins.js';
6
+ import { withRetry } from '../helpers/helpers.retry.js';
7
+ /**
8
+ * Abstract base class for all features
9
+ * Provides common functionality for connection management, state tracking, and retry logic
10
+ */
11
+ export class Feature extends plugins.events.EventEmitter {
12
+ /**
13
+ * The port used by this feature
14
+ */
15
+ _port;
16
+ /**
17
+ * Current feature state
18
+ */
19
+ _state = 'disconnected';
20
+ /**
21
+ * Last error encountered
22
+ */
23
+ _lastError;
24
+ /**
25
+ * Reference to the parent device
26
+ */
27
+ _device;
28
+ /**
29
+ * Retry configuration
30
+ */
31
+ _retryConfig;
32
+ /**
33
+ * Additional metadata from discovery
34
+ */
35
+ _metadata;
36
+ constructor(device, port, options) {
37
+ super();
38
+ this._device = device;
39
+ this._port = port;
40
+ this._metadata = options?.metadata ?? {};
41
+ // Setup retry config
42
+ const retryOpts = options?.retryOptions ?? {};
43
+ this._retryConfig = {
44
+ maxRetries: retryOpts.maxRetries ?? 3,
45
+ baseDelay: retryOpts.baseDelay ?? 1000,
46
+ maxDelay: retryOpts.maxDelay ?? 30000,
47
+ multiplier: retryOpts.multiplier ?? 2,
48
+ jitter: retryOpts.jitter ?? true,
49
+ };
50
+ }
51
+ // ============================================================================
52
+ // Public Properties
53
+ // ============================================================================
54
+ /**
55
+ * Get the feature port
56
+ */
57
+ get port() {
58
+ return this._port;
59
+ }
60
+ /**
61
+ * Get the current feature state
62
+ */
63
+ get state() {
64
+ return this._state;
65
+ }
66
+ /**
67
+ * Check if the feature is connected
68
+ */
69
+ get isConnected() {
70
+ return this._state === 'connected';
71
+ }
72
+ /**
73
+ * Get the last error
74
+ */
75
+ get lastError() {
76
+ return this._lastError;
77
+ }
78
+ /**
79
+ * Get the device address
80
+ */
81
+ get address() {
82
+ return this._device.address;
83
+ }
84
+ /**
85
+ * Get the device ID
86
+ */
87
+ get deviceId() {
88
+ return this._device.id;
89
+ }
90
+ // ============================================================================
91
+ // Connection Management
92
+ // ============================================================================
93
+ /**
94
+ * Connect to the feature endpoint
95
+ */
96
+ async connect() {
97
+ if (this._state === 'connected') {
98
+ return;
99
+ }
100
+ if (this._state === 'connecting') {
101
+ throw new Error(`Feature ${this.type} is already connecting`);
102
+ }
103
+ this.setState('connecting');
104
+ this._lastError = undefined;
105
+ try {
106
+ await this.withRetry(() => this.doConnect());
107
+ this.setState('connected');
108
+ this.emit('connected');
109
+ }
110
+ catch (error) {
111
+ this._lastError = error instanceof Error ? error : new Error(String(error));
112
+ this.setState('error');
113
+ this.emit('error', this._lastError);
114
+ throw this._lastError;
115
+ }
116
+ }
117
+ /**
118
+ * Disconnect from the feature endpoint
119
+ */
120
+ async disconnect() {
121
+ if (this._state === 'disconnected') {
122
+ return;
123
+ }
124
+ try {
125
+ await this.doDisconnect();
126
+ }
127
+ finally {
128
+ this.setState('disconnected');
129
+ this.emit('disconnected');
130
+ }
131
+ }
132
+ // ============================================================================
133
+ // Helper Methods
134
+ // ============================================================================
135
+ /**
136
+ * Set the feature state and emit change event
137
+ */
138
+ setState(state) {
139
+ if (this._state !== state) {
140
+ const oldState = this._state;
141
+ this._state = state;
142
+ this.emit('state:changed', { oldState, newState: state });
143
+ }
144
+ }
145
+ /**
146
+ * Execute an operation with retry logic
147
+ */
148
+ async withRetry(operation) {
149
+ return withRetry(operation, this._retryConfig);
150
+ }
151
+ /**
152
+ * Get base feature info
153
+ */
154
+ getBaseFeatureInfo() {
155
+ return {
156
+ type: this.type,
157
+ protocol: this.protocol,
158
+ port: this._port,
159
+ state: this._state,
160
+ };
161
+ }
162
+ /**
163
+ * Clear error state
164
+ */
165
+ clearError() {
166
+ this._lastError = undefined;
167
+ if (this._state === 'error') {
168
+ this.setState('disconnected');
169
+ }
170
+ }
171
+ }
172
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmVhdHVyZS5hYnN0cmFjdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2ZlYXR1cmVzL2ZlYXR1cmUuYWJzdHJhY3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBRUgsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFTekMsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBYXhEOzs7R0FHRztBQUNILE1BQU0sT0FBZ0IsT0FBUSxTQUFRLE9BQU8sQ0FBQyxNQUFNLENBQUMsWUFBWTtJQVcvRDs7T0FFRztJQUNPLEtBQUssQ0FBUztJQUV4Qjs7T0FFRztJQUNPLE1BQU0sR0FBa0IsY0FBYyxDQUFDO0lBRWpEOztPQUVHO0lBQ08sVUFBVSxDQUFTO0lBRTdCOztPQUVHO0lBQ08sT0FBTyxDQUFtQjtJQUVwQzs7T0FFRztJQUNPLFlBQVksQ0FBMEI7SUFFaEQ7O09BRUc7SUFDTyxTQUFTLENBQTBCO0lBRTdDLFlBQ0UsTUFBd0IsRUFDeEIsSUFBWSxFQUNaLE9BQXlCO1FBRXpCLEtBQUssRUFBRSxDQUFDO1FBQ1IsSUFBSSxDQUFDLE9BQU8sR0FBRyxNQUFNLENBQUM7UUFDdEIsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUM7UUFDbEIsSUFBSSxDQUFDLFNBQVMsR0FBRyxPQUFPLEVBQUUsUUFBUSxJQUFJLEVBQUUsQ0FBQztRQUV6QyxxQkFBcUI7UUFDckIsTUFBTSxTQUFTLEdBQUcsT0FBTyxFQUFFLFlBQVksSUFBSSxFQUFFLENBQUM7UUFDOUMsSUFBSSxDQUFDLFlBQVksR0FBRztZQUNsQixVQUFVLEVBQUUsU0FBUyxDQUFDLFVBQVUsSUFBSSxDQUFDO1lBQ3JDLFNBQVMsRUFBRSxTQUFTLENBQUMsU0FBUyxJQUFJLElBQUk7WUFDdEMsUUFBUSxFQUFFLFNBQVMsQ0FBQyxRQUFRLElBQUksS0FBSztZQUNyQyxVQUFVLEVBQUUsU0FBUyxDQUFDLFVBQVUsSUFBSSxD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