hap-nodejs 1.0.0-beta.2 → 1.0.0-beta.4

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 (265) hide show
  1. package/@types/bonjour-hap.d.ts +4 -3
  2. package/@types/simple-plist.d.ts +2 -1
  3. package/README.md +2 -1
  4. package/dist/BridgedCore.js +7 -5
  5. package/dist/BridgedCore.js.map +1 -1
  6. package/dist/Core.js +14 -8
  7. package/dist/Core.js.map +1 -1
  8. package/dist/accessories/AirConditioner_accessory.d.ts +2 -0
  9. package/dist/accessories/AirConditioner_accessory.d.ts.map +1 -0
  10. package/dist/accessories/AirConditioner_accessory.js +128 -0
  11. package/dist/accessories/AirConditioner_accessory.js.map +1 -0
  12. package/dist/accessories/AppleTVRemote_accessory.d.ts +2 -0
  13. package/dist/accessories/AppleTVRemote_accessory.d.ts.map +1 -0
  14. package/dist/accessories/AppleTVRemote_accessory.js +159 -0
  15. package/dist/accessories/AppleTVRemote_accessory.js.map +1 -0
  16. package/dist/accessories/Camera_accessory.d.ts +2 -0
  17. package/dist/accessories/Camera_accessory.d.ts.map +1 -0
  18. package/dist/accessories/Camera_accessory.js +630 -0
  19. package/dist/accessories/Camera_accessory.js.map +1 -0
  20. package/dist/accessories/Fan_accessory.d.ts +2 -0
  21. package/dist/accessories/Fan_accessory.d.ts.map +1 -0
  22. package/dist/accessories/Fan_accessory.js +80 -0
  23. package/dist/accessories/Fan_accessory.js.map +1 -0
  24. package/dist/accessories/GarageDoorOpener_accessory.d.ts +2 -0
  25. package/dist/accessories/GarageDoorOpener_accessory.d.ts.map +1 -0
  26. package/dist/accessories/GarageDoorOpener_accessory.js +78 -0
  27. package/dist/accessories/GarageDoorOpener_accessory.js.map +1 -0
  28. package/dist/accessories/Light-AdaptiveLighting_accessory.d.ts +2 -0
  29. package/dist/accessories/Light-AdaptiveLighting_accessory.d.ts.map +1 -0
  30. package/dist/accessories/Light-AdaptiveLighting_accessory.js +96 -0
  31. package/dist/accessories/Light-AdaptiveLighting_accessory.js.map +1 -0
  32. package/dist/accessories/Light_accessory.d.ts +2 -0
  33. package/dist/accessories/Light_accessory.d.ts.map +1 -0
  34. package/dist/accessories/Light_accessory.js +148 -0
  35. package/dist/accessories/Light_accessory.js.map +1 -0
  36. package/dist/accessories/Lock_accessory.d.ts +2 -0
  37. package/dist/accessories/Lock_accessory.d.ts.map +1 -0
  38. package/dist/accessories/Lock_accessory.js +76 -0
  39. package/dist/accessories/Lock_accessory.js.map +1 -0
  40. package/dist/accessories/MotionSensor_accessory.d.ts +2 -0
  41. package/dist/accessories/MotionSensor_accessory.d.ts.map +1 -0
  42. package/dist/accessories/MotionSensor_accessory.js +45 -0
  43. package/dist/accessories/MotionSensor_accessory.js.map +1 -0
  44. package/dist/accessories/Outlet_accessory.d.ts +2 -0
  45. package/dist/accessories/Outlet_accessory.d.ts.map +1 -0
  46. package/dist/accessories/Outlet_accessory.js +79 -0
  47. package/dist/accessories/Outlet_accessory.js.map +1 -0
  48. package/dist/accessories/SmartSpeaker_accessory.d.ts +2 -0
  49. package/dist/accessories/SmartSpeaker_accessory.d.ts.map +1 -0
  50. package/dist/accessories/SmartSpeaker_accessory.js +44 -0
  51. package/dist/accessories/SmartSpeaker_accessory.js.map +1 -0
  52. package/dist/accessories/Sprinkler_accessory.d.ts +2 -0
  53. package/dist/accessories/Sprinkler_accessory.d.ts.map +1 -0
  54. package/dist/accessories/Sprinkler_accessory.js +128 -0
  55. package/dist/accessories/Sprinkler_accessory.js.map +1 -0
  56. package/dist/accessories/TV_accessory.d.ts +2 -0
  57. package/dist/accessories/TV_accessory.d.ts.map +1 -0
  58. package/dist/accessories/TV_accessory.js +101 -0
  59. package/dist/accessories/TV_accessory.js.map +1 -0
  60. package/dist/accessories/TemperatureSensor_accessory.d.ts +2 -0
  61. package/dist/accessories/TemperatureSensor_accessory.d.ts.map +1 -0
  62. package/dist/accessories/TemperatureSensor_accessory.js +44 -0
  63. package/dist/accessories/TemperatureSensor_accessory.js.map +1 -0
  64. package/dist/accessories/Wi-FiRouter_accessory.d.ts +3 -0
  65. package/dist/accessories/Wi-FiRouter_accessory.d.ts.map +1 -0
  66. package/dist/accessories/Wi-FiRouter_accessory.js +17 -0
  67. package/dist/accessories/Wi-FiRouter_accessory.js.map +1 -0
  68. package/dist/accessories/Wi-FiSatellite_accessory.d.ts +3 -0
  69. package/dist/accessories/Wi-FiSatellite_accessory.d.ts.map +1 -0
  70. package/dist/accessories/Wi-FiSatellite_accessory.js +19 -0
  71. package/dist/accessories/Wi-FiSatellite_accessory.js.map +1 -0
  72. package/dist/accessories/gstreamer-audioProducer.d.ts +25 -0
  73. package/dist/accessories/gstreamer-audioProducer.d.ts.map +1 -0
  74. package/dist/accessories/gstreamer-audioProducer.js +155 -0
  75. package/dist/accessories/gstreamer-audioProducer.js.map +1 -0
  76. package/dist/accessories/types.d.ts +78 -0
  77. package/dist/accessories/types.d.ts.map +1 -0
  78. package/dist/accessories/types.js +88 -0
  79. package/dist/accessories/types.js.map +1 -0
  80. package/dist/index.d.ts +54 -27
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/index.js +34 -11
  83. package/dist/index.js.map +1 -1
  84. package/dist/internal-types.d.ts +65 -124
  85. package/dist/internal-types.d.ts.map +1 -1
  86. package/dist/internal-types.js +66 -5
  87. package/dist/internal-types.js.map +1 -1
  88. package/dist/lib/Accessory.d.ts +147 -60
  89. package/dist/lib/Accessory.d.ts.map +1 -1
  90. package/dist/lib/Accessory.js +566 -475
  91. package/dist/lib/Accessory.js.map +1 -1
  92. package/dist/lib/AccessoryLoader.d.ts +20 -8
  93. package/dist/lib/AccessoryLoader.d.ts.map +1 -1
  94. package/dist/lib/AccessoryLoader.js +115 -93
  95. package/dist/lib/AccessoryLoader.js.map +1 -1
  96. package/dist/lib/Advertiser.d.ts +99 -5
  97. package/dist/lib/Advertiser.d.ts.map +1 -1
  98. package/dist/lib/Advertiser.js +564 -22
  99. package/dist/lib/Advertiser.js.map +1 -1
  100. package/dist/lib/Bridge.d.ts +3 -1
  101. package/dist/lib/Bridge.d.ts.map +1 -1
  102. package/dist/lib/Bridge.js +2 -0
  103. package/dist/lib/Bridge.js.map +1 -1
  104. package/dist/lib/Characteristic.d.ts +918 -59
  105. package/dist/lib/Characteristic.d.ts.map +1 -1
  106. package/dist/lib/Characteristic.js +308 -257
  107. package/dist/lib/Characteristic.js.map +1 -1
  108. package/dist/lib/HAPServer.d.ts +114 -43
  109. package/dist/lib/HAPServer.d.ts.map +1 -1
  110. package/dist/lib/HAPServer.js +269 -405
  111. package/dist/lib/HAPServer.js.map +1 -1
  112. package/dist/lib/Service.d.ts +339 -15
  113. package/dist/lib/Service.d.ts.map +1 -1
  114. package/dist/lib/Service.js +59 -50
  115. package/dist/lib/Service.js.map +1 -1
  116. package/dist/lib/camera/Camera.d.ts +15 -6
  117. package/dist/lib/camera/Camera.d.ts.map +1 -1
  118. package/dist/lib/camera/Camera.js +6 -3
  119. package/dist/lib/camera/Camera.js.map +1 -1
  120. package/dist/lib/camera/RTPProxy.d.ts +24 -19
  121. package/dist/lib/camera/RTPProxy.d.ts.map +1 -1
  122. package/dist/lib/camera/RTPProxy.js +230 -207
  123. package/dist/lib/camera/RTPProxy.js.map +1 -1
  124. package/dist/lib/camera/RTPStreamManagement.d.ts +202 -43
  125. package/dist/lib/camera/RTPStreamManagement.d.ts.map +1 -1
  126. package/dist/lib/camera/RTPStreamManagement.js +303 -189
  127. package/dist/lib/camera/RTPStreamManagement.js.map +1 -1
  128. package/dist/lib/camera/RecordingManagement.d.ts +326 -0
  129. package/dist/lib/camera/RecordingManagement.d.ts.map +1 -0
  130. package/dist/lib/camera/RecordingManagement.js +833 -0
  131. package/dist/lib/camera/RecordingManagement.js.map +1 -0
  132. package/dist/lib/camera/index.d.ts +4 -3
  133. package/dist/lib/camera/index.d.ts.map +1 -1
  134. package/dist/lib/camera/index.js +1 -0
  135. package/dist/lib/camera/index.js.map +1 -1
  136. package/dist/lib/controller/AdaptiveLightingController.d.ts +37 -11
  137. package/dist/lib/controller/AdaptiveLightingController.d.ts.map +1 -1
  138. package/dist/lib/controller/AdaptiveLightingController.js +101 -86
  139. package/dist/lib/controller/AdaptiveLightingController.js.map +1 -1
  140. package/dist/lib/controller/CameraController.d.ts +290 -12
  141. package/dist/lib/controller/CameraController.d.ts.map +1 -1
  142. package/dist/lib/controller/CameraController.js +403 -47
  143. package/dist/lib/controller/CameraController.js.map +1 -1
  144. package/dist/lib/controller/Controller.d.ts +31 -10
  145. package/dist/lib/controller/Controller.d.ts.map +1 -1
  146. package/dist/lib/controller/Controller.js +7 -0
  147. package/dist/lib/controller/Controller.js.map +1 -1
  148. package/dist/lib/controller/DoorbellController.d.ts +47 -1
  149. package/dist/lib/controller/DoorbellController.d.ts.map +1 -1
  150. package/dist/lib/controller/DoorbellController.js +65 -11
  151. package/dist/lib/controller/DoorbellController.js.map +1 -1
  152. package/dist/lib/controller/RemoteController.d.ts +111 -42
  153. package/dist/lib/controller/RemoteController.d.ts.map +1 -1
  154. package/dist/lib/controller/RemoteController.js +228 -203
  155. package/dist/lib/controller/RemoteController.js.map +1 -1
  156. package/dist/lib/controller/index.d.ts +4 -4
  157. package/dist/lib/datastream/DataStreamManagement.d.ts +25 -19
  158. package/dist/lib/datastream/DataStreamManagement.d.ts.map +1 -1
  159. package/dist/lib/datastream/DataStreamManagement.js +42 -35
  160. package/dist/lib/datastream/DataStreamManagement.js.map +1 -1
  161. package/dist/lib/datastream/DataStreamParser.d.ts +63 -24
  162. package/dist/lib/datastream/DataStreamParser.d.ts.map +1 -1
  163. package/dist/lib/datastream/DataStreamParser.js +133 -87
  164. package/dist/lib/datastream/DataStreamParser.js.map +1 -1
  165. package/dist/lib/datastream/DataStreamServer.d.ts +154 -50
  166. package/dist/lib/datastream/DataStreamServer.d.ts.map +1 -1
  167. package/dist/lib/datastream/DataStreamServer.js +242 -147
  168. package/dist/lib/datastream/DataStreamServer.js.map +1 -1
  169. package/dist/lib/datastream/index.d.ts +3 -3
  170. package/dist/lib/definitions/CharacteristicDefinitions.d.ts +181 -0
  171. package/dist/lib/definitions/CharacteristicDefinitions.d.ts.map +1 -1
  172. package/dist/lib/definitions/CharacteristicDefinitions.js +968 -499
  173. package/dist/lib/definitions/CharacteristicDefinitions.js.map +1 -1
  174. package/dist/lib/definitions/ServiceDefinitions.d.ts +58 -0
  175. package/dist/lib/definitions/ServiceDefinitions.d.ts.map +1 -1
  176. package/dist/lib/definitions/ServiceDefinitions.js +173 -6
  177. package/dist/lib/definitions/ServiceDefinitions.js.map +1 -1
  178. package/dist/lib/definitions/generate-definitions.d.ts +1 -0
  179. package/dist/lib/definitions/generate-definitions.d.ts.map +1 -1
  180. package/dist/lib/definitions/generate-definitions.js +29 -21
  181. package/dist/lib/definitions/generate-definitions.js.map +1 -1
  182. package/dist/lib/definitions/generator-configuration.d.ts.map +1 -1
  183. package/dist/lib/definitions/generator-configuration.js +62 -29
  184. package/dist/lib/definitions/generator-configuration.js.map +1 -1
  185. package/dist/lib/model/AccessoryInfo.d.ts +16 -13
  186. package/dist/lib/model/AccessoryInfo.d.ts.map +1 -1
  187. package/dist/lib/model/AccessoryInfo.js +88 -83
  188. package/dist/lib/model/AccessoryInfo.js.map +1 -1
  189. package/dist/lib/model/ControllerStorage.d.ts +3 -0
  190. package/dist/lib/model/ControllerStorage.d.ts.map +1 -1
  191. package/dist/lib/model/ControllerStorage.js +7 -4
  192. package/dist/lib/model/ControllerStorage.js.map +1 -1
  193. package/dist/lib/model/HAPStorage.d.ts +3 -0
  194. package/dist/lib/model/HAPStorage.d.ts.map +1 -1
  195. package/dist/lib/model/HAPStorage.js +4 -0
  196. package/dist/lib/model/HAPStorage.js.map +1 -1
  197. package/dist/lib/model/IdentifierCache.d.ts +12 -11
  198. package/dist/lib/model/IdentifierCache.d.ts.map +1 -1
  199. package/dist/lib/model/IdentifierCache.js +68 -65
  200. package/dist/lib/model/IdentifierCache.js.map +1 -1
  201. package/dist/lib/tv/AccessControlManagement.d.ts +12 -1
  202. package/dist/lib/tv/AccessControlManagement.d.ts.map +1 -1
  203. package/dist/lib/tv/AccessControlManagement.js +13 -5
  204. package/dist/lib/tv/AccessControlManagement.js.map +1 -1
  205. package/dist/lib/util/clone.d.ts +2 -1
  206. package/dist/lib/util/clone.d.ts.map +1 -1
  207. package/dist/lib/util/clone.js +2 -0
  208. package/dist/lib/util/clone.js.map +1 -1
  209. package/dist/lib/util/color-utils.d.ts +4 -1
  210. package/dist/lib/util/color-utils.d.ts.map +1 -1
  211. package/dist/lib/util/color-utils.js +5 -2
  212. package/dist/lib/util/color-utils.js.map +1 -1
  213. package/dist/lib/util/eventedhttp.d.ts +62 -22
  214. package/dist/lib/util/eventedhttp.d.ts.map +1 -1
  215. package/dist/lib/util/eventedhttp.js +245 -188
  216. package/dist/lib/util/eventedhttp.js.map +1 -1
  217. package/dist/lib/util/hapCrypto.d.ts +35 -7
  218. package/dist/lib/util/hapCrypto.d.ts.map +1 -1
  219. package/dist/lib/util/hapCrypto.js +84 -78
  220. package/dist/lib/util/hapCrypto.js.map +1 -1
  221. package/dist/lib/util/hapStatusError.d.ts +2 -0
  222. package/dist/lib/util/hapStatusError.d.ts.map +1 -1
  223. package/dist/lib/util/hapStatusError.js +5 -3
  224. package/dist/lib/util/hapStatusError.js.map +1 -1
  225. package/dist/lib/util/net-utils.d.ts +7 -0
  226. package/dist/lib/util/net-utils.d.ts.map +1 -1
  227. package/dist/lib/util/net-utils.js +14 -7
  228. package/dist/lib/util/net-utils.js.map +1 -1
  229. package/dist/lib/util/once.d.ts +6 -1
  230. package/dist/lib/util/once.d.ts.map +1 -1
  231. package/dist/lib/util/once.js +9 -3
  232. package/dist/lib/util/once.js.map +1 -1
  233. package/dist/lib/util/promise-utils.d.ts +15 -0
  234. package/dist/lib/util/promise-utils.d.ts.map +1 -0
  235. package/dist/lib/util/promise-utils.js +36 -0
  236. package/dist/lib/util/promise-utils.js.map +1 -0
  237. package/dist/lib/util/request-util.d.ts +16 -0
  238. package/dist/lib/util/request-util.d.ts.map +1 -1
  239. package/dist/lib/util/request-util.js +43 -27
  240. package/dist/lib/util/request-util.js.map +1 -1
  241. package/dist/lib/util/time.d.ts +7 -1
  242. package/dist/lib/util/time.d.ts.map +1 -1
  243. package/dist/lib/util/time.js +13 -7
  244. package/dist/lib/util/time.js.map +1 -1
  245. package/dist/lib/util/tlv.d.ts +95 -5
  246. package/dist/lib/util/tlv.d.ts.map +1 -1
  247. package/dist/lib/util/tlv.js +96 -24
  248. package/dist/lib/util/tlv.js.map +1 -1
  249. package/dist/lib/util/uuid.d.ts +2 -3
  250. package/dist/lib/util/uuid.d.ts.map +1 -1
  251. package/dist/lib/util/uuid.js +25 -19
  252. package/dist/lib/util/uuid.js.map +1 -1
  253. package/dist/types.d.ts +271 -18
  254. package/dist/types.d.ts.map +1 -1
  255. package/dist/types.js +8 -0
  256. package/dist/types.js.map +1 -1
  257. package/package.json +30 -29
  258. package/dist/lib/util/setupcode.d.ts +0 -5
  259. package/dist/lib/util/setupcode.d.ts.map +0 -1
  260. package/dist/lib/util/setupcode.js +0 -49
  261. package/dist/lib/util/setupcode.js.map +0 -1
  262. package/dist/lib/util/setupid.d.ts +0 -5
  263. package/dist/lib/util/setupid.d.ts.map +0 -1
  264. package/dist/lib/util/setupid.js +0 -52
  265. package/dist/lib/util/setupid.js.map +0 -1
@@ -12,26 +12,32 @@ var os_1 = tslib_1.__importDefault(require("os"));
12
12
  var hapCrypto = tslib_1.__importStar(require("./hapCrypto"));
13
13
  var net_utils_1 = require("./net-utils");
14
14
  var uuid = tslib_1.__importStar(require("./uuid"));
15
- var debug = debug_1.default('HAP-NodeJS:EventedHTTPServer');
16
- var debugCon = debug_1.default("HAP-NodeJS:EventedHTTPServer:Connection");
15
+ var debug = (0, debug_1.default)("HAP-NodeJS:EventedHTTPServer");
16
+ var debugCon = (0, debug_1.default)("HAP-NodeJS:EventedHTTPServer:Connection");
17
+ var debugEvents = (0, debug_1.default)("HAP-NodeJS:EventEmitter");
17
18
  /**
18
19
  * Simple struct to hold vars needed to support HAP encryption.
20
+ *
21
+ * @group Cryptography
19
22
  */
20
23
  var HAPEncryption = /** @class */ (function () {
21
24
  function HAPEncryption(clientPublicKey, secretKey, publicKey, sharedSecret, hkdfPairEncryptionKey) {
22
25
  this.accessoryToControllerCount = 0;
23
26
  this.controllerToAccessoryCount = 0;
24
- this.accessoryToControllerKey = Buffer.alloc(0);
25
- this.controllerToAccessoryKey = Buffer.alloc(0);
26
27
  this.clientPublicKey = clientPublicKey;
27
28
  this.secretKey = secretKey;
28
29
  this.publicKey = publicKey;
29
30
  this.sharedSecret = sharedSecret;
30
31
  this.hkdfPairEncryptionKey = hkdfPairEncryptionKey;
32
+ this.accessoryToControllerKey = Buffer.alloc(0);
33
+ this.controllerToAccessoryKey = Buffer.alloc(0);
31
34
  }
32
35
  return HAPEncryption;
33
36
  }());
34
37
  exports.HAPEncryption = HAPEncryption;
38
+ /**
39
+ * @group HAP Accessory Server
40
+ */
35
41
  var EventedHTTPServerEvent;
36
42
  (function (EventedHTTPServerEvent) {
37
43
  EventedHTTPServerEvent["LISTENING"] = "listening";
@@ -45,7 +51,7 @@ var EventedHTTPServerEvent;
45
51
  * Implementation
46
52
  * --------------
47
53
  * In order to implement the "custom HTTP" server required by the HAP protocol (see HAPServer.js) without completely
48
- * reinventing the wheel, we create both a generic TCP socket server as well as a standard Node HTTP server.
54
+ * reinventing the wheel, we create both a generic TCP socket server and a standard Node HTTP server.
49
55
  * The TCP socket server acts as a proxy, allowing users of this class to transform data (for encryption) as necessary
50
56
  * and passing through bytes directly to the HTTP server for processing. This way we get Node to do all
51
57
  * the "heavy lifting" of HTTP like parsing headers and formatting responses.
@@ -55,6 +61,8 @@ var EventedHTTPServerEvent;
55
61
  *
56
62
  * Each connection to the main TCP server gets its own internal HTTP server, so we can track ongoing requests/responses
57
63
  * for safe event insertion.
64
+ *
65
+ * @group HAP Accessory Server
58
66
  */
59
67
  var EventedHTTPServer = /** @class */ (function (_super) {
60
68
  tslib_1.__extends(EventedHTTPServer, _super);
@@ -70,32 +78,10 @@ var EventedHTTPServer = /** @class */ (function (_super) {
70
78
  */
71
79
  _this.connectionsByUsername = new Map();
72
80
  _this.tcpServer = net_1.default.createServer();
73
- var interval = setInterval(function () {
74
- var e_1, _a;
75
- var connectionString = "";
76
- try {
77
- for (var _b = tslib_1.__values(_this.connections), _c = _b.next(); !_c.done; _c = _b.next()) {
78
- var connection = _c.value;
79
- if (connectionString) {
80
- connectionString += ", ";
81
- }
82
- connectionString += connection.remoteAddress + ":" + connection.remotePort;
83
- }
84
- }
85
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
86
- finally {
87
- try {
88
- if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
89
- }
90
- finally { if (e_1) throw e_1.error; }
91
- }
92
- debug("Currently " + _this.connections.size + " hap connections open: " + connectionString);
93
- }, 60000);
94
- interval.unref();
95
81
  return _this;
96
82
  }
97
83
  EventedHTTPServer.prototype.scheduleNextConnectionIdleTimeout = function () {
98
- var e_2, _a;
84
+ var e_1, _a;
99
85
  this.connectionIdleTimeout = undefined;
100
86
  if (!this.tcpServer.listening) {
101
87
  return;
@@ -116,28 +102,45 @@ var EventedHTTPServer = /** @class */ (function (_super) {
116
102
  }
117
103
  }
118
104
  }
119
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
105
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
120
106
  finally {
121
107
  try {
122
108
  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
123
109
  }
124
- finally { if (e_2) throw e_2.error; }
110
+ finally { if (e_1) throw e_1.error; }
125
111
  }
126
112
  if (this.connections.size >= EventedHTTPServer.CONNECTION_TIMEOUT_LIMIT) {
127
113
  this.connectionIdleTimeout = setTimeout(this.scheduleNextConnectionIdleTimeout.bind(this), nextTimeout);
128
114
  }
129
115
  };
116
+ EventedHTTPServer.prototype.address = function () {
117
+ return this.tcpServer.address();
118
+ };
130
119
  EventedHTTPServer.prototype.listen = function (targetPort, hostname) {
131
120
  var _this = this;
132
121
  this.tcpServer.listen(targetPort, hostname, function () {
133
122
  var address = _this.tcpServer.address(); // address() is only a string when listening to unix domain sockets
134
- debug("Server listening on %s:%s", address.family === "IPv6" ? "[" + address.address + "]" : address.address, address.port);
135
- _this.emit("listening" /* LISTENING */, address.port, address.address);
123
+ debug("Server listening on %s:%s", address.family === "IPv6" ? "[".concat(address.address, "]") : address.address, address.port);
124
+ _this.connectionLoggingInterval = setInterval(function () {
125
+ var connectionInformation = tslib_1.__spreadArray([], tslib_1.__read(_this.connections), false).map(function (connection) { return "".concat(connection.remoteAddress, ":").concat(connection.remotePort); })
126
+ .join(", ");
127
+ debug("Currently %d hap connections open: %s", _this.connections.size, connectionInformation);
128
+ }, 60000);
129
+ _this.connectionLoggingInterval.unref();
130
+ _this.emit("listening" /* EventedHTTPServerEvent.LISTENING */, address.port, address.address);
136
131
  });
137
132
  this.tcpServer.on("connection", this.onConnection.bind(this));
138
133
  };
139
134
  EventedHTTPServer.prototype.stop = function () {
140
- var e_3, _a;
135
+ var e_2, _a;
136
+ if (this.connectionLoggingInterval != null) {
137
+ clearInterval(this.connectionLoggingInterval);
138
+ this.connectionLoggingInterval = undefined;
139
+ }
140
+ if (this.connectionIdleTimeout != null) {
141
+ clearTimeout(this.connectionIdleTimeout);
142
+ this.connectionIdleTimeout = undefined;
143
+ }
141
144
  this.tcpServer.close();
142
145
  try {
143
146
  for (var _b = tslib_1.__values(this.connections), _c = _b.next(); !_c.done; _c = _b.next()) {
@@ -145,12 +148,12 @@ var EventedHTTPServer = /** @class */ (function (_super) {
145
148
  connection.close();
146
149
  }
147
150
  }
148
- catch (e_3_1) { e_3 = { error: e_3_1 }; }
151
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
149
152
  finally {
150
153
  try {
151
154
  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
152
155
  }
153
- finally { if (e_3) throw e_3.error; }
156
+ finally { if (e_2) throw e_2.error; }
154
157
  }
155
158
  };
156
159
  EventedHTTPServer.prototype.destroy = function () {
@@ -158,18 +161,18 @@ var EventedHTTPServer = /** @class */ (function (_super) {
158
161
  this.removeAllListeners();
159
162
  };
160
163
  /**
161
- * Send a even notification for given characteristic and changed value to all connected clients.
162
- * If {@param originator} is specified, the given {@link HAPConnection} will be excluded from the broadcast.
164
+ * Send an event notification for given characteristic and changed value to all connected clients.
165
+ * If `originator` is specified, the given {@link HAPConnection} will be excluded from the broadcast.
163
166
  *
164
167
  * @param aid - The accessory id of the updated characteristic.
165
168
  * @param iid - The instance id of the updated characteristic.
166
169
  * @param value - The newly set value of the characteristic.
167
- * @param originator - If specified, the connection will not get a event message.
170
+ * @param originator - If specified, the connection will not get an event message.
168
171
  * @param immediateDelivery - The HAP spec requires some characteristics to be delivery immediately.
169
- * Namely for the {@link ButtonEvent} and the {@link ProgrammableSwitchEvent} characteristics.
172
+ * Namely, for the {@link Characteristic.ButtonEvent} and the {@link Characteristic.ProgrammableSwitchEvent} characteristics.
170
173
  */
171
174
  EventedHTTPServer.prototype.broadcastEvent = function (aid, iid, value, originator, immediateDelivery) {
172
- var e_4, _a;
175
+ var e_3, _a;
173
176
  try {
174
177
  for (var _b = tslib_1.__values(this.connections), _c = _b.next(); !_c.done; _c = _b.next()) {
175
178
  var connection = _c.value;
@@ -180,25 +183,26 @@ var EventedHTTPServer = /** @class */ (function (_super) {
180
183
  connection.sendEvent(aid, iid, value, immediateDelivery);
181
184
  }
182
185
  }
183
- catch (e_4_1) { e_4 = { error: e_4_1 }; }
186
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
184
187
  finally {
185
188
  try {
186
189
  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
187
190
  }
188
- finally { if (e_4) throw e_4.error; }
191
+ finally { if (e_3) throw e_3.error; }
189
192
  }
190
193
  };
191
194
  EventedHTTPServer.prototype.onConnection = function (socket) {
192
195
  var _this = this;
196
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
193
197
  var connection = new HAPConnection(this, socket);
194
- connection.on("request" /* REQUEST */, function (request, response) {
195
- _this.emit("request" /* REQUEST */, connection, request, response);
198
+ connection.on("request" /* HAPConnectionEvent.REQUEST */, function (request, response) {
199
+ _this.emit("request" /* EventedHTTPServerEvent.REQUEST */, connection, request, response);
196
200
  });
197
- connection.on("authenticated" /* AUTHENTICATED */, this.handleConnectionAuthenticated.bind(this, connection));
198
- connection.on("closed" /* CLOSED */, this.handleConnectionClose.bind(this, connection));
201
+ connection.on("authenticated" /* HAPConnectionEvent.AUTHENTICATED */, this.handleConnectionAuthenticated.bind(this, connection));
202
+ connection.on("closed" /* HAPConnectionEvent.CLOSED */, this.handleConnectionClose.bind(this, connection));
199
203
  this.connections.add(connection);
200
204
  debug("[%s] New connection from client on interface %s (%s)", connection.remoteAddress, connection.networkInterface, connection.localAddress);
201
- this.emit("connection-opened" /* CONNECTION_OPENED */, connection);
205
+ this.emit("connection-opened" /* EventedHTTPServerEvent.CONNECTION_OPENED */, connection);
202
206
  if (this.connections.size >= EventedHTTPServer.CONNECTION_TIMEOUT_LIMIT && !this.connectionIdleTimeout) {
203
207
  this.scheduleNextConnectionIdleTimeout();
204
208
  }
@@ -213,7 +217,7 @@ var EventedHTTPServer = /** @class */ (function (_super) {
213
217
  }
214
218
  };
215
219
  EventedHTTPServer.prototype.handleConnectionClose = function (connection) {
216
- this.emit("connection-closed" /* CONNECTION_CLOSED */, connection);
220
+ this.emit("connection-closed" /* EventedHTTPServerEvent.CONNECTION_CLOSED */, connection);
217
221
  this.connections.delete(connection);
218
222
  if (connection.username) { // aka connection was authenticated
219
223
  var connections = this.connectionsByUsername.get(connection.username);
@@ -228,8 +232,18 @@ var EventedHTTPServer = /** @class */ (function (_super) {
228
232
  }
229
233
  }
230
234
  };
235
+ /**
236
+ * This method is to be called when a given {@link HAPConnection} performs a request that should result in the disconnection
237
+ * of all other {@link HAPConnection} with the same {@link HAPUsername}.
238
+ *
239
+ * The initiator MUST be in the middle of a http request were the response was not served yet.
240
+ * Otherwise, the initiator connection might reside in a state where it isn't disconnected and can't make any further requests.
241
+ *
242
+ * @param initiator - The connection that requested to disconnect all connections of the same username.
243
+ * @param username - The username for which all connections shall be closed.
244
+ */
231
245
  EventedHTTPServer.destroyExistingConnectionsAfterUnpair = function (initiator, username) {
232
- var e_5, _a;
246
+ var e_4, _a;
233
247
  var connections = initiator.server.connectionsByUsername.get(username);
234
248
  if (connections) {
235
249
  try {
@@ -238,12 +252,12 @@ var EventedHTTPServer = /** @class */ (function (_super) {
238
252
  connection.closeConnectionAsOfUnpair(initiator);
239
253
  }
240
254
  }
241
- catch (e_5_1) { e_5 = { error: e_5_1 }; }
255
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
242
256
  finally {
243
257
  try {
244
258
  if (connections_1_1 && !connections_1_1.done && (_a = connections_1.return)) _a.call(connections_1);
245
259
  }
246
- finally { if (e_5) throw e_5.error; }
260
+ finally { if (e_4) throw e_4.error; }
247
261
  }
248
262
  }
249
263
  };
@@ -254,18 +268,22 @@ var EventedHTTPServer = /** @class */ (function (_super) {
254
268
  exports.EventedHTTPServer = EventedHTTPServer;
255
269
  /**
256
270
  * @private
271
+ * @group HAP Accessory Server
257
272
  */
258
273
  var HAPConnectionState;
259
274
  (function (HAPConnectionState) {
260
275
  HAPConnectionState[HAPConnectionState["CONNECTING"] = 0] = "CONNECTING";
261
276
  HAPConnectionState[HAPConnectionState["FULLY_SET_UP"] = 1] = "FULLY_SET_UP";
262
277
  HAPConnectionState[HAPConnectionState["AUTHENTICATED"] = 2] = "AUTHENTICATED";
263
- // above signals are represent a alive connection
278
+ // above signals represent an alive connection
264
279
  // below states are considered "closed or soon closed"
265
280
  HAPConnectionState[HAPConnectionState["TO_BE_TEARED_DOWN"] = 3] = "TO_BE_TEARED_DOWN";
266
281
  HAPConnectionState[HAPConnectionState["CLOSING"] = 4] = "CLOSING";
267
282
  HAPConnectionState[HAPConnectionState["CLOSED"] = 5] = "CLOSED";
268
283
  })(HAPConnectionState = exports.HAPConnectionState || (exports.HAPConnectionState = {}));
284
+ /**
285
+ * @group HAP Accessory Server
286
+ */
269
287
  var HAPConnectionEvent;
270
288
  (function (HAPConnectionEvent) {
271
289
  HAPConnectionEvent["REQUEST"] = "request";
@@ -274,51 +292,84 @@ var HAPConnectionEvent;
274
292
  })(HAPConnectionEvent = exports.HAPConnectionEvent || (exports.HAPConnectionEvent = {}));
275
293
  /**
276
294
  * Manages a single iOS-initiated HTTP connection during its lifetime.
277
- * @private
295
+ * @group HAP Accessory Server
278
296
  */
279
297
  var HAPConnection = /** @class */ (function (_super) {
280
298
  tslib_1.__extends(HAPConnection, _super);
281
299
  function HAPConnection(server, clientSocket) {
282
300
  var _this = _super.call(this) || this;
283
- _this.state = 0 /* CONNECTING */;
301
+ _this.state = 0 /* HAPConnectionState.CONNECTING */;
284
302
  _this.lastSocketOperation = new Date().getTime();
285
303
  _this.pendingClientSocketData = Buffer.alloc(0); // data received from client before HTTP proxy is fully setup
286
304
  _this.handlingRequest = false; // true while we are composing an HTTP response (so events can wait)
287
305
  _this.registeredEvents = new Set();
288
- _this.queuedEvents = new Map();
289
- _this.pendingEventData = []; // queue of unencrypted event data waiting to be sent until after an in-progress HTTP response is being written
306
+ _this.queuedEvents = [];
307
+ /**
308
+ * If true, the above {@link queuedEvents} contains events which are set to be delivered immediately!
309
+ */
310
+ _this.eventsQueuedForImmediateDelivery = false;
290
311
  _this.server = server;
291
- _this.sessionID = uuid.generate(clientSocket.remoteAddress + ':' + clientSocket.remotePort);
312
+ _this.sessionID = uuid.generate(clientSocket.remoteAddress + ":" + clientSocket.remotePort);
292
313
  _this.localAddress = clientSocket.localAddress;
293
314
  _this.remoteAddress = clientSocket.remoteAddress; // cache because it becomes undefined in 'onClientSocketClose'
294
315
  _this.remotePort = clientSocket.remotePort;
295
316
  _this.networkInterface = HAPConnection.getLocalNetworkInterface(clientSocket);
296
317
  // clientSocket is the socket connected to the actual iOS device
297
318
  _this.tcpSocket = clientSocket;
298
- _this.tcpSocket.on('data', _this.onTCPSocketData.bind(_this));
299
- _this.tcpSocket.on('close', _this.onTCPSocketClose.bind(_this));
300
- _this.tcpSocket.on('error', _this.onTCPSocketError.bind(_this)); // we MUST register for this event, otherwise the error will bubble up to the top and crash the node process entirely.
319
+ _this.tcpSocket.on("data", _this.onTCPSocketData.bind(_this));
320
+ _this.tcpSocket.on("close", _this.onTCPSocketClose.bind(_this));
321
+ // we MUST register for this event, otherwise the error will bubble up to the top and crash the node process entirely.
322
+ _this.tcpSocket.on("error", _this.onTCPSocketError.bind(_this));
301
323
  _this.tcpSocket.setNoDelay(true); // disable Nagle algorithm
302
324
  // "HAP accessory servers must not use keepalive messages, which periodically wake up iOS devices".
303
- // Thus we don't configure any tcp keepalive
325
+ // Thus, we don't configure any tcp keepalive
304
326
  // create our internal HTTP server for this connection that we will proxy data to and from
305
327
  _this.internalHttpServer = http_1.default.createServer();
306
328
  _this.internalHttpServer.timeout = 0; // clients expect to hold connections open as long as they want
307
329
  _this.internalHttpServer.keepAliveTimeout = 0; // workaround for https://github.com/nodejs/node/issues/13391
308
330
  _this.internalHttpServer.on("listening", _this.onHttpServerListening.bind(_this));
309
- _this.internalHttpServer.on('request', _this.handleHttpServerRequest.bind(_this));
310
- _this.internalHttpServer.on('error', _this.onHttpServerError.bind(_this));
331
+ _this.internalHttpServer.on("request", _this.handleHttpServerRequest.bind(_this));
332
+ _this.internalHttpServer.on("error", _this.onHttpServerError.bind(_this));
311
333
  // close event is added later on the "connect" event as possible listen retries would throw unnecessary close events
312
- _this.internalHttpServer.listen(0, _this.internalHttpServerAddress = net_utils_1.getOSLoopbackAddressIfAvailable());
334
+ _this.internalHttpServer.listen(0, _this.internalHttpServerAddress = (0, net_utils_1.getOSLoopbackAddressIfAvailable)());
313
335
  return _this;
314
336
  }
315
- Object.defineProperty(HAPConnection.prototype, "connected", {
316
- get: function () {
317
- return this.state !== 0 /* CONNECTING */ && this.state !== 5 /* CLOSED */;
318
- },
319
- enumerable: false,
320
- configurable: true
321
- });
337
+ HAPConnection.prototype.debugListenerRegistration = function (event, registration, beforeCount) {
338
+ if (registration === void 0) { registration = true; }
339
+ if (beforeCount === void 0) { beforeCount = -1; }
340
+ var stackTrace = new Error().stack.split("\n")[3];
341
+ var eventCount = this.listeners(event).length;
342
+ var tabs1 = event === "authenticated" /* HAPConnectionEvent.AUTHENTICATED */ ? "\t" : "\t\t";
343
+ var tabs2 = !registration ? "\t" : "\t\t";
344
+ // eslint-disable-next-line max-len
345
+ debugEvents("[".concat(this.remoteAddress, "] ").concat(registration ? "Registered" : "Unregistered", " event '").concat(String(event).toUpperCase(), "' ").concat(tabs1, "(total: ").concat(eventCount).concat(!registration ? " Before: " + beforeCount : "", ") ").concat(tabs2).concat(stackTrace));
346
+ };
347
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
348
+ HAPConnection.prototype.on = function (event, listener) {
349
+ var result = _super.prototype.on.call(this, event, listener);
350
+ this.debugListenerRegistration(event);
351
+ return result;
352
+ };
353
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
354
+ HAPConnection.prototype.addListener = function (event, listener) {
355
+ var result = _super.prototype.addListener.call(this, event, listener);
356
+ this.debugListenerRegistration(event);
357
+ return result;
358
+ };
359
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
360
+ HAPConnection.prototype.removeListener = function (event, listener) {
361
+ var beforeCount = this.listeners(event).length;
362
+ var result = _super.prototype.removeListener.call(this, event, listener);
363
+ this.debugListenerRegistration(event, false, beforeCount);
364
+ return result;
365
+ };
366
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
367
+ HAPConnection.prototype.off = function (event, listener) {
368
+ var result = _super.prototype.off.call(this, event, listener);
369
+ var beforeCount = this.listeners(event).length;
370
+ this.debugListenerRegistration(event, false, beforeCount);
371
+ return result;
372
+ };
322
373
  /**
323
374
  * This method is called once the connection has gone through pair-verify.
324
375
  * As any HomeKit controller will initiate a pair-verify after the pair-setup procedure, this method gets
@@ -327,25 +378,25 @@ var HAPConnection = /** @class */ (function (_super) {
327
378
  * Once this method has been called, the connection is authenticated and encryption is turned on.
328
379
  */
329
380
  HAPConnection.prototype.connectionAuthenticated = function (username) {
330
- this.state = 2 /* AUTHENTICATED */;
381
+ this.state = 2 /* HAPConnectionState.AUTHENTICATED */;
331
382
  this.username = username;
332
- this.emit("authenticated" /* AUTHENTICATED */, username);
383
+ this.emit("authenticated" /* HAPConnectionEvent.AUTHENTICATED */, username);
333
384
  };
334
385
  HAPConnection.prototype.isAuthenticated = function () {
335
- return this.state === 2 /* AUTHENTICATED */;
386
+ return this.state === 2 /* HAPConnectionState.AUTHENTICATED */;
336
387
  };
337
388
  HAPConnection.prototype.close = function () {
338
- if (this.state >= 4 /* CLOSING */) {
389
+ if (this.state >= 4 /* HAPConnectionState.CLOSING */) {
339
390
  return; // already closed/closing
340
391
  }
341
- this.state = 4 /* CLOSING */;
392
+ this.state = 4 /* HAPConnectionState.CLOSING */;
342
393
  this.tcpSocket.destroy();
343
394
  };
344
395
  HAPConnection.prototype.closeConnectionAsOfUnpair = function (initiator) {
345
396
  if (this === initiator) {
346
397
  // the initiator of the unpair request is this connection, meaning it unpaired itself.
347
398
  // we still need to send the response packet to the unpair request.
348
- this.state = 3 /* TO_BE_TEARED_DOWN */;
399
+ this.state = 3 /* HAPConnectionState.TO_BE_TEARED_DOWN */;
349
400
  }
350
401
  else {
351
402
  // as HomeKit requires it, destroy any active session which got unpaired
@@ -353,110 +404,110 @@ var HAPConnection = /** @class */ (function (_super) {
353
404
  }
354
405
  };
355
406
  HAPConnection.prototype.sendEvent = function (aid, iid, value, immediateDelivery) {
356
- assert_1.default(aid != undefined, "HAPConnection.sendEvent: aid must be defined!");
357
- assert_1.default(iid != undefined, "HAPConnection.sendEvent: iid must be defined!");
407
+ (0, assert_1.default)(aid != null, "HAPConnection.sendEvent: aid must be defined!");
408
+ (0, assert_1.default)(iid != null, "HAPConnection.sendEvent: iid must be defined!");
358
409
  var eventName = aid + "." + iid;
359
410
  if (!this.registeredEvents.has(eventName)) {
411
+ // non verified connections can't register events, so this case is covered!
360
412
  return;
361
413
  }
414
+ var event = {
415
+ aid: aid,
416
+ iid: iid,
417
+ value: value,
418
+ };
362
419
  if (immediateDelivery) {
363
420
  // some characteristics are required to deliver notifications immediately
364
- this.writeEventNotification({
365
- characteristics: [{
366
- aid: aid,
367
- iid: iid,
368
- value: value,
369
- }],
370
- });
421
+ // we will flush all other events too, on that occasion.
422
+ this.queuedEvents.push(event);
423
+ this.eventsQueuedForImmediateDelivery = true;
424
+ if (this.eventsTimer) {
425
+ clearTimeout(this.eventsTimer);
426
+ this.eventsTimer = undefined;
427
+ }
428
+ this.handleEventsTimeout();
429
+ return;
371
430
  }
372
- else {
373
- // TODO should a new event not remove a previous event (to support censor open -> censor closed :thinking:)
374
- // any only remove previous events if the same value was set?
375
- this.queuedEvents.set(eventName, {
376
- aid: aid,
377
- iid: iid,
378
- value: value,
379
- });
380
- if (!this.handlingRequest && !this.eventsTimer) { // if we are handling a request or there is already a timer running we just add it in the queue
381
- this.eventsTimer = setTimeout(this.handleEventsTimeout.bind(this), 250);
382
- this.eventsTimer.unref();
431
+ // we search the list of queued events in reverse order.
432
+ // if the last element with the same aid and iid has the same value we don't want to send the event notification twice.
433
+ // BUT, we do not want to override previous event notifications which have a different value. Automations must be executed!
434
+ for (var i = this.queuedEvents.length - 1; i >= 0; i--) {
435
+ var queuedEvent = this.queuedEvents[i];
436
+ if (queuedEvent.aid === aid && queuedEvent.iid === iid) {
437
+ if (queuedEvent.value === value) {
438
+ return; // the same event was already queued. do not add it again!
439
+ }
440
+ break; // we break in any case
383
441
  }
384
442
  }
443
+ this.queuedEvents.push(event);
444
+ // if there is already a timer running we just add it in the queue.
445
+ if (!this.eventsTimer) {
446
+ this.eventsTimer = setTimeout(this.handleEventsTimeout.bind(this), 250);
447
+ this.eventsTimer.unref();
448
+ }
385
449
  };
386
450
  HAPConnection.prototype.handleEventsTimeout = function () {
387
451
  this.eventsTimer = undefined;
388
- if (this.state > 2 /* AUTHENTICATED */ || this.handlingRequest) {
452
+ if (this.state > 2 /* HAPConnectionState.AUTHENTICATED */) {
389
453
  // connection is closed or about to be closed. no need to send any further events
390
- // OR we are currently sending a response
391
454
  return;
392
455
  }
393
456
  this.writeQueuedEventNotifications();
394
457
  };
395
- HAPConnection.prototype.writePendingEventNotifications = function () {
396
- var e_6, _a;
397
- try {
398
- for (var _b = tslib_1.__values(this.pendingEventData), _c = _b.next(); !_c.done; _c = _b.next()) {
399
- var buffer = _c.value;
400
- this.tcpSocket.write(this.encrypt(buffer));
401
- }
402
- }
403
- catch (e_6_1) { e_6 = { error: e_6_1 }; }
404
- finally {
405
- try {
406
- if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
407
- }
408
- finally { if (e_6) throw e_6.error; }
409
- }
410
- this.pendingEventData.splice(0, this.pendingEventData.length);
411
- };
412
458
  HAPConnection.prototype.writeQueuedEventNotifications = function () {
413
- var e_7, _a;
414
- if (this.queuedEvents.size === 0 || this.eventsTimer) {
415
- return; // don't send empty event notifications or if there is a timeout running
459
+ var e_5, _a;
460
+ if (this.queuedEvents.length === 0 || this.handlingRequest) {
461
+ return; // don't send empty event notifications or if we are currently handling a request
462
+ }
463
+ if (this.eventsTimer) {
464
+ // this method might be called when we have enqueued data AND data that is queued for immediate delivery!
465
+ clearTimeout(this.eventsTimer);
466
+ this.eventsTimer = undefined;
416
467
  }
417
- var eventData = { characteristics: [] };
468
+ var eventData = {
469
+ characteristics: [],
470
+ };
418
471
  try {
419
472
  for (var _b = tslib_1.__values(this.queuedEvents), _c = _b.next(); !_c.done; _c = _b.next()) {
420
- var _d = tslib_1.__read(_c.value, 2), eventName = _d[0], characteristic = _d[1];
421
- if (!this.registeredEvents.has(eventName)) { // client unregistered events in the mean time
422
- continue;
473
+ var queuedEvent = _c.value;
474
+ if (!this.registeredEvents.has(queuedEvent.aid + "." + queuedEvent.iid)) {
475
+ continue; // client unregistered that event in the meantime
423
476
  }
424
- eventData.characteristics.push(characteristic);
477
+ eventData.characteristics.push(queuedEvent);
425
478
  }
426
479
  }
427
- catch (e_7_1) { e_7 = { error: e_7_1 }; }
480
+ catch (e_5_1) { e_5 = { error: e_5_1 }; }
428
481
  finally {
429
482
  try {
430
483
  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
431
484
  }
432
- finally { if (e_7) throw e_7.error; }
485
+ finally { if (e_5) throw e_5.error; }
433
486
  }
434
- this.queuedEvents.clear();
487
+ this.queuedEvents.splice(0, this.queuedEvents.length);
488
+ this.eventsQueuedForImmediateDelivery = false;
435
489
  this.writeEventNotification(eventData);
436
490
  };
437
491
  /**
438
492
  * This will create an EVENT/1.0 notification header with the provided event notification.
439
- * If currently a HTTP request is in progress the assembled packet will be
493
+ * If currently an HTTP request is in progress the assembled packet will be
440
494
  * added to the pending events list.
441
495
  *
442
496
  * @param notification - The event which should be sent out
443
497
  */
444
498
  HAPConnection.prototype.writeEventNotification = function (notification) {
445
499
  debugCon("[%s] Sending HAP event notifications %o", this.remoteAddress, notification.characteristics);
500
+ (0, assert_1.default)(!this.handlingRequest, "Can't write event notifications while handling a request!");
501
+ // Apple backend processes events in reverse order, so we need to reverse the array
502
+ // so that events are processed in chronological order.
503
+ notification.characteristics.reverse();
446
504
  var dataBuffer = Buffer.from(JSON.stringify(notification), "utf8");
447
505
  var header = Buffer.from("EVENT/1.0 200 OK\r\n" +
448
506
  "Content-Type: application/hap+json\r\n" +
449
507
  "Content-Length: " + dataBuffer.length + "\r\n" +
450
- "\r\n", "utf8" // buffer encoding
451
- );
508
+ "\r\n", "utf8");
452
509
  var buffer = Buffer.concat([header, dataBuffer]);
453
- if (this.handlingRequest) {
454
- // it is important that we not encrypt the pending event data. This would increment the nonce used in encryption
455
- this.pendingEventData.push(buffer);
456
- }
457
- else {
458
- this.tcpSocket.write(this.encrypt(buffer), this.handleTCPSocketWriteFulfilled.bind(this));
459
- }
510
+ this.tcpSocket.write(this.encrypt(buffer), this.handleTCPSocketWriteFulfilled.bind(this));
460
511
  };
461
512
  HAPConnection.prototype.enableEventNotifications = function (aid, iid) {
462
513
  this.registeredEvents.add(aid + "." + iid);
@@ -481,34 +532,35 @@ var HAPConnection = /** @class */ (function (_super) {
481
532
  if (this.encryption && this.encryption.accessoryToControllerKey.length > 0 && this.encryption.controllerToAccessoryCount > 0) {
482
533
  return hapCrypto.layerEncrypt(data, this.encryption);
483
534
  }
484
- return data; // otherwise we don't encrypt and return plaintext
535
+ return data; // otherwise, we don't encrypt and return plaintext
485
536
  };
486
537
  HAPConnection.prototype.decrypt = function (data) {
487
538
  if (this.encryption && this.encryption.controllerToAccessoryKey.length > 0) {
488
539
  // below call may throw an error if decryption failed
489
540
  return hapCrypto.layerDecrypt(data, this.encryption);
490
541
  }
491
- return data; // otherwise we don't decrypt and return plaintext
542
+ return data; // otherwise, we don't decrypt and return plaintext
492
543
  };
493
544
  HAPConnection.prototype.onHttpServerListening = function () {
494
545
  var _this = this;
495
546
  var addressInfo = this.internalHttpServer.address(); // address() is only a string when listening to unix domain sockets
496
- var addressString = addressInfo.family === "IPv6" ? "[" + addressInfo.address + "]" : addressInfo.address;
547
+ var addressString = addressInfo.family === "IPv6" ? "[".concat(addressInfo.address, "]") : addressInfo.address;
497
548
  this.internalHttpServerPort = addressInfo.port;
498
549
  debugCon("[%s] Internal HTTP server listening on %s:%s", this.remoteAddress, addressString, addressInfo.port);
499
- this.internalHttpServer.on('close', this.onHttpServerClose.bind(this));
550
+ this.internalHttpServer.on("close", this.onHttpServerClose.bind(this));
500
551
  // now we can establish a connection to this running HTTP server for proxying data
501
552
  this.httpSocket = net_1.default.createConnection(this.internalHttpServerPort, this.internalHttpServerAddress); // previously we used addressInfo.address
502
553
  this.httpSocket.setNoDelay(true); // disable Nagle algorithm
503
- this.httpSocket.on('data', this.handleHttpServerResponse.bind(this));
504
- this.httpSocket.on('error', this.onHttpSocketError.bind(this)); // we MUST register for this event, otherwise the error will bubble up to the top and crash the node process entirely.
505
- this.httpSocket.on('close', this.onHttpSocketClose.bind(this));
506
- this.httpSocket.on('connect', function () {
554
+ this.httpSocket.on("data", this.handleHttpServerResponse.bind(this));
555
+ // we MUST register for this event, otherwise the error will bubble up to the top and crash the node process entirely.
556
+ this.httpSocket.on("error", this.onHttpSocketError.bind(this));
557
+ this.httpSocket.on("close", this.onHttpSocketClose.bind(this));
558
+ this.httpSocket.on("connect", function () {
507
559
  // we are now fully set up:
508
560
  // - clientSocket is connected to the iOS device
509
561
  // - serverSocket is connected to the httpServer
510
562
  // - ready to proxy data!
511
- _this.state = 1 /* FULLY_SET_UP */;
563
+ _this.state = 1 /* HAPConnectionState.FULLY_SET_UP */;
512
564
  debugCon("[%s] Internal HTTP socket connected. HAPConnection now fully set up!", _this.remoteAddress);
513
565
  // start by flushing any pending buffered data received from the client while we were setting up
514
566
  if (_this.pendingClientSocketData && _this.pendingClientSocketData.length > 0) {
@@ -522,7 +574,7 @@ var HAPConnection = /** @class */ (function (_super) {
522
574
  * We store the data if the internal http server is not read yet, or forward it to the http server.
523
575
  */
524
576
  HAPConnection.prototype.onTCPSocketData = function (data) {
525
- if (this.state > 2 /* AUTHENTICATED */) {
577
+ if (this.state > 2 /* HAPConnectionState.AUTHENTICATED */) {
526
578
  // don't accept data of a connection which is about to be closed or already closed
527
579
  return;
528
580
  }
@@ -536,7 +588,7 @@ var HAPConnection = /** @class */ (function (_super) {
536
588
  this.close();
537
589
  return;
538
590
  }
539
- if (this.state < 1 /* FULLY_SET_UP */) { // we're not setup yet, so add this data to our intermediate buffer
591
+ if (this.state < 1 /* HAPConnectionState.FULLY_SET_UP */) { // we're not setup yet, so add this data to our intermediate buffer
540
592
  this.pendingClientSocketData = Buffer.concat([this.pendingClientSocketData, data]);
541
593
  }
542
594
  else {
@@ -549,14 +601,13 @@ var HAPConnection = /** @class */ (function (_super) {
549
601
  * data unencrypted to the internal http server. And now it landed here, fully parsed as a http request.
550
602
  */
551
603
  HAPConnection.prototype.handleHttpServerRequest = function (request, response) {
552
- if (this.state > 2 /* AUTHENTICATED */) {
604
+ if (this.state > 2 /* HAPConnectionState.AUTHENTICATED */) {
553
605
  // don't accept data of a connection which is about to be closed or already closed
554
606
  return;
555
607
  }
556
- request.socket.setNoDelay(true);
557
- response.connection.setNoDelay(true); // deprecated since 13.0.0
558
608
  debugCon("[%s] HTTP request: %s", this.remoteAddress, request.url);
559
- this.emit("request" /* REQUEST */, request, response);
609
+ request.socket.setNoDelay(true);
610
+ this.emit("request" /* HAPConnectionEvent.REQUEST */, request, response);
560
611
  };
561
612
  /**
562
613
  * This event handler is called by the socket which is connected to our internal http server.
@@ -569,12 +620,15 @@ var HAPConnection = /** @class */ (function (_super) {
569
620
  this.tcpSocket.write(data, this.handleTCPSocketWriteFulfilled.bind(this));
570
621
  debugCon("[%s] HTTP Response is finished", this.remoteAddress);
571
622
  this.handlingRequest = false;
572
- if (this.state === 3 /* TO_BE_TEARED_DOWN */) {
623
+ if (this.state === 3 /* HAPConnectionState.TO_BE_TEARED_DOWN */) {
573
624
  setTimeout(function () { return _this.close(); }, 10);
574
625
  }
575
- else if (this.state < 3 /* TO_BE_TEARED_DOWN */) {
576
- this.writePendingEventNotifications();
577
- this.writeQueuedEventNotifications();
626
+ else if (this.state < 3 /* HAPConnectionState.TO_BE_TEARED_DOWN */) {
627
+ if (!this.eventsTimer || this.eventsQueuedForImmediateDelivery) {
628
+ // we deliver events if there is no eventsTimer (meaning it ran out in the meantime)
629
+ // or when the queue contains events set to be delivered immediately
630
+ this.writeQueuedEventNotifications();
631
+ }
578
632
  }
579
633
  };
580
634
  HAPConnection.prototype.handleTCPSocketWriteFulfilled = function () {
@@ -585,21 +639,21 @@ var HAPConnection = /** @class */ (function (_super) {
585
639
  // onTCPSocketClose will be called next
586
640
  };
587
641
  HAPConnection.prototype.onTCPSocketClose = function () {
588
- this.state = 5 /* CLOSED */;
642
+ this.state = 5 /* HAPConnectionState.CLOSED */;
589
643
  debugCon("[%s] Client connection closed", this.remoteAddress);
590
644
  if (this.httpSocket) {
591
645
  this.httpSocket.destroy();
592
646
  }
593
647
  this.internalHttpServer.close();
594
- this.emit("closed" /* CLOSED */); // sending final closed event
648
+ this.emit("closed" /* HAPConnectionEvent.CLOSED */); // sending final closed event
595
649
  this.removeAllListeners(); // cleanup listeners, we are officially dead now
596
650
  };
597
651
  HAPConnection.prototype.onHttpServerError = function (err) {
598
652
  debugCon("[%s] HTTP server error: %s", this.remoteAddress, err.message);
599
- if (err.code === 'EADDRINUSE') {
653
+ if (err.code === "EADDRINUSE") {
600
654
  this.internalHttpServerPort = undefined;
601
655
  this.internalHttpServer.close();
602
- this.internalHttpServer.listen(0, this.internalHttpServerAddress = net_utils_1.getOSLoopbackAddressIfAvailable());
656
+ this.internalHttpServer.listen(0, this.internalHttpServerAddress = (0, net_utils_1.getOSLoopbackAddressIfAvailable)());
603
657
  }
604
658
  };
605
659
  HAPConnection.prototype.onHttpServerClose = function () {
@@ -618,23 +672,25 @@ var HAPConnection = /** @class */ (function (_super) {
618
672
  this.internalHttpServer.close();
619
673
  };
620
674
  HAPConnection.prototype.getLocalAddress = function (ipVersion) {
621
- var e_8, _a, e_9, _b;
622
- var infos = os_1.default.networkInterfaces()[this.networkInterface];
675
+ var e_6, _a, e_7, _b;
676
+ var _c;
677
+ var infos = (_c = os_1.default.networkInterfaces()[this.networkInterface]) !== null && _c !== void 0 ? _c : [];
623
678
  if (ipVersion === "ipv4") {
624
679
  try {
625
680
  for (var infos_1 = tslib_1.__values(infos), infos_1_1 = infos_1.next(); !infos_1_1.done; infos_1_1 = infos_1.next()) {
626
681
  var info = infos_1_1.value;
627
- if (info.family === "IPv4") {
682
+ // @ts-expect-error Nodejs 18+ uses the number 4 the string "IPv4"
683
+ if (info.family === "IPv4" || info.family === 4) {
628
684
  return info.address;
629
685
  }
630
686
  }
631
687
  }
632
- catch (e_8_1) { e_8 = { error: e_8_1 }; }
688
+ catch (e_6_1) { e_6 = { error: e_6_1 }; }
633
689
  finally {
634
690
  try {
635
691
  if (infos_1_1 && !infos_1_1.done && (_a = infos_1.return)) _a.call(infos_1);
636
692
  }
637
- finally { if (e_8) throw e_8.error; }
693
+ finally { if (e_6) throw e_6.error; }
638
694
  }
639
695
  throw new Error("Could not find " + ipVersion + " address for interface " + this.networkInterface);
640
696
  }
@@ -643,7 +699,8 @@ var HAPConnection = /** @class */ (function (_super) {
643
699
  try {
644
700
  for (var infos_2 = tslib_1.__values(infos), infos_2_1 = infos_2.next(); !infos_2_1.done; infos_2_1 = infos_2.next()) {
645
701
  var info = infos_2_1.value;
646
- if (info.family === "IPv6") {
702
+ // @ts-expect-error Nodejs 18+ uses the number 6 instead of the string "IPv6"
703
+ if (info.family === "IPv6" || info.family === 6) {
647
704
  if (!info.scopeid) {
648
705
  return info.address;
649
706
  }
@@ -653,12 +710,12 @@ var HAPConnection = /** @class */ (function (_super) {
653
710
  }
654
711
  }
655
712
  }
656
- catch (e_9_1) { e_9 = { error: e_9_1 }; }
713
+ catch (e_7_1) { e_7 = { error: e_7_1 }; }
657
714
  finally {
658
715
  try {
659
716
  if (infos_2_1 && !infos_2_1.done && (_b = infos_2.return)) _b.call(infos_2);
660
717
  }
661
- finally { if (e_9) throw e_9.error; }
718
+ finally { if (e_7) throw e_7.error; }
662
719
  }
663
720
  if (!localUniqueAddress) {
664
721
  throw new Error("Could not find " + ipVersion + " address for interface " + this.networkInterface);
@@ -667,7 +724,7 @@ var HAPConnection = /** @class */ (function (_super) {
667
724
  }
668
725
  };
669
726
  HAPConnection.getLocalNetworkInterface = function (socket) {
670
- var e_10, _a, e_11, _b, e_12, _c, e_13, _d;
727
+ var e_8, _a, e_9, _b, e_10, _c, e_11, _d;
671
728
  var localAddress = socket.localAddress;
672
729
  if (localAddress.startsWith("::ffff:")) { // IPv4-Mapped IPv6 Address https://tools.ietf.org/html/rfc4291#section-2.5.5.2
673
730
  localAddress = localAddress.substring(7);
@@ -683,63 +740,63 @@ var HAPConnection = /** @class */ (function (_super) {
683
740
  for (var _e = tslib_1.__values(Object.entries(interfaces)), _f = _e.next(); !_f.done; _f = _e.next()) {
684
741
  var _g = tslib_1.__read(_f.value, 2), name = _g[0], infos = _g[1];
685
742
  try {
686
- for (var infos_3 = (e_11 = void 0, tslib_1.__values(infos)), infos_3_1 = infos_3.next(); !infos_3_1.done; infos_3_1 = infos_3.next()) {
687
- var info = infos_3_1.value;
743
+ for (var _h = (e_9 = void 0, tslib_1.__values(infos !== null && infos !== void 0 ? infos : [])), _j = _h.next(); !_j.done; _j = _h.next()) {
744
+ var info = _j.value;
688
745
  if (info.address === localAddress) {
689
746
  return name;
690
747
  }
691
748
  }
692
749
  }
693
- catch (e_11_1) { e_11 = { error: e_11_1 }; }
750
+ catch (e_9_1) { e_9 = { error: e_9_1 }; }
694
751
  finally {
695
752
  try {
696
- if (infos_3_1 && !infos_3_1.done && (_b = infos_3.return)) _b.call(infos_3);
753
+ if (_j && !_j.done && (_b = _h.return)) _b.call(_h);
697
754
  }
698
- finally { if (e_11) throw e_11.error; }
755
+ finally { if (e_9) throw e_9.error; }
699
756
  }
700
757
  }
701
758
  }
702
- catch (e_10_1) { e_10 = { error: e_10_1 }; }
759
+ catch (e_8_1) { e_8 = { error: e_8_1 }; }
703
760
  finally {
704
761
  try {
705
762
  if (_f && !_f.done && (_a = _e.return)) _a.call(_e);
706
763
  }
707
- finally { if (e_10) throw e_10.error; }
764
+ finally { if (e_8) throw e_8.error; }
708
765
  }
709
766
  // we couldn't map the address from above, we try now to match subnets (see https://github.com/homebridge/HAP-NodeJS/issues/847)
710
767
  var family = net_1.default.isIPv4(localAddress) ? "IPv4" : "IPv6";
711
768
  try {
712
- for (var _h = tslib_1.__values(Object.entries(interfaces)), _j = _h.next(); !_j.done; _j = _h.next()) {
713
- var _k = tslib_1.__read(_j.value, 2), name = _k[0], infos = _k[1];
769
+ for (var _k = tslib_1.__values(Object.entries(interfaces)), _l = _k.next(); !_l.done; _l = _k.next()) {
770
+ var _m = tslib_1.__read(_l.value, 2), name = _m[0], infos = _m[1];
714
771
  try {
715
- for (var infos_4 = (e_13 = void 0, tslib_1.__values(infos)), infos_4_1 = infos_4.next(); !infos_4_1.done; infos_4_1 = infos_4.next()) {
716
- var info = infos_4_1.value;
772
+ for (var _o = (e_11 = void 0, tslib_1.__values(infos !== null && infos !== void 0 ? infos : [])), _p = _o.next(); !_p.done; _p = _o.next()) {
773
+ var info = _p.value;
717
774
  if (info.family !== family) {
718
775
  continue;
719
776
  }
720
777
  // check if the localAddress is in the same subnet
721
- if (domain_formatter_1.getNetAddress(localAddress, info.netmask) === domain_formatter_1.getNetAddress(info.address, info.netmask)) {
778
+ if ((0, domain_formatter_1.getNetAddress)(localAddress, info.netmask) === (0, domain_formatter_1.getNetAddress)(info.address, info.netmask)) {
722
779
  return name;
723
780
  }
724
781
  }
725
782
  }
726
- catch (e_13_1) { e_13 = { error: e_13_1 }; }
783
+ catch (e_11_1) { e_11 = { error: e_11_1 }; }
727
784
  finally {
728
785
  try {
729
- if (infos_4_1 && !infos_4_1.done && (_d = infos_4.return)) _d.call(infos_4);
786
+ if (_p && !_p.done && (_d = _o.return)) _d.call(_o);
730
787
  }
731
- finally { if (e_13) throw e_13.error; }
788
+ finally { if (e_11) throw e_11.error; }
732
789
  }
733
790
  }
734
791
  }
735
- catch (e_12_1) { e_12 = { error: e_12_1 }; }
792
+ catch (e_10_1) { e_10 = { error: e_10_1 }; }
736
793
  finally {
737
794
  try {
738
- if (_j && !_j.done && (_c = _h.return)) _c.call(_h);
795
+ if (_l && !_l.done && (_c = _k.return)) _c.call(_k);
739
796
  }
740
- finally { if (e_12) throw e_12.error; }
797
+ finally { if (e_10) throw e_10.error; }
741
798
  }
742
- console.log("WARNING couldn't map socket coming from remote address " + socket.remoteAddress + ":" + socket.remotePort + " at local address " + socket.localAddress + " to a interface!");
799
+ console.log("WARNING couldn't map socket coming from remote address ".concat(socket.remoteAddress, ":").concat(socket.remotePort, " at local address ").concat(socket.localAddress, " to a interface!"));
743
800
  return Object.keys(interfaces)[1]; // just use the first interface after the loopback interface as fallback
744
801
  };
745
802
  return HAPConnection;