eufy-security-client 3.6.0 → 3.7.1

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 (74) hide show
  1. package/.prettierignore/342/200/216 +8 -0
  2. package/.prettierrc +11 -0
  3. package/README.md +18 -0
  4. package/a.ts +61 -0
  5. package/build/error.js.map +1 -1
  6. package/build/eufysecurity.d.ts +1 -0
  7. package/build/eufysecurity.js +721 -224
  8. package/build/eufysecurity.js.map +1 -1
  9. package/build/http/api.d.ts +29 -0
  10. package/build/http/api.js +991 -701
  11. package/build/http/api.js.map +1 -1
  12. package/build/http/cache.js.map +1 -1
  13. package/build/http/const.d.ts +6 -1
  14. package/build/http/const.js +2044 -7536
  15. package/build/http/const.js.map +1 -1
  16. package/build/http/device.d.ts +4 -0
  17. package/build/http/device.js +1325 -440
  18. package/build/http/device.js.map +1 -1
  19. package/build/http/error.js.map +1 -1
  20. package/build/http/index.js.map +1 -1
  21. package/build/http/interfaces.d.ts +22 -15
  22. package/build/http/models.d.ts +2 -1
  23. package/build/http/parameter.js +74 -63
  24. package/build/http/parameter.js.map +1 -1
  25. package/build/http/station.d.ts +20 -2
  26. package/build/http/station.js +8639 -3566
  27. package/build/http/station.js.map +1 -1
  28. package/build/http/types.d.ts +12 -0
  29. package/build/http/types.js +297 -155
  30. package/build/http/types.js.map +1 -1
  31. package/build/http/utils.d.ts +16 -6
  32. package/build/http/utils.js +335 -208
  33. package/build/http/utils.js.map +1 -1
  34. package/build/index.js.map +1 -1
  35. package/build/interfaces.d.ts +4 -3
  36. package/build/logging.js +8 -13
  37. package/build/logging.js.map +1 -1
  38. package/build/mqtt/interface.d.ts +2 -2
  39. package/build/mqtt/service.js +12 -3
  40. package/build/mqtt/service.js.map +1 -1
  41. package/build/p2p/ble.js +7 -6
  42. package/build/p2p/ble.js.map +1 -1
  43. package/build/p2p/error.js.map +1 -1
  44. package/build/p2p/interfaces.d.ts +41 -6
  45. package/build/p2p/session.js +1484 -383
  46. package/build/p2p/session.js.map +1 -1
  47. package/build/p2p/talkback.js.map +1 -1
  48. package/build/p2p/types.js +36 -36
  49. package/build/p2p/types.js.map +1 -1
  50. package/build/p2p/utils.d.ts +10 -0
  51. package/build/p2p/utils.js +183 -90
  52. package/build/p2p/utils.js.map +1 -1
  53. package/build/push/client.js +15 -4
  54. package/build/push/client.js.map +1 -1
  55. package/build/push/error.js.map +1 -1
  56. package/build/push/interfaces.d.ts +8 -8
  57. package/build/push/models.js.map +1 -1
  58. package/build/push/parser.js +6 -2
  59. package/build/push/parser.js.map +1 -1
  60. package/build/push/service.js +214 -85
  61. package/build/push/service.js.map +1 -1
  62. package/build/push/types.js.map +1 -1
  63. package/build/push/utils.js.map +1 -1
  64. package/build/utils.js +7 -15
  65. package/build/utils.js.map +1 -1
  66. package/coverage/clover.xml +11133 -13648
  67. package/coverage/coverage-final.json +20 -30
  68. package/coverage/lcov-report/error.ts.html +3 -3
  69. package/coverage/lcov-report/index.html +50 -65
  70. package/coverage/lcov-report/logging.ts.html +598 -0
  71. package/coverage/lcov.info +21072 -25751
  72. package/dont-care.js +101 -0
  73. package/package.json +9 -5
  74. package/build/package.json +0 -81
@@ -3,7 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.loadEventImage = exports.loadImageOverP2P = exports.getWaitSeconds = exports.isSmartLockNotification = exports.switchSmartLockNotification = exports.getLockEventType = exports.getFloodLightT8425Notification = exports.isFloodlightT8425NotitficationEnabled = exports.getIndoorNotification = exports.isIndoorNotitficationEnabled = exports.getIndoorS350DetectionMode = exports.isIndoorS350DetectionModeEnabled = exports.getT8170DetectionMode = exports.isT8170DetectionModeEnabled = exports.decryptTrackerData = exports.isPrioritySourceType = exports.getImage = exports.getImagePath = exports.decodeImage = exports.getImageKey = exports.getImageSeed = exports.getImageBaseCode = exports.getIdSuffix = exports.randomNumber = exports.hexStringScheduleToSchedule = exports.hexWeek = exports.hexTime = exports.hexDate = exports.encodePasscode = exports.ParsePayload = exports.WritePayload = exports.getAdvancedLockTimezone = exports.getEufyTimezone = exports.getHB3DetectionMode = exports.isHB3DetectionModeEnabled = exports.getDistances = exports.getBlocklist = exports.decryptAPIData = exports.encryptAPIData = exports.calculateCellularSignalLevel = exports.calculateWifiSignalLevel = exports.switchNotificationMode = exports.isNotificationSwitchMode = exports.getImageFilePath = exports.getAbsoluteFilePath = exports.getTimezoneGMTString = exports.pad = exports.isGreaterEqualMinVersion = void 0;
6
+ exports.getWaitSeconds = exports.isSmartLockNotification = exports.switchSmartLockNotification = exports.getLockEventType = exports.getFloodLightT8425Notification = exports.isFloodlightT8425NotitficationEnabled = exports.getIndoorNotification = exports.isIndoorNotitficationEnabled = exports.getIndoorS350DetectionMode = exports.isIndoorS350DetectionModeEnabled = exports.getT8110DetectionMode = exports.isT8110DetectionModeEnabled = exports.getT8170DetectionMode = exports.isT8170DetectionModeEnabled = exports.decryptTrackerData = exports.isPrioritySourceType = exports.getImage = exports.getImagePath = exports.decodeImage = exports.getImageKey = exports.getImageSeed = exports.getImageBaseCode = exports.getIdSuffix = exports.randomNumber = exports.hexStringScheduleToSchedule = exports.hexWeek = exports.hexTime = exports.hexDate = exports.encodePasscode = exports.ParsePayload = exports.WritePayload = exports.getAdvancedLockTimezone = exports.getEufyTimezone = exports.getHB3DetectionMode = exports.isHB3DetectionModeEnabled = exports.isDeliveryPackageType = exports.getDistances = exports.getBlocklist = exports.decryptAPIData = exports.encryptAPIData = exports.calculateCellularSignalLevel = exports.calculateWifiSignalLevel = exports.switchNotificationMode = exports.isNotificationSwitchMode = exports.getImageFilePath = exports.getAbsoluteFilePath = exports.getTimezoneGMTString = exports.pad = exports.isGreaterEqualMinVersion = exports.normalizeVersionString = void 0;
7
+ exports.getRandomPhoneModel = exports.loadEventImage = exports.loadImageOverP2P = void 0;
7
8
  const crypto_1 = require("crypto");
8
9
  const const_1 = require("./const");
9
10
  const md5_1 = __importDefault(require("crypto-js/md5"));
@@ -16,72 +17,110 @@ const types_2 = require("./../push/types");
16
17
  const logging_1 = require("../logging");
17
18
  const utils_1 = require("../utils");
18
19
  const normalizeVersionString = function (version) {
19
- const trimmed = version ? version.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1") : "";
20
- const pieces = trimmed.split(RegExp("\\."));
21
- const parts = [];
22
- let value, piece, num, i;
23
- for (i = 0; i < pieces.length; i += 1) {
24
- piece = pieces[i].replace(RegExp("\\D"), "");
25
- num = parseInt(piece, 10);
26
- if (isNaN(num)) {
27
- num = 0;
28
- }
29
- parts.push(num);
30
- }
31
- const partsLength = parts.length;
32
- for (i = partsLength - 1; i >= 0; i -= 1) {
33
- value = parts[i];
34
- if (value === 0) {
35
- parts.length -= 1;
36
- }
37
- else {
38
- break;
39
- }
20
+ /**
21
+ *
22
+ * Normalise version strings into an array of integers, otherwise if a version was not found it returns null
23
+ * Example of a version is 1.4.30.33
24
+ *
25
+ * @param version
26
+ */
27
+ const match = version.match(/\d+(?:\.\d+)+/);
28
+ if (match == null)
29
+ return null;
30
+ else {
31
+ return match[0].split(".").map(Number);
40
32
  }
41
- return parts;
42
33
  };
34
+ exports.normalizeVersionString = normalizeVersionString;
43
35
  const isGreaterEqualMinVersion = function (minimal_version, current_version) {
44
- const x = normalizeVersionString(minimal_version);
45
- const y = normalizeVersionString(current_version);
46
- const size = Math.min(x.length, y.length);
36
+ /**
37
+ *
38
+ * Test the minimal version set is working with the current version by return true if it is equal or greater than min version.
39
+ *
40
+ * @param minimal_version
41
+ * @param current_version
42
+ */
43
+ const min_version = (0, exports.normalizeVersionString)(minimal_version);
44
+ const actual_version = (0, exports.normalizeVersionString)(current_version);
45
+ // Failed to parse actually version
46
+ if (actual_version === null)
47
+ return false;
48
+ // Failed to a parse min version but the current did, so we assume it is greater
49
+ if (min_version === null)
50
+ return true;
51
+ const version_slots = Math.min(min_version.length, actual_version.length);
47
52
  let i;
48
- for (i = 0; i < size; i += 1) {
49
- if (x[i] !== y[i]) {
50
- return x[i] < y[i] ? true : false;
53
+ // Loop for each slot to ensure it is greater or equal
54
+ for (i = 0; i < version_slots; i += 1) {
55
+ if (min_version[i] !== actual_version[i]) {
56
+ return min_version[i] < actual_version[i];
51
57
  }
52
58
  }
53
- if (x.length === y.length) {
59
+ // If none of the slots are different but the length is the same, it is most likely the slots are the same
60
+ if (min_version.length === actual_version.length) {
54
61
  return true;
55
62
  }
56
- return (x.length < y.length) ? true : false;
63
+ return min_version.length < actual_version.length;
57
64
  };
58
65
  exports.isGreaterEqualMinVersion = isGreaterEqualMinVersion;
59
66
  const pad = function (num) {
67
+ /**
68
+ *
69
+ * Convert the number to be absolute, round down and return "0" if lower than 10 or "" otherwise
70
+ * Seems to be used in a scenario where need to add a zero decimal to format a 2 digit string
71
+ *
72
+ * @param num
73
+ */
60
74
  const norm = Math.floor(Math.abs(num));
61
75
  return (norm < 10 ? "0" : "") + norm;
62
76
  };
63
77
  exports.pad = pad;
64
78
  const getTimezoneGMTString = function () {
79
+ /**
80
+ * Get timezone to string
81
+ *
82
+ */
65
83
  const tzo = -new Date().getTimezoneOffset();
66
84
  const dif = tzo >= 0 ? "+" : "-";
67
85
  return `GMT${dif}${(0, exports.pad)(tzo / 60)}:${(0, exports.pad)(tzo % 60)}`;
68
86
  };
69
87
  exports.getTimezoneGMTString = getTimezoneGMTString;
70
88
  const getAbsoluteFilePath = function (device_type, channel, filename) {
71
- if (device_type === types_1.DeviceType.FLOODLIGHT) {
72
- return `/mnt/data/Camera${String(channel).padStart(2, "0")}/${filename}.dat`;
73
- }
74
- return `/media/mmcblk0p1/Camera${String(channel).padStart(2, "0")}/${filename}.dat`;
89
+ /**
90
+ *
91
+ * Create the path based on two different devices
92
+ *
93
+ * @param device_type
94
+ * @param channel
95
+ * @param filename
96
+ */
97
+ // TODO : might need to extend to others device with local storage? not sure why only floodlight
98
+ const prefix = device_type === types_1.DeviceType.FLOODLIGHT ? const_1.PATH_DATA_CAMERA : const_1.PATH_MMC_CAMERA;
99
+ return `${prefix}${String(channel).padStart(2, "0")}/${filename}.dat`;
75
100
  };
76
101
  exports.getAbsoluteFilePath = getAbsoluteFilePath;
77
102
  const getImageFilePath = function (device_type, channel, filename) {
78
- if (device_type === types_1.DeviceType.FLOODLIGHT) {
79
- return `/mnt/data/video/${filename}_c${String(channel).padStart(2, "0")}.jpg`;
80
- }
81
- return `/media/mmcblk0p1/video/${filename}_c${String(channel).padStart(2, "0")}.jpg`;
103
+ /**
104
+ *
105
+ * Create the image path from a video filename
106
+ *
107
+ * @param device_type
108
+ * @param channel
109
+ * @param filename
110
+ */
111
+ // TODO : might need to extend to others device with local storage? not sure why only floodlight
112
+ const prefix = device_type === types_1.DeviceType.FLOODLIGHT ? const_1.PATH_DATA_VIDEO : const_1.PATH_MMC_VIDEO;
113
+ return `${prefix}/${filename}_c${String(channel).padStart(2, "0")}.jpg`;
82
114
  };
83
115
  exports.getImageFilePath = getImageFilePath;
84
116
  const isNotificationSwitchMode = function (value, mode) {
117
+ /**
118
+ *
119
+ * Check if the mode is set to notification
120
+ *
121
+ * @param value
122
+ * @param mode
123
+ */
85
124
  if (value === 1)
86
125
  value = 240;
87
126
  return (value & mode) !== 0;
@@ -98,146 +137,170 @@ const switchNotificationMode = function (currentValue, mode, enable) {
98
137
  else {
99
138
  result = ~mode & currentValue;
100
139
  }
101
- if ((0, exports.isNotificationSwitchMode)(result, types_1.NotificationSwitchMode.SCHEDULE) && (0, exports.isNotificationSwitchMode)(result, types_1.NotificationSwitchMode.APP) && (0, exports.isNotificationSwitchMode)(result, types_1.NotificationSwitchMode.GEOFENCE) && (0, exports.isNotificationSwitchMode)(result, types_1.NotificationSwitchMode.KEYPAD)) {
140
+ if ((0, exports.isNotificationSwitchMode)(result, types_1.NotificationSwitchMode.SCHEDULE) &&
141
+ (0, exports.isNotificationSwitchMode)(result, types_1.NotificationSwitchMode.APP) &&
142
+ (0, exports.isNotificationSwitchMode)(result, types_1.NotificationSwitchMode.GEOFENCE) &&
143
+ (0, exports.isNotificationSwitchMode)(result, types_1.NotificationSwitchMode.KEYPAD)) {
102
144
  result = 1; /* ALL */
103
145
  }
104
146
  return result;
105
147
  };
106
148
  exports.switchNotificationMode = switchNotificationMode;
149
+ // TODO : remove device , not needed
107
150
  const calculateWifiSignalLevel = function (device, rssi) {
108
- if (device.isWiredDoorbell()) {
109
- if (rssi >= -65) {
110
- return types_1.SignalLevel.FULL;
111
- }
112
- if (rssi >= -75) {
113
- return types_1.SignalLevel.STRONG;
114
- }
115
- return rssi >= -80 ? types_1.SignalLevel.NORMAL : types_1.SignalLevel.WEAK;
116
- }
117
- else if (device.isCamera2Product()) {
118
- if (rssi >= 0) {
119
- return types_1.SignalLevel.NO_SIGNAL;
120
- }
121
- if (rssi >= -65) {
122
- return types_1.SignalLevel.FULL;
123
- }
124
- if (rssi >= -75) {
125
- return types_1.SignalLevel.STRONG;
126
- }
127
- return rssi >= -85 ? types_1.SignalLevel.NORMAL : types_1.SignalLevel.WEAK;
128
- }
129
- else if (device.isFloodLight()) {
130
- if (rssi >= 0) {
131
- return types_1.SignalLevel.NO_SIGNAL;
132
- }
133
- if (rssi >= -60) {
134
- return types_1.SignalLevel.FULL;
135
- }
136
- if (rssi >= -70) {
137
- return types_1.SignalLevel.STRONG;
138
- }
139
- return rssi >= -80 ? types_1.SignalLevel.NORMAL : types_1.SignalLevel.WEAK;
140
- }
141
- else if (device.isBatteryDoorbell()) {
142
- if (rssi >= -65) {
143
- return types_1.SignalLevel.FULL;
144
- }
145
- if (rssi >= -75) {
146
- return types_1.SignalLevel.STRONG;
147
- }
148
- return rssi >= -85 ? types_1.SignalLevel.NORMAL : types_1.SignalLevel.WEAK;
149
- }
150
- else {
151
- if (rssi >= 0) {
152
- return types_1.SignalLevel.NO_SIGNAL;
153
- }
154
- if (rssi >= -65) {
155
- return types_1.SignalLevel.FULL;
156
- }
157
- if (rssi >= -75) {
158
- return types_1.SignalLevel.STRONG;
159
- }
160
- return rssi >= -85 ? types_1.SignalLevel.NORMAL : types_1.SignalLevel.WEAK;
161
- }
151
+ /**
152
+ * Calculate the signal strength based on the RSSI
153
+ *
154
+ * Using this scale for reference
155
+ * Excellent/Very Strong (-30 dBm to -50 dBm)
156
+ * Good/Strong (-50 dBm to -60 dBm)
157
+ * Fair/Good (-60 dBm to -67 dBm)
158
+ * Weak/Fair (-67 dBm to -70 dBm)
159
+ * Very Weak/Poor (-70 dBm to -80 dBm)
160
+ * Unusable (-80 dBm to -90 dBm or lower)
161
+ *
162
+ */
163
+ if (rssi >= -50)
164
+ return types_1.SignalLevel.FULL;
165
+ else if (rssi < -50 && rssi >= -60)
166
+ return types_1.SignalLevel.STRONG;
167
+ else if (rssi < -60 && rssi >= -67)
168
+ return types_1.SignalLevel.NORMAL;
169
+ else if (rssi < -67 && rssi >= -80)
170
+ return types_1.SignalLevel.WEAK;
171
+ else
172
+ return types_1.SignalLevel.NO_SIGNAL;
162
173
  };
163
174
  exports.calculateWifiSignalLevel = calculateWifiSignalLevel;
164
175
  const calculateCellularSignalLevel = function (rssi) {
165
- if (rssi >= 0) {
176
+ /**
177
+ * Calculate the signal strength from the RSSI ( this has a different scale than wifi )
178
+ *
179
+ * Excellent (>-65 to -70 dBm)
180
+ * Good (-70 to -85 dBm)
181
+ * Fair (-85 to -95 dBm)
182
+ * Poor (-95 to -100 dBm)
183
+ * Unusable/No Signal (<-100 to -110 dBm)
184
+ *
185
+ */
186
+ if (rssi >= 0)
166
187
  return types_1.SignalLevel.NO_SIGNAL;
167
- }
168
- if (rssi >= -90) {
188
+ if (rssi >= -70)
169
189
  return types_1.SignalLevel.FULL;
170
- }
171
- if (rssi >= -95) {
190
+ else if (rssi < -70 && rssi >= -85)
172
191
  return types_1.SignalLevel.STRONG;
173
- }
174
- return rssi >= -105 ? types_1.SignalLevel.NORMAL : types_1.SignalLevel.WEAK;
192
+ else if (rssi < -85 && rssi >= -95)
193
+ return types_1.SignalLevel.NORMAL;
194
+ else if (rssi < -95 && rssi >= -100)
195
+ return types_1.SignalLevel.WEAK;
196
+ else
197
+ return types_1.SignalLevel.NO_SIGNAL;
175
198
  };
176
199
  exports.calculateCellularSignalLevel = calculateCellularSignalLevel;
177
200
  const encryptAPIData = (data, key) => {
178
201
  const cipher = (0, crypto_1.createCipheriv)("aes-256-cbc", key, key.subarray(0, 16));
179
- return (cipher.update(data, "utf8", "base64") +
180
- cipher.final("base64"));
202
+ return cipher.update(data, "utf8", "base64") + cipher.final("base64");
181
203
  };
182
204
  exports.encryptAPIData = encryptAPIData;
183
205
  const decryptAPIData = (data, key) => {
184
206
  const cipher = (0, crypto_1.createDecipheriv)("aes-256-cbc", key, key.subarray(0, 16));
185
- return Buffer.concat([
186
- cipher.update(data, "base64"),
187
- cipher.final()
188
- ]);
207
+ return Buffer.concat([cipher.update(data, "base64"), cipher.final()]);
189
208
  };
190
209
  exports.decryptAPIData = decryptAPIData;
191
- const getBlocklist = function (directions) {
192
- const result = [];
193
- for (let distance = 1; distance <= 5; distance++) {
194
- let i = 0;
195
- let j = 0;
196
- let k = 1;
197
- for (const directionDistance of directions) {
198
- if (directionDistance >= distance) {
199
- j += k;
210
+ const getBlocklist = function (distanceArray) {
211
+ /**
212
+ * It looks like it taken from the decompiled app from Eufy in the file SimpleDetectionGroup.java
213
+ *
214
+ * From asking, AI, this function it creates a bitmask representing which radar points meet that distance requirement.
215
+ * Finally, it applies a specific bitwise transformation to that mask.
216
+ *
217
+ * Potential description: Generates radar configuration parameters based on distance thresholds.
218
+ *
219
+ * * @param {number[]} distanceArray - An array of integers representing distances.
220
+ * * @returns {number[]} A list of 5 bitmask integers.
221
+ */
222
+ const requestParams = [];
223
+ for (let threshold = 1; threshold <= 5; threshold++) {
224
+ let bitmask = 0;
225
+ let bitPosition = 1;
226
+ // Iterate through each distance in the array
227
+ for (const distance of distanceArray) {
228
+ if (distance >= threshold) {
229
+ bitmask |= bitPosition;
200
230
  }
201
- k <<= 1;
231
+ // Shift bitPosition left by 1 (multiply by 2)
232
+ bitPosition <<= 1;
202
233
  }
203
- if (j == 0) {
204
- i = 65535;
234
+ let finalValue = 0;
235
+ // Logic for specific bit patterns
236
+ if (bitmask === 0) {
237
+ finalValue = 0xffff; // 65535
205
238
  }
206
- else if (!(j == 255 || j == 65535)) {
207
- i = (j ^ 255) + 65280;
239
+ else if (bitmask !== 0xff && bitmask !== 0xffff) {
240
+ // Flip the bits and add the 0xFF00 (65280) high-byte padding
241
+ finalValue = (bitmask ^ 0xff) + 0xff00;
208
242
  }
209
- result.push(65535 & i);
243
+ requestParams.push(finalValue);
210
244
  }
211
- return result;
245
+ return requestParams;
212
246
  };
213
247
  exports.getBlocklist = getBlocklist;
214
- const getDistances = function (blocklist) {
215
- const result = [3, 3, 3, 3, 3, 3, 3, 3];
216
- let calcDistance = 0;
217
- for (const blockElement of blocklist) {
218
- let valueOf = blockElement ^ 65535;
219
- calcDistance++;
220
- if (valueOf !== 0) {
221
- for (let i = 0; i < result.length; i++) {
222
- const intValue = valueOf & 1;
223
- if (intValue > 0) {
224
- result[i] = calcDistance;
248
+ const getDistances = function (rawDistanceData) {
249
+ /**
250
+ * It looks like it taken from the decompiled app from Eufy in the file SimpleDetectionGroup.java
251
+ *
252
+ * From asking AI:
253
+ * Processes raw radar sensor data to map object detections into spatial sectors.
254
+ * This method iterates through a list of distance data, where each element represents
255
+ * a depth level and its bits represent angular sectors. It inverts the bitmask,
256
+ * identifies active detections via bit-shifting, and updates a collection of
257
+ * RadarSelectInfo objects with the corresponding angle and proximity distance.
258
+ *
259
+ * @param rawDistanceData A list of integers where each bit represents a detection
260
+ * at a specific angle, and the list index represents depth.
261
+ */
262
+ const radarSectors = [3, 3, 3, 3, 3, 3, 3, 3];
263
+ let distanceStep = 0;
264
+ for (const rawValue of rawDistanceData) {
265
+ // Bitwise NOT/XOR to invert the signal (common in hardware where 0=detected)
266
+ let invertedBits = rawValue ^ 65535;
267
+ distanceStep++;
268
+ if (invertedBits !== 0) {
269
+ for (let i = 0; i < radarSectors.length; i++) {
270
+ const isObjectDetected = invertedBits & 1; // Check if the lowest bit is set
271
+ // If the bit was 1, mark this sector with the current distance
272
+ if (isObjectDetected > 0) {
273
+ radarSectors[i] = distanceStep;
225
274
  }
226
- valueOf = valueOf >> 1;
275
+ // Shift bits to check the next angle in the next iteration
276
+ invertedBits = invertedBits >> 1;
227
277
  }
228
278
  }
229
279
  }
230
- return result;
280
+ return radarSectors;
231
281
  };
232
282
  exports.getDistances = getDistances;
283
+ const isDeliveryPackageType = function (value) {
284
+ /**
285
+ * Seems to be coming from EventData.java
286
+ *
287
+ */
288
+ return (value & 65536) == 65536;
289
+ };
290
+ exports.isDeliveryPackageType = isDeliveryPackageType;
233
291
  const isHB3DetectionModeEnabled = function (value, type) {
292
+ /**
293
+ * Detection if Mode is enabled
294
+ *
295
+ */
296
+ const prefixCode = (type & value) == type;
234
297
  if (type === types_1.HB3DetectionTypes.HUMAN_RECOGNITION) {
235
- return (type & value) == type && (value & 65536) == 65536;
298
+ return prefixCode && (0, exports.isDeliveryPackageType)(value);
236
299
  }
237
300
  else if (type === types_1.HB3DetectionTypes.HUMAN_DETECTION) {
238
- return (type & value) == type && (value & 1) == 1;
301
+ return prefixCode && (value & 1) == 1;
239
302
  }
240
- return (type & value) == type;
303
+ return prefixCode;
241
304
  };
242
305
  exports.isHB3DetectionModeEnabled = isHB3DetectionModeEnabled;
243
306
  const getHB3DetectionMode = function (value, type, enable) {
@@ -245,7 +308,7 @@ const getHB3DetectionMode = function (value, type, enable) {
245
308
  if (!enable) {
246
309
  if (type === types_1.HB3DetectionTypes.HUMAN_RECOGNITION) {
247
310
  const tmp = (type & value) == type ? type ^ value : value;
248
- result = (value & 65536) == 65536 ? tmp ^ 65536 : tmp;
311
+ result = (0, exports.isDeliveryPackageType)(value) ? tmp ^ 65536 : tmp;
249
312
  }
250
313
  else if (type === types_1.HB3DetectionTypes.HUMAN_DETECTION) {
251
314
  const tmp = (type & value) == type ? type ^ value : value;
@@ -281,6 +344,7 @@ exports.getEufyTimezone = getEufyTimezone;
281
344
  const getAdvancedLockTimezone = function (stationSN) {
282
345
  const timezone = (0, exports.getEufyTimezone)();
283
346
  if (timezone !== undefined) {
347
+ // TODO: make this a method to check whatever we need to check for the station
284
348
  if (stationSN.startsWith("T8520") && (0, exports.isGreaterEqualMinVersion)("1.2.8.6", stationSN))
285
349
  return `${timezone.timeZoneGMT}|1.${timezone.timeSn}`;
286
350
  else
@@ -294,7 +358,12 @@ class WritePayload {
294
358
  data = Buffer.from([]);
295
359
  write(bytes) {
296
360
  const tmp_data = Buffer.from(bytes);
297
- this.data = Buffer.concat([this.data, Buffer.from([this.split_byte]), Buffer.from([tmp_data.length & 255]), tmp_data]);
361
+ this.data = Buffer.concat([
362
+ this.data,
363
+ Buffer.from([this.split_byte]),
364
+ Buffer.from([tmp_data.length & 255]),
365
+ tmp_data,
366
+ ]);
298
367
  this.split_byte += 1;
299
368
  }
300
369
  getData() {
@@ -303,6 +372,11 @@ class WritePayload {
303
372
  }
304
373
  exports.WritePayload = WritePayload;
305
374
  class ParsePayload {
375
+ /**
376
+ * extract specific pieces of data from a binary buffer
377
+ *
378
+ * @private
379
+ */
306
380
  data;
307
381
  constructor(data) {
308
382
  this.data = data;
@@ -371,7 +445,7 @@ class ParsePayload {
371
445
  break;
372
446
  }
373
447
  const nextStep = this.getNextStep(value, currentPosition, this.data);
374
- if ((currentPosition + nextStep) >= this.data.length) {
448
+ if (currentPosition + nextStep >= this.data.length) {
375
449
  break;
376
450
  }
377
451
  if (nextStep == 1) {
@@ -387,31 +461,17 @@ class ParsePayload {
387
461
  }
388
462
  getNextStep(indexValue, position, data) {
389
463
  const newPosition = position + 1 + data.readUInt8(position);
390
- return (newPosition == data.length || newPosition > data.length || data.readInt8(newPosition) == indexValue + 1) ? 1 : 2;
464
+ return newPosition == data.length || newPosition > data.length || data.readInt8(newPosition) == indexValue + 1
465
+ ? 1
466
+ : 2;
391
467
  }
392
468
  }
393
469
  exports.ParsePayload = ParsePayload;
394
- /*export const generateHash = function(data: Buffer): number {
395
- let result = 0;
396
- for (const value of data) {
397
- result = result ^ value;
398
- }
399
- return result;
400
- }
401
-
402
- export const encodeSmartSafeData = function(command: number, payload: Buffer): Buffer {
403
- const header = Buffer.from(SmartSafe.DATA_HEADER);
404
- const size = Buffer.allocUnsafe(2);
405
- size.writeInt16LE(payload.length + 9);
406
- const versionCode = Buffer.from([SmartSafe.VERSION_CODE]);
407
- const dataType = Buffer.from([-1]);
408
- const commandCode = Buffer.from([command]);
409
- const packageFlag = Buffer.from([-64]);
410
- const data = Buffer.concat([header, size, versionCode, dataType, commandCode, packageFlag, payload]);
411
- const hash = generateHash(data);
412
- return Buffer.concat([data, Buffer.from([hash])]);
413
- }*/
414
470
  const encodePasscode = function (pass) {
471
+ /**
472
+ * Encode the passcode for smart lock
473
+ *
474
+ */
415
475
  let result = "";
416
476
  for (let i = 0; i < pass.length; i++)
417
477
  result += pass.charCodeAt(i).toString(16);
@@ -438,7 +498,7 @@ const hexWeek = function (schedule) {
438
498
  const MONDAY = 2;
439
499
  const TUESDAY = 4;
440
500
  const WEDNESDAY = 8;
441
- const THUERSDAY = 16;
501
+ const THURSDAY = 16;
442
502
  const FRIDAY = 32;
443
503
  const SATURDAY = 64;
444
504
  let result = 0;
@@ -456,7 +516,7 @@ const hexWeek = function (schedule) {
456
516
  result |= WEDNESDAY;
457
517
  }
458
518
  if (schedule.week.thursday) {
459
- result |= THUERSDAY;
519
+ result |= THURSDAY;
460
520
  }
461
521
  if (schedule.week.friday) {
462
522
  result |= FRIDAY;
@@ -474,18 +534,22 @@ const hexStringScheduleToSchedule = function (startDay, startTime, endDay, endTi
474
534
  const MONDAY = 2;
475
535
  const TUESDAY = 4;
476
536
  const WEDNESDAY = 8;
477
- const THUERSDAY = 16;
537
+ const THURSDAY = 16;
478
538
  const FRIDAY = 32;
479
539
  const SATURDAY = 64;
480
540
  const weekNumber = Number.parseInt(week, 16);
481
541
  return {
482
- startDateTime: startDay === "00000000" ? undefined : new Date(Number.parseInt(`${startDay.substring(2, 4)}${startDay.substring(0, 2)}`, 16), Number.parseInt(startDay.substring(4, 6), 16) - 1, Number.parseInt(startDay.substring(6, 8), 16), Number.parseInt(startTime.substring(0, 2), 16), Number.parseInt(startTime.substring(2, 4), 16)),
483
- endDateTime: endDay === "ffffffff" ? undefined : new Date(Number.parseInt(`${endDay.substring(2, 4)}${endDay.substring(0, 2)}`, 16), Number.parseInt(endDay.substring(4, 6), 16) - 1, Number.parseInt(endDay.substring(6, 8), 16), Number.parseInt(endTime.substring(0, 2), 16), Number.parseInt(endTime.substring(2, 4), 16)),
542
+ startDateTime: startDay === "00000000"
543
+ ? undefined
544
+ : new Date(Number.parseInt(`${startDay.substring(2, 4)}${startDay.substring(0, 2)}`, 16), Number.parseInt(startDay.substring(4, 6), 16) - 1, Number.parseInt(startDay.substring(6, 8), 16), Number.parseInt(startTime.substring(0, 2), 16), Number.parseInt(startTime.substring(2, 4), 16)),
545
+ endDateTime: endDay === "ffffffff"
546
+ ? undefined
547
+ : new Date(Number.parseInt(`${endDay.substring(2, 4)}${endDay.substring(0, 2)}`, 16), Number.parseInt(endDay.substring(4, 6), 16) - 1, Number.parseInt(endDay.substring(6, 8), 16), Number.parseInt(endTime.substring(0, 2), 16), Number.parseInt(endTime.substring(2, 4), 16)),
484
548
  week: {
485
549
  monday: (weekNumber & MONDAY) == MONDAY,
486
550
  tuesday: (weekNumber & TUESDAY) == TUESDAY,
487
551
  wednesday: (weekNumber & WEDNESDAY) == WEDNESDAY,
488
- thursday: (weekNumber & THUERSDAY) == THUERSDAY,
552
+ thursday: (weekNumber & THURSDAY) == THURSDAY,
489
553
  friday: (weekNumber & FRIDAY) == FRIDAY,
490
554
  saturday: (weekNumber & SATURDAY) == SATURDAY,
491
555
  sunday: (weekNumber & SUNDAY) == SUNDAY,
@@ -514,36 +578,42 @@ const getIdSuffix = function (p2pDid) {
514
578
  return result;
515
579
  };
516
580
  exports.getIdSuffix = getIdSuffix;
517
- const getImageBaseCode = function (serialnumber, p2pDid) {
581
+ const getImageBaseCode = function (serialNumber, p2pDid) {
518
582
  let nr = 0;
519
583
  try {
520
- nr = Number.parseInt(`0x${serialnumber[serialnumber.length - 1]}`);
584
+ nr = Number.parseInt(`0x${serialNumber[serialNumber.length - 1]}`);
521
585
  }
522
586
  catch (err) {
523
587
  const error = (0, error_1.ensureError)(err);
524
- throw new error_2.ImageBaseCodeError("Error generating image base code", { cause: error, context: { serialnumber: serialnumber, p2pDid: p2pDid } });
588
+ throw new error_2.ImageBaseCodeError("Error generating image base code", {
589
+ cause: error,
590
+ context: { serialnumber: serialNumber, p2pDid: p2pDid },
591
+ });
525
592
  }
526
593
  nr = (nr + 10) % 10;
527
- const base = serialnumber.substring(nr);
594
+ const base = serialNumber.substring(nr);
528
595
  return `${base}${(0, exports.getIdSuffix)(p2pDid)}`;
529
596
  };
530
597
  exports.getImageBaseCode = getImageBaseCode;
531
598
  const getImageSeed = function (p2pDid, code) {
532
599
  try {
533
- const ncode = Number.parseInt(code.substring(2));
600
+ const nCode = Number.parseInt(code.substring(2));
534
601
  const prefix = 1000 - (0, exports.getIdSuffix)(p2pDid);
535
- return (0, md5_1.default)(`${prefix}${ncode}`).toString(enc_hex_1.default).toUpperCase();
602
+ return (0, md5_1.default)(`${prefix}${nCode}`).toString(enc_hex_1.default).toUpperCase();
536
603
  }
537
604
  catch (err) {
538
605
  const error = (0, error_1.ensureError)(err);
539
- throw new error_2.ImageBaseCodeError("Error generating image seed", { cause: error, context: { p2pDid: p2pDid, code: code } });
606
+ throw new error_2.ImageBaseCodeError("Error generating image seed", {
607
+ cause: error,
608
+ context: { p2pDid: p2pDid, code: code },
609
+ });
540
610
  }
541
611
  };
542
612
  exports.getImageSeed = getImageSeed;
543
- const getImageKey = function (serialnumber, p2pDid, code) {
544
- const basecode = (0, exports.getImageBaseCode)(serialnumber, p2pDid);
613
+ const getImageKey = function (serialNumber, p2pDid, code) {
614
+ const baseCode = (0, exports.getImageBaseCode)(serialNumber, p2pDid);
545
615
  const seed = (0, exports.getImageSeed)(p2pDid, code);
546
- const data = `01${basecode}${seed}`;
616
+ const data = `01${baseCode}${seed}`;
547
617
  const hash = (0, sha256_1.default)(data);
548
618
  const hashBytes = [...Buffer.from(hash.toString(enc_hex_1.default), "hex")];
549
619
  const startByte = hashBytes[10];
@@ -553,10 +623,10 @@ const getImageKey = function (serialnumber, p2pDid, code) {
553
623
  if (i < 31) {
554
624
  fixed_byte = hashBytes[i + 1];
555
625
  }
556
- if ((i == 31) || ((i & 1) != 0)) {
626
+ if (i == 31 || (i & 1) != 0) {
557
627
  hashBytes[10] = fixed_byte;
558
- if ((126 < byte) || (126 < hashBytes[10])) {
559
- if (byte < hashBytes[10] || (byte - hashBytes[10]) == 0) {
628
+ if (126 < byte || 126 < hashBytes[10]) {
629
+ if (byte < hashBytes[10] || byte - hashBytes[10] == 0) {
560
630
  hashBytes[i] = hashBytes[10] - byte;
561
631
  }
562
632
  else {
@@ -564,7 +634,7 @@ const getImageKey = function (serialnumber, p2pDid, code) {
564
634
  }
565
635
  }
566
636
  }
567
- else if ((byte < 125) || (fixed_byte < 125)) {
637
+ else if (byte < 125 || fixed_byte < 125) {
568
638
  hashBytes[i] = fixed_byte + byte;
569
639
  }
570
640
  }
@@ -575,17 +645,14 @@ const decodeImage = function (p2pDid, data) {
575
645
  if (data.length >= 12) {
576
646
  const header = data.subarray(0, 12).toString();
577
647
  if (header === "eufysecurity") {
578
- const serialnumber = data.subarray(13, 29).toString();
648
+ const serialNumber = data.subarray(13, 29).toString();
579
649
  const code = data.subarray(30, 40).toString();
580
- const imageKey = (0, exports.getImageKey)(serialnumber, p2pDid, code);
650
+ const imageKey = (0, exports.getImageKey)(serialNumber, p2pDid, code);
581
651
  const otherData = data.subarray(41);
582
652
  const encryptedData = otherData.subarray(0, 256);
583
653
  const cipher = (0, crypto_1.createDecipheriv)("aes-128-ecb", Buffer.from(imageKey, "utf-8").subarray(0, 16), null);
584
654
  cipher.setAutoPadding(false);
585
- const decryptedData = Buffer.concat([
586
- cipher.update(encryptedData),
587
- cipher.final()
588
- ]);
655
+ const decryptedData = Buffer.concat([cipher.update(encryptedData), cipher.final()]);
589
656
  decryptedData.copy(otherData);
590
657
  return otherData;
591
658
  }
@@ -594,47 +661,47 @@ const decodeImage = function (p2pDid, data) {
594
661
  };
595
662
  exports.decodeImage = decodeImage;
596
663
  const getImagePath = function (path) {
597
- const splittedPath = path.split("~");
598
- if (splittedPath.length === 2) {
599
- return splittedPath[1];
664
+ const splitPath = path.split("~");
665
+ if (splitPath.length === 2) {
666
+ return splitPath[1];
600
667
  }
601
668
  return path;
602
669
  };
603
670
  exports.getImagePath = getImagePath;
671
+ // TODO: make up some testing
604
672
  const getImage = async function (api, serial, url) {
605
673
  const { default: imageType } = await import("image-type");
606
674
  const image = await api.getImage(serial, url);
607
675
  const type = await imageType(image);
608
676
  return {
609
677
  data: image,
610
- type: type !== null && type !== undefined ? type : { ext: "unknown", mime: "application/octet-stream" }
678
+ type: type !== null && type !== undefined ? type : { ext: "unknown", mime: "application/octet-stream" },
611
679
  };
612
680
  };
613
681
  exports.getImage = getImage;
614
682
  const isPrioritySourceType = function (current, update) {
615
- if (((current === "http" || current === "p2p" || current === "push" || current === "mqtt" || current === undefined) && (update === "p2p" || update === "push" || update === "mqtt")) ||
616
- ((current === "http" || current === undefined) && update === "http")) {
617
- return true;
618
- }
619
- return false;
683
+ return (((current === "http" || current === "p2p" || current === "push" || current === "mqtt" || current === undefined) &&
684
+ (update === "p2p" || update === "push" || update === "mqtt")) ||
685
+ ((current === "http" || current === undefined) && update === "http"));
620
686
  };
621
687
  exports.isPrioritySourceType = isPrioritySourceType;
622
688
  const decryptTrackerData = (data, key) => {
623
689
  const decipher = (0, crypto_1.createDecipheriv)("aes-128-ecb", key, null);
624
690
  decipher.setAutoPadding(false);
625
- return Buffer.concat([
626
- decipher.update(data),
627
- decipher.final()
628
- ]);
691
+ return Buffer.concat([decipher.update(data), decipher.final()]);
629
692
  };
630
693
  exports.decryptTrackerData = decryptTrackerData;
694
+ // TODO: this seems to be used before above
631
695
  const isT8170DetectionModeEnabled = function (value, type) {
632
696
  return (type & value) == type;
633
697
  };
634
698
  exports.isT8170DetectionModeEnabled = isT8170DetectionModeEnabled;
699
+ // TODO this seems like getHB3DetectionMode
635
700
  const getT8170DetectionMode = function (value, type, enable) {
636
701
  let result = 0;
637
- if ((Object.values(types_1.T8170DetectionTypes).includes(type) && Object.values(types_1.T8170DetectionTypes).includes(value)) && !enable)
702
+ if (Object.values(types_1.T8170DetectionTypes).includes(type) &&
703
+ Object.values(types_1.T8170DetectionTypes).includes(value) &&
704
+ !enable)
638
705
  return value;
639
706
  if (!enable) {
640
707
  result = type ^ value;
@@ -645,13 +712,37 @@ const getT8170DetectionMode = function (value, type, enable) {
645
712
  return result;
646
713
  };
647
714
  exports.getT8170DetectionMode = getT8170DetectionMode;
715
+ // TODO: Tidy up!!
716
+ const isT8110DetectionModeEnabled = function (value, type) {
717
+ return (type & value) == type;
718
+ };
719
+ exports.isT8110DetectionModeEnabled = isT8110DetectionModeEnabled;
720
+ const getT8110DetectionMode = function (value, type, enable) {
721
+ let result = 0;
722
+ if (Object.values(types_1.EufyCamC35DetectionTypes).includes(type) &&
723
+ Object.values(types_1.EufyCamC35DetectionTypes).includes(value) &&
724
+ !enable)
725
+ return value;
726
+ if (!enable) {
727
+ result = type ^ value;
728
+ }
729
+ else {
730
+ result = type | value;
731
+ }
732
+ return result;
733
+ };
734
+ exports.getT8110DetectionMode = getT8110DetectionMode;
735
+ // TODO: this is like isT8170DetectionModeEnabled
648
736
  const isIndoorS350DetectionModeEnabled = function (value, type) {
649
737
  return (type & value) == type;
650
738
  };
651
739
  exports.isIndoorS350DetectionModeEnabled = isIndoorS350DetectionModeEnabled;
740
+ // TODO: this is like getT8170DetectionMode
652
741
  const getIndoorS350DetectionMode = function (value, type, enable) {
653
742
  let result = 0;
654
- if ((Object.values(types_1.IndoorS350DetectionTypes).includes(type) && Object.values(types_1.IndoorS350DetectionTypes).includes(value)) && !enable)
743
+ if (Object.values(types_1.IndoorS350DetectionTypes).includes(type) &&
744
+ Object.values(types_1.IndoorS350DetectionTypes).includes(value) &&
745
+ !enable)
655
746
  return value;
656
747
  if (!enable) {
657
748
  result = type ^ value;
@@ -662,10 +753,12 @@ const getIndoorS350DetectionMode = function (value, type, enable) {
662
753
  return result;
663
754
  };
664
755
  exports.getIndoorS350DetectionMode = getIndoorS350DetectionMode;
756
+ // TODO: this is like isT8170DetectionModeEnabled
665
757
  const isIndoorNotitficationEnabled = function (value, type) {
666
758
  return (type & value) == type;
667
759
  };
668
760
  exports.isIndoorNotitficationEnabled = isIndoorNotitficationEnabled;
761
+ // TODO: this is like getT8170DetectionMode
669
762
  const getIndoorNotification = function (value, type, enable) {
670
763
  let result = 0;
671
764
  if (!enable) {
@@ -677,14 +770,16 @@ const getIndoorNotification = function (value, type, enable) {
677
770
  return result;
678
771
  };
679
772
  exports.getIndoorNotification = getIndoorNotification;
773
+ // TODO: this is like isT8170DetectionModeEnabled
680
774
  const isFloodlightT8425NotitficationEnabled = function (value, type) {
681
775
  return (type & value) == type;
682
776
  };
683
777
  exports.isFloodlightT8425NotitficationEnabled = isFloodlightT8425NotitficationEnabled;
778
+ // TODO: this is like getT8170DetectionMode
684
779
  const getFloodLightT8425Notification = function (value, type, enable) {
685
780
  let result = 0;
686
781
  if (!enable) {
687
- result = (type ^ value);
782
+ result = type ^ value;
688
783
  }
689
784
  else {
690
785
  result = type | value;
@@ -718,6 +813,7 @@ const getLockEventType = function (event) {
718
813
  return 0;
719
814
  };
720
815
  exports.getLockEventType = getLockEventType;
816
+ // TODO: this is like getT8170DetectionMode
721
817
  const switchSmartLockNotification = function (currentValue, mode, enable) {
722
818
  let result = 0;
723
819
  if (enable) {
@@ -729,6 +825,7 @@ const switchSmartLockNotification = function (currentValue, mode, enable) {
729
825
  return result;
730
826
  };
731
827
  exports.switchSmartLockNotification = switchSmartLockNotification;
828
+ // TODO: this is like isT8170DetectionModeEnabled
732
829
  const isSmartLockNotification = function (value, mode) {
733
830
  return (value & mode) !== 0;
734
831
  };
@@ -761,7 +858,8 @@ const loadEventImage = function (station, api, device, message, p2pTimeouts) {
761
858
  }
762
859
  else {
763
860
  if (!(0, utils_1.isEmpty)(message.pic_url)) {
764
- (0, exports.getImage)(api, device.getSerial(), message.pic_url).then((image) => {
861
+ (0, exports.getImage)(api, device.getSerial(), message.pic_url)
862
+ .then((image) => {
765
863
  if (image.data.length > 0) {
766
864
  if (p2pTimeouts.get(device.getSerial()) !== undefined) {
767
865
  clearTimeout(p2pTimeouts.get(device.getSerial()));
@@ -773,9 +871,15 @@ const loadEventImage = function (station, api, device, message, p2pTimeouts) {
773
871
  //fallback
774
872
  (0, exports.loadImageOverP2P)(station, device, device.getSerial(), p2pTimeouts);
775
873
  }
776
- }).catch((err) => {
874
+ })
875
+ .catch((err) => {
777
876
  const error = (0, error_1.ensureError)(err);
778
- logging_1.rootHTTPLogger.debug(`Device load event image - Fallback Error`, { error: (0, utils_1.getError)(error), stationSN: station.getSerial(), deviceSN: device.getSerial(), message: JSON.stringify(message) });
877
+ logging_1.rootHTTPLogger.debug(`Device load event image - Fallback Error`, {
878
+ error: (0, utils_1.getError)(error),
879
+ stationSN: station.getSerial(),
880
+ deviceSN: device.getSerial(),
881
+ message: JSON.stringify(message),
882
+ });
779
883
  (0, exports.loadImageOverP2P)(station, device, device.getSerial(), p2pTimeouts);
780
884
  });
781
885
  }
@@ -786,4 +890,27 @@ const loadEventImage = function (station, api, device, message, p2pTimeouts) {
786
890
  }
787
891
  };
788
892
  exports.loadEventImage = loadEventImage;
893
+ const getRandomPhoneModel = function () {
894
+ /**
895
+ * Generate a random phone model based on a structure
896
+ */
897
+ const brandKeys = Object.keys(const_1.PhoneModelStructure);
898
+ const randomBrandName = brandKeys[Math.floor(Math.random() * brandKeys.length)];
899
+ const pick = (arr) => arr[Math.floor(Math.random() * arr.length)];
900
+ let part1 = "";
901
+ let part2 = "";
902
+ const dataBrand = const_1.PhoneModelStructure[randomBrandName];
903
+ if (dataBrand.first && dataBrand.second) {
904
+ part1 = pick(dataBrand.first);
905
+ part2 = pick(dataBrand.second);
906
+ }
907
+ if (dataBrand.numbers && dataBrand.letters) {
908
+ const minNum = Math.pow(10, dataBrand.numbers - 1);
909
+ const maxNum = Math.pow(10, dataBrand.numbers) - 1;
910
+ part1 = String(Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);
911
+ part2 = pick(dataBrand.letters);
912
+ }
913
+ return `${randomBrandName}${part1}${part2}`.trim();
914
+ };
915
+ exports.getRandomPhoneModel = getRandomPhoneModel;
789
916
  //# sourceMappingURL=utils.js.map