@iobroker/js-controller-common 4.0.21 → 4.1.0-alpha.0-20220819-74ceeddc

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.
@@ -1,31 +1,58 @@
1
- 'use strict';
2
-
3
- const fs = require('fs-extra');
4
- const path = require('path');
5
- const semver = require('semver');
6
- const os = require('os');
7
- const forge = require('node-forge');
8
- const deepClone = require('deep-clone');
9
- const cpPromise = require('promisify-child-process');
10
- const jwt = require('jsonwebtoken');
11
- const { createInterface } = require('readline');
12
- const { PassThrough } = require('stream');
13
- const { detectPackageManager, packageManagers } = require('@alcalzone/pak');
14
- const EXIT_CODES = require('./exitCodes');
15
- const zlib = require('zlib');
16
-
17
- // @ts-ignore
18
- require('events').EventEmitter.prototype._maxListeners = 100;
19
- let request;
20
- let axios;
21
- let extend;
22
- let password;
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.execAsync = exports.getInstances = exports.getAllEnums = exports.getAllInstances = exports.validateGeneralObjectProperties = exports.parseDependencies = exports.removeIdFromAllEnums = exports.formatAliasValue = exports.measureEventLoopLag = exports.isArray = exports.isObject = exports.decrypt = exports.encrypt = exports.appendStackTrace = exports.pattern2RegEx = exports.setQualityForInstance = exports.promiseSequence = exports.promisifyNoError = exports.promisify = exports.getConfigFileName = exports.getDefaultDataDir = exports.getControllerDir = exports.getHostInfo = exports.generateDefaultCertificates = exports.getCertificateInfo = exports.getDiskInfo = exports.rebuildNodeModules = exports.uninstallNodeModule = exports.installNodeModule = exports.getHostName = exports.getAdapterDir = exports.sendDiagInfo = exports.getRepositoryFileAsync = exports.getRepositoryFile = exports.getInstalledInfo = exports.getJsonAsync = exports.getJson = exports.getFile = exports.createUuid = exports.isDocker = exports.findIPs = exports.rmdirRecursiveSync = exports.appName = exports.isHostRunning = exports.isSingleHost = exports.decryptPhrase = exports.upToDate = exports.checkNonEditable = exports.FORBIDDEN_CHARS = exports.ERRORS = void 0;
21
+ exports.maybeArrayToString = exports.compressFileGZip = exports.updateLicenses = exports.setExecutableCapabilities = exports.getInstancesOrderedByStartPrio = exports.getLogger = exports.getInstanceIndicatorObjects = exports.removePreservedProperties = exports.parseGithubPathname = exports.isGithubPathname = exports.parseShortGithubUrl = exports.isShortGithubUrl = exports.getDefaultNodeArgs = exports.resolveAdapterMainFile = exports.pipeLinewise = void 0;
22
+ const fs_extra_1 = __importDefault(require("fs-extra"));
23
+ const path_1 = __importDefault(require("path"));
24
+ const semver_1 = __importDefault(require("semver"));
25
+ const os_1 = __importDefault(require("os"));
26
+ const node_forge_1 = __importDefault(require("node-forge"));
27
+ const deep_clone_1 = __importDefault(require("deep-clone"));
28
+ const promisify_child_process_1 = require("promisify-child-process");
29
+ const readline_1 = require("readline");
30
+ const stream_1 = require("stream");
31
+ const pak_1 = require("@alcalzone/pak");
32
+ const exitCodes_1 = require("./exitCodes");
33
+ const zlib_1 = __importDefault(require("zlib"));
34
+ const password_1 = require("./password");
35
+ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
36
+ const axios_1 = __importDefault(require("axios"));
37
+ const crypto_1 = __importDefault(require("crypto"));
38
+ const child_process_1 = require("child_process");
39
+ const url_1 = require("url");
40
+ const events_1 = __importDefault(require("events"));
41
+ const maybeCallback_1 = require("./maybeCallback");
42
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
43
+ const extend = require('node.extend');
44
+ var ERRORS;
45
+ (function (ERRORS) {
46
+ ERRORS["ERROR_NOT_FOUND"] = "Not exists";
47
+ ERRORS["ERROR_EMPTY_OBJECT"] = "null object";
48
+ ERRORS["ERROR_NO_OBJECT"] = "no object";
49
+ ERRORS["ERROR_DB_CLOSED"] = "DB closed";
50
+ })(ERRORS = exports.ERRORS || (exports.ERRORS = {}));
51
+ events_1.default.EventEmitter.prototype.setMaxListeners(100);
23
52
  let npmVersion;
24
- let crypto;
25
53
  let diskusage;
26
54
  const randomID = Math.round(Math.random() * 10000000000000); // Used for creation of User-Agent
27
55
  const VENDOR_FILE = '/etc/iob-vendor.json';
28
-
29
56
  let lastCalculationOfIps;
30
57
  let ownIpArr = [];
31
58
  // Here we define all characters that are forbidden in IDs. Since we want to allow multiple
@@ -41,59 +68,54 @@ let ownIpArr = [];
41
68
  // · " :!#$%&()+=@^{}|~" (for legacy reasons)
42
69
  //
43
70
  /** All characters that may not appear in an object ID. */
44
- const FORBIDDEN_CHARS = /[^._\-/ :!#$%&()+=@^{}|~\p{Ll}\p{Lu}\p{Nd}]+/gu;
45
-
71
+ exports.FORBIDDEN_CHARS = /[^._\-/ :!#$%&()+=@^{}|~\p{Ll}\p{Lu}\p{Nd}]+/gu;
46
72
  /**
47
73
  * recursively copy values from old object to new one
48
74
  *
49
75
  * @alias copyAttributes
50
76
  * @memberof tools
51
- * @param {object} oldObj source object
52
- * @param {object} newObj destination object
53
- * @param {object} [originalObj] optional object for read __no_change__ values
54
- * @param {boolean} [isNonEdit] optional indicator if copy is in nonEdit part
77
+ * @param oldObj source object
78
+ * @param newObj destination object
79
+ * @param originalObj optional object for read __no_change__ values
80
+ * @param isNonEdit optional indicator if copy is in nonEdit part
55
81
  *
56
82
  */
57
83
  function copyAttributes(oldObj, newObj, originalObj, isNonEdit) {
58
84
  for (const attr of Object.keys(oldObj)) {
59
- if (
60
- oldObj[attr] === undefined ||
85
+ if (oldObj[attr] === undefined ||
61
86
  oldObj[attr] === null ||
62
87
  typeof oldObj[attr] !== 'object' ||
63
- oldObj[attr] instanceof Array
64
- ) {
88
+ oldObj[attr] instanceof Array) {
65
89
  if (oldObj[attr] === '__no_change__' && originalObj && !isNonEdit) {
66
90
  if (originalObj[attr] !== undefined) {
67
- newObj[attr] = deepClone(originalObj[attr]);
68
- } else {
91
+ newObj[attr] = (0, deep_clone_1.default)(originalObj[attr]);
92
+ }
93
+ else {
69
94
  console.log(`Attribute ${attr} ignored by copying`);
70
95
  }
71
- } else if (oldObj[attr] === '__delete__' && !isNonEdit) {
96
+ }
97
+ else if (oldObj[attr] === '__delete__' && !isNonEdit) {
72
98
  if (newObj[attr] !== undefined) {
73
99
  delete newObj[attr];
74
100
  }
75
- } else {
101
+ }
102
+ else {
76
103
  newObj[attr] = oldObj[attr];
77
104
  }
78
- } else {
105
+ }
106
+ else {
79
107
  newObj[attr] = newObj[attr] || {};
80
- copyAttributes(
81
- oldObj[attr],
82
- newObj[attr],
83
- originalObj && originalObj[attr],
84
- isNonEdit || attr === 'nonEdit'
85
- );
108
+ copyAttributes(oldObj[attr], newObj[attr], originalObj && originalObj[attr], isNonEdit || attr === 'nonEdit');
86
109
  }
87
110
  }
88
111
  }
89
-
90
112
  /**
91
113
  * Checks the flag nonEdit and restores non-changeable values if required
92
114
  *
93
115
  * @alias checkNonEditable
94
116
  * @memberof tools
95
- * @param {object} oldObject source object
96
- * @param {object} newObject destination object
117
+ * @param oldObject source object
118
+ * @param newObject destination object
97
119
  *
98
120
  */
99
121
  function checkNonEditable(oldObject, newObject) {
@@ -103,51 +125,47 @@ function checkNonEditable(oldObject, newObject) {
103
125
  if (!oldObject.nonEdit && !newObject.nonEdit) {
104
126
  return true;
105
127
  }
106
-
107
128
  // if nonEdit is protected with password
108
129
  if (oldObject.nonEdit && oldObject.nonEdit.passHash) {
109
130
  // If new Object wants to update the nonEdit information
110
131
  if (newObject.nonEdit && newObject.nonEdit.password) {
111
- crypto = crypto || require('crypto');
112
- const hash = crypto.createHash('sha256').update(newObject.nonEdit.password.toString()).digest('base64');
132
+ const hash = crypto_1.default.createHash('sha256').update(newObject.nonEdit.password.toString()).digest('base64');
113
133
  if (oldObject.nonEdit.passHash !== hash) {
114
134
  delete newObject.nonEdit;
115
135
  return false;
116
- } else {
117
- oldObject.nonEdit = deepClone(newObject.nonEdit);
136
+ }
137
+ else {
138
+ oldObject.nonEdit = (0, deep_clone_1.default)(newObject.nonEdit);
118
139
  delete oldObject.nonEdit.password;
119
140
  delete newObject.nonEdit.password;
120
141
  oldObject.nonEdit.passHash = hash;
121
142
  newObject.nonEdit.passHash = hash;
122
143
  }
123
144
  copyAttributes(newObject.nonEdit, newObject, newObject);
124
-
125
145
  if (newObject.passHash) {
126
146
  delete newObject.passHash;
127
147
  }
128
148
  if (newObject.nonEdit && newObject.nonEdit.password) {
129
149
  delete newObject.nonEdit.password;
130
150
  }
131
-
132
151
  return true;
133
- } else {
152
+ }
153
+ else {
134
154
  newObject.nonEdit = oldObject.nonEdit;
135
155
  }
136
- } else if (newObject.nonEdit) {
137
- oldObject.nonEdit = deepClone(newObject.nonEdit);
156
+ }
157
+ else if (newObject.nonEdit) {
158
+ oldObject.nonEdit = (0, deep_clone_1.default)(newObject.nonEdit);
138
159
  if (newObject.nonEdit.password) {
139
- crypto = crypto || require('crypto');
140
- const hash = crypto.createHash('sha256').update(newObject.nonEdit.password.toString()).digest('base64');
160
+ const hash = crypto_1.default.createHash('sha256').update(newObject.nonEdit.password.toString()).digest('base64');
141
161
  delete oldObject.nonEdit.password;
142
162
  delete newObject.nonEdit.password;
143
163
  oldObject.nonEdit.passHash = hash;
144
164
  newObject.nonEdit.passHash = hash;
145
165
  }
146
166
  }
147
-
148
167
  // restore settings
149
168
  copyAttributes(oldObject.nonEdit, newObject, oldObject);
150
-
151
169
  if (newObject.passHash) {
152
170
  delete newObject.passHash;
153
171
  }
@@ -156,22 +174,20 @@ function checkNonEditable(oldObject, newObject) {
156
174
  }
157
175
  return true;
158
176
  }
159
-
177
+ exports.checkNonEditable = checkNonEditable;
160
178
  /**
161
- * @param {string} repoVersion
162
- * @param {string} installedVersion
179
+ * @param repoVersion
180
+ * @param installedVersion
163
181
  * @throws {Error} if version is invalid
164
182
  */
165
183
  function upToDate(repoVersion, installedVersion) {
166
184
  // Check if the installed version is at least the repo version
167
- return semver.gte(installedVersion, repoVersion);
185
+ return semver_1.default.gte(installedVersion, repoVersion);
168
186
  }
169
-
187
+ exports.upToDate = upToDate;
170
188
  // TODO: this is only here for backward compatibility, if MULTIHOST password was still setup with old decryption
171
189
  function decryptPhrase(password, data, callback) {
172
- crypto = crypto || require('crypto');
173
- const decipher = crypto.createDecipher('aes192', password);
174
-
190
+ const decipher = crypto_1.default.createDecipher('aes192', password);
175
191
  try {
176
192
  let decrypted = '';
177
193
  decipher.on('readable', () => {
@@ -184,43 +200,46 @@ function decryptPhrase(password, data, callback) {
184
200
  console.error('Cannot decode secret: ' + error);
185
201
  callback(null);
186
202
  });
187
-
188
203
  decipher.on('end', () => callback(decrypted));
189
-
190
204
  decipher.write(data, 'hex');
191
205
  decipher.end();
192
- } catch (e) {
206
+ }
207
+ catch (e) {
193
208
  console.error(`Cannot decode secret: ${e.message}`);
194
209
  callback(null);
195
210
  }
196
211
  }
197
-
212
+ exports.decryptPhrase = decryptPhrase;
198
213
  /**
199
214
  * Checks if multiple host objects exists, without using object views
200
215
  *
201
- * @param {object} objects the objects db
202
- * @return {Promise<boolean>} true if only one host object exists
216
+ * @param objects the objects db
217
+ * @return true if only one host object exists
203
218
  */
204
219
  async function isSingleHost(objects) {
205
- const res = await objects.getObjectList({ startkey: 'system.host.', endkey: 'system.host.\u9999' });
220
+ const res = await objects.getObjectList({
221
+ startkey: 'system.host.',
222
+ endkey: 'system.host.\u9999'
223
+ });
206
224
  const hostObjs = res.rows.filter(obj => obj.value && obj.value.type === 'host');
207
225
  return hostObjs.length <= 1; // on setup no host object is there yet
208
226
  }
209
-
227
+ exports.isSingleHost = isSingleHost;
210
228
  /**
211
229
  * Checks if at least one host is running in a MH environment
212
230
  *
213
- * @param {object} objects the objects db
214
- * @param {object} states the states db
215
- * @return Promise<boolean> true if one or more hosts running else false
231
+ * @param objects the objects db
232
+ * @param states the states db
233
+ * @return true if one or more hosts running else false
216
234
  */
217
235
  async function isHostRunning(objects, states) {
218
236
  // do it without object view for now, can be reverted if no one downgrades to < 4 (redis-sets)
219
237
  // const res = await objects.getObjectViewAsync('system', 'host', { startkey: '', endkey: '\u9999' });
220
-
221
- const res = await objects.getObjectList({ startkey: 'system.host.', endkey: 'system.host.\u9999' });
238
+ const res = await objects.getObjectList({
239
+ startkey: 'system.host.',
240
+ endkey: 'system.host.\u9999'
241
+ });
222
242
  res.rows = res.rows.filter(obj => obj.value && obj.value.type === 'host');
223
-
224
243
  for (const hostObj of res.rows) {
225
244
  const state = await states.getState(`${hostObj.id}.alive`);
226
245
  if (state && state.val) {
@@ -229,102 +248,111 @@ async function isHostRunning(objects, states) {
229
248
  }
230
249
  return false;
231
250
  }
232
-
251
+ exports.isHostRunning = isHostRunning;
252
+ /**
253
+ * Checks if ioBroker is installed in a dev environment
254
+ * @private
255
+ * @return {boolean}
256
+ */
257
+ function _isDevInstallation() {
258
+ return fs_extra_1.default.pathExistsSync(`${__dirname}/../../../../../packages/controller`);
259
+ }
233
260
  function getAppName() {
234
- if (fs.existsSync(__dirname + '/../../../../packages/controller')) {
261
+ if (_isDevInstallation()) {
235
262
  // dev install - GitHub folder is uppercase
236
263
  return 'ioBroker';
237
264
  }
238
-
239
265
  return 'iobroker';
240
266
  }
241
-
267
+ exports.appName = getAppName();
242
268
  function rmdirRecursiveSync(path) {
243
- if (fs.existsSync(path)) {
244
- fs.readdirSync(path).forEach(file => {
269
+ if (fs_extra_1.default.existsSync(path)) {
270
+ fs_extra_1.default.readdirSync(path).forEach(file => {
245
271
  const curPath = `${path}/${file}`;
246
272
  try {
247
- if (fs.statSync(curPath).isDirectory()) {
273
+ if (fs_extra_1.default.statSync(curPath).isDirectory()) {
248
274
  // recurse
249
275
  rmdirRecursiveSync(curPath);
250
- } else {
276
+ }
277
+ else {
251
278
  // delete file
252
- fs.unlinkSync(curPath);
279
+ fs_extra_1.default.unlinkSync(curPath);
253
280
  }
254
- } catch (e) {
281
+ }
282
+ catch (e) {
255
283
  if (e.code !== 'ENOENT') {
256
284
  console.log(`Cannot delete file ${path}: ${e.message}`);
257
- } else {
285
+ }
286
+ else {
258
287
  throw e;
259
288
  }
260
289
  }
261
290
  });
262
291
  // delete (hopefully) empty folder
263
292
  try {
264
- fs.rmdirSync(path);
265
- } catch (e) {
293
+ fs_extra_1.default.rmdirSync(path);
294
+ }
295
+ catch (e) {
266
296
  if (e.code !== 'ENOENT') {
267
297
  console.log(`Cannot delete directory ${path}: ${e.message}`);
268
- } else {
298
+ }
299
+ else {
269
300
  throw e;
270
301
  }
271
302
  }
272
303
  }
273
304
  }
274
-
305
+ exports.rmdirRecursiveSync = rmdirRecursiveSync;
275
306
  function findIPs() {
276
307
  if (!lastCalculationOfIps || Date.now() - lastCalculationOfIps > 10000) {
277
308
  lastCalculationOfIps = Date.now();
278
309
  ownIpArr = [];
279
310
  try {
280
- const ifaces = require('os').networkInterfaces();
281
- Object.keys(ifaces).forEach(dev =>
282
- ifaces[dev].forEach(
283
- details =>
284
- // noinspection JSUnresolvedVariable
285
- !details.internal && ownIpArr.push(details.address)
286
- )
287
- );
288
- } catch (e) {
311
+ const ifaces = os_1.default.networkInterfaces();
312
+ for (const iface of Object.values(ifaces)) {
313
+ iface === null || iface === void 0 ? void 0 : iface.forEach(details => !details.internal && ownIpArr.push(details.address));
314
+ }
315
+ }
316
+ catch (e) {
289
317
  console.error(`Can not find local IPs: ${e.message}`);
290
318
  }
291
319
  }
292
-
293
320
  return ownIpArr;
294
321
  }
295
-
322
+ exports.findIPs = findIPs;
296
323
  function findPath(path, url) {
297
324
  if (!url) {
298
325
  return '';
299
326
  }
300
- if (url.substring(0, 'http://'.length) === 'http://' || url.substring(0, 'https://'.length) === 'https://') {
327
+ if (url.startsWith('http://') || url.startsWith('https://')) {
301
328
  return url;
302
- } else {
303
- if (path.substring(0, 'http://'.length) === 'http://' || path.substring(0, 'https://'.length) === 'https://') {
329
+ }
330
+ else {
331
+ if (path.startsWith('http://') || path.startsWith('https://')) {
304
332
  return (path + url).replace(/\/\//g, '/').replace('http:/', 'http://').replace('https:/', 'https://');
305
- } else {
333
+ }
334
+ else {
306
335
  if (url[0] === '/') {
307
- return __dirname + '/..' + url;
308
- } else {
309
- return __dirname + '/../' + path + url;
336
+ return `${__dirname}/..${url}`;
337
+ }
338
+ else {
339
+ return `${__dirname}/../${path}${url}`;
310
340
  }
311
341
  }
312
342
  }
313
343
  }
314
-
315
344
  function getMac(callback) {
316
345
  const macRegex = /(?:[a-z0-9]{2}[:-]){5}[a-z0-9]{2}/gi;
317
346
  const zeroRegex = /(?:[0]{2}[:-]){5}[0]{2}/;
318
347
  const command = process.platform.indexOf('win') === 0 ? 'getmac' : 'ifconfig || ip link';
319
-
320
- require('child_process').exec(command, { windowsHide: true }, (err, stdout, _stderr) => {
348
+ (0, child_process_1.exec)(command, { windowsHide: true }, (err, stdout, _stderr) => {
321
349
  if (err) {
322
350
  callback(err);
323
- } else {
351
+ }
352
+ else {
324
353
  let macAddress;
325
354
  let match;
326
355
  let result = null;
327
-
328
356
  while (true) {
329
357
  match = macRegex.exec(stdout);
330
358
  if (!match) {
@@ -335,92 +363,86 @@ function getMac(callback) {
335
363
  result = macAddress;
336
364
  }
337
365
  }
338
-
339
366
  if (result === null) {
340
367
  callback(new Error('could not determine the mac address from:\n' + stdout));
341
- } else {
368
+ }
369
+ else {
342
370
  callback(null, result.replace(/-/g, ':').toLowerCase());
343
371
  }
344
372
  }
345
373
  });
346
374
  }
347
-
348
375
  /**
349
376
  * Checks if we are running inside a docker container
350
- * @returns {boolean}
351
377
  */
352
378
  function isDocker() {
353
379
  try {
354
- fs.statSync('/.dockerenv');
380
+ fs_extra_1.default.statSync('/.dockerenv');
355
381
  return true;
356
- } catch {
382
+ }
383
+ catch {
357
384
  // ignore error
358
385
  }
359
-
360
386
  try {
361
387
  // check docker group
362
- return fs.readFileSync('/proc/self/cgroup', 'utf8').includes('docker');
363
- } catch {
388
+ return fs_extra_1.default.readFileSync('/proc/self/cgroup', 'utf8').includes('docker');
389
+ }
390
+ catch {
364
391
  return false;
365
392
  }
366
393
  }
367
-
394
+ exports.isDocker = isDocker;
368
395
  // Build unique uuid based on MAC address if possible
369
396
  function uuid(givenMac, callback) {
370
397
  if (typeof givenMac === 'function') {
371
398
  callback = givenMac;
372
399
  givenMac = '';
373
400
  }
374
-
375
401
  const _isDocker = isDocker();
376
-
377
402
  // return constant UUID for all CI environments to keep the statistics clean
403
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
378
404
  if (require('ci-info').isCI) {
379
405
  return callback('55travis-pipe-line-cior-githubaction');
380
406
  }
381
-
382
407
  let mac = givenMac !== null ? givenMac || '' : null;
383
408
  let u;
384
-
385
409
  if (!_isDocker && mac === '') {
386
- const ifaces = require('os').networkInterfaces();
387
-
410
+ const ifaces = os_1.default.networkInterfaces();
388
411
  // Find first not empty MAC
389
- for (const n of Object.keys(ifaces)) {
390
- for (let c = 0; c < ifaces[n].length; c++) {
391
- if (ifaces[n][c].mac && ifaces[n][c].mac !== '00:00:00:00:00:00') {
392
- mac = ifaces[n][c].mac;
393
- break;
412
+ for (const iface of Object.values(ifaces)) {
413
+ if (iface) {
414
+ for (const entry of iface) {
415
+ if (entry.mac !== '00:00:00:00:00:00') {
416
+ mac = entry.mac;
417
+ break;
418
+ }
394
419
  }
395
420
  }
396
-
397
421
  if (mac) {
398
422
  break;
399
423
  }
400
424
  }
401
425
  }
402
-
403
426
  if (!_isDocker && mac === '') {
404
427
  return getMac((_err, mac) => uuid(mac || null, callback));
405
428
  }
406
-
407
429
  if (!_isDocker && mac) {
408
- const md5sum = require('crypto').createHash('md5');
430
+ const md5sum = crypto_1.default.createHash('md5');
409
431
  md5sum.update(mac);
410
432
  mac = md5sum.digest('hex');
411
433
  u =
412
434
  mac.substring(0, 8) +
413
- '-' +
414
- mac.substring(8, 12) +
415
- '-' +
416
- mac.substring(12, 16) +
417
- '-' +
418
- mac.substring(16, 20) +
419
- '-' +
420
- mac.substring(20);
421
- } else {
435
+ '-' +
436
+ mac.substring(8, 12) +
437
+ '-' +
438
+ mac.substring(12, 16) +
439
+ '-' +
440
+ mac.substring(16, 20) +
441
+ '-' +
442
+ mac.substring(20);
443
+ }
444
+ else {
422
445
  // Returns a RFC4122 compliant v4 UUID https://gist.github.com/LeverOne/1308368 (DO WTF YOU WANT TO PUBLIC LICENSE)
423
- /** @type {any} */
424
446
  let a;
425
447
  let b;
426
448
  b = a = '';
@@ -429,269 +451,244 @@ function uuid(givenMac, callback) {
429
451
  }
430
452
  u = b;
431
453
  }
432
-
433
454
  callback(u);
434
455
  }
435
-
436
456
  function updateUuid(newUuid, _objects, callback) {
437
457
  uuid('', _uuid => {
438
458
  _uuid = newUuid || _uuid;
439
459
  // Add vendor prefix to UUID
440
- if (fs.existsSync(VENDOR_FILE)) {
460
+ if (fs_extra_1.default.existsSync(VENDOR_FILE)) {
441
461
  try {
462
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
442
463
  const vendor = require(VENDOR_FILE);
443
464
  if (vendor.vendor && vendor.vendor.uuidPrefix && vendor.vendor.uuidPrefix.length === 2) {
444
465
  _uuid = vendor.vendor.uuidPrefix + _uuid;
445
466
  }
446
- } catch {
467
+ }
468
+ catch {
447
469
  console.error(`Cannot parse ${VENDOR_FILE}`);
448
470
  }
449
471
  }
450
-
451
- _objects.setObject(
452
- 'system.meta.uuid',
453
- {
454
- type: 'meta',
455
- common: {
456
- name: 'uuid',
457
- type: 'uuid'
458
- },
459
- ts: new Date().getTime(),
460
- from: 'system.host.' + getHostName() + '.tools',
461
- native: {
462
- uuid: _uuid
463
- }
472
+ _objects.setObject('system.meta.uuid', {
473
+ type: 'meta',
474
+ common: {
475
+ name: 'uuid',
476
+ type: 'uuid'
464
477
  },
465
- err => {
466
- if (err) {
467
- console.error('object system.meta.uuid cannot be updated: ' + err);
468
- callback();
469
- } else {
470
- _objects.getObject('system.meta.uuid', (err, obj) => {
471
- if (obj.native.uuid !== _uuid) {
472
- console.error('object system.meta.uuid cannot be updated: write protected');
473
- } else {
474
- console.log('object system.meta.uuid created: ' + _uuid);
475
- }
476
- callback(_uuid);
477
- });
478
- }
478
+ ts: new Date().getTime(),
479
+ from: `system.host.${getHostName()}.tools`,
480
+ native: {
481
+ uuid: _uuid
482
+ }
483
+ }, (err) => {
484
+ if (err) {
485
+ console.error(`object system.meta.uuid cannot be updated: ${err.message}`);
486
+ callback();
487
+ }
488
+ else {
489
+ _objects.getObject('system.meta.uuid', (err, obj) => {
490
+ if (obj.native.uuid !== _uuid) {
491
+ console.error('object system.meta.uuid cannot be updated: write protected');
492
+ }
493
+ else {
494
+ console.log(`object system.meta.uuid created: ${_uuid}`);
495
+ }
496
+ callback(_uuid);
497
+ });
479
498
  }
480
- );
499
+ });
481
500
  });
482
501
  }
483
-
484
502
  /**
485
503
  * Generates a new uuid if non existing
486
504
  *
487
- * @param {object} objects - objects DB
488
- * @return {Promise<void|string>} uuid if successfully created/updated
505
+ * @param objects - objects DB
506
+ * @return uuid if successfully created/updated
489
507
  */
490
508
  async function createUuid(objects) {
491
- const promiseCheckPassword = new Promise(resolve =>
492
- objects.getObject('system.user.admin', (err, obj) => {
493
- if (err || !obj) {
494
- password = password || require('./password');
495
-
496
- // Default Password for user 'admin' is application name in lower case
497
- password(module.exports.appName).hash(null, null, (err, res) => {
498
- err && console.error(err);
499
-
500
- // Create user here and not in io-package.js because of hash password
501
- objects.setObject(
502
- 'system.user.admin',
503
- {
504
- type: 'user',
505
- common: {
506
- name: 'admin',
507
- password: res,
508
- dontDelete: true,
509
- enabled: true
510
- },
511
- ts: new Date().getTime(),
512
- from: `system.host.${getHostName()}.tools`,
513
- native: {}
514
- },
515
- () => {
516
- console.log('object system.user.admin created');
517
- resolve();
518
- }
519
- );
509
+ const promiseCheckPassword = new Promise(resolve => objects.getObject('system.user.admin', (err, obj) => {
510
+ if (err || !obj) {
511
+ // Default Password for user 'admin' is application name in lower case
512
+ (0, password_1.password)(exports.appName).hash(null, null, (err, res) => {
513
+ err && console.error(err);
514
+ // Create user here and not in io-package.js because of hash password
515
+ objects.setObject('system.user.admin', {
516
+ type: 'user',
517
+ common: {
518
+ name: 'admin',
519
+ password: res,
520
+ dontDelete: true,
521
+ enabled: true
522
+ },
523
+ ts: new Date().getTime(),
524
+ from: `system.host.${getHostName()}.tools`,
525
+ native: {}
526
+ }, () => {
527
+ console.log('object system.user.admin created');
528
+ resolve();
520
529
  });
521
- } else {
522
- resolve();
523
- }
524
- })
525
- );
526
- const promiseCheckUuid = new Promise(resolve =>
527
- objects.getObject('system.meta.uuid', (err, obj) => {
528
- if (!err && obj && obj.native && obj.native.uuid) {
529
- const PROBLEM_UUIDS = [
530
- 'ab265f4a-67f9-a46a-c0b2-61e4b95cefe5',
531
- '7abd3182-d399-f7bd-da19-9550d8babede',
532
- 'deb6f2a8-fe69-5491-0a50-a9f9b8f3419c',
533
- 'ec66c85e-fc36-f6f9-f1c9-f5a2882d23c7',
534
- 'e6203b03-f5f4-253a-e4f6-b295fc543ab7',
535
- 'd659fa3d-7ef9-202a-ea23-acd0aff67b24'
536
- ];
537
-
538
- // if COMMON invalid docker uuid
539
- if (PROBLEM_UUIDS.includes(obj.native.uuid)) {
540
- // Read vis license
541
- objects.getObject('system.adapter.vis.0', (err, licObj) => {
542
- if (!licObj || !licObj.native || !licObj.native.license) {
530
+ });
531
+ }
532
+ else {
533
+ resolve();
534
+ }
535
+ }));
536
+ const promiseCheckUuid = new Promise(resolve => objects.getObject('system.meta.uuid', (err, obj) => {
537
+ if (!err && obj && obj.native && obj.native.uuid) {
538
+ const PROBLEM_UUIDS = [
539
+ 'ab265f4a-67f9-a46a-c0b2-61e4b95cefe5',
540
+ '7abd3182-d399-f7bd-da19-9550d8babede',
541
+ 'deb6f2a8-fe69-5491-0a50-a9f9b8f3419c',
542
+ 'ec66c85e-fc36-f6f9-f1c9-f5a2882d23c7',
543
+ 'e6203b03-f5f4-253a-e4f6-b295fc543ab7',
544
+ 'd659fa3d-7ef9-202a-ea23-acd0aff67b24'
545
+ ];
546
+ // if COMMON invalid docker uuid
547
+ if (PROBLEM_UUIDS.includes(obj.native.uuid)) {
548
+ // Read vis license
549
+ objects.getObject('system.adapter.vis.0', (err, licObj) => {
550
+ if (!licObj || !licObj.native || !licObj.native.license) {
551
+ // generate new UUID
552
+ updateUuid('', objects, _uuid => resolve(_uuid));
553
+ }
554
+ else {
555
+ // decode obj.native.license
556
+ let data;
557
+ try {
558
+ data = jsonwebtoken_1.default.decode(licObj.native.license);
559
+ }
560
+ catch {
561
+ data = null;
562
+ }
563
+ if (!data || typeof data === 'string' || !data.uuid) {
543
564
  // generate new UUID
544
- updateUuid('', objects, _uuid => resolve(_uuid));
545
- } else {
546
- // decode obj.native.license
547
- let data;
548
- try {
549
- data = jwt.decode(licObj.native.license);
550
- } catch {
551
- data = null;
565
+ updateUuid('', objects, __uuid => resolve(__uuid));
566
+ }
567
+ else {
568
+ if (data.uuid !== obj.native.uuid) {
569
+ updateUuid(data.correct ? data.uuid : '', objects, _uuid => resolve(_uuid));
552
570
  }
553
-
554
- if (!data || !data.uuid) {
555
- // generate new UUID
556
- updateUuid('', objects, __uuid => resolve(__uuid));
557
- } else {
558
- if (data.uuid !== obj.native.uuid) {
559
- updateUuid(data.correct ? data.uuid : '', objects, _uuid => resolve(_uuid));
560
- } else {
561
- // Show error
562
- console.warn(
563
- `Your iobroker.vis license must be updated. Please contact info@iobroker.net to get a new license!`
564
- );
565
- console.warn(
566
- `Provide following information in email: ${data.email}, invoice: ${data.invoice}`
567
- );
568
- resolve();
569
- }
571
+ else {
572
+ // Show error
573
+ console.warn(`Your iobroker.vis license must be updated. Please contact info@iobroker.net to get a new license!`);
574
+ console.warn(`Provide following information in email: ${data.email}, invoice: ${data.invoice}`);
575
+ resolve();
570
576
  }
571
577
  }
572
- });
573
- } else {
574
- resolve();
575
- }
576
- } else {
577
- // generate new UUID
578
- updateUuid('', objects, _uuid => resolve(_uuid));
578
+ }
579
+ });
580
+ }
581
+ else {
582
+ resolve();
579
583
  }
580
- })
581
- );
582
-
584
+ }
585
+ else {
586
+ // generate new UUID
587
+ updateUuid('', objects, _uuid => resolve(_uuid));
588
+ }
589
+ }));
583
590
  const result = await Promise.all([promiseCheckPassword, promiseCheckUuid]);
584
591
  return result[1];
585
592
  }
586
-
593
+ exports.createUuid = createUuid;
587
594
  // Download file to tmp or return file name directly
588
- function getFile(urlOrPath, fileName, callback) {
589
- request = request || require('request');
590
-
595
+ async function getFile(urlOrPath, fileName, callback) {
591
596
  // If object was read
592
- if (
593
- urlOrPath.substring(0, 'http://'.length) === 'http://' ||
594
- urlOrPath.substring(0, 'https://'.length) === 'https://'
595
- ) {
597
+ if (urlOrPath.substring(0, 'http://'.length) === 'http://' ||
598
+ urlOrPath.substring(0, 'https://'.length) === 'https://') {
596
599
  const tmpFile = `${__dirname}/../tmp/${fileName || Math.floor(Math.random() * 0xffffffe) + '.zip'}`;
597
- // Add some information to user-agent, like chrome, IE and Firefox do
598
- request({
599
- url: urlOrPath,
600
- gzip: true,
601
- headers: { 'User-Agent': `${module.exports.appName}, RND: ${randomID}, N: ${process.version}` }
602
- })
603
- .on('error', error => {
604
- console.log(`Cannot download "${tmpFile}": ${error}`);
605
- callback && callback(tmpFile);
606
- })
607
- .pipe(fs.createWriteStream(tmpFile))
608
- .on('close', () => {
609
- console.log('downloaded ' + tmpFile);
600
+ try {
601
+ // Add some information to user-agent, like chrome, IE and Firefox do
602
+ const res = await axios_1.default.get(urlOrPath, {
603
+ responseType: 'stream',
604
+ headers: {
605
+ 'User-Agent': `${exports.appName}, RND: ${randomID}, N: ${process.version}`,
606
+ 'Accept-Encoding': 'gzip'
607
+ }
608
+ });
609
+ res.data.pipe(fs_extra_1.default.createWriteStream(tmpFile)).on('close', () => {
610
+ console.log(`downloaded ${tmpFile}`);
610
611
  callback && callback(tmpFile);
611
612
  });
612
- } else {
613
+ }
614
+ catch (e) {
615
+ console.log(`Cannot download "${tmpFile}": ${e.message}`);
616
+ callback && callback(tmpFile);
617
+ }
618
+ }
619
+ else {
613
620
  try {
614
- if (fs.existsSync(urlOrPath)) {
621
+ if (fs_extra_1.default.existsSync(urlOrPath)) {
615
622
  callback && callback(urlOrPath);
616
- } else if (fs.existsSync(`${__dirname}/../${urlOrPath}`)) {
623
+ }
624
+ else if (fs_extra_1.default.existsSync(`${__dirname}/../${urlOrPath}`)) {
617
625
  callback && callback(`${__dirname}/../${urlOrPath}`);
618
- } else if (fs.existsSync(`${__dirname}/../tmp/${urlOrPath}`)) {
626
+ }
627
+ else if (fs_extra_1.default.existsSync(`${__dirname}/../tmp/${urlOrPath}`)) {
619
628
  callback && callback(`${__dirname}/../tmp/${urlOrPath}`);
620
- } else {
629
+ }
630
+ else {
621
631
  console.log('File not found: ' + urlOrPath);
622
- process.exit(EXIT_CODES.FILE_NOT_FOUND);
632
+ process.exit(exitCodes_1.EXIT_CODES.FILE_NOT_FOUND);
623
633
  }
624
- } catch (err) {
634
+ }
635
+ catch (err) {
625
636
  console.log(`File "${urlOrPath}" could no be read: ${err.message}`);
626
- process.exit(EXIT_CODES.FILE_NOT_FOUND);
637
+ process.exit(exitCodes_1.EXIT_CODES.FILE_NOT_FOUND);
627
638
  }
628
639
  }
629
640
  }
630
-
641
+ exports.getFile = getFile;
631
642
  // Return content of the json file. Download it or read directly
632
- function getJson(urlOrPath, agent, callback) {
643
+ async function getJson(urlOrPath, agent, callback) {
633
644
  if (typeof agent === 'function') {
634
645
  callback = agent;
635
646
  agent = '';
636
647
  }
637
648
  agent = agent || '';
638
-
639
- request = request || require('request');
640
649
  let sources = {};
641
650
  // If object was read
642
651
  if (urlOrPath && typeof urlOrPath === 'object') {
643
652
  if (callback) {
644
653
  callback(urlOrPath);
645
654
  }
646
- } else if (!urlOrPath) {
655
+ }
656
+ else if (!urlOrPath) {
647
657
  console.log('Empty url!');
648
658
  if (callback) {
649
659
  callback(null);
650
660
  }
651
- } else {
652
- if (
653
- urlOrPath.substring(0, 'http://'.length) === 'http://' ||
654
- urlOrPath.substring(0, 'https://'.length) === 'https://'
655
- ) {
656
- request(
657
- {
658
- url: urlOrPath,
659
- timeout: 10000,
660
- gzip: true,
661
- headers: { 'User-Agent': agent }
662
- },
663
- (error, response, body) => {
664
- if (error || !body || response.statusCode !== 200) {
665
- console.warn(`Cannot download json from ${urlOrPath}. Error: ${error || body}`);
666
- if (callback) {
667
- callback(null, urlOrPath);
668
- }
669
- return;
670
- }
671
- try {
672
- sources = JSON.parse(body);
673
- } catch {
674
- console.error('Json file is invalid on ' + urlOrPath);
675
- if (callback) {
676
- callback(null, urlOrPath);
677
- }
678
- return;
679
- }
680
-
681
- if (callback) {
682
- callback(sources, urlOrPath);
683
- }
661
+ }
662
+ else {
663
+ if (urlOrPath.substring(0, 'http://'.length) === 'http://' ||
664
+ urlOrPath.substring(0, 'https://'.length) === 'https://') {
665
+ try {
666
+ const res = await axios_1.default.get(urlOrPath, {
667
+ headers: { 'Accept-Encoding': 'gzip', timeout: 10000, 'User-Agent': agent }
668
+ });
669
+ if (res.status !== 200 || !res.data) {
670
+ throw new Error(`Invalid response, body: ${res.data}, status code: ${res.status}`);
684
671
  }
685
- ).on('error', _error => {
686
- //console.log('Cannot download json from ' + urlOrPath + '. Error: ' + error);
687
- //if (callback) callback(null, urlOrPath);
688
- });
689
- } else {
690
- if (fs.existsSync(urlOrPath)) {
672
+ sources = res.data;
673
+ if (callback) {
674
+ callback(sources, urlOrPath);
675
+ }
676
+ }
677
+ catch (e) {
678
+ console.warn(`Cannot download json from ${urlOrPath}. Error: ${e.message}`);
679
+ if (callback) {
680
+ callback(null, urlOrPath);
681
+ }
682
+ return;
683
+ }
684
+ }
685
+ else {
686
+ if (fs_extra_1.default.existsSync(urlOrPath)) {
691
687
  try {
692
- sources = fs.readJSONSync(urlOrPath);
693
- } catch (e) {
694
- console.log('Cannot parse json file from ' + urlOrPath + '. Error: ' + e.message);
688
+ sources = fs_extra_1.default.readJSONSync(urlOrPath);
689
+ }
690
+ catch (e) {
691
+ console.log(`Cannot parse json file from ${urlOrPath}. Error: ${e.message}`);
695
692
  if (callback) {
696
693
  callback(null, urlOrPath);
697
694
  }
@@ -700,13 +697,13 @@ function getJson(urlOrPath, agent, callback) {
700
697
  if (callback) {
701
698
  callback(sources, urlOrPath);
702
699
  }
703
- } else if (fs.existsSync(__dirname + '/../' + urlOrPath)) {
700
+ }
701
+ else if (fs_extra_1.default.existsSync(`${__dirname}/../${urlOrPath}`)) {
704
702
  try {
705
- sources = fs.readJSONSync(__dirname + '/../' + urlOrPath);
706
- } catch (e) {
707
- console.log(
708
- 'Cannot parse json file from ' + __dirname + '/../' + urlOrPath + '. Error: ' + e.message
709
- );
703
+ sources = fs_extra_1.default.readJSONSync(`${__dirname}/../${urlOrPath}`);
704
+ }
705
+ catch (e) {
706
+ console.log(`Cannot parse json file from ${__dirname}/../${urlOrPath}. Error: ${e.message}`);
710
707
  if (callback) {
711
708
  callback(null, urlOrPath);
712
709
  }
@@ -715,13 +712,13 @@ function getJson(urlOrPath, agent, callback) {
715
712
  if (callback) {
716
713
  callback(sources, urlOrPath);
717
714
  }
718
- } else if (fs.existsSync(__dirname + '/../tmp/' + urlOrPath)) {
715
+ }
716
+ else if (fs_extra_1.default.existsSync(`${__dirname}/../tmp/${urlOrPath}`)) {
719
717
  try {
720
- sources = fs.readJSONSync(__dirname + '/../tmp/' + urlOrPath);
721
- } catch (e) {
722
- console.log(
723
- 'Cannot parse json file from ' + __dirname + '/../tmp/' + urlOrPath + '. Error: ' + e.message
724
- );
718
+ sources = fs_extra_1.default.readJSONSync(`${__dirname}/../tmp/${urlOrPath}`);
719
+ }
720
+ catch (e) {
721
+ console.log(`Cannot parse json file from ${__dirname}/../tmp/${urlOrPath}. Error: ${e.message}`);
725
722
  if (callback) {
726
723
  callback(null, urlOrPath);
727
724
  }
@@ -730,7 +727,8 @@ function getJson(urlOrPath, agent, callback) {
730
727
  if (callback) {
731
728
  callback(sources, urlOrPath);
732
729
  }
733
- } else {
730
+ }
731
+ else {
734
732
  //if (urlOrPath.indexOf('/example/') === -1) console.log('Json file not found: ' + urlOrPath);
735
733
  if (callback) {
736
734
  callback(null, urlOrPath);
@@ -739,97 +737,105 @@ function getJson(urlOrPath, agent, callback) {
739
737
  }
740
738
  }
741
739
  }
742
-
740
+ exports.getJson = getJson;
743
741
  /**
744
742
  * Return content of the json file. Download it or read directly
745
- * @param {string|object} urlOrPath URL where the json file could be found
746
- * @param {string} agent optional agent identifier like "Windows Chrome 12.56"
747
- * @returns {object} json object
743
+ * @param urlOrPath URL where the json file could be found
744
+ * @param agent optional agent identifier like "Windows Chrome 12.56"
745
+ * @returns json object
748
746
  */
749
747
  async function getJsonAsync(urlOrPath, agent) {
750
748
  agent = agent || '';
751
-
752
- axios = axios || require('axios');
753
749
  let sources = {};
754
750
  // If object was read
755
751
  if (urlOrPath && typeof urlOrPath === 'object') {
756
752
  return urlOrPath;
757
- } else if (!urlOrPath) {
753
+ }
754
+ else if (!urlOrPath) {
758
755
  console.log('Empty url!');
759
756
  return null;
760
- } else {
757
+ }
758
+ else {
761
759
  if (urlOrPath.startsWith('http://') || urlOrPath.startsWith('https://')) {
762
760
  try {
763
- const result = await axios(urlOrPath, {
761
+ const result = await (0, axios_1.default)(urlOrPath, {
764
762
  timeout: 10000,
765
763
  headers: { 'User-Agent': agent },
766
764
  validateStatus: status => status !== 200
767
765
  });
768
766
  return result.data;
769
- } catch (error) {
770
- console.warn(`Cannot download json from ${urlOrPath}. Error: ${error}`);
767
+ }
768
+ catch (e) {
769
+ console.warn(`Cannot download json from ${urlOrPath}. Error: ${e.message}`);
771
770
  return null;
772
771
  }
773
- } else {
774
- if (fs.existsSync(urlOrPath)) {
772
+ }
773
+ else {
774
+ if (fs_extra_1.default.existsSync(urlOrPath)) {
775
775
  try {
776
- sources = fs.readJSONSync(urlOrPath);
777
- } catch (e) {
776
+ sources = fs_extra_1.default.readJSONSync(urlOrPath);
777
+ }
778
+ catch (e) {
778
779
  console.warn(`Cannot parse json file from ${urlOrPath}. Error: ${e.message}`);
779
780
  return null;
780
781
  }
781
782
  return sources;
782
- } else if (fs.existsSync(__dirname + '/../' + urlOrPath)) {
783
+ }
784
+ else if (fs_extra_1.default.existsSync(__dirname + '/../' + urlOrPath)) {
783
785
  try {
784
- sources = fs.readJSONSync(`${__dirname}/../${urlOrPath}`);
785
- } catch (e) {
786
+ sources = fs_extra_1.default.readJSONSync(`${__dirname}/../${urlOrPath}`);
787
+ }
788
+ catch (e) {
786
789
  console.warn(`Cannot parse json file from ${__dirname}/../${urlOrPath}. Error: ${e.message}`);
787
790
  return null;
788
791
  }
789
792
  return sources;
790
- } else if (fs.existsSync(`${__dirname}/../tmp/${urlOrPath}`)) {
793
+ }
794
+ else if (fs_extra_1.default.existsSync(`${__dirname}/../tmp/${urlOrPath}`)) {
791
795
  try {
792
- sources = fs.readJSONSync(`${__dirname}/../tmp/${urlOrPath}`);
793
- } catch (e) {
796
+ sources = fs_extra_1.default.readJSONSync(`${__dirname}/../tmp/${urlOrPath}`);
797
+ }
798
+ catch (e) {
794
799
  console.log(`Cannot parse json file from ${__dirname}/../tmp/${urlOrPath}. Error: ${e.message}`);
795
800
  return null;
796
801
  }
797
802
  return sources;
798
- } else {
803
+ }
804
+ else {
799
805
  //if (urlOrPath.indexOf('/example/') === -1) console.log('Json file not found: ' + urlOrPath);
800
806
  return null;
801
807
  }
802
808
  }
803
809
  }
804
810
  }
805
-
811
+ exports.getJsonAsync = getJsonAsync;
806
812
  function scanDirectory(dirName, list, regExp) {
807
- if (fs.existsSync(dirName)) {
813
+ if (fs_extra_1.default.existsSync(dirName)) {
808
814
  let dirs;
809
815
  try {
810
- dirs = fs.readdirSync(dirName);
811
- } catch (e) {
816
+ dirs = fs_extra_1.default.readdirSync(dirName);
817
+ }
818
+ catch (e) {
812
819
  console.log(`Cannot read or parse ${dirName}: ${e.message}`);
813
820
  return;
814
821
  }
815
822
  for (let i = 0; i < dirs.length; i++) {
816
823
  try {
817
- const fullPath = path.join(dirName, dirs[i]);
818
- const fileIoName = path.join(fullPath, 'io-package.json');
819
- const fileName = path.join(fullPath, 'package.json');
820
- if (regExp.test(dirs[i]) && fs.existsSync(fileIoName)) {
821
- const ioPackage = fs.readJSONSync(fileIoName);
822
- const package_ = fs.existsSync(fileName) ? fs.readJSONSync(fileName) : {};
824
+ const fullPath = path_1.default.join(dirName, dirs[i]);
825
+ const fileIoName = path_1.default.join(fullPath, 'io-package.json');
826
+ const fileName = path_1.default.join(fullPath, 'package.json');
827
+ if (regExp.test(dirs[i]) && fs_extra_1.default.existsSync(fileIoName)) {
828
+ const ioPackage = fs_extra_1.default.readJSONSync(fileIoName);
829
+ const package_ = fs_extra_1.default.existsSync(fileName) ? fs_extra_1.default.readJSONSync(fileName) : {};
823
830
  const localIcon = ioPackage.common.icon
824
- ? `/adapter/${dirs[i].substring(module.exports.appName.length + 1)}/${ioPackage.common.icon}`
831
+ ? `/adapter/${dirs[i].substring(exports.appName.length + 1)}/${ioPackage.common.icon}`
825
832
  : '';
826
- //noinspection JSUnresolvedVariable
827
833
  list[ioPackage.common.name] = {
828
834
  controller: ioPackage.common.controller || false,
829
835
  version: ioPackage.common.version,
830
836
  icon: ioPackage.common.extIcon || localIcon,
831
837
  localIcon,
832
- title: ioPackage.common.title, // deprecated 2021.04.18 BF
838
+ title: ioPackage.common.title,
833
839
  titleLang: ioPackage.common.titleLang,
834
840
  desc: ioPackage.common.desc,
835
841
  platform: ioPackage.common.platform,
@@ -839,47 +845,48 @@ function scanDirectory(dirName, list, regExp) {
839
845
  license: ioPackage.common.license
840
846
  ? ioPackage.common.license
841
847
  : package_.licenses && package_.licenses.length
842
- ? package_.licenses[0].type
843
- : '',
848
+ ? package_.licenses[0].type
849
+ : '',
844
850
  licenseUrl: package_.licenses && package_.licenses.length ? package_.licenses[0].url : ''
845
851
  };
846
852
  }
847
- } catch (e) {
848
- console.log(
849
- `Cannot read or parse ${__dirname}/../node_modules/${dirs[i]}/io-package.json: ${e.message}`
850
- );
853
+ }
854
+ catch (e) {
855
+ console.log(`Cannot read or parse ${__dirname}/../node_modules/${dirs[i]}/io-package.json: ${e.message}`);
851
856
  }
852
857
  }
853
858
  }
854
859
  }
855
-
856
860
  /**
857
861
  * Get list of all installed adapters and controller version on this host
858
- * @param {string} [hostRunningVersion] Version of the running js-controller, will be included in the returned information if provided
859
- * @returns {object} object containing information about installed host
862
+ * @param hostRunningVersion Version of the running js-controller, will be included in the returned information if provided
863
+ * @returns object containing information about installed host
860
864
  */
861
865
  function getInstalledInfo(hostRunningVersion) {
862
866
  const result = {};
863
867
  const fullPath = getControllerDir();
864
-
868
+ if (!fullPath) {
869
+ console.error('Could not determine controller directory on getInstalledInfo.');
870
+ return result;
871
+ }
865
872
  // Get info about host
866
873
  let ioPackage;
867
874
  try {
868
- ioPackage = fs.readJSONSync(path.join(fullPath, 'io-package.json'));
869
- } catch (e) {
875
+ ioPackage = fs_extra_1.default.readJSONSync(path_1.default.join(fullPath, 'io-package.json'));
876
+ }
877
+ catch (e) {
870
878
  console.error(`Cannot get installed host information: ${e.message}`);
871
879
  }
872
- const package_ = fs.existsSync(path.join(fullPath, 'package.json'))
873
- ? fs.readJSONSync(path.join(fullPath, 'package.json'))
880
+ const package_ = fs_extra_1.default.existsSync(path_1.default.join(fullPath, 'package.json'))
881
+ ? fs_extra_1.default.readJSONSync(path_1.default.join(fullPath, 'package.json'))
874
882
  : {};
875
- const regExp = new RegExp(`^${module.exports.appName}\\.`, 'i');
876
-
883
+ const regExp = new RegExp(`^${exports.appName}\\.`, 'i');
877
884
  if (ioPackage) {
878
885
  result[ioPackage.common.name] = {
879
886
  controller: true,
880
887
  version: ioPackage.common.version,
881
888
  icon: ioPackage.common.extIcon || ioPackage.common.icon,
882
- title: ioPackage.common.title, // deprecated 2021.04.18 BF
889
+ title: ioPackage.common.title,
883
890
  titleLang: ioPackage.common.titleLang,
884
891
  desc: ioPackage.common.desc,
885
892
  platform: ioPackage.common.platform,
@@ -889,32 +896,27 @@ function getInstalledInfo(hostRunningVersion) {
889
896
  license: ioPackage.common.license
890
897
  ? ioPackage.common.license
891
898
  : package_.licenses && package_.licenses.length
892
- ? package_.licenses[0].type
893
- : '',
899
+ ? package_.licenses[0].type
900
+ : '',
894
901
  licenseUrl: package_.licenses && package_.licenses.length ? package_.licenses[0].url : ''
895
902
  };
896
903
  }
897
-
898
904
  // we scan the sub node modules of controller and same hierarchy as controller
899
- scanDirectory(path.join(fullPath, 'node_modules'), result, regExp);
900
- scanDirectory(path.join(fullPath, '..'), result, regExp);
901
-
905
+ scanDirectory(path_1.default.join(fullPath, 'node_modules'), result, regExp);
906
+ scanDirectory(path_1.default.join(fullPath, '..'), result, regExp);
902
907
  return result;
903
908
  }
904
-
909
+ exports.getInstalledInfo = getInstalledInfo;
905
910
  /**
906
911
  * Reads an adapter's npm version
907
- * @param {string | null} adapter The adapter to read the npm version from. Null for the root ioBroker packet
908
- * @param {(err: Error | null, version?: string) => void} [callback]
912
+ * @param adapter The adapter to read the npm version from. Null for the root ioBroker packet
913
+ * @param callback
909
914
  */
910
915
  function getNpmVersion(adapter, callback) {
911
- adapter = adapter ? module.exports.appName + '.' + adapter : module.exports.appName;
916
+ adapter = adapter ? `${exports.appName}.${adapter}` : exports.appName;
912
917
  adapter = adapter.toLowerCase();
913
-
914
918
  const cliCommand = `npm view ${adapter}@latest version`;
915
-
916
- const exec = require('child_process').exec;
917
- exec(cliCommand, { timeout: 2000, windowsHide: true }, (error, stdout, _stderr) => {
919
+ (0, child_process_1.exec)(cliCommand, { timeout: 2000, windowsHide: true }, (error, stdout, _stderr) => {
918
920
  let version;
919
921
  if (error) {
920
922
  // command failed
@@ -922,17 +924,17 @@ function getNpmVersion(adapter, callback) {
922
924
  callback(error);
923
925
  return;
924
926
  }
925
- } else if (stdout) {
926
- version = semver.valid(stdout.trim());
927
+ }
928
+ else if (stdout) {
929
+ version = semver_1.default.valid(stdout.trim());
927
930
  }
928
931
  if (typeof callback === 'function') {
929
932
  callback(null, version);
930
933
  }
931
934
  });
932
935
  }
933
-
934
936
  function getIoPack(sources, name, callback) {
935
- getJson(sources[name].meta, ioPack => {
937
+ getJson(sources[name].meta, '', ioPack => {
936
938
  const packUrl = sources[name].meta.replace('io-package.json', 'package.json');
937
939
  if (!ioPack) {
938
940
  if (sources._helper) {
@@ -941,9 +943,10 @@ function getIoPack(sources, name, callback) {
941
943
  if (callback) {
942
944
  callback(sources, name);
943
945
  }
944
- } else {
946
+ }
947
+ else {
945
948
  setImmediate(() => {
946
- getJson(packUrl, pack => {
949
+ getJson(packUrl, '', pack => {
947
950
  const version = sources[name].version;
948
951
  const type = sources[name].type;
949
952
  // If installed from git or something else
@@ -951,7 +954,6 @@ function getIoPack(sources, name, callback) {
951
954
  if (sources[name].url && name !== 'js-controller') {
952
955
  if (ioPack && ioPack.common) {
953
956
  sources[name] = extend(true, sources[name], ioPack.common);
954
-
955
957
  // overwrite type of adapter from repository
956
958
  if (type) {
957
959
  sources[name].type = type;
@@ -965,11 +967,11 @@ function getIoPack(sources, name, callback) {
965
967
  }
966
968
  }
967
969
  }
968
-
969
970
  if (callback) {
970
971
  callback(sources, name);
971
972
  }
972
- } else {
973
+ }
974
+ else {
973
975
  if (ioPack && ioPack.common) {
974
976
  sources[name] = extend(true, sources[name], ioPack.common);
975
977
  if (pack && pack.licenses && pack.licenses.length) {
@@ -981,34 +983,33 @@ function getIoPack(sources, name, callback) {
981
983
  }
982
984
  }
983
985
  }
984
-
985
986
  // overwrite type of adapter from repository
986
987
  if (type) {
987
988
  sources[name].type = type;
988
989
  }
989
-
990
990
  if (version) {
991
991
  sources[name].version = version;
992
992
  if (callback) {
993
993
  callback(sources, name);
994
994
  }
995
- } else {
996
- if (
997
- sources[name].meta.substring(0, 'http://'.length) === 'http://' ||
998
- sources[name].meta.substring(0, 'https://'.length) === 'https://'
999
- ) {
995
+ }
996
+ else {
997
+ if (sources[name].meta.substring(0, 'http://'.length) === 'http://' ||
998
+ sources[name].meta.substring(0, 'https://'.length) === 'https://') {
1000
999
  //installed from npm
1001
1000
  getNpmVersion(name, (_err, version) => {
1002
1001
  if (version) {
1003
1002
  sources[name].version = version;
1004
- } else {
1003
+ }
1004
+ else {
1005
1005
  sources[name].version = 'npm error';
1006
1006
  }
1007
1007
  if (callback) {
1008
1008
  callback(sources, name);
1009
1009
  }
1010
1010
  });
1011
- } else {
1011
+ }
1012
+ else {
1012
1013
  if (callback) {
1013
1014
  callback(sources, name);
1014
1015
  }
@@ -1020,7 +1021,6 @@ function getIoPack(sources, name, callback) {
1020
1021
  }
1021
1022
  });
1022
1023
  }
1023
-
1024
1024
  function _getRepositoryFile(sources, path, callback) {
1025
1025
  if (!sources._helper) {
1026
1026
  let count = 0;
@@ -1031,7 +1031,6 @@ function _getRepositoryFile(sources, path, callback) {
1031
1031
  count++;
1032
1032
  }
1033
1033
  sources._helper = { failCounter: [] };
1034
-
1035
1034
  sources._helper.timeout = setTimeout(() => {
1036
1035
  if (sources._helper) {
1037
1036
  delete sources._helper;
@@ -1041,18 +1040,16 @@ function _getRepositoryFile(sources, path, callback) {
1041
1040
  }
1042
1041
  }
1043
1042
  if (callback) {
1044
- callback(`Timeout by read all package.json (${count}) seconds`, sources);
1043
+ callback(new Error(`Timeout by read all package.json (${count}) seconds`), sources);
1045
1044
  }
1046
- callback = null;
1045
+ callback = undefined;
1047
1046
  }
1048
1047
  }, count * 1000);
1049
1048
  }
1050
-
1051
1049
  for (const name of Object.keys(sources)) {
1052
1050
  if (sources[name].processed || name === '_helper') {
1053
1051
  continue;
1054
1052
  }
1055
-
1056
1053
  sources[name].processed = true;
1057
1054
  if (sources[name].url) {
1058
1055
  sources[name].url = findPath(path, sources[name].url);
@@ -1063,7 +1060,6 @@ function _getRepositoryFile(sources, path, callback) {
1063
1060
  if (sources[name].icon) {
1064
1061
  sources[name].icon = findPath(path, sources[name].icon);
1065
1062
  }
1066
-
1067
1063
  if (!sources[name].name && sources[name].meta) {
1068
1064
  getIoPack(sources, name, _ignore => {
1069
1065
  if (sources._helper) {
@@ -1076,10 +1072,11 @@ function _getRepositoryFile(sources, path, callback) {
1076
1072
  }
1077
1073
  }
1078
1074
  if (callback) {
1079
- callback('Looks like there is no internet.', sources);
1075
+ callback(new Error('Looks like there is no internet.'), sources);
1080
1076
  }
1081
- callback = null;
1082
- } else {
1077
+ callback = undefined;
1078
+ }
1079
+ else {
1083
1080
  // process next
1084
1081
  setImmediate(() => _getRepositoryFile(sources, path, callback));
1085
1082
  }
@@ -1088,12 +1085,11 @@ function _getRepositoryFile(sources, path, callback) {
1088
1085
  return;
1089
1086
  }
1090
1087
  }
1091
-
1092
1088
  // all packages are processed
1093
1089
  if (sources._helper) {
1094
1090
  let err;
1095
1091
  if (sources._helper.failCounter.length) {
1096
- err = 'Following packages cannot be read: ' + sources._helper.failCounter.join(', ');
1092
+ err = new Error(`Following packages cannot be read: ${sources._helper.failCounter.join(', ')}`);
1097
1093
  }
1098
1094
  clearTimeout(sources._helper.timeout);
1099
1095
  delete sources._helper;
@@ -1105,129 +1101,125 @@ function _getRepositoryFile(sources, path, callback) {
1105
1101
  if (callback) {
1106
1102
  callback(err, sources);
1107
1103
  }
1108
- callback = null;
1104
+ callback = undefined;
1109
1105
  }
1110
1106
  }
1111
-
1112
- function _checkRepositoryFileHash(urlOrPath, additionalInfo, callback) {
1113
- request = request || require('request');
1114
-
1107
+ async function _checkRepositoryFileHash(urlOrPath, additionalInfo, callback) {
1115
1108
  // read hash of file
1116
1109
  if (urlOrPath.startsWith('http://') || urlOrPath.startsWith('https://')) {
1117
1110
  urlOrPath = urlOrPath.replace(/\.json$/, '-hash.json');
1118
1111
  let json = null;
1119
- request({ url: urlOrPath, timeout: 10000, gzip: true }, (error, response, body) => {
1120
- if (error || !body || response.statusCode !== 200) {
1121
- console.warn(`Cannot download json from ${urlOrPath}. Error: ${error || body}`);
1122
- } else {
1123
- try {
1124
- json = JSON.parse(body);
1125
- } catch {
1126
- console.error('Json file is invalid on ' + urlOrPath);
1127
- }
1112
+ try {
1113
+ const res = await axios_1.default.get(urlOrPath, { headers: { 'Accept-Encoding': 'gzip', timeout: 10000 } });
1114
+ if (!res.data || res.status !== 200) {
1115
+ throw new Error(`Invalid response, body: ${res.data}, status code: ${res.status}`);
1128
1116
  }
1129
- if (json && json.hash) {
1130
- // The hash download was successful
1131
- if (additionalInfo && additionalInfo.sources && json.hash === additionalInfo.hash) {
1132
- // The hash is the same as for the cached sources
1133
- console.log('hash unchanged, use cached sources');
1134
- callback(null, additionalInfo.sources, json.hash);
1135
- } else {
1136
- // Either we have no sources cached or the hash changed
1137
- // => force download of new sources
1138
- console.log('hash changed or no sources cached => force download of new sources');
1139
- callback(null, null, json.hash);
1140
- }
1141
- } else {
1142
- // Could not download new sources, use the old ones
1143
- console.log('failed to download new sources, use cached sources');
1144
- callback(null, additionalInfo.sources, '');
1145
- }
1146
- }).on('error', _error => {
1147
- //console.log('Cannot download json from ' + urlOrPath + '. Error: ' + error);
1148
- //if (callback) callback(null, urlOrPath);
1149
- });
1150
- } else {
1117
+ json = res.data;
1118
+ }
1119
+ catch (e) {
1120
+ console.warn(`Cannot download json from ${urlOrPath}. Error: ${e.message}`);
1121
+ }
1122
+ if (json && json.hash) {
1123
+ // The hash download was successful
1124
+ if (additionalInfo && additionalInfo.sources && json.hash === additionalInfo.hash) {
1125
+ // The hash is the same as for the cached sources
1126
+ console.log('hash unchanged, use cached sources');
1127
+ callback(null, additionalInfo.sources, json.hash);
1128
+ }
1129
+ else {
1130
+ // Either we have no sources cached or the hash changed
1131
+ // => force download of new sources
1132
+ console.log('hash changed or no sources cached => force download of new sources');
1133
+ callback(null, null, json.hash);
1134
+ }
1135
+ }
1136
+ else {
1137
+ // Could not download new sources, use the old ones
1138
+ console.log('failed to download new sources, use cached sources');
1139
+ callback(null, additionalInfo.sources, '');
1140
+ }
1141
+ }
1142
+ else {
1151
1143
  // it is a file and file has not hash
1152
1144
  callback(null, null, 0);
1153
1145
  }
1154
1146
  }
1155
-
1156
1147
  /**
1157
1148
  * Get list of all adapters and controller in some repository file or in /conf/source-dist.json
1158
1149
  *
1159
1150
  * @alias getRepositoryFile
1160
1151
  * @memberof tools
1161
- * @param {string} urlOrPath URL starting with http:// or https:// or local file link
1162
- * @param {object} additionalInfo destination object
1163
- * @param {function} callback function (err, sources, actualHash) { }
1152
+ * @param urlOrPath URL starting with http:// or https:// or local file link
1153
+ * @param additionalInfo destination object
1154
+ * @param callback function (err, sources, actualHash) { }
1164
1155
  *
1165
1156
  */
1166
1157
  function getRepositoryFile(urlOrPath, additionalInfo, callback) {
1167
1158
  let sources = {};
1168
- let path = '';
1169
-
1159
+ let _path = '';
1170
1160
  if (typeof additionalInfo === 'function') {
1161
+ // @ts-expect-error: fix all fun calls then remove
1171
1162
  callback = additionalInfo;
1172
1163
  additionalInfo = {};
1173
1164
  }
1174
-
1175
1165
  additionalInfo = additionalInfo || {};
1176
-
1177
- extend = extend || require('node.extend');
1178
-
1179
1166
  if (urlOrPath) {
1180
1167
  const parts = urlOrPath.split('/');
1181
- path = parts.splice(0, parts.length - 1).join('/') + '/';
1168
+ _path = parts.splice(0, parts.length - 1).join('/') + '/';
1182
1169
  }
1183
-
1184
1170
  // If object was read
1185
1171
  if (urlOrPath && typeof urlOrPath === 'object') {
1186
1172
  if (typeof callback === 'function') {
1187
1173
  callback(null, urlOrPath);
1188
1174
  }
1189
- } else if (!urlOrPath) {
1175
+ }
1176
+ else if (!urlOrPath) {
1190
1177
  try {
1191
- sources = fs.readJSONSync(getDefaultDataDir() + 'sources.json');
1192
- } catch {
1178
+ const controllerDir = getControllerDir();
1179
+ if (controllerDir) {
1180
+ sources = fs_extra_1.default.readJSONSync(path_1.default.join(controllerDir, getDefaultDataDir(), 'sources.json'));
1181
+ }
1182
+ }
1183
+ catch {
1193
1184
  sources = {};
1194
1185
  }
1195
1186
  try {
1196
- const sourcesDist = fs.readJSONSync(__dirname + '/../conf/sources-dist.json');
1197
- sources = extend(true, sourcesDist, sources);
1198
- } catch {
1187
+ const controllerDir = getControllerDir();
1188
+ if (controllerDir) {
1189
+ const sourcesDist = fs_extra_1.default.readJSONSync(path_1.default.join(controllerDir, 'conf', 'sources-dist.json'));
1190
+ sources = extend(true, sourcesDist, sources);
1191
+ }
1192
+ }
1193
+ catch {
1199
1194
  // continue regardless of error
1200
1195
  }
1201
-
1202
1196
  for (const s of Object.keys(sources)) {
1203
1197
  if (additionalInfo[s] && additionalInfo[s].published) {
1204
1198
  sources[s].published = additionalInfo[s].published;
1205
1199
  }
1206
1200
  }
1207
-
1208
- _getRepositoryFile(sources, path, err => {
1201
+ _getRepositoryFile(sources, _path, err => {
1209
1202
  if (err) {
1210
- console.error(`[${new Date()}] ${err}`);
1203
+ console.error(`[${new Date().toString()}] ${err.message}`);
1211
1204
  }
1212
1205
  if (typeof callback === 'function') {
1213
1206
  callback(err, sources);
1214
1207
  }
1215
1208
  });
1216
- } else {
1209
+ }
1210
+ else {
1217
1211
  let agent = '';
1218
1212
  if (additionalInfo) {
1219
1213
  // Add some information to user-agent, like chrome, IE and Firefox do
1220
- agent = `${additionalInfo.name}, RND: ${additionalInfo.randomID || randomID}, Node:${
1221
- additionalInfo.node
1222
- }, V:${additionalInfo.controller}`;
1214
+ agent = `${additionalInfo.name}, RND: ${additionalInfo.randomID || randomID}, Node:${additionalInfo.node}, V:${additionalInfo.controller}`;
1223
1215
  }
1224
-
1225
1216
  // load hash of file first to not load the whole 1MB of sources
1226
1217
  _checkRepositoryFileHash(urlOrPath, additionalInfo, (err, sources, actualSourcesHash) => {
1227
1218
  if (!err && sources) {
1228
1219
  // Source file was not changed
1229
1220
  typeof callback === 'function' && callback(err, sources, actualSourcesHash);
1230
- } else {
1221
+ }
1222
+ else {
1231
1223
  getJson(urlOrPath, agent, sources => {
1232
1224
  if (sources) {
1233
1225
  for (const s of Object.keys(sources)) {
@@ -1235,147 +1227,135 @@ function getRepositoryFile(urlOrPath, additionalInfo, callback) {
1235
1227
  sources[s].published = additionalInfo[s].published;
1236
1228
  }
1237
1229
  }
1238
- setImmediate(() =>
1239
- _getRepositoryFile(sources, path, err => {
1240
- err && console.error(`[${new Date()}] ${err}`);
1241
- typeof callback === 'function' && callback(err, sources, actualSourcesHash);
1242
- })
1243
- );
1244
- } else {
1230
+ setImmediate(() => _getRepositoryFile(sources, _path, err => {
1231
+ err && console.error(`[${new Date().toString()}] ${err.message}`);
1232
+ typeof callback === 'function' && callback(err, sources, actualSourcesHash);
1233
+ }));
1234
+ }
1235
+ else {
1245
1236
  // return cached sources, because no sources found
1246
- console.log(
1247
- `failed to download new sources, ${
1248
- additionalInfo.sources ? 'use cached sources' : 'no cached sources available'
1249
- }`
1250
- );
1251
- return maybeCallbackWithError(
1252
- callback,
1253
- `Cannot read "${urlOrPath}"`,
1254
- additionalInfo.sources,
1255
- ''
1256
- );
1237
+ console.log(`failed to download new sources, ${additionalInfo.sources ? 'use cached sources' : 'no cached sources available'}`);
1238
+ return (0, maybeCallback_1.maybeCallbackWithError)(callback, `Cannot read "${urlOrPath}"`, additionalInfo.sources, '');
1257
1239
  }
1258
1240
  });
1259
1241
  }
1260
1242
  });
1261
1243
  }
1262
1244
  }
1263
-
1245
+ exports.getRepositoryFile = getRepositoryFile;
1264
1246
  /**
1265
1247
  * Read on repository
1266
1248
  *
1267
1249
  * @alias getRepositoryFileAsync
1268
1250
  * @memberof tools
1269
- * @param {string} url URL starting with http:// or https:// or local file link
1270
- * @param {string} hash actual hash
1271
- * @param {boolean} force Force repository update despite on hash
1272
- * @param {object} _actualRepo Actual repository
1251
+ * @param url URL starting with http:// or https:// or local file link
1252
+ * @param hash actual hash
1253
+ * @param force Force repository update despite on hash
1254
+ * @param _actualRepo Actual repository
1273
1255
  *
1274
1256
  */
1275
1257
  async function getRepositoryFileAsync(url, hash, force, _actualRepo) {
1276
1258
  let _hash;
1277
1259
  let data;
1278
-
1279
1260
  if (url.startsWith('http://') || url.startsWith('https://')) {
1280
- axios = axios || require('axios');
1281
1261
  try {
1282
- _hash = await axios({ url: url.replace(/\.json$/, '-hash.json'), timeout: 10000 });
1283
- } catch {
1262
+ _hash = await (0, axios_1.default)({ url: url.replace(/\.json$/, '-hash.json'), timeout: 10000 });
1263
+ }
1264
+ catch {
1284
1265
  // ignore missing hash file
1285
1266
  }
1286
-
1287
1267
  if (_actualRepo && !force && hash && _hash && _hash.data && _hash.data.hash === hash) {
1288
1268
  data = _actualRepo;
1289
- } else {
1290
- const agent = `${module.exports.appName}, RND: ${randomID}, Node:${process.version}, V:${
1291
- require('../../package.json').version
1292
- }`;
1269
+ }
1270
+ else {
1271
+ const agent = `${exports.appName}, RND: ${randomID}, Node:${process.version}, V:${
1272
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
1273
+ require('@iobroker/js-controller-common/package.json').version}`;
1293
1274
  try {
1294
- data = await axios({
1275
+ data = await (0, axios_1.default)({
1295
1276
  url,
1296
1277
  timeout: 10000,
1297
1278
  headers: { 'User-Agent': agent }
1298
1279
  });
1299
1280
  data = data.data;
1300
- } catch (e) {
1281
+ }
1282
+ catch (e) {
1301
1283
  throw new Error(`Cannot download repository file from "${url}": ${e.message}`);
1302
1284
  }
1303
1285
  }
1304
- } else {
1305
- if (fs.existsSync(url)) {
1286
+ }
1287
+ else {
1288
+ if (fs_extra_1.default.existsSync(url)) {
1306
1289
  try {
1307
- data = JSON.parse(fs.readFileSync(url).toString('utf8'));
1308
- } catch (e) {
1290
+ data = JSON.parse(fs_extra_1.default.readFileSync(url).toString('utf8'));
1291
+ }
1292
+ catch (e) {
1309
1293
  throw new Error(`Error: Cannot read or parse file "${url}": ${e}`);
1310
1294
  }
1311
- } else {
1295
+ }
1296
+ else {
1312
1297
  throw new Error(`Error: Cannot find file "${url}"`);
1313
1298
  }
1314
1299
  }
1315
-
1316
1300
  return {
1317
1301
  json: data,
1318
1302
  changed: _hash && _hash.data ? hash !== _hash.data.hash : true,
1319
1303
  hash: _hash && _hash.data ? _hash.data.hash : ''
1320
1304
  };
1321
1305
  }
1322
-
1306
+ exports.getRepositoryFileAsync = getRepositoryFileAsync;
1323
1307
  /**
1324
1308
  * Sends the given object to the diagnosis server
1325
1309
  *
1326
- * @param {object} obj - diagnosis object
1327
- * @return {Promise<void>}
1310
+ * @param obj - diagnosis object
1328
1311
  */
1329
1312
  async function sendDiagInfo(obj) {
1330
1313
  const objStr = JSON.stringify(obj);
1331
1314
  console.log(`Send diag info: ${objStr}`);
1332
- axios = axios || require('axios');
1333
- const params = new URLSearchParams();
1315
+ const params = new url_1.URLSearchParams();
1334
1316
  params.append('data', objStr);
1335
1317
  const config = {
1336
1318
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
1337
1319
  timeout: 4000
1338
1320
  };
1339
-
1340
1321
  try {
1341
- await axios.post(`http://download.${module.exports.appName}.net/diag.php`, params, config);
1342
- } catch (e) {
1322
+ await axios_1.default.post(`http://download.${exports.appName}.net/diag.php`, params, config);
1323
+ }
1324
+ catch (e) {
1343
1325
  console.log(`Cannot send diag info: ${e.message}`);
1344
1326
  }
1345
1327
  }
1346
-
1328
+ exports.sendDiagInfo = sendDiagInfo;
1347
1329
  /**
1348
1330
  * Finds the adapter directory of a given adapter
1349
1331
  *
1350
1332
  * @alias getAdapterDir
1351
1333
  * @memberof tools
1352
- * @param {string} adapter name of the adapter, e.g. hm-rpc
1353
- * @returns {string|null} path to adapter directory or null if no directory found
1334
+ * @param adapter name of the adapter, e.g. hm-rpc
1335
+ * @returns path to adapter directory or null if no directory found
1354
1336
  */
1355
1337
  function getAdapterDir(adapter) {
1356
- const appName = module.exports.appName;
1357
-
1358
1338
  // snip off 'iobroker.'
1359
- if (adapter.startsWith(appName + '.')) {
1360
- adapter = adapter.substring(appName.length + 1);
1339
+ if (adapter.startsWith(exports.appName + '.')) {
1340
+ adapter = adapter.substring(exports.appName.length + 1);
1361
1341
  }
1362
1342
  // snip off instance id
1363
1343
  if (/\.\d+$/.test(adapter)) {
1364
1344
  adapter = adapter.substr(0, adapter.lastIndexOf('.'));
1365
1345
  }
1366
-
1367
- const possibilities = [`${appName.toLowerCase()}.${adapter}/package.json`, `${appName}.${adapter}/package.json`];
1368
-
1346
+ const possibilities = [`${exports.appName.toLowerCase()}.${adapter}/package.json`, `${exports.appName}.${adapter}/package.json`];
1369
1347
  /** @type {string} */
1370
1348
  let adapterPath;
1371
1349
  for (const possibility of possibilities) {
1372
1350
  // special case to not read adapters from js-controller/node_module/adapter and check first in parent directory
1373
- if (fs.existsSync(`${__dirname}/../../${possibility}`)) {
1351
+ if (fs_extra_1.default.existsSync(`${__dirname}/../../${possibility}`)) {
1374
1352
  adapterPath = `${__dirname}/../../${possibility}`;
1375
- } else {
1353
+ }
1354
+ else {
1376
1355
  try {
1377
1356
  adapterPath = require.resolve(possibility);
1378
- } catch {
1357
+ }
1358
+ catch {
1379
1359
  // not found
1380
1360
  }
1381
1361
  }
@@ -1383,41 +1363,42 @@ function getAdapterDir(adapter) {
1383
1363
  break;
1384
1364
  }
1385
1365
  }
1386
-
1387
1366
  if (!adapterPath) {
1388
1367
  return null; // inactive
1389
- } else {
1390
- const parts = path.normalize(adapterPath).split(/[\\/]/g);
1368
+ }
1369
+ else {
1370
+ const parts = path_1.default.normalize(adapterPath).split(/[\\/]/g);
1391
1371
  parts.pop();
1392
1372
  return parts.join('/');
1393
1373
  }
1394
1374
  }
1395
-
1375
+ exports.getAdapterDir = getAdapterDir;
1396
1376
  /**
1397
1377
  * Returns the hostname of this host
1398
1378
  * @alias getHostName
1399
- * @returns {string}
1400
1379
  */
1401
1380
  function getHostName() {
1381
+ var _a;
1402
1382
  // for tests purposes
1403
1383
  if (process.env.IOB_HOSTNAME) {
1404
1384
  return process.env.IOB_HOSTNAME;
1405
1385
  }
1406
1386
  try {
1407
1387
  const configName = getConfigFileName();
1408
- const config = fs.readJSONSync(configName);
1409
- return config.system ? config.system.hostname || require('os').hostname() : require('os').hostname();
1410
- } catch {
1411
- return require('os').hostname();
1388
+ const config = fs_extra_1.default.readJSONSync(configName);
1389
+ return ((_a = config.system) === null || _a === void 0 ? void 0 : _a.hostname) || os_1.default.hostname();
1390
+ }
1391
+ catch {
1392
+ return os_1.default.hostname();
1412
1393
  }
1413
1394
  }
1414
-
1395
+ exports.getHostName = getHostName;
1415
1396
  /**
1416
1397
  * Read version of system npm
1417
1398
  *
1418
1399
  * @alias getSystemNpmVersion
1419
1400
  * @memberof Tools
1420
- * @param {function} callback return result
1401
+ * @param callback return result
1421
1402
  * <pre><code>
1422
1403
  * function (err, version) {
1423
1404
  * adapter.log.debug('NPM version is: ' + version);
@@ -1425,27 +1406,27 @@ function getHostName() {
1425
1406
  * </code></pre>
1426
1407
  */
1427
1408
  function getSystemNpmVersion(callback) {
1428
- const exec = require('child_process').exec;
1429
-
1409
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
1410
+ const { exec } = require('child_process');
1430
1411
  // remove local node_modules\.bin dir from path
1431
1412
  // or we potentially get a wrong npm version
1432
1413
  const newEnv = Object.assign({}, process.env);
1414
+ // @ts-expect-error TODO
1433
1415
  newEnv.PATH = (newEnv.PATH || newEnv.Path || newEnv.path)
1434
- .split(path.delimiter)
1416
+ .split(path_1.default.delimiter)
1435
1417
  .filter(dir => {
1436
- dir = dir.toLowerCase();
1437
- return !dir.includes('iobroker') || !dir.includes(path.join('node_modules', '.bin'));
1438
- })
1439
- .join(path.delimiter);
1418
+ dir = dir.toLowerCase();
1419
+ return !dir.includes('iobroker') || !dir.includes(path_1.default.join('node_modules', '.bin'));
1420
+ })
1421
+ .join(path_1.default.delimiter);
1440
1422
  try {
1441
1423
  let timeout = setTimeout(() => {
1442
1424
  timeout = null;
1443
1425
  if (callback) {
1444
- callback('timeout');
1445
- callback = null;
1426
+ callback(new Error('timeout'));
1427
+ callback = undefined;
1446
1428
  }
1447
1429
  }, 10000);
1448
-
1449
1430
  exec('npm -v', { encoding: 'utf8', env: newEnv, windowsHide: true }, (error, stdout) => {
1450
1431
  //, stderr) {
1451
1432
  if (timeout) {
@@ -1453,67 +1434,54 @@ function getSystemNpmVersion(callback) {
1453
1434
  timeout = null;
1454
1435
  }
1455
1436
  if (stdout) {
1456
- stdout = semver.valid(stdout.trim());
1437
+ stdout = semver_1.default.valid(stdout.trim());
1457
1438
  }
1458
1439
  if (callback) {
1459
1440
  callback(error, stdout);
1460
- callback = null;
1441
+ callback = undefined;
1461
1442
  }
1462
1443
  });
1463
- } catch (e) {
1444
+ }
1445
+ catch (e) {
1464
1446
  if (callback) {
1465
1447
  callback(e);
1466
- callback = null;
1448
+ callback = undefined;
1467
1449
  }
1468
1450
  }
1469
1451
  }
1470
-
1471
1452
  const getSystemNpmVersionAsync = promisify(getSystemNpmVersion);
1472
-
1473
1453
  /**
1474
1454
  * @private
1475
1455
  * Figure out which package manager is in charge, but with a fallback to npm.
1476
- * @param {string} [cwd] Which directory to work in. If none is given, this defaults to ioBroker's root directory.
1477
- * @returns {Promise<PackageManager>}
1456
+ * @param cwd Which directory to work in. If none is given, this defaults to ioBroker's root directory.
1478
1457
  */
1479
1458
  async function detectPackageManagerWithFallback(cwd) {
1480
1459
  try {
1481
1460
  // For the first attempt, use pak's default of requiring a lockfile. This makes sure we find ioBroker's root dir
1482
- return await detectPackageManager(
1483
- typeof cwd === 'string'
1484
- ? // If a cwd was provided, use it
1485
- { cwd }
1486
- : // Otherwise try to find the ioBroker root dir
1487
- {
1488
- cwd: __dirname,
1489
- setCwdToPackageRoot: true
1490
- }
1491
- );
1492
- } catch {
1461
+ return await (0, pak_1.detectPackageManager)(typeof cwd === 'string'
1462
+ ? // If a cwd was provided, use it
1463
+ { cwd }
1464
+ : // Otherwise try to find the ioBroker root dir
1465
+ {
1466
+ cwd: __dirname,
1467
+ setCwdToPackageRoot: true
1468
+ });
1469
+ }
1470
+ catch {
1493
1471
  // Lockfile not found, use default to avoid picking up a wrong package manager
1494
1472
  // like a globally installed yarn
1495
1473
  }
1496
-
1497
1474
  // Since we have no lockfile to rely on, assume the root dir is 2 levels above js-controller
1498
- const ioBrokerRootDir = path.join(getControllerDir(), '../..');
1475
+ const ioBrokerRootDir = path_1.default.join(getControllerDir(), '..', '..');
1499
1476
  // And fallback to npm
1500
- const pak = new packageManagers.npm();
1477
+ const pak = new pak_1.packageManagers.npm();
1501
1478
  pak.cwd = cwd || ioBrokerRootDir;
1502
1479
  return pak;
1503
1480
  }
1504
-
1505
- /**
1506
- * @typedef {object} InstallNodeModuleOptions
1507
- * @property {boolean} [unsafePerm] Whether the `--unsafe-perm` flag should be used
1508
- * @property {boolean} [debug] Whether to include `stderr` in the output and increase the loglevel to include more than errors
1509
- * @property {string} [cwd] Which directory to work in. If none is given, this defaults to ioBroker's root directory.
1510
- */
1511
-
1512
1481
  /**
1513
1482
  * Installs a node module using npm or a similar package manager
1514
- * @param {string} npmUrl Which node module to install
1515
- * @param {InstallNodeModuleOptions} options Options for the installation
1516
- * @returns {Promise<import('@alcalzone/pak').CommandResult>}
1483
+ * @param npmUrl Which node module to install
1484
+ * @param options Options for the installation
1517
1485
  */
1518
1486
  async function installNodeModule(npmUrl, options = {}) {
1519
1487
  // Figure out which package manager is in charge (probably npm at this point)
@@ -1522,38 +1490,29 @@ async function installNodeModule(npmUrl, options = {}) {
1522
1490
  if (!options.debug) {
1523
1491
  pak.loglevel = 'error';
1524
1492
  }
1525
-
1526
1493
  // Set up streams to pass the command output through
1527
1494
  if (options.debug) {
1528
- const stdall = new PassThrough();
1495
+ const stdall = new stream_1.PassThrough();
1529
1496
  pak.stdall = stdall;
1530
1497
  pipeLinewise(stdall, process.stdout);
1531
- } else {
1532
- const stdout = new PassThrough();
1498
+ }
1499
+ else {
1500
+ const stdout = new stream_1.PassThrough();
1533
1501
  pak.stdout = stdout;
1534
1502
  pipeLinewise(stdout, process.stdout);
1535
1503
  }
1536
-
1537
1504
  // And install the module
1538
- /** @type {import('@alcalzone/pak').InstallOptions} */
1539
1505
  const installOpts = {};
1540
1506
  if (options.unsafePerm) {
1541
1507
  installOpts.additionalArgs = ['--unsafe-perm'];
1542
1508
  }
1543
1509
  return pak.install([npmUrl], installOpts);
1544
1510
  }
1545
-
1546
- /**
1547
- * @typedef {object} UninstallNodeModuleOptions
1548
- * @property {boolean} [debug] Whether to include `stderr` in the output and increase the loglevel to include more than errors
1549
- * @property {string} [cwd] Which directory to work in. If none is given, this defaults to ioBroker's root directory.
1550
- */
1551
-
1511
+ exports.installNodeModule = installNodeModule;
1552
1512
  /**
1553
1513
  * Uninstalls a node module using npm or a similar package manager
1554
- * @param {string} packageName Which node module to uninstall
1555
- * @param {UninstallNodeModuleOptions} options Options for the installation
1556
- * @returns {Promise<import('@alcalzone/pak').CommandResult>}
1514
+ * @param packageName Which node module to uninstall
1515
+ * @param options Options for the installation
1557
1516
  */
1558
1517
  async function uninstallNodeModule(packageName, options = {}) {
1559
1518
  // Figure out which package manager is in charge (probably npm at this point)
@@ -1562,33 +1521,24 @@ async function uninstallNodeModule(packageName, options = {}) {
1562
1521
  if (!options.debug) {
1563
1522
  pak.loglevel = 'error';
1564
1523
  }
1565
-
1566
1524
  // Set up streams to pass the command output through
1567
1525
  if (options.debug) {
1568
- const stdall = new PassThrough();
1526
+ const stdall = new stream_1.PassThrough();
1569
1527
  pak.stdall = stdall;
1570
1528
  pipeLinewise(stdall, process.stdout);
1571
- } else {
1572
- const stdout = new PassThrough();
1529
+ }
1530
+ else {
1531
+ const stdout = new stream_1.PassThrough();
1573
1532
  pak.stdout = stdout;
1574
1533
  pipeLinewise(stdout, process.stdout);
1575
1534
  }
1576
-
1577
1535
  return pak.uninstall([packageName]);
1578
1536
  }
1579
-
1580
- /**
1581
- * @typedef {object} RebuildNodeModulesOptions
1582
- * @property {boolean} [debug] Whether to include `stderr` in the output and increase the loglevel to include more than errors
1583
- * @property {string} [cwd] Which directory to work in. If none is given, this defaults to ioBroker's root directory.
1584
- * @property {string} [module] single module which needs rebuild, can contain version too like module@version
1585
- */
1586
-
1537
+ exports.uninstallNodeModule = uninstallNodeModule;
1587
1538
  /**
1588
1539
  * Rebuilds all native node_modules that are dependencies of the project in the current working directory / project root.
1589
1540
  * If `options.cwd` is given, the directory must contain a lockfile.
1590
- * @param {RebuildNodeModulesOptions} options Options for the rebuild
1591
- * @returns {Promise<import('@alcalzone/pak').CommandResult>}
1541
+ * @param options Options for the rebuild
1592
1542
  */
1593
1543
  async function rebuildNodeModules(options = {}) {
1594
1544
  // Figure out which package manager is in charge (probably npm at this point)
@@ -1597,28 +1547,27 @@ async function rebuildNodeModules(options = {}) {
1597
1547
  if (!options.debug) {
1598
1548
  pak.loglevel = 'error';
1599
1549
  }
1600
-
1601
1550
  // Set up streams to pass the command output through
1602
1551
  if (options.debug) {
1603
- const stdall = new PassThrough();
1552
+ const stdall = new stream_1.PassThrough();
1604
1553
  pak.stdall = stdall;
1605
1554
  pipeLinewise(stdall, process.stdout);
1606
- } else {
1607
- const stdout = new PassThrough();
1555
+ }
1556
+ else {
1557
+ const stdout = new stream_1.PassThrough();
1608
1558
  pak.stdout = stdout;
1609
1559
  pipeLinewise(stdout, process.stdout);
1610
1560
  }
1611
-
1612
1561
  return pak.rebuild(options.module ? [options.module] : undefined);
1613
1562
  }
1614
-
1563
+ exports.rebuildNodeModules = rebuildNodeModules;
1615
1564
  /**
1616
1565
  * Read disk free space
1617
1566
  *
1618
1567
  * @alias getDiskInfo
1619
1568
  * @memberof Tools
1620
- * @param {string} platform result of os.platform() (win32 => Windows, darwin => OSX)
1621
- * @param {function} callback return result
1569
+ * @param platform result of os.platform() (win32 => Windows, darwin => OSX)
1570
+ * @param callback return result
1622
1571
  * <pre><code>
1623
1572
  * function (err, infos) {
1624
1573
  * adapter.log.debug('Disks sizes is: ' + info['Disk size'] + ' - ' + info['Disk free']);
@@ -1626,19 +1575,20 @@ async function rebuildNodeModules(options = {}) {
1626
1575
  * </code></pre>
1627
1576
  */
1628
1577
  function getDiskInfo(platform, callback) {
1629
- platform = platform || require('os').platform();
1578
+ platform = platform || os_1.default.platform();
1630
1579
  if (diskusage) {
1631
1580
  try {
1632
1581
  const path = platform === 'win32' ? __dirname.substring(0, 2) : '/';
1633
1582
  const info = diskusage.checkSync(path);
1634
1583
  return callback && callback(null, { 'Disk size': info.total, 'Disk free': info.free });
1635
- } catch (err) {
1584
+ }
1585
+ catch (err) {
1636
1586
  console.log(err);
1637
1587
  }
1638
- } else {
1639
- const exec = require('child_process').exec;
1588
+ }
1589
+ else {
1640
1590
  try {
1641
- if (platform === 'Windows' || platform === 'win32') {
1591
+ if (platform === 'win32') {
1642
1592
  // Caption FreeSpace Size
1643
1593
  // A:
1644
1594
  // C: 66993807360 214640357376
@@ -1646,65 +1596,58 @@ function getDiskInfo(platform, callback) {
1646
1596
  // Y: 116649795584 148368257024
1647
1597
  // Z: 116649795584 148368257024
1648
1598
  const disk = __dirname.substring(0, 2).toUpperCase();
1649
-
1650
- exec(
1651
- 'wmic logicaldisk get size,freespace,caption',
1652
- {
1653
- encoding: 'utf8',
1654
- windowsHide: true
1655
- },
1656
- (error, stdout) => {
1657
- //, stderr) {
1658
- if (stdout) {
1659
- const lines = stdout.split('\n');
1660
- const line = lines.find(line => {
1661
- const parts = line.split(/\s+/);
1662
- return parts[0].toUpperCase() === disk;
1663
- });
1664
- if (line) {
1665
- const parts = line.split(/\s+/);
1666
- return (
1667
- callback &&
1668
- callback(error, {
1669
- 'Disk size': parseInt(parts[2]),
1670
- 'Disk free': parseInt(parts[1])
1671
- })
1672
- );
1673
- }
1599
+ (0, child_process_1.exec)('wmic logicaldisk get size,freespace,caption', {
1600
+ encoding: 'utf8',
1601
+ windowsHide: true
1602
+ }, (error, stdout) => {
1603
+ //, stderr) {
1604
+ if (stdout) {
1605
+ const lines = stdout.split('\n');
1606
+ const line = lines.find(line => {
1607
+ const parts = line.split(/\s+/);
1608
+ return parts[0].toUpperCase() === disk;
1609
+ });
1610
+ if (line) {
1611
+ const parts = line.split(/\s+/);
1612
+ return (callback &&
1613
+ callback(error, {
1614
+ 'Disk size': parseInt(parts[2]),
1615
+ 'Disk free': parseInt(parts[1])
1616
+ }));
1674
1617
  }
1675
- callback && callback(error, null);
1676
1618
  }
1677
- );
1678
- } else {
1679
- exec('df -k /', { encoding: 'utf8', windowsHide: true }, (error, stdout) => {
1619
+ callback && callback(error, null);
1620
+ });
1621
+ }
1622
+ else {
1623
+ (0, child_process_1.exec)('df -k /', { encoding: 'utf8', windowsHide: true }, (error, stdout) => {
1680
1624
  //, stderr) {
1681
1625
  // Filesystem 1K-blocks Used Available Use% Mounted on
1682
1626
  // /dev/mapper/vg00-lv01 162544556 9966192 145767152 7% /
1683
1627
  try {
1684
1628
  if (stdout) {
1685
1629
  const parts = stdout.split('\n')[1].split(/\s+/);
1686
- return (
1687
- callback &&
1630
+ return (callback &&
1688
1631
  callback(error, {
1689
1632
  'Disk size': parseInt(parts[1]) * 1024,
1690
1633
  'Disk free': parseInt(parts[3]) * 1024
1691
- })
1692
- );
1634
+ }));
1693
1635
  }
1694
- } catch {
1636
+ }
1637
+ catch {
1695
1638
  // continue regardless of error
1696
1639
  }
1697
1640
  callback && callback(error, null);
1698
1641
  });
1699
1642
  }
1700
- } catch (e) {
1643
+ }
1644
+ catch (e) {
1701
1645
  callback && callback(e, null);
1702
1646
  }
1703
1647
  }
1704
1648
  }
1705
-
1649
+ exports.getDiskInfo = getDiskInfo;
1706
1650
  const getDiskInfoAsync = promisify(getDiskInfo);
1707
-
1708
1651
  /**
1709
1652
  * Returns information about a certificate
1710
1653
  *
@@ -1724,28 +1667,23 @@ const getDiskInfoAsync = promisify(getDiskInfo);
1724
1667
  *
1725
1668
  * @alias getCertificateInfo
1726
1669
  * @memberof Tools
1727
- * @param {string} cert
1670
+ * @param cert
1728
1671
  * @return certificate information object
1729
1672
  */
1730
1673
  function getCertificateInfo(cert) {
1731
1674
  let info = null;
1732
-
1733
1675
  if (!cert) {
1734
1676
  return null;
1735
1677
  }
1736
- // https://github.com/digitalbazaar/forge
1737
- forge.options.usePureJavaScript = false;
1738
- const pki = forge.pki;
1739
-
1678
+ const pki = node_forge_1.default.pki;
1740
1679
  let certFile = null;
1741
1680
  try {
1742
- if (typeof cert === 'string' && cert.length < 1024 && fs.existsSync(cert)) {
1681
+ if (typeof cert === 'string' && cert.length < 1024 && fs_extra_1.default.existsSync(cert)) {
1743
1682
  certFile = cert;
1744
- cert = fs.readFileSync(cert, 'utf8');
1683
+ cert = fs_extra_1.default.readFileSync(cert, 'utf8');
1745
1684
  }
1746
-
1685
+ // cast to any we use some undocumented? properties below
1747
1686
  const crt = pki.certificateFromPem(cert);
1748
-
1749
1687
  info = {
1750
1688
  certificateFilename: certFile,
1751
1689
  certificate: cert,
@@ -1760,16 +1698,16 @@ function getCertificateInfo(cert) {
1760
1698
  validityNotBefore: crt.validity.notBefore,
1761
1699
  validityNotAfter: crt.validity.notAfter
1762
1700
  };
1763
-
1764
1701
  // do not return info about values
1765
1702
  delete info.keyUsage.value;
1766
1703
  delete info.extKeyUsage.value;
1767
1704
  return info;
1768
- } catch {
1705
+ }
1706
+ catch {
1769
1707
  return null;
1770
1708
  }
1771
1709
  }
1772
-
1710
+ exports.getCertificateInfo = getCertificateInfo;
1773
1711
  /**
1774
1712
  * Returns default SSL certificates (private and public)
1775
1713
  *
@@ -1780,44 +1718,31 @@ function getCertificateInfo(cert) {
1780
1718
  *
1781
1719
  * @alias generateDefaultCertificates
1782
1720
  * @memberof Tools
1783
- * @returns {{ defaultPrivate: any[];defaultPublic: any[] }}
1784
1721
  * <pre><code>
1785
1722
  * const certificates = tools.generateDefaultCertificates();
1786
1723
  * </code></pre>
1787
1724
  */
1788
1725
  function generateDefaultCertificates() {
1789
- // If at any time you wish to disable the use of native code, where available, for particular forge features
1790
- // like its secure random number generator, you may set the forge.options.usePureJavaScript flag to true. It
1791
- // is not recommended that you set this flag as native code is typically more performant and may have stronger
1792
- // security properties. It may be useful to set this flag to test certain features that you plan to run in
1793
- // environments that are different from your testing environment.
1794
- // https://github.com/digitalbazaar/forge
1795
- forge.options.usePureJavaScript = false;
1796
- const pki = forge.pki;
1726
+ const pki = node_forge_1.default.pki;
1797
1727
  const keys = pki.rsa.generateKeyPair({ bits: 2048, e: 0x10001 });
1798
1728
  const cert = pki.createCertificate();
1799
-
1800
1729
  cert.publicKey = keys.publicKey;
1801
- cert.serialNumber = '0' + makeid(17);
1730
+ cert.serialNumber = `0${makeid(17)}`;
1802
1731
  cert.validity.notBefore = new Date();
1803
1732
  cert.validity.notAfter = new Date();
1804
1733
  cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1);
1805
-
1806
1734
  const subAttrs = [
1807
1735
  { name: 'commonName', value: getHostName() },
1808
1736
  { name: 'organizationName', value: 'ioBroker GmbH' },
1809
1737
  { shortName: 'OU', value: 'iobroker' }
1810
1738
  ];
1811
-
1812
1739
  const issAttrs = [
1813
1740
  { name: 'commonName', value: 'iobroker' },
1814
1741
  { name: 'organizationName', value: 'ioBroker GmbH' },
1815
1742
  { shortName: 'OU', value: 'iobroker' }
1816
1743
  ];
1817
-
1818
1744
  cert.setSubject(subAttrs);
1819
1745
  cert.setIssuer(issAttrs);
1820
-
1821
1746
  cert.setExtensions([
1822
1747
  {
1823
1748
  name: 'basicConstraints',
@@ -1842,7 +1767,7 @@ function generateDefaultCertificates() {
1842
1767
  altNames: [
1843
1768
  {
1844
1769
  type: 2,
1845
- value: os.hostname()
1770
+ value: os_1.default.hostname()
1846
1771
  }
1847
1772
  ]
1848
1773
  },
@@ -1861,21 +1786,15 @@ function generateDefaultCertificates() {
1861
1786
  name: 'authorityKeyIdentifier'
1862
1787
  }
1863
1788
  ]);
1864
-
1865
- cert.sign(keys.privateKey, forge.md.sha256.create());
1866
-
1789
+ cert.sign(keys.privateKey, node_forge_1.default.md.sha256.create());
1867
1790
  const pem_pkey = pki.privateKeyToPem(keys.privateKey);
1868
1791
  const pem_cert = pki.certificateToPem(cert);
1869
-
1870
- //console.log(pem_pkey);
1871
- //console.log(pem_cert);
1872
-
1873
1792
  return {
1874
1793
  defaultPrivate: pem_pkey,
1875
1794
  defaultPublic: pem_cert
1876
1795
  };
1877
1796
  }
1878
-
1797
+ exports.generateDefaultCertificates = generateDefaultCertificates;
1879
1798
  function makeid(length) {
1880
1799
  let result = '';
1881
1800
  const characters = 'abcdef0123456789';
@@ -1885,7 +1804,6 @@ function makeid(length) {
1885
1804
  }
1886
1805
  return result;
1887
1806
  }
1888
-
1889
1807
  /**
1890
1808
  * Collects information about host and available adapters
1891
1809
  *
@@ -1896,50 +1814,46 @@ function makeid(length) {
1896
1814
  *
1897
1815
  * @alias getHostInfo
1898
1816
  * @memberof Tools
1899
- * @param {object} objects
1817
+ * @param objects db
1818
+ * @param callback
1900
1819
  * <pre><code>
1901
- * function (err, result) {
1820
+ * function (result) {
1902
1821
  * adapter.log.debug('Info about host: ' + JSON.stringify(result, null, 2);
1903
1822
  * }
1904
1823
  * </code></pre>
1905
1824
  */
1906
1825
  async function getHostInfo(objects, callback) {
1907
- const os = require('os');
1908
-
1909
- if (diskusage !== false) {
1826
+ if (diskusage) {
1910
1827
  try {
1911
1828
  diskusage = diskusage || require('diskusage');
1912
- } catch {
1913
- diskusage = false;
1829
+ }
1830
+ catch {
1831
+ // ignore
1914
1832
  }
1915
1833
  }
1916
-
1917
- const cpus = os.cpus();
1834
+ const cpus = os_1.default.cpus();
1918
1835
  const dateObj = new Date();
1919
-
1920
1836
  const data = {
1921
- Platform: isDocker() ? 'docker' : os.platform(),
1837
+ Platform: isDocker() ? 'docker' : os_1.default.platform(),
1922
1838
  os: process.platform,
1923
- Architecture: os.arch(),
1839
+ Architecture: os_1.default.arch(),
1924
1840
  CPUs: cpus && Array.isArray(cpus) ? cpus.length : null,
1925
1841
  Speed: cpus && Array.isArray(cpus) ? cpus[0].speed : null,
1926
1842
  Model: cpus && Array.isArray(cpus) ? cpus[0].model : null,
1927
- RAM: os.totalmem(),
1928
- 'System uptime': Math.round(os.uptime()),
1843
+ RAM: os_1.default.totalmem(),
1844
+ 'System uptime': Math.round(os_1.default.uptime()),
1929
1845
  'Node.js': process.version,
1930
- time: dateObj.getTime(), // give infos to compare the local times
1846
+ time: dateObj.getTime(),
1931
1847
  timeOffset: dateObj.getTimezoneOffset()
1932
1848
  };
1933
-
1934
1849
  if (data.Platform === 'win32') {
1935
1850
  data.Platform = 'Windows';
1936
- } else if (data.Platform === 'darwin') {
1851
+ }
1852
+ else if (data.Platform === 'darwin') {
1937
1853
  data.Platform = 'OSX';
1938
1854
  }
1939
-
1940
1855
  const systemConfig = await objects.getObjectAsync('system.config');
1941
1856
  const systemRepos = await objects.getObjectAsync('system.repositories');
1942
-
1943
1857
  // Check if repositories exists
1944
1858
  const allRepos = {};
1945
1859
  if (systemRepos && systemRepos.native && systemRepos.native.repositories) {
@@ -1949,37 +1863,37 @@ async function getHostInfo(objects, callback) {
1949
1863
  repos
1950
1864
  .filter(repo => systemRepos.native.repositories[repo] && systemRepos.native.repositories[repo].json)
1951
1865
  .forEach(repo => Object.assign(allRepos, systemRepos.native.repositories[repo].json));
1952
-
1953
1866
  data['adapters count'] = Object.keys(allRepos).length;
1954
1867
  }
1955
-
1956
1868
  if (!npmVersion) {
1957
1869
  try {
1958
1870
  const version = await getSystemNpmVersionAsync();
1959
- data['NPM'] = 'v' + (version || ' ---');
1871
+ data.NPM = `v${version || ' ---'}`;
1960
1872
  npmVersion = version;
1961
- } catch (e) {
1962
- console.error('Cannot get NPM version: ' + e);
1963
1873
  }
1964
- } else {
1965
- data['NPM'] = npmVersion;
1874
+ catch (e) {
1875
+ console.error(`Cannot get NPM version: ${e.message}`);
1876
+ }
1877
+ }
1878
+ else {
1879
+ data.NPM = npmVersion;
1966
1880
  }
1967
1881
  try {
1968
1882
  const info = await getDiskInfoAsync(data.Platform);
1969
1883
  if (info) {
1970
1884
  Object.assign(data, info);
1971
1885
  }
1972
- } catch (e) {
1973
- console.error('Cannot get disk information: ' + e);
1886
+ }
1887
+ catch (e) {
1888
+ console.error(`Cannot get disk information: ${e.message}`);
1974
1889
  }
1975
1890
  callback && callback(data);
1976
-
1977
1891
  return data;
1978
1892
  }
1979
-
1893
+ exports.getHostInfo = getHostInfo;
1980
1894
  /**
1981
1895
  * Finds the controller root directory
1982
- * @returns {string}
1896
+ * @returns absolute path to controller dir
1983
1897
  */
1984
1898
  function getControllerDir() {
1985
1899
  const possibilities = ['iobroker.js-controller', 'ioBroker.js-controller'];
@@ -1988,106 +1902,100 @@ function getControllerDir() {
1988
1902
  // package.json is guaranteed to be in the module root folder
1989
1903
  // so once that is resolved, take the dirname and we're done
1990
1904
  const possiblePath = require.resolve(`${pkg}/package.json`);
1991
- if (fs.existsSync(possiblePath)) {
1992
- return path.dirname(possiblePath);
1905
+ if (fs_extra_1.default.existsSync(possiblePath)) {
1906
+ return path_1.default.dirname(possiblePath);
1993
1907
  }
1994
- } catch {
1908
+ }
1909
+ catch {
1995
1910
  /* not found */
1996
1911
  }
1997
1912
  }
1998
-
1999
1913
  // Apparently, checking vs null/undefined may miss the odd case of controllerPath being ""
2000
1914
  // Thus we check for falsyness, which includes failing on an empty path
2001
- let checkPath = path.join(__dirname, '../..');
1915
+ let checkPath = path_1.default.join(__dirname, '../..');
2002
1916
  // Also check in the current check dir (along with iobroker.js-controller subdirs)
2003
1917
  possibilities.unshift('');
2004
1918
  while (true) {
2005
1919
  for (const pkg of possibilities) {
2006
1920
  try {
2007
- const possiblePath = path.join(checkPath, pkg);
2008
- if (fs.existsSync(path.join(possiblePath, 'iob.bat'))) {
1921
+ const possiblePath = path_1.default.join(checkPath, pkg);
1922
+ if (fs_extra_1.default.existsSync(path_1.default.join(possiblePath, 'iob.bat'))) {
2009
1923
  return possiblePath;
2010
1924
  }
2011
- } catch {
1925
+ }
1926
+ catch {
2012
1927
  // not found, continue with next possiblity
2013
1928
  }
2014
1929
  }
2015
-
2016
1930
  // Controller not found here - go to the parent dir
2017
- const newPath = path.dirname(checkPath);
1931
+ const newPath = path_1.default.dirname(checkPath);
2018
1932
  if (newPath === checkPath) {
2019
1933
  // We already reached the root dir, abort
2020
1934
  break;
2021
1935
  }
2022
1936
  checkPath = newPath;
2023
1937
  }
1938
+ throw new Error('Could not determine controller directory');
2024
1939
  }
2025
-
2026
- // All paths are returned always relative to /node_modules/' + module.exports.appName + '.js-controller
1940
+ exports.getControllerDir = getControllerDir;
1941
+ // All paths are returned always relative to /node_modules/' + appName + '.js-controller
2027
1942
  // the result has always "/" as last symbol
2028
1943
  function getDefaultDataDir() {
2029
- if (fs.existsSync(__dirname + '/../../../../packages/controller')) {
1944
+ if (_isDevInstallation()) {
2030
1945
  // dev install
2031
1946
  return './data/';
2032
1947
  }
2033
-
2034
- const appName = module.exports.appName.toLowerCase();
2035
-
1948
+ const _appName = exports.appName.toLowerCase();
2036
1949
  // if debugging with npm5
2037
- if (fs.existsSync(__dirname + '/../../node_modules/' + appName + '.js-controller')) {
2038
- return '../' + appName + '-data/';
2039
- } else {
1950
+ if (fs_extra_1.default.existsSync(`${__dirname}/../../../node_modules/${_appName}.js-controller`)) {
1951
+ return `../${_appName}-data/`;
1952
+ }
1953
+ else {
2040
1954
  // If installed with npm
2041
- return '../../' + appName + '-data/';
1955
+ return `../../${_appName}-data/`;
2042
1956
  }
2043
1957
  }
2044
-
1958
+ exports.getDefaultDataDir = getDefaultDataDir;
2045
1959
  /**
2046
1960
  * Returns the path of the config file
2047
- *
2048
- * @returns {string}
2049
1961
  */
2050
1962
  function getConfigFileName() {
2051
- /** @type {string|string[]} */
2052
1963
  let configDir = __dirname.replace(/\\/g, '/');
2053
1964
  configDir = configDir.split('/');
2054
- const appName = module.exports.appName.toLowerCase();
2055
-
2056
- if (fs.existsSync(__dirname + '/../../../../packages/controller')) {
1965
+ const _appName = exports.appName.toLowerCase();
1966
+ if (_isDevInstallation()) {
2057
1967
  // dev install -> Remove /lib
2058
- configDir.splice(configDir.length - 3, 3);
1968
+ configDir.splice(configDir.length - 4, 4);
2059
1969
  configDir = configDir.join('/');
2060
1970
  configDir += '/controller'; // go inside controller dir
2061
- if (fs.existsSync(`${configDir}/conf/${appName}.json`)) {
2062
- return `${configDir}/conf/${appName}.json`;
2063
- } else {
2064
- return `${configDir}/data/${appName}.json`;
1971
+ if (fs_extra_1.default.existsSync(`${configDir}/conf/${_appName}.json`)) {
1972
+ return `${configDir}/conf/${_appName}.json`;
1973
+ }
1974
+ else {
1975
+ return `${configDir}/data/${_appName}.json`;
2065
1976
  }
2066
1977
  }
2067
-
2068
1978
  // if debugging with npm5 -> node_modules on e.g. /opt/node_modules
2069
- if (
2070
- fs.existsSync(`${__dirname}/../../../../../../../node_modules/${appName.toLowerCase()}.js-controller`) ||
2071
- fs.existsSync(`${__dirname}/../../../../../../../node_modules/${appName}.js-controller`)
2072
- ) {
1979
+ if (fs_extra_1.default.existsSync(`${__dirname}/../../../../../../../../node_modules/${_appName.toLowerCase()}.js-controller`) ||
1980
+ fs_extra_1.default.existsSync(`${__dirname}/../../../../../../../../node_modules/${_appName}.js-controller`)) {
2073
1981
  // remove /node_modules/' + appName + '.js-controller/lib
2074
- configDir.splice(configDir.length - 7, 7);
1982
+ configDir.splice(configDir.length - 8, 8);
2075
1983
  configDir = configDir.join('/');
2076
- } else {
2077
- // If installed with npm -> remove node_modules/@iobroker/js-controller-common/lib/common
2078
- configDir.splice(configDir.length - 5, 5);
1984
+ }
1985
+ else {
1986
+ // If installed with npm -> remove node_modules/@iobroker/js-controller-common/src/lib/common
1987
+ configDir.splice(configDir.length - 6, 6);
2079
1988
  configDir = configDir.join('/');
2080
1989
  }
2081
-
2082
- return `${configDir}/${appName}-data/${appName}.json`;
1990
+ return `${configDir}/${_appName}-data/${_appName}.json`;
2083
1991
  }
2084
-
1992
+ exports.getConfigFileName = getConfigFileName;
2085
1993
  /**
2086
1994
  * Puts all values from an `arguments` object into an array, starting at the given index
2087
- * @param {IArguments} argsObj An `arguments` object as passed to a function
2088
- * @param {number} [startIndex=0] The optional index to start taking the arguments from
1995
+ * @param argsObj An `arguments` object as passed to a function
1996
+ * @param startIndex The optional index to start taking the arguments from
2089
1997
  */
2090
- function sliceArgs(argsObj, startIndex) {
1998
+ function sliceArgs(argsObj, startIndex = 0) {
2091
1999
  if (startIndex === null || startIndex === undefined) {
2092
2000
  startIndex = 0;
2093
2001
  }
@@ -2097,200 +2005,183 @@ function sliceArgs(argsObj, startIndex) {
2097
2005
  }
2098
2006
  return ret;
2099
2007
  }
2100
-
2101
2008
  /**
2102
2009
  * Promisifies a function which returns an error as the first argument in its callback
2103
- * @param {Function} fn The function to promisify
2104
- * @param {any} [context=this] (optional) The context (value of `this` to bind the function to)
2105
- * @param {string[]} [returnArgNames] (optional) If the callback contains multiple arguments,
2010
+ * @param fn The function to promisify
2011
+ * @param context (optional) The context (value of `this` to bind the function to)
2012
+ * @param returnArgNames (optional) If the callback contains multiple arguments,
2106
2013
  * you can combine them into one object by passing the names as an array.
2107
2014
  * Otherwise the Promise will resolve with an array
2108
- * @returns {(...args: any[]) => Promise<any>}
2109
2015
  */
2110
2016
  function promisify(fn, context, returnArgNames) {
2111
2017
  return function () {
2018
+ // eslint-disable-next-line prefer-rest-params
2112
2019
  const args = sliceArgs(arguments);
2113
- // @ts-ignore we cannot know the type of `this`
2020
+ // @ts-expect-error we cannot know the type of `this`
2114
2021
  context = context || this;
2115
2022
  return new Promise((resolve, reject) => {
2116
- fn.apply(
2117
- context,
2118
- args.concat([
2119
- function (error, result) {
2120
- if (error) {
2121
- return reject(error instanceof Error ? error : new Error(error));
2122
- } else {
2123
- // decide on how we want to return the callback arguments
2124
- switch (arguments.length) {
2125
- case 1: // only an error was given
2126
- return resolve(); // Promise<void>
2127
- case 2: // a single value (result) was returned
2128
- return resolve(result);
2129
- default: {
2130
- // multiple values should be returned
2131
- /** @type {{} | any[]} */
2132
- let ret;
2133
- const extraArgs = sliceArgs(arguments, 1);
2134
- if (returnArgNames && returnArgNames.length === extraArgs.length) {
2135
- // we can build an object
2136
- ret = {};
2137
- for (let i = 0; i < returnArgNames.length; i++) {
2138
- ret[returnArgNames[i]] = extraArgs[i];
2139
- }
2140
- } else {
2141
- // we return the raw array
2142
- ret = extraArgs;
2023
+ fn.apply(context, args.concat([
2024
+ function (error, result) {
2025
+ if (error) {
2026
+ return reject(error instanceof Error ? error : new Error(error));
2027
+ }
2028
+ else {
2029
+ // decide on how we want to return the callback arguments
2030
+ switch (arguments.length) {
2031
+ case 1: // only an error was given
2032
+ return resolve(); // Promise<void>
2033
+ case 2: // a single value (result) was returned
2034
+ return resolve(result);
2035
+ default: {
2036
+ // multiple values should be returned
2037
+ let ret;
2038
+ // eslint-disable-next-line prefer-rest-params
2039
+ const extraArgs = sliceArgs(arguments, 1);
2040
+ if (returnArgNames && returnArgNames.length === extraArgs.length) {
2041
+ // we can build an object
2042
+ ret = {};
2043
+ for (let i = 0; i < returnArgNames.length; i++) {
2044
+ ret[returnArgNames[i]] = extraArgs[i];
2143
2045
  }
2144
- return resolve(ret);
2145
2046
  }
2047
+ else {
2048
+ // we return the raw array
2049
+ ret = extraArgs;
2050
+ }
2051
+ return resolve(ret);
2146
2052
  }
2147
2053
  }
2148
2054
  }
2149
- ])
2150
- );
2055
+ }
2056
+ ]));
2151
2057
  });
2152
2058
  };
2153
2059
  }
2154
-
2060
+ exports.promisify = promisify;
2155
2061
  /**
2156
2062
  * Promisifies a function which does not provide an error as the first argument in its callback
2157
- * @param {Function} fn The function to promisify
2158
- * @param {any} [context] (optional) The context (value of `this` to bind the function to)
2159
- * @param {string[]} [returnArgNames] (optional) If the callback contains multiple arguments,
2063
+ * @param fn The function to promisify
2064
+ * @param context (optional) The context (value of `this` to bind the function to)
2065
+ * @param returnArgNames (optional) If the callback contains multiple arguments,
2160
2066
  * you can combine them into one object by passing the names as an array.
2161
2067
  * Otherwise the Promise will resolve with an array
2162
- * @returns {(...args: any[]) => Promise<any>}
2163
2068
  */
2164
2069
  function promisifyNoError(fn, context, returnArgNames) {
2165
2070
  return function () {
2071
+ // eslint-disable-next-line prefer-rest-params
2166
2072
  const args = sliceArgs(arguments);
2167
- // @ts-ignore we cannot know the type of `this`
2073
+ // @ts-expect-error we cannot know the type of `this`
2168
2074
  context = context || this;
2169
2075
  return new Promise((resolve, _reject) => {
2170
- fn.apply(
2171
- context,
2172
- args.concat([
2173
- function (result) {
2174
- // decide on how we want to return the callback arguments
2175
- switch (arguments.length) {
2176
- case 0: // no arguments were given
2177
- return resolve(); // Promise<void>
2178
- case 1: // a single value (result) was returned
2179
- return resolve(result);
2180
- default: {
2181
- // multiple values should be returned
2182
- /** @type {{} | any[]} */
2183
- let ret;
2184
- const extraArgs = sliceArgs(arguments, 0);
2185
- if (returnArgNames && returnArgNames.length === extraArgs.length) {
2186
- // we can build an object
2187
- ret = {};
2188
- for (let i = 0; i < returnArgNames.length; i++) {
2189
- ret[returnArgNames[i]] = extraArgs[i];
2190
- }
2191
- } else {
2192
- // we return the raw array
2193
- ret = extraArgs;
2076
+ fn.apply(context, args.concat([
2077
+ function (result) {
2078
+ // decide on how we want to return the callback arguments
2079
+ switch (arguments.length) {
2080
+ case 0: // no arguments were given
2081
+ return resolve(); // Promise<void>
2082
+ case 1: // a single value (result) was returned
2083
+ return resolve(result);
2084
+ default: {
2085
+ // multiple values should be returned
2086
+ let ret;
2087
+ // eslint-disable-next-line prefer-rest-params
2088
+ const extraArgs = sliceArgs(arguments, 0);
2089
+ if (returnArgNames && returnArgNames.length === extraArgs.length) {
2090
+ // we can build an object
2091
+ ret = {};
2092
+ for (let i = 0; i < returnArgNames.length; i++) {
2093
+ ret[returnArgNames[i]] = extraArgs[i];
2194
2094
  }
2195
- return resolve(ret);
2196
2095
  }
2096
+ else {
2097
+ // we return the raw array
2098
+ ret = extraArgs;
2099
+ }
2100
+ return resolve(ret);
2197
2101
  }
2198
2102
  }
2199
- ])
2200
- );
2103
+ }
2104
+ ]));
2201
2105
  });
2202
2106
  };
2203
2107
  }
2204
-
2108
+ exports.promisifyNoError = promisifyNoError;
2205
2109
  /**
2206
2110
  * Creates and executes an array of promises in sequence
2207
- * @param {((...args: any[]) => Promise<any>)[]} promiseFactories An array of promise-returning functions
2111
+ * @param promiseFactories An array of promise-returning functions
2208
2112
  */
2209
2113
  function promiseSequence(promiseFactories) {
2114
+ /** @ts-expect-error don't want to touch now */
2210
2115
  return promiseFactories.reduce((promise, factory) => {
2211
2116
  return promise.then(result => factory().then(Array.prototype.concat.bind(result)));
2212
2117
  }, Promise.resolve([]));
2213
2118
  }
2214
-
2215
- function _setQualityForStates(states, keys, quality, cb) {
2216
- if (!keys || !states || !keys.length) {
2217
- cb();
2218
- } else {
2219
- states.setState(
2220
- keys.shift(),
2221
- {
2222
- ack: null,
2223
- q: quality
2224
- },
2225
- () => setImmediate(_setQualityForStates, states, keys, quality, cb)
2226
- );
2119
+ exports.promiseSequence = promiseSequence;
2120
+ async function _setQualityForStates(states, keys, quality) {
2121
+ for (const key of keys) {
2122
+ try {
2123
+ await states.setState(key, { ack: null, q: quality });
2124
+ }
2125
+ catch {
2126
+ // ignore
2127
+ }
2227
2128
  }
2228
2129
  }
2229
-
2230
2130
  function setQualityForInstance(objects, states, namespace, q) {
2231
2131
  return new Promise((resolve, reject) => {
2232
- objects.getObjectView(
2233
- 'system',
2234
- 'state',
2235
- {
2236
- startkey: namespace + '.',
2237
- endkey: namespace + '.\u9999',
2238
- include_docs: false
2239
- },
2240
- (err, _states) => {
2241
- if (err) {
2242
- reject(err);
2243
- } else {
2244
- let keys = [];
2245
- if (_states && _states.rows) {
2246
- for (let s = 0; s < _states.rows.length; s++) {
2247
- const id = _states.rows[s].id;
2248
- // if instance still active, but device is offline
2249
- if (!(q & 0x10) && id.match(/\.info\.connection$/)) {
2250
- continue;
2251
- }
2252
- keys.push(id);
2132
+ objects.getObjectView('system', 'state', {
2133
+ startkey: `${namespace}.`,
2134
+ endkey: `${namespace}.\u9999`,
2135
+ include_docs: false
2136
+ }, (err, _states) => {
2137
+ if (err) {
2138
+ reject(err);
2139
+ }
2140
+ else {
2141
+ let keys = [];
2142
+ if (_states && _states.rows) {
2143
+ for (let s = 0; s < _states.rows.length; s++) {
2144
+ const id = _states.rows[s].id;
2145
+ // if instance still active, but device is offline
2146
+ if (!(q & 0x10) && id.match(/\.info\.connection$/)) {
2147
+ continue;
2253
2148
  }
2149
+ keys.push(id);
2254
2150
  }
2255
- // read all values for IDs
2256
- states.getStates(keys, (_err, values) => {
2257
- // Get only states, that have ack = true
2258
- keys = keys.filter((_id, i) => values[i] && values[i].ack);
2259
- // update quality code of the states to new one
2260
- _setQualityForStates(states, keys, q, err => (err ? reject(err) : resolve()));
2261
- });
2262
2151
  }
2152
+ // read all values for IDs
2153
+ states.getStates(keys, async (_err, values) => {
2154
+ // Get only states, that have ack = true
2155
+ keys = keys.filter((_id, i) => values[i] && values[i].ack);
2156
+ // update quality code of the states to new one
2157
+ await _setQualityForStates(states, keys, q);
2158
+ resolve();
2159
+ });
2263
2160
  }
2264
- );
2161
+ });
2265
2162
  });
2266
2163
  }
2267
-
2164
+ exports.setQualityForInstance = setQualityForInstance;
2268
2165
  /**
2269
2166
  * Converts ioB pattern into regex.
2270
- * @param {string} pattern - Regex string to use it in new RegExp(pattern)
2271
- * @returns {string}
2167
+ * @param pattern - Regex string to use it in new RegExp(pattern)
2272
2168
  */
2273
2169
  function pattern2RegEx(pattern) {
2274
2170
  pattern = (pattern || '').toString();
2275
-
2276
2171
  const startsWithWildcard = pattern[0] === '*';
2277
2172
  const endsWithWildcard = pattern[pattern.length - 1] === '*';
2278
-
2279
2173
  pattern = pattern.replace(/[-/\\^$+?.()|[\]{}]/g, '\\$&').replace(/\*/g, '.*');
2280
-
2281
2174
  return (startsWithWildcard ? '' : '^') + pattern + (endsWithWildcard ? '' : '$');
2282
2175
  }
2283
-
2176
+ exports.pattern2RegEx = pattern2RegEx;
2284
2177
  /**
2285
2178
  * Generates a stack trace that can be added to log outputs to trace their source
2286
- * @param {string} [wrapperName = 'captureStackTrace'] The wrapper function after which the stack trace should begin
2287
- * @returns {string}
2179
+ * @param [wrapperName = 'captureStackTrace'] The wrapper function after which the stack trace should begin
2288
2180
  */
2289
2181
  function captureStackTrace(wrapperName) {
2290
2182
  if (typeof wrapperName !== 'string') {
2291
2183
  wrapperName = 'captureStackTrace';
2292
2184
  }
2293
-
2294
2185
  const ret = new Error();
2295
2186
  if (ret.stack) {
2296
2187
  let foundSelf = false;
@@ -2308,28 +2199,25 @@ function captureStackTrace(wrapperName) {
2308
2199
  }
2309
2200
  return '';
2310
2201
  }
2311
-
2312
2202
  /**
2313
2203
  * Appends the stack trace generated by `captureStackTrace` to the given string
2314
- * @param {string} str - The string to append the stack trace to
2315
- * @returns {string}
2204
+ * @param str - The string to append the stack trace to
2316
2205
  */
2317
2206
  function appendStackTrace(str) {
2318
2207
  // Convert anything that isn't a string into a string
2319
2208
  if (typeof str !== 'string') {
2320
2209
  str = String(str);
2321
2210
  }
2322
- if (str.substr(-1) !== '\n') {
2211
+ if (!str.endsWith('\n')) {
2323
2212
  str += '\n';
2324
2213
  }
2325
2214
  return str + captureStackTrace('appendStackTrace');
2326
2215
  }
2327
-
2216
+ exports.appendStackTrace = appendStackTrace;
2328
2217
  /**
2329
2218
  * Encrypt the password/value with given key
2330
- * @param {string} key - Secret key
2331
- * @param {string} value - value to encrypt
2332
- * @returns {string}
2219
+ * @param key - Secret key
2220
+ * @param value - value to encrypt
2333
2221
  */
2334
2222
  function encryptLegacy(key, value) {
2335
2223
  let result = '';
@@ -2338,12 +2226,10 @@ function encryptLegacy(key, value) {
2338
2226
  }
2339
2227
  return result;
2340
2228
  }
2341
-
2342
2229
  /**
2343
2230
  * Decrypt the password/value with given key
2344
- * @param {string} key - Secret key
2345
- * @param {string} value - value to decrypt
2346
- * @returns {string}
2231
+ * @param key - Secret key
2232
+ * @param value - value to decrypt
2347
2233
  */
2348
2234
  function decryptLegacy(key, value) {
2349
2235
  let result = '';
@@ -2352,59 +2238,46 @@ function decryptLegacy(key, value) {
2352
2238
  }
2353
2239
  return result;
2354
2240
  }
2355
-
2356
2241
  /**
2357
2242
  * encrypts a value by a given key via AES-192-CBC
2358
2243
  *
2359
- * @param {string} key - Secret key
2360
- * @param {string} value - value to decrypt
2361
- * @returns {string}
2244
+ * @param key - Secret key
2245
+ * @param value - value to decrypt
2362
2246
  */
2363
2247
  function encrypt(key, value) {
2364
2248
  if (!/^[0-9a-f]{48}$/.test(key)) {
2365
2249
  // key length is not matching for AES-192-CBC or key is no valid hex - fallback to old encryption
2366
2250
  return encryptLegacy(key, value);
2367
2251
  }
2368
-
2369
- crypto = crypto || require('crypto');
2370
-
2371
- const iv = crypto.randomBytes(16);
2372
- const cipher = crypto.createCipheriv('aes-192-cbc', Buffer.from(key, 'hex'), iv);
2373
-
2252
+ const iv = crypto_1.default.randomBytes(16);
2253
+ const cipher = crypto_1.default.createCipheriv('aes-192-cbc', Buffer.from(key, 'hex'), iv);
2374
2254
  const encrypted = Buffer.concat([cipher.update(value), cipher.final()]);
2375
-
2376
2255
  return `$/aes-192-cbc:${iv.toString('hex')}:${encrypted.toString('hex')}`;
2377
2256
  }
2378
-
2257
+ exports.encrypt = encrypt;
2379
2258
  /**
2380
2259
  * encrypts a value by a given key via AES-192-CBC
2381
2260
  *
2382
- * @param {string} key - Secret key
2383
- * @param {string} value - value to decrypt
2384
- * @returns {string}
2261
+ * @param key - Secret key
2262
+ * @param value - value to decrypt
2385
2263
  */
2386
2264
  function decrypt(key, value) {
2387
2265
  // if not encrypted as aes-192 or key not a valid 48 digit hex -> fallback
2388
2266
  if (!value.startsWith(`$/aes-192-cbc:`) || !/^[0-9a-f]{48}$/.test(key)) {
2389
2267
  return decryptLegacy(key, value);
2390
2268
  }
2391
-
2392
- crypto = crypto || require('crypto');
2393
-
2394
- const textParts = value.split(':');
2269
+ const textParts = value.split(':', 3);
2395
2270
  const iv = Buffer.from(textParts[1], 'hex');
2396
- const encryptedText = Buffer.from(textParts.pop(), 'hex');
2397
- const decipher = crypto.createDecipheriv('aes-192-cbc', Buffer.from(key, 'hex'), iv);
2398
-
2271
+ const encryptedText = Buffer.from(textParts[2], 'hex');
2272
+ const decipher = crypto_1.default.createDecipheriv('aes-192-cbc', Buffer.from(key, 'hex'), iv);
2399
2273
  const decrypted = Buffer.concat([decipher.update(encryptedText), decipher.final()]);
2400
-
2401
2274
  return decrypted.toString();
2402
2275
  }
2403
-
2276
+ exports.decrypt = decrypt;
2404
2277
  /**
2405
2278
  * Tests whether the given variable is a real object and not an Array
2406
- * @param {any} it The variable to test
2407
- * @returns {it is Record<string, any>}
2279
+ * @param it The variable to test
2280
+ * @returns true if it is Record<string, any>
2408
2281
  */
2409
2282
  function isObject(it) {
2410
2283
  // This is necessary because:
@@ -2414,200 +2287,149 @@ function isObject(it) {
2414
2287
  return Object.prototype.toString.call(it) === '[object Object]'; // this code is 25% faster then below one
2415
2288
  // return it && typeof it === 'object' && !(it instanceof Array);
2416
2289
  }
2417
-
2290
+ exports.isObject = isObject;
2418
2291
  /**
2419
2292
  * Tests whether the given variable is really an Array
2420
- * @param {any} it The variable to test
2293
+ * @param it The variable to test
2421
2294
  */
2422
2295
  function isArray(it) {
2423
2296
  return Array.isArray(it); // from node 0.1 is a part of engine
2424
2297
  }
2425
-
2298
+ exports.isArray = isArray;
2426
2299
  /**
2427
2300
  * Measure the Node.js event loop lag and repeatedly call the provided callback function with the updated results
2428
- * @param {number} ms The number of milliseconds for monitoring
2429
- * @param {function} cb Callback function to call for each new value
2301
+ * @param ms The number of milliseconds for monitoring
2302
+ * @param cb Callback function to call for each new value
2430
2303
  */
2431
2304
  function measureEventLoopLag(ms, cb) {
2432
2305
  let start = hrtime();
2433
-
2434
2306
  let timeout = setTimeout(check, ms);
2435
2307
  timeout.unref();
2436
-
2437
2308
  function check() {
2438
2309
  // workaround for https://github.com/joyent/node/issues/8364
2439
2310
  clearTimeout(timeout);
2440
-
2441
2311
  // how much time has actually elapsed in the loop beyond what
2442
2312
  // setTimeout says is supposed to happen. we use setTimeout to
2443
2313
  // cover multiple iterations of the event loop, getting a larger
2444
2314
  // sample of what the process is working on.
2445
2315
  const t = hrtime();
2446
-
2447
2316
  // we use Math.max to handle case where timers are running efficiently
2448
2317
  // and our callback executes earlier than `ms` due to how timers are
2449
2318
  // implemented. this is ok. it means we're healthy.
2450
2319
  cb && cb(Math.max(0, t - start - ms));
2451
2320
  start = t;
2452
-
2453
2321
  timeout = setTimeout(check, ms);
2454
2322
  timeout.unref();
2455
2323
  }
2456
-
2457
2324
  function hrtime() {
2458
2325
  const t = process.hrtime();
2459
2326
  return t[0] * 1e3 + t[1] / 1e6;
2460
2327
  }
2461
2328
  }
2462
-
2329
+ exports.measureEventLoopLag = measureEventLoopLag;
2463
2330
  /**
2464
2331
  * This function convert state values by read and write of aliases. Function is synchron.
2465
2332
  *
2466
- * @param {object} sourceObj
2467
- * @param {object} targetObj
2468
- * @param {object} state Object with val, ack and so on
2469
- * @param {object} logger Logging object
2470
- * @param {string} logNamespace optional Logging namespace
2333
+ * @param sourceObj
2334
+ * @param targetObj
2335
+ * @param state Object with val, ack and so on
2336
+ * @param logger Logging object
2337
+ * @param logNamespace optional Logging namespace
2471
2338
  */
2472
2339
  function formatAliasValue(sourceObj, targetObj, state, logger, logNamespace) {
2473
- logNamespace = logNamespace ? logNamespace + ' ' : '';
2474
-
2340
+ logNamespace = logNamespace ? `${logNamespace} ` : '';
2475
2341
  if (!state) {
2476
- return;
2342
+ return null;
2477
2343
  }
2478
2344
  if (state.val === undefined) {
2479
2345
  state.val = null;
2480
2346
  return state;
2481
2347
  }
2482
-
2483
2348
  if (targetObj && targetObj.alias && targetObj.alias.read) {
2484
2349
  try {
2485
2350
  // process the value here
2486
- const func = new Function(
2487
- 'val',
2488
- 'type',
2489
- 'min',
2490
- 'max',
2491
- 'sType',
2492
- 'sMin',
2493
- 'sMax',
2494
- 'return ' + targetObj.alias.read
2495
- );
2496
- state.val = func(
2497
- state.val,
2498
- targetObj.type,
2499
- targetObj.min,
2500
- targetObj.max,
2501
- sourceObj.type,
2502
- sourceObj.min,
2503
- sourceObj.max
2504
- );
2505
- } catch (e) {
2506
- logger.error(
2507
- `${logNamespace} Invalid read function for ${targetObj._id}: ${targetObj.alias.read} => ${e.message}`
2508
- );
2351
+ const func = new Function('val', 'type', 'min', 'max', 'sType', 'sMin', 'sMax', `return ${targetObj.alias.read}`);
2352
+ state.val = func(state.val, targetObj.type, targetObj.min, targetObj.max, sourceObj.type, sourceObj.min, sourceObj.max);
2353
+ }
2354
+ catch (e) {
2355
+ logger.error(`${logNamespace} Invalid read function for ${targetObj._id}: ${targetObj.alias.read} => ${e.message}`);
2509
2356
  return null;
2510
2357
  }
2511
2358
  }
2512
-
2513
2359
  if (sourceObj && sourceObj.alias && sourceObj.alias.write) {
2514
2360
  try {
2515
2361
  // process the value here
2516
- const func = new Function(
2517
- 'val',
2518
- 'type',
2519
- 'min',
2520
- 'max',
2521
- 'tType',
2522
- 'tMin',
2523
- 'tMax',
2524
- 'return ' + sourceObj.alias.write
2525
- );
2526
- state.val = func(
2527
- state.val,
2528
- sourceObj.type,
2529
- sourceObj.min,
2530
- sourceObj.max,
2531
- targetObj.type,
2532
- targetObj.min,
2533
- targetObj.max
2534
- );
2535
- } catch (e) {
2536
- logger.error(
2537
- `${logNamespace} Invalid write function for ${sourceObj._id}: ${sourceObj.alias.write} => ${e.message}`
2538
- );
2362
+ const func = new Function('val', 'type', 'min', 'max', 'tType', 'tMin', 'tMax', `return ${sourceObj.alias.write}`);
2363
+ state.val = func(state.val, sourceObj.type, sourceObj.min, sourceObj.max, targetObj.type, targetObj.min, targetObj.max);
2364
+ }
2365
+ catch (e) {
2366
+ logger.error(`${logNamespace} Invalid write function for ${sourceObj._id}: ${sourceObj.alias.write} => ${e.message}`);
2539
2367
  return null;
2540
2368
  }
2541
2369
  }
2542
-
2543
2370
  if (targetObj && typeof state.val !== targetObj.type && state.val !== null) {
2544
2371
  if (targetObj.type === 'boolean') {
2545
2372
  const lowerVal = typeof state.val === 'string' ? state.val.toLowerCase() : state.val;
2546
2373
  if (lowerVal === 'off' || lowerVal === 'aus' || state.val === '0') {
2547
2374
  state.val = false;
2548
- } else {
2375
+ }
2376
+ else {
2549
2377
  // this also handles strings like "EIN" or such that will be true
2550
2378
  state.val = !!state.val;
2551
2379
  }
2552
- } else if (targetObj.type === 'number') {
2380
+ }
2381
+ else if (targetObj.type === 'number') {
2553
2382
  state.val = parseFloat(state.val);
2554
- } else if (targetObj.type === 'string') {
2383
+ }
2384
+ else if (targetObj.type === 'string') {
2555
2385
  state.val = state.val.toString();
2556
2386
  }
2557
2387
  }
2558
-
2559
2388
  // auto-scaling, only if val not null and unit for target (x)or source is %
2560
- if (
2561
- ((targetObj && targetObj.alias && !targetObj.alias.read) ||
2562
- (sourceObj && sourceObj.alias && !sourceObj.alias.write)) &&
2563
- state.val !== null
2564
- ) {
2565
- if (
2566
- targetObj &&
2389
+ if (((targetObj && targetObj.alias && !targetObj.alias.read) ||
2390
+ (sourceObj && sourceObj.alias && !sourceObj.alias.write)) &&
2391
+ state.val !== null) {
2392
+ if (targetObj &&
2567
2393
  targetObj.type === 'number' &&
2568
2394
  targetObj.unit === '%' &&
2569
2395
  sourceObj &&
2570
2396
  sourceObj.type === 'number' &&
2571
2397
  sourceObj.unit !== '%' &&
2572
2398
  sourceObj.min !== undefined &&
2573
- sourceObj.max !== undefined
2574
- ) {
2399
+ sourceObj.max !== undefined) {
2575
2400
  // scale target between 0 and 100 % based on sources min/max
2576
2401
  state.val = ((state.val - sourceObj.min) / (sourceObj.max - sourceObj.min)) * 100;
2577
- } else if (
2578
- sourceObj &&
2402
+ }
2403
+ else if (sourceObj &&
2579
2404
  sourceObj.type === 'number' &&
2580
2405
  sourceObj.unit === '%' &&
2581
2406
  targetObj &&
2582
2407
  targetObj.unit !== '%' &&
2583
2408
  targetObj.type === 'number' &&
2584
2409
  targetObj.min !== undefined &&
2585
- targetObj.max !== undefined
2586
- ) {
2410
+ targetObj.max !== undefined) {
2587
2411
  // scale target based on its min/max by its source (assuming source is meant to be 0 - 100 %)
2588
2412
  state.val = ((targetObj.max - targetObj.min) * state.val) / 100 + targetObj.min;
2589
2413
  }
2590
2414
  }
2591
-
2592
2415
  return state;
2593
2416
  }
2594
-
2417
+ exports.formatAliasValue = formatAliasValue;
2595
2418
  /**
2596
2419
  * remove given id from all enums
2597
2420
  *
2598
2421
  * @alias removeIdFromAllEnums
2599
2422
  * @memberof tools
2600
- * @param {object} objects object to access objects db
2601
- * @param {string} id the object id which will be deleted from enums
2602
- * @param {object} [allEnums] objects with all enums to use - if not provided all enums will be queried
2603
- * @returns {Promise} All objects are tried to be updated - reject will happen as soon as one fails with the error of the first fail
2423
+ * @param objects object to access objects db
2424
+ * @param id the object id which will be deleted from enums
2425
+ * @param allEnums objects with all enums to use - if not provided all enums will be queried
2426
+ * @returns Promise All objects are tried to be updated - reject will happen as soon as one fails with the error of the first fail
2604
2427
  *
2605
2428
  */
2606
2429
  async function removeIdFromAllEnums(objects, id, allEnums) {
2607
2430
  if (!allEnums) {
2608
- allEnums = await this.getAllEnums(objects);
2431
+ allEnums = await getAllEnums(objects);
2609
2432
  }
2610
-
2611
2433
  let error = null;
2612
2434
  for (const [enumId, enumObj] of Object.entries(allEnums)) {
2613
2435
  const idx = enumObj.common.members ? enumObj.common.members.indexOf(id) : -1;
@@ -2618,7 +2440,8 @@ async function removeIdFromAllEnums(objects, id, allEnums) {
2618
2440
  await objects.setObjectAsync(enumId, enumObj);
2619
2441
  // update cache directly to prevent race conditions when sending many delete in a short time
2620
2442
  allEnums[enumId] = enumObj;
2621
- } catch (err) {
2443
+ }
2444
+ catch (err) {
2622
2445
  if (!error) {
2623
2446
  error = err;
2624
2447
  }
@@ -2629,14 +2452,14 @@ async function removeIdFromAllEnums(objects, id, allEnums) {
2629
2452
  throw error;
2630
2453
  }
2631
2454
  }
2632
-
2455
+ exports.removeIdFromAllEnums = removeIdFromAllEnums;
2633
2456
  /**
2634
2457
  * Parses dependencies to standardized object of form
2635
2458
  *
2636
2459
  * @alias parseDependencies
2637
2460
  * @memberof tools
2638
- * @param {string[]|Record<string, string>[]|string|Record<string, string>} dependencies dependencies array or single dependency
2639
- * @returns {Record<string, string>} parsed dependencies
2461
+ * @param dependencies dependencies array or single dependency
2462
+ * @returns parsedDeps parsed dependencies
2640
2463
  */
2641
2464
  function parseDependencies(dependencies) {
2642
2465
  let adapters = {};
@@ -2645,29 +2468,32 @@ function parseDependencies(dependencies) {
2645
2468
  if (typeof rule === 'string') {
2646
2469
  // No version given, all are okay
2647
2470
  adapters[rule] = '*';
2648
- } else if (isObject(rule)) {
2471
+ }
2472
+ else if (isObject(rule)) {
2649
2473
  // can be object containing single adapter or multiple
2650
2474
  Object.keys(rule)
2651
2475
  .filter(adapter => !adapters[adapter])
2652
2476
  .forEach(adapter => (adapters[adapter] = rule[adapter]));
2653
2477
  }
2654
2478
  });
2655
- } else if (typeof dependencies === 'string') {
2479
+ }
2480
+ else if (typeof dependencies === 'string') {
2656
2481
  // its a single string without version requirement
2657
2482
  adapters[dependencies] = '*';
2658
- } else if (isObject(dependencies)) {
2483
+ }
2484
+ else if (isObject(dependencies)) {
2659
2485
  // if dependencies is already an object, just use it
2660
2486
  adapters = dependencies;
2661
2487
  }
2662
2488
  return adapters;
2663
2489
  }
2664
-
2490
+ exports.parseDependencies = parseDependencies;
2665
2491
  /**
2666
2492
  * Validates types of obj.common properties and object.type, if invalid types are used, an error is thrown.
2667
2493
  * If attributes of obj.common are not provided, no error is thrown. obj.type has to be there and has to be valid.
2668
2494
  *
2669
- * @param {object} obj an object which will be validated
2670
- * @param {boolean} [extend] (optional) if true checks will allow more optional cases for extendObject calls
2495
+ * @param obj an object which will be validated
2496
+ * @param extend (optional) if true checks will allow more optional cases for extendObject calls
2671
2497
  * @throws Error if a property has the wrong type or obj.type is non existing
2672
2498
  */
2673
2499
  function validateGeneralObjectProperties(obj, extend) {
@@ -2675,15 +2501,12 @@ function validateGeneralObjectProperties(obj, extend) {
2675
2501
  if (obj && obj.type === undefined && obj.views !== undefined) {
2676
2502
  return;
2677
2503
  }
2678
-
2679
2504
  if (!obj || (obj.type === undefined && !extend)) {
2680
2505
  throw new Error(`obj.type has to exist`);
2681
2506
  }
2682
-
2683
2507
  if (obj.type !== undefined && typeof obj.type !== 'string') {
2684
2508
  throw new Error(`obj.type has an invalid type! Expected "string", received "${typeof obj.type}"`);
2685
2509
  }
2686
-
2687
2510
  const allowedObjectTypes = [
2688
2511
  'state',
2689
2512
  'channel',
@@ -2701,175 +2524,115 @@ function validateGeneralObjectProperties(obj, extend) {
2701
2524
  'folder'
2702
2525
  ];
2703
2526
  if (obj.type !== undefined && !allowedObjectTypes.includes(obj.type)) {
2704
- throw new Error(
2705
- `obj.type has an invalid value (${obj.type}) but has to be one of ${allowedObjectTypes.join(', ')}`
2706
- );
2527
+ throw new Error(`obj.type has an invalid value (${obj.type}) but has to be one of ${allowedObjectTypes.join(', ')}`);
2707
2528
  }
2708
-
2709
2529
  // obj.common is optional in general check
2710
2530
  if (!obj.common) {
2711
2531
  return;
2712
2532
  }
2713
-
2714
2533
  if (obj.common.name !== undefined && typeof obj.common.name !== 'string' && typeof obj.common.name !== 'object') {
2715
- throw new Error(
2716
- `obj.common.name has an invalid type! Expected "string" or "object", received "${typeof obj.common.name}"`
2717
- );
2718
- } else if (['adapter'].includes(obj.type) && typeof obj.common.name !== 'string') {
2534
+ throw new Error(`obj.common.name has an invalid type! Expected "string" or "object", received "${typeof obj.common.name}"`);
2535
+ }
2536
+ else if (['adapter'].includes(obj.type) && typeof obj.common.name !== 'string') {
2719
2537
  // TODO: we need this for group/user too, but have to solve problems described in #1266
2720
2538
  // for some types, name needs to be a unique string
2721
2539
  throw new Error(`obj.common.name has an invalid type! Expected "string", received "${typeof obj.common.name}"`);
2722
2540
  }
2723
-
2724
2541
  if (obj.common.type !== undefined) {
2725
2542
  if (typeof obj.common.type !== 'string') {
2726
- throw new Error(
2727
- `obj.common.type has an invalid type! Expected "string", received "${typeof obj.common.type}"`
2728
- );
2543
+ throw new Error(`obj.common.type has an invalid type! Expected "string", received "${typeof obj.common.type}"`);
2729
2544
  }
2730
-
2731
2545
  if (obj.type === 'state') {
2732
2546
  // if object type indicates a state, check that common.type matches
2733
2547
  const allowedStateTypes = ['number', 'string', 'boolean', 'array', 'object', 'mixed', 'file', 'json'];
2734
2548
  if (!allowedStateTypes.includes(obj.common.type)) {
2735
- throw new Error(
2736
- `obj.common.type has an invalid value (${
2737
- obj.common.type
2738
- }) but has to be one of ${allowedStateTypes.join(', ')}`
2739
- );
2549
+ throw new Error(`obj.common.type has an invalid value (${obj.common.type}) but has to be one of ${allowedStateTypes.join(', ')}`);
2740
2550
  }
2741
-
2742
2551
  // ensure that min max only exists for common.type number and is number itself
2743
2552
  if (obj.common.min !== undefined) {
2744
2553
  if (typeof obj.common.min !== 'number') {
2745
- throw new Error(
2746
- `obj.common.min has an invalid type! Expected "number", received "${typeof obj.common.min}"`
2747
- );
2554
+ throw new Error(`obj.common.min has an invalid type! Expected "number", received "${typeof obj.common.min}"`);
2748
2555
  }
2749
-
2750
2556
  if (obj.common.type !== 'number' && obj.common.type !== 'mixed') {
2751
- throw new Error(
2752
- `obj.common.min is only allowed on obj.common.type "number" or "mixed", received "${obj.common.type}"`
2753
- );
2557
+ throw new Error(`obj.common.min is only allowed on obj.common.type "number" or "mixed", received "${obj.common.type}"`);
2754
2558
  }
2755
2559
  }
2756
-
2757
2560
  if (obj.common.max !== undefined) {
2758
2561
  if (typeof obj.common.max !== 'number') {
2759
- throw new Error(
2760
- `obj.common.max has an invalid type! Expected "number", received "${typeof obj.common.max}"`
2761
- );
2562
+ throw new Error(`obj.common.max has an invalid type! Expected "number", received "${typeof obj.common.max}"`);
2762
2563
  }
2763
-
2764
2564
  if (obj.common.type !== 'number' && obj.common.type !== 'mixed') {
2765
- throw new Error(
2766
- `obj.common.max is only allowed on obj.common.type "number" or "mixed", received "${obj.common.type}"`
2767
- );
2565
+ throw new Error(`obj.common.max is only allowed on obj.common.type "number" or "mixed", received "${obj.common.type}"`);
2768
2566
  }
2769
-
2770
2567
  if (obj.common.min !== undefined && obj.common.min > obj.common.max) {
2771
- throw new Error(
2772
- `obj.common.min (${obj.common.min}) needs to be less than or equal to obj.common.max (${obj.common.max})`
2773
- );
2568
+ throw new Error(`obj.common.min (${obj.common.min}) needs to be less than or equal to obj.common.max (${obj.common.max})`);
2774
2569
  }
2775
2570
  }
2776
-
2777
2571
  // ensure, that default value has correct type
2778
2572
  if (obj.common.def !== undefined && obj.common.def !== null) {
2779
2573
  if (obj.common.type === 'file') {
2780
2574
  // defaults are set via setState but would need setBinaryState
2781
2575
  throw new Error('Default value is not supported for type "file"');
2782
2576
  }
2783
-
2784
2577
  // else do what strictObjectChecks does for val
2785
- if (
2786
- !(
2787
- (obj.common.type === 'mixed' && typeof obj.common.def !== 'object') ||
2788
- (obj.common.type !== 'object' && obj.common.type === typeof obj.common.def) ||
2789
- (obj.common.type === 'array' && typeof obj.common.def === 'string') ||
2790
- (obj.common.type === 'json' && typeof obj.common.def === 'string') ||
2791
- (obj.common.type === 'file' && typeof obj.common.def === 'string') ||
2792
- (obj.common.type === 'object' && typeof obj.common.def === 'string')
2793
- )
2794
- ) {
2578
+ if (!((obj.common.type === 'mixed' && typeof obj.common.def !== 'object') ||
2579
+ (obj.common.type !== 'object' && obj.common.type === typeof obj.common.def) ||
2580
+ (obj.common.type === 'array' && typeof obj.common.def === 'string') ||
2581
+ (obj.common.type === 'json' && typeof obj.common.def === 'string') ||
2582
+ (obj.common.type === 'file' && typeof obj.common.def === 'string') ||
2583
+ (obj.common.type === 'object' && typeof obj.common.def === 'string'))) {
2795
2584
  // types can be 'number', 'string', 'boolean', 'array', 'object', 'mixed', 'file', 'json'
2796
2585
  // array, object, json need to be string
2797
2586
  if (['object', 'json', 'file', 'array'].includes(obj.common.type)) {
2798
- throw new Error(
2799
- `Default value has to be stringified but received type "${typeof obj.common.def}"`
2800
- );
2801
- } else {
2802
- throw new Error(
2803
- `Default value has to be ${
2804
- obj.common.type === 'mixed'
2805
- ? `one of type "string", "number", "boolean"`
2806
- : `type "${obj.common.type}"`
2807
- } but received type "${typeof obj.common.def}"`
2808
- );
2587
+ throw new Error(`Default value has to be stringified but received type "${typeof obj.common.def}"`);
2588
+ }
2589
+ else {
2590
+ throw new Error(`Default value has to be ${obj.common.type === 'mixed'
2591
+ ? `one of type "string", "number", "boolean"`
2592
+ : `type "${obj.common.type}"`} but received type "${typeof obj.common.def}"`);
2809
2593
  }
2810
2594
  }
2811
2595
  }
2812
2596
  }
2813
2597
  }
2814
-
2815
2598
  if (obj.common.read !== undefined && typeof obj.common.read !== 'boolean') {
2816
- throw new Error(
2817
- `obj.common.read has an invalid type! Expected "boolean", received "${typeof obj.common.read}"`
2818
- );
2599
+ throw new Error(`obj.common.read has an invalid type! Expected "boolean", received "${typeof obj.common.read}"`);
2819
2600
  }
2820
-
2821
2601
  if (obj.common.write !== undefined && typeof obj.common.write !== 'boolean') {
2822
- throw new Error(
2823
- `obj.common.write has an invalid type! Expected "boolean", received "${typeof obj.common.write}"`
2824
- );
2602
+ throw new Error(`obj.common.write has an invalid type! Expected "boolean", received "${typeof obj.common.write}"`);
2825
2603
  }
2826
-
2827
2604
  if (obj.common.role !== undefined && typeof obj.common.role !== 'string') {
2828
2605
  throw new Error(`obj.common.role has an invalid type! Expected "string", received "${typeof obj.common.role}"`);
2829
2606
  }
2830
-
2831
2607
  if (obj.common.desc !== undefined && typeof obj.common.desc !== 'string' && typeof obj.common.desc !== 'object') {
2832
- throw new Error(
2833
- `obj.common.desc has an invalid type! Expected "string" or "object", received "${typeof obj.common.desc}"`
2834
- );
2608
+ throw new Error(`obj.common.desc has an invalid type! Expected "string" or "object", received "${typeof obj.common.desc}"`);
2835
2609
  }
2836
-
2837
- if (
2838
- obj.type === 'state' &&
2610
+ if (obj.type === 'state' &&
2839
2611
  obj.common.custom !== undefined &&
2840
2612
  obj.common.custom !== null &&
2841
- !isObject(obj.common.custom)
2842
- ) {
2843
- throw new Error(
2844
- `obj.common.custom has an invalid type! Expected "object", received "${typeof obj.common.custom}"`
2845
- );
2613
+ !isObject(obj.common.custom)) {
2614
+ throw new Error(`obj.common.custom has an invalid type! Expected "object", received "${typeof obj.common.custom}"`);
2846
2615
  }
2847
-
2848
2616
  // common.states needs to be a real object or an array
2849
- if (
2850
- obj.common.states !== null && // we allow null for deletion TODO: implement https://github.com/ioBroker/ioBroker.js-controller/issues/1735
2617
+ if (obj.common.states !== null && // we allow null for deletion TODO: implement https://github.com/ioBroker/ioBroker.js-controller/issues/1735
2851
2618
  obj.common.states !== undefined &&
2852
2619
  !isObject(obj.common.states) &&
2853
- !Array.isArray(obj.common.states)
2854
- ) {
2855
- throw new Error(
2856
- `obj.common.states has an invalid type! Expected "object", received "${typeof obj.common.states}"`
2857
- );
2620
+ !Array.isArray(obj.common.states)) {
2621
+ throw new Error(`obj.common.states has an invalid type! Expected "object", received "${typeof obj.common.states}"`);
2858
2622
  }
2859
2623
  }
2860
-
2624
+ exports.validateGeneralObjectProperties = validateGeneralObjectProperties;
2861
2625
  /**
2862
2626
  * get all instances of all adapters in the list
2863
2627
  *
2864
2628
  * @alias getAllInstances
2865
2629
  * @memberof tools
2866
- * @param {string[]} adapters list of adapter names to get instances for
2867
- * @param {object} objects class redis objects
2868
- * @returns {Promise<string[]>} - array of IDs
2630
+ * @param adapters list of adapter names to get instances for
2631
+ * @param objects class redis objects
2632
+ * @returns array of IDs
2869
2633
  */
2870
2634
  async function getAllInstances(adapters, objects) {
2871
2635
  const instances = [];
2872
-
2873
2636
  for (let i = 0; i < adapters.length; i++) {
2874
2637
  if (!adapters[i]) {
2875
2638
  continue;
@@ -2881,21 +2644,21 @@ async function getAllInstances(adapters, objects) {
2881
2644
  instances.push(inst[j]);
2882
2645
  }
2883
2646
  }
2884
- } else {
2647
+ }
2648
+ else {
2885
2649
  if (!instances.includes(adapters[i])) {
2886
2650
  instances.push(adapters[i]);
2887
2651
  }
2888
2652
  }
2889
2653
  }
2890
-
2891
2654
  return instances;
2892
2655
  }
2893
-
2656
+ exports.getAllInstances = getAllInstances;
2894
2657
  /**
2895
2658
  * Get all existing enums
2896
2659
  *
2897
- * @param {object} objects - objects db
2898
- * @returns {Promise<{}>}
2660
+ * @param objects - objects db
2661
+ * @returns Promise
2899
2662
  */
2900
2663
  async function getAllEnums(objects) {
2901
2664
  const allEnums = {};
@@ -2908,22 +2671,21 @@ async function getAllEnums(objects) {
2908
2671
  allEnums[row.id] = row.value;
2909
2672
  }
2910
2673
  }
2911
-
2912
2674
  return allEnums;
2913
2675
  }
2914
-
2676
+ exports.getAllEnums = getAllEnums;
2915
2677
  /**
2916
2678
  * get async all instances of one adapter
2917
2679
  *
2918
2680
  * @alias getInstances
2919
- * @param {string} adapter name of the adapter
2920
- * @param {object}objects objects DB
2921
- * @param {boolean} withObjects return objects instead of only ids
2681
+ * @param adapter name of the adapter
2682
+ * @param objects objects DB
2683
+ * @param withObjects return objects instead of only ids
2922
2684
  */
2923
2685
  async function getInstances(adapter, objects, withObjects) {
2924
2686
  const arr = await objects.getObjectListAsync({
2925
- startkey: 'system.adapter.' + adapter + '.',
2926
- endkey: 'system.adapter.' + adapter + '.\u9999'
2687
+ startkey: `system.adapter.${adapter}.`,
2688
+ endkey: `system.adapter.${adapter}.\u9999`
2927
2689
  });
2928
2690
  const instances = [];
2929
2691
  if (arr && arr.rows) {
@@ -2933,62 +2695,21 @@ async function getInstances(adapter, objects, withObjects) {
2933
2695
  }
2934
2696
  if (withObjects) {
2935
2697
  instances.push(arr.rows[i].value);
2936
- } else {
2698
+ }
2699
+ else {
2937
2700
  instances.push(arr.rows[i].value._id);
2938
2701
  }
2939
2702
  }
2940
2703
  }
2941
-
2942
2704
  return instances;
2943
2705
  }
2944
-
2945
- /**
2946
- * Checks if the given callback is a function and if so calls it with the given parameter immediately, else a resolved Promise is returned
2947
- *
2948
- * @param {(...args: any[]) => void | null | undefined} callback - callback function to be executed
2949
- * @param {...any} args - as many arguments as needed, which will be returned by the callback function or by the Promise
2950
- * @returns {Promise<any>} - if Promise is resolved with multiple arguments, an array is returned
2951
- */
2952
- function maybeCallback(callback, ...args) {
2953
- if (typeof callback === 'function') {
2954
- // if function we call it with given param
2955
- setImmediate(callback, ...args);
2956
- } else {
2957
- return Promise.resolve(args.length > 1 ? args : args[0]);
2958
- }
2959
- }
2960
-
2961
- /**
2962
- * Checks if the given callback is a function and if so calls it with the given error and parameter immediately, else a resolved or rejected Promise is returned. Error ERROR_DB_CLOSED are not rejecting the promise
2963
- *
2964
- * @param {((error: Error | null | undefined, ...args: any[]) => void) | null | undefined} callback - callback function to be executed
2965
- * @param {Error | string | null | undefined} error - error which will be used by the callback function. If callback is not a function and
2966
- * error is given, a rejected Promise is returned. If error is given but it is not an instance of Error, it is converted into one.
2967
- * @param {...any} args - as many arguments as needed, which will be returned by the callback function or by the Promise
2968
- * @returns {Promise<any>} - if Promise is resolved with multiple arguments, an array is returned
2969
- */
2970
- function maybeCallbackWithError(callback, error, ...args) {
2971
- if (error !== undefined && error !== null && !(error instanceof Error)) {
2972
- // if it's not a real Error, we convert it into one
2973
- error = new Error(error);
2974
- }
2975
- const isDbError = error ? error.message === ERROR_DB_CLOSED : false;
2976
-
2977
- if (typeof callback === 'function') {
2978
- setImmediate(callback, error, ...args);
2979
- } else if (error && !isDbError) {
2980
- return Promise.reject(error);
2981
- } else {
2982
- return Promise.resolve(args.length > 1 ? args : args[0]);
2983
- }
2984
- }
2985
-
2706
+ exports.getInstances = getInstances;
2986
2707
  /**
2987
2708
  * Executes a command asynchronously. On success, the promise resolves with stdout and stderr.
2988
2709
  * On error, the promise rejects with the exit code or signal, as well as stdout and stderr.
2989
- * @param {string} command The command to execute
2990
- * @param {import('child_process').ExecOptions} [execOptions] The options for child_process.exec
2991
- * @returns {import('child_process').ChildProcess & Promise<{stdout?: string; stderr?: string}>}
2710
+ * @param command The command to execute
2711
+ * @param execOptions The options for child_process.exec
2712
+ * @returns child process promise
2992
2713
  */
2993
2714
  function execAsync(command, execOptions) {
2994
2715
  const defaultOptions = {
@@ -2997,80 +2718,79 @@ function execAsync(command, execOptions) {
2997
2718
  // And we want to capture stdout/stderr
2998
2719
  encoding: 'utf8'
2999
2720
  };
3000
- // @ts-ignore We set the encoding, so stdout/stdrr must be a string
3001
- return cpPromise.exec(command, { ...defaultOptions, ...execOptions });
2721
+ return (0, promisify_child_process_1.exec)(command, { ...defaultOptions, ...execOptions });
3002
2722
  }
3003
-
2723
+ exports.execAsync = execAsync;
3004
2724
  /**
3005
2725
  * Takes input from one stream and writes it to another as soon as a complete line was read.
3006
- * @param {NodeJS.ReadableStream} input The stream to read from
3007
- * @param {NodeJS.WritableStream} output The stream to write into
2726
+ * @param input The stream to read from
2727
+ * @param output The stream to write into
3008
2728
  */
3009
2729
  function pipeLinewise(input, output) {
3010
- const rl = createInterface({
2730
+ const rl = (0, readline_1.createInterface)({
3011
2731
  input,
3012
2732
  crlfDelay: Infinity
3013
2733
  });
3014
2734
  rl.on('line', line => {
3015
2735
  try {
3016
- output.write(line + os.EOL);
3017
- } catch {
2736
+ output.write(line + os_1.default.EOL);
2737
+ }
2738
+ catch {
3018
2739
  // ignore
3019
2740
  }
3020
2741
  });
3021
- rl.on('error', () => {}); // Ignore errors
2742
+ rl.on('error', () => {
2743
+ /** Ignore Errors */
2744
+ });
3022
2745
  }
3023
-
2746
+ exports.pipeLinewise = pipeLinewise;
3024
2747
  /**
3025
2748
  * Find the adapter main file as full path
3026
2749
  *
3027
2750
  * @memberof tools
3028
- * @param {string} adapter - adapter name of the adapter, e.g. hm-rpc
3029
- * @returns {Promise<string>}
2751
+ * @param adapter - adapter name of the adapter, e.g. hm-rpc
2752
+ * @returns full file name
3030
2753
  */
3031
2754
  async function resolveAdapterMainFile(adapter) {
3032
2755
  const adapterDir = getAdapterDir(adapter);
3033
2756
  if (!adapterDir) {
3034
2757
  throw new Error(`Could not find adapter dir of ${adapter}`);
3035
2758
  }
3036
-
3037
2759
  const possibleMainFiles = ['main.js', `${adapter}.js`];
3038
-
3039
2760
  // Add package.json -> main as the 2nd choice
3040
2761
  try {
3041
- const pack = JSON.parse(await fs.readFile(path.join(adapterDir, 'package.json'), 'utf8'));
2762
+ const pack = JSON.parse(await fs_extra_1.default.readFile(path_1.default.join(adapterDir, 'package.json'), 'utf8'));
3042
2763
  if (pack && typeof pack.main === 'string') {
3043
2764
  possibleMainFiles.unshift(pack.main);
3044
2765
  }
3045
- } catch {
2766
+ }
2767
+ catch {
3046
2768
  // Ignore, we have fallback solutions
3047
2769
  }
3048
-
3049
2770
  // Add io-package.json -> common.main as the preferred choice
3050
2771
  try {
3051
- const ioPack = JSON.parse(await fs.readFile(path.join(adapterDir, 'io-package.json'), 'utf8'));
2772
+ const ioPack = JSON.parse(await fs_extra_1.default.readFile(path_1.default.join(adapterDir, 'io-package.json'), 'utf8'));
3052
2773
  if (ioPack && ioPack.common && typeof ioPack.common.main === 'string') {
3053
2774
  possibleMainFiles.unshift(ioPack.common.main);
3054
2775
  }
3055
- } catch {
2776
+ }
2777
+ catch {
3056
2778
  // Ignore, we have fallback solutions
3057
2779
  }
3058
-
3059
2780
  // Try all possible main files
3060
2781
  for (const mainFile of possibleMainFiles) {
3061
- const fullFileName = path.join(adapterDir, mainFile);
3062
- if (await fs.pathExists(fullFileName)) {
2782
+ const fullFileName = path_1.default.join(adapterDir, mainFile);
2783
+ if (await fs_extra_1.default.pathExists(fullFileName)) {
3063
2784
  return fullFileName;
3064
2785
  }
3065
2786
  }
3066
-
3067
2787
  throw new Error(`Could not find main file of ${adapter}`);
3068
2788
  }
3069
-
2789
+ exports.resolveAdapterMainFile = resolveAdapterMainFile;
3070
2790
  /**
3071
2791
  * Returns the default nodeArgs required to execute the main file, e.g. transpile hooks for TypeScript
3072
- * @param {string} mainFile
3073
- * @returns {string[]}
2792
+ * @param mainFile
2793
+ * @returns default node args for cli
3074
2794
  */
3075
2795
  function getDefaultNodeArgs(mainFile) {
3076
2796
  if (mainFile.endsWith('.ts')) {
@@ -3078,22 +2798,20 @@ function getDefaultNodeArgs(mainFile) {
3078
2798
  }
3079
2799
  return [];
3080
2800
  }
3081
-
2801
+ exports.getDefaultNodeArgs = getDefaultNodeArgs;
3082
2802
  /** This is used for the short github URL format that NPM accepts (<githubname>/<githubrepo>[#<commit-ish>]) */
3083
2803
  const shortGithubUrlRegex = /^(?<user>[^/]+)\/(?<repo>[^#]+)(?:#(?<commit>.+))?$/;
3084
-
3085
2804
  /**
3086
2805
  * Tests if the given URL matches the format <githubname>/<githubrepo>[#<commit-ish>]
3087
- * @param {string} url The URL to parse
2806
+ * @param url The URL to parse
3088
2807
  */
3089
2808
  function isShortGithubUrl(url) {
3090
2809
  return shortGithubUrlRegex.test(url);
3091
2810
  }
3092
-
2811
+ exports.isShortGithubUrl = isShortGithubUrl;
3093
2812
  /**
3094
2813
  * Tries to parse an URL in the format <githubname>/<githubrepo>[#<commit-ish>] into its separate parts
3095
- * @param {string} url The URL to parse
3096
- * @returns {{user: string; repo: string; commit?: string} | null}
2814
+ * @param url The URL to parse
3097
2815
  */
3098
2816
  function parseShortGithubUrl(url) {
3099
2817
  const match = shortGithubUrlRegex.exec(url);
@@ -3106,23 +2824,20 @@ function parseShortGithubUrl(url) {
3106
2824
  commit: match.groups.commit
3107
2825
  };
3108
2826
  }
3109
-
2827
+ exports.parseShortGithubUrl = parseShortGithubUrl;
3110
2828
  /** This is used to parse the pathname of a github URL */
3111
- const githubPathnameRegex =
3112
- /^\/(?<user>[^/]+)\/(?<repo>[^/]*?)(?:\.git)?(?:\/(?:tree|tarball|archive)\/(?<commit>.*?)(?:\.(?:zip|gz|tar\.gz))?)?$/;
3113
-
2829
+ const githubPathnameRegex = /^\/(?<user>[^/]+)\/(?<repo>[^/]*?)(?:\.git)?(?:\/(?:tree|tarball|archive)\/(?<commit>.*?)(?:\.(?:zip|gz|tar\.gz))?)?$/;
3114
2830
  /**
3115
2831
  * Tests if the given pathname matches the format /<githubname>/<githubrepo>[.git][/<tarball|tree|archive>/<commit-ish>[.zip|.gz]]
3116
- * @param {string} pathname The pathname part of a Github URL
2832
+ * @param pathname The pathname part of a Github URL
3117
2833
  */
3118
2834
  function isGithubPathname(pathname) {
3119
2835
  return githubPathnameRegex.test(pathname);
3120
2836
  }
3121
-
2837
+ exports.isGithubPathname = isGithubPathname;
3122
2838
  /**
3123
2839
  * Tries to a github pathname format /<githubname>/<githubrepo>[.git][/<tarball|tree|archive>/<commit-ish>[.zip|.gz|.tar.gz]] into its separate parts
3124
- * @param {string} pathname The pathname part of a Github URL
3125
- * @returns {{user: string; repo: string; commit: string} | null}
2840
+ * @param pathname The pathname part of a Github URL
3126
2841
  */
3127
2842
  function parseGithubPathname(pathname) {
3128
2843
  const match = githubPathnameRegex.exec(pathname);
@@ -3135,23 +2850,25 @@ function parseGithubPathname(pathname) {
3135
2850
  commit: match.groups.commit
3136
2851
  };
3137
2852
  }
3138
-
2853
+ exports.parseGithubPathname = parseGithubPathname;
3139
2854
  /**
3140
2855
  * Removes properties which are given by preserve
3141
- * @param {object} preserve - object which has true entries (or array of selected attributes) for all attributes which should be removed from currObj
3142
- * @param {object} oldObj - old object
3143
- * @param {object} newObj - new object
2856
+ * @param preserve - object which has true entries (or array of selected attributes) for all attributes which should be removed from currObj
2857
+ * @param oldObj - old object
2858
+ * @param newObj - new object
3144
2859
  */
3145
2860
  function removePreservedProperties(preserve, oldObj, newObj) {
3146
2861
  for (const prop of Object.keys(preserve)) {
3147
2862
  if (isObject(preserve[prop]) && isObject(newObj[prop])) {
3148
2863
  // we have to go one step deeper
3149
2864
  removePreservedProperties(preserve[prop], oldObj[prop], newObj[prop]);
3150
- } else if (newObj && newObj[prop] !== undefined && oldObj && oldObj[prop] !== undefined) {
2865
+ }
2866
+ else if (newObj && newObj[prop] !== undefined && oldObj && oldObj[prop] !== undefined) {
3151
2867
  // we only need to remove something if its in the old object and in the new one
3152
2868
  if (typeof preserve[prop] === 'boolean') {
3153
2869
  delete newObj[prop];
3154
- } else if (Array.isArray(preserve[prop])) {
2870
+ }
2871
+ else if (Array.isArray(preserve[prop])) {
3155
2872
  // array, only rm selected subattributes instead of whole attribute
3156
2873
  for (const rmProp of preserve[prop]) {
3157
2874
  if (oldObj[prop][rmProp] !== undefined && newObj[prop][rmProp] !== undefined) {
@@ -3163,13 +2880,12 @@ function removePreservedProperties(preserve, oldObj, newObj) {
3163
2880
  }
3164
2881
  }
3165
2882
  }
3166
-
2883
+ exports.removePreservedProperties = removePreservedProperties;
3167
2884
  /**
3168
2885
  * Returns the array of system.adapter.<namespace>.* objects which are created for every instance
3169
2886
  *
3170
- * @param {string} namespace - adapter namespace + id, e.g. hm-rpc.0
3171
- * @param {boolean} createWakeup - indicator to create wakeup object too
3172
- * @returns {object[]}
2887
+ * @param namespace - adapter namespace + id, e.g. hm-rpc.0
2888
+ * @param createWakeup - indicator to create wakeup object too
3173
2889
  */
3174
2890
  function getInstanceIndicatorObjects(namespace, createWakeup) {
3175
2891
  const id = `system.adapter.${namespace}`;
@@ -3358,7 +3074,6 @@ function getInstanceIndicatorObjects(namespace, createWakeup) {
3358
3074
  native: {}
3359
3075
  }
3360
3076
  ];
3361
-
3362
3077
  if (createWakeup) {
3363
3078
  objs.push({
3364
3079
  _id: `${id}.wakeup`,
@@ -3373,10 +3088,9 @@ function getInstanceIndicatorObjects(namespace, createWakeup) {
3373
3088
  native: {}
3374
3089
  });
3375
3090
  }
3376
-
3377
3091
  return objs;
3378
3092
  }
3379
-
3093
+ exports.getInstanceIndicatorObjects = getInstanceIndicatorObjects;
3380
3094
  function getLogger(log) {
3381
3095
  if (!log) {
3382
3096
  log = {
@@ -3396,92 +3110,89 @@ function getLogger(log) {
3396
3110
  console.log(msg);
3397
3111
  }
3398
3112
  };
3399
- } else if (!log.silly) {
3113
+ }
3114
+ else if (!log.silly) {
3400
3115
  log.silly = log.debug;
3401
3116
  }
3402
3117
  return log;
3403
3118
  }
3404
-
3119
+ exports.getLogger = getLogger;
3405
3120
  /**
3406
3121
  * Get ordered instances according to tier level
3407
3122
  *
3408
- * @param {object} objects - Objects DB
3409
- * @param {object} logger - logger object
3410
- * @param {string} [logPrefix] - prefix for logging
3411
- * @return {Promise<object[]>}
3123
+ * @param objects - Objects DB
3124
+ * @param logger - logger object
3125
+ * @param logPrefix prefix for logging
3412
3126
  */
3413
3127
  async function getInstancesOrderedByStartPrio(objects, logger, logPrefix = '') {
3414
3128
  const instances = { 1: [], 2: [], 3: [], admin: [] };
3415
3129
  const allowedTiers = [1, 2, 3];
3416
-
3417
3130
  if (logPrefix) {
3418
3131
  // append space if we have a prefix
3419
3132
  logPrefix += ' ';
3420
3133
  }
3421
-
3422
- let doc = {};
3134
+ let doc = { rows: [] };
3423
3135
  try {
3424
3136
  doc = await objects.getObjectViewAsync('system', 'instance', {
3425
3137
  startkey: 'system.adapter.',
3426
3138
  endkey: 'system.adapter.\u9999'
3427
3139
  });
3428
- } catch (e) {
3140
+ }
3141
+ catch (e) {
3429
3142
  if (e.message && e.message.startsWith('Cannot find ')) {
3430
- logger.error(`${logPrefix} _design/system missing - call node ${module.exports.appName}.js setup`);
3431
- } else {
3143
+ logger.error(`${logPrefix} _design/system missing - call node ${exports.appName}.js setup`);
3144
+ }
3145
+ else {
3432
3146
  logger.error(`${logPrefix} Can not get instances: ${e.message}`);
3433
3147
  }
3434
3148
  }
3435
-
3436
3149
  if (!doc.rows || doc.rows.length === 0) {
3437
3150
  logger.info(`${logPrefix} no instances found`);
3438
- } else {
3151
+ }
3152
+ else {
3439
3153
  for (const row of doc.rows) {
3440
3154
  if (row && row.value) {
3441
3155
  if (row.value._id.startsWith('system.adapter.admin')) {
3442
3156
  instances.admin.push(row.value);
3443
- } else if (row.value.common && allowedTiers.includes(parseInt(row.value.common.tier))) {
3157
+ /** @ts-expect-error https://github.com/ioBroker/adapter-core/issues/427 */
3158
+ }
3159
+ else if (row.value.common && allowedTiers.includes(parseInt(row.value.common.tier))) {
3160
+ /** @ts-expect-error we have checked that it is in allowedTiers, thus it is valid */
3444
3161
  instances[row.value.common.tier].push(row.value);
3445
- } else {
3162
+ }
3163
+ else {
3446
3164
  // no valid tier so put it in the last one
3447
3165
  instances['3'].push(row.value);
3448
3166
  }
3449
3167
  }
3450
3168
  }
3451
3169
  }
3452
-
3453
3170
  return [...instances.admin, ...instances['1'], ...instances['2'], ...instances['3']];
3454
3171
  }
3455
-
3172
+ exports.getInstancesOrderedByStartPrio = getInstancesOrderedByStartPrio;
3456
3173
  /**
3457
3174
  * Set capabilities of the given executable on Linux systems
3458
- * @param {string} execPath - path to the executable for node you can determine it via process.execPath
3459
- * @param {string[]} capabilities - capabilities to set, e.g. ['cap_net_admin', 'cap_net_bind_service']
3460
- * @param {boolean} [modeEffective] - add effective mode
3461
- * @param {boolean} [modePermitted] - add permitted mode
3462
- * @param {boolean} [modeInherited] - add inherited mode
3463
- * @returns {Promise<void>}
3175
+ * @param execPath - path to the executable for node you can determine it via process.execPath
3176
+ * @param capabilities - capabilities to set, e.g. ['cap_net_admin', 'cap_net_bind_service']
3177
+ * @param modeEffective - add effective mode
3178
+ * @param modePermitted - add permitted mode
3179
+ * @param modeInherited - add inherited mode
3464
3180
  */
3465
3181
  async function setExecutableCapabilities(execPath, capabilities, modeEffective, modePermitted, modeInherited) {
3466
- if (!Array.isArray(capabilities) || !capabilities.length) {
3467
- throw new Error('No capabilities array provided');
3468
- }
3469
-
3470
3182
  // if not linux do nothing and silently exit
3471
- if (os.platform() !== 'linux') {
3183
+ if (os_1.default.platform() !== 'linux') {
3472
3184
  return;
3473
3185
  }
3474
-
3475
3186
  // if Docker and Admin Capabilities should be set check if we are allowed to do that
3476
3187
  if (isDocker() && capabilities.includes('cap_net_admin')) {
3477
3188
  try {
3478
- const systemCaps = fs.readFileSync(`/proc/${process.pid}/status`, 'utf-8');
3189
+ const systemCaps = fs_extra_1.default.readFileSync(`/proc/${process.pid}/status`, 'utf-8');
3479
3190
  const capBnd = systemCaps.match(/^CapBnd:\s(.+)$/m);
3480
3191
  // We found a value in CapBnd line
3481
3192
  if (capBnd && capBnd[1]) {
3482
3193
  const { stdout } = await execAsync(`capsh --decode=${capBnd[1]}`);
3483
3194
  // Stdout looks like "0x00000000a80425fb=cap_chown,cap_dac_override,..."
3484
- if (stdout && stdout.startsWith(`0x${capBnd[1]}=`)) {
3195
+ if (typeof stdout === 'string' && stdout.startsWith(`0x${capBnd[1]}=`)) {
3485
3196
  const capBndArr = stdout.substring(capBnd[1].length + 3).split(',');
3486
3197
  // if Admin Capability is not included in System Capabilities we remove it from array
3487
3198
  if (!capBndArr.includes('cap_net_admin')) {
@@ -3489,87 +3200,79 @@ async function setExecutableCapabilities(execPath, capabilities, modeEffective,
3489
3200
  }
3490
3201
  }
3491
3202
  }
3492
- } catch {
3203
+ }
3204
+ catch {
3493
3205
  // Ok we could not find it out, so update Caps but better without Admin Capability
3494
3206
  capabilities = capabilities.filter(c => c !== 'cap_net_admin');
3495
3207
  }
3496
3208
  }
3497
-
3498
3209
  if (capabilities.length) {
3499
3210
  let modes = '';
3500
3211
  const capabilitiesStr = capabilities.join(',');
3501
-
3502
3212
  if (modeEffective) {
3503
3213
  modes += 'e';
3504
3214
  }
3505
-
3506
3215
  if (modePermitted) {
3507
3216
  modes += 'p';
3508
3217
  }
3509
-
3510
3218
  if (modeInherited) {
3511
3219
  modes += 'i';
3512
3220
  }
3513
-
3514
3221
  if (modes.length) {
3515
3222
  modes = `+${modes}`;
3516
3223
  }
3517
-
3518
3224
  // if this throws it needs to be caught outside
3519
- await cpPromise.exec(`sudo setcap ${capabilitiesStr}${modes} ${execPath}`);
3225
+ await execAsync(`sudo setcap ${capabilitiesStr}${modes} ${execPath}`);
3520
3226
  }
3521
3227
  }
3522
-
3228
+ exports.setExecutableCapabilities = setExecutableCapabilities;
3523
3229
  /**
3524
3230
  * Requests the licenses from ioBroker.net
3525
- * @param {string} login Login for ioBroker.net
3526
- * @param {string} password Decoded password for ioBroker.net
3527
- * @returns {Promise<object[]>} array of all licenses stored on iobroker.net
3231
+ * @param login Login for ioBroker.net
3232
+ * @param password Decoded password for ioBroker.net
3233
+ * @returns array of all licenses stored on iobroker.net
3528
3234
  */
3529
3235
  async function _readLicenses(login, password) {
3530
- axios = axios || require('axios');
3531
3236
  const config = {
3532
- headers: { Authorization: `Basic ${Buffer.from(login + ':' + password).toString('base64')}` },
3237
+ headers: { Authorization: `Basic ${Buffer.from(`${login}:${password}`).toString('base64')}` },
3533
3238
  timeout: 4000
3534
3239
  };
3535
-
3536
3240
  try {
3537
- const response = await axios.get(`https://iobroker.net:3001/api/v1/licenses`, config);
3241
+ const response = await axios_1.default.get(`https://iobroker.net:3001/api/v1/licenses`, config);
3538
3242
  if (response.data && response.data.length) {
3539
3243
  const now = Date.now();
3540
- response.data = response.data.filter(
3541
- license =>
3542
- !license.validTill ||
3543
- license.validTill === '0000-00-00 00:00:00' ||
3544
- new Date(license.validTill).getTime() > now
3545
- );
3546
- }
3547
-
3244
+ response.data = response.data.filter((license) => !license.validTill ||
3245
+ license.validTill === '0000-00-00 00:00:00' ||
3246
+ new Date(license.validTill).getTime() > now);
3247
+ }
3548
3248
  return response.data;
3549
- } catch (err) {
3249
+ }
3250
+ catch (err) {
3550
3251
  if (err.response) {
3551
3252
  throw new Error((err.response.data && err.response.data.error) || err.response.data || err.response.status);
3552
- } else if (err.request) {
3253
+ }
3254
+ else if (err.request) {
3553
3255
  throw new Error('no response');
3554
- } else {
3256
+ }
3257
+ else {
3555
3258
  throw err;
3556
3259
  }
3557
3260
  }
3558
3261
  }
3559
-
3560
3262
  /**
3561
3263
  * Reads the licenses from iobroker.net
3562
3264
  * Reads the licenses from iobroker.net and if no login/password provided stores it in system.licenses
3563
- * @param {object} objects Object store instance
3564
- * @param {string} login Login for ioBroker.net
3565
- * @param {string} password Decoded password for ioBroker.net
3566
- * @returns {Promise<object[]>} array of all licenses stored on iobroker.net
3265
+ * @param objects Object store instance
3266
+ * @param login Login for ioBroker.net
3267
+ * @param password Decoded password for ioBroker.net
3268
+ * @returns array of all licenses stored on iobroker.net
3567
3269
  */
3568
3270
  async function updateLicenses(objects, login, password) {
3569
3271
  // if login and password provided in the message, just try to read without saving it in system.licenses
3570
3272
  if (login && password) {
3571
3273
  return _readLicenses(login, password);
3572
- } else {
3274
+ }
3275
+ else {
3573
3276
  // get actual object
3574
3277
  const systemLicenses = await objects.getObjectAsync('system.licenses');
3575
3278
  // If password and login exist
@@ -3577,15 +3280,14 @@ async function updateLicenses(objects, login, password) {
3577
3280
  try {
3578
3281
  // get the secret to decode the password
3579
3282
  const systemConfig = await objects.getObjectAsync('system.config');
3580
-
3581
3283
  // decode the password
3582
3284
  let password;
3583
3285
  try {
3584
3286
  password = decrypt(systemConfig.native.secret, systemLicenses.native.password);
3585
- } catch (err) {
3287
+ }
3288
+ catch (err) {
3586
3289
  throw new Error(`Cannot decode password: ${err.message}`);
3587
3290
  }
3588
-
3589
3291
  // read licenses from iobroker.net
3590
3292
  const licenses = await _readLicenses(systemLicenses.native.login, password);
3591
3293
  // save licenses to system.licenses and remember the time
@@ -3600,41 +3302,34 @@ async function updateLicenses(objects, login, password) {
3600
3302
  }
3601
3303
  }
3602
3304
  });
3603
-
3604
3305
  systemLicenses.native.readTime = new Date().toISOString();
3605
-
3606
3306
  // update read time
3607
3307
  await objects.setObjectAsync('system.licenses', systemLicenses);
3608
3308
  return licenses;
3609
- } catch (err) {
3309
+ }
3310
+ catch (err) {
3610
3311
  // if password is invalid
3611
- if (
3612
- err.message.includes('Authentication required') ||
3613
- err.message.includes('Cannot decode password:')
3614
- ) {
3312
+ if (err.message.includes('Authentication required') ||
3313
+ err.message.includes('Cannot decode password:')) {
3615
3314
  // clear existing licenses if exist
3616
- if (
3617
- systemLicenses &&
3315
+ if (systemLicenses &&
3618
3316
  systemLicenses.native &&
3619
3317
  systemLicenses.native.licenses &&
3620
- systemLicenses.native.licenses.length
3621
- ) {
3318
+ systemLicenses.native.licenses.length) {
3622
3319
  systemLicenses.native.licenses = [];
3623
3320
  systemLicenses.native.readTime = new Date().toISOString();
3624
3321
  await objects.setObjectAsync('system.licenses', systemLicenses);
3625
3322
  }
3626
3323
  }
3627
-
3628
3324
  throw err;
3629
3325
  }
3630
- } else {
3326
+ }
3327
+ else {
3631
3328
  // if password or login are empty => clear existing licenses if exist
3632
- if (
3633
- systemLicenses &&
3329
+ if (systemLicenses &&
3634
3330
  systemLicenses.native &&
3635
3331
  systemLicenses.native.licenses &&
3636
- systemLicenses.native.licenses.length
3637
- ) {
3332
+ systemLicenses.native.licenses.length) {
3638
3333
  systemLicenses.native.licenses = [];
3639
3334
  systemLicenses.native.readTime = new Date().toISOString();
3640
3335
  await objects.setObjectAsync('system.licenses', systemLicenses);
@@ -3643,26 +3338,19 @@ async function updateLicenses(objects, login, password) {
3643
3338
  }
3644
3339
  }
3645
3340
  }
3646
-
3647
- /**
3648
- * @typedef {object} GZipFileOptions
3649
- * @property {boolean} [deleteInput] Delete the input file after compression. Default: false.
3650
- */
3651
-
3341
+ exports.updateLicenses = updateLicenses;
3652
3342
  /**
3653
3343
  * Compresses an input file using GZip and writes it somewhere else
3654
- * @param {string} inputFilename The filename of the input file that should be gzipped
3655
- * @param {string} outputFilename The filename of the output file where the gzipped content should be written to
3656
- * @param {GZipFileOptions} [options] Options for the compression
3657
- * @returns {Promise<void>}
3344
+ * @param inputFilename The filename of the input file that should be gzipped
3345
+ * @param outputFilename The filename of the output file where the gzipped content should be written to
3346
+ * @param options Options for the compression
3658
3347
  */
3659
3348
  function compressFileGZip(inputFilename, outputFilename, options = {}) {
3660
3349
  const { deleteInput = false } = options;
3661
-
3662
3350
  return new Promise((resolve, reject) => {
3663
- const input = fs.createReadStream(inputFilename);
3664
- const output = fs.createWriteStream(outputFilename);
3665
- const compress = zlib.createGzip();
3351
+ const input = fs_extra_1.default.createReadStream(inputFilename);
3352
+ const output = fs_extra_1.default.createWriteStream(outputFilename);
3353
+ const compress = zlib_1.default.createGzip();
3666
3354
  input.on('error', err => {
3667
3355
  reject(err);
3668
3356
  });
@@ -3675,97 +3363,30 @@ function compressFileGZip(inputFilename, outputFilename, options = {}) {
3675
3363
  output.on('close', () => {
3676
3364
  if (deleteInput) {
3677
3365
  try {
3678
- fs.unlinkSync(inputFilename);
3679
- } catch {
3366
+ fs_extra_1.default.unlinkSync(inputFilename);
3367
+ }
3368
+ catch {
3680
3369
  // Ignore
3681
3370
  }
3682
3371
  }
3683
3372
  resolve();
3684
3373
  });
3685
-
3686
3374
  input.pipe(compress).pipe(output);
3687
3375
  });
3688
3376
  }
3689
-
3690
- const ERROR_NOT_FOUND = 'Not exists';
3691
- const ERROR_EMPTY_OBJECT = 'null object';
3692
- const ERROR_NO_OBJECT = 'no object';
3693
- const ERROR_DB_CLOSED = 'DB closed';
3694
-
3695
- module.exports = {
3696
- appName: getAppName(),
3697
- createUuid,
3698
- decryptPhrase,
3699
- execAsync,
3700
- findIPs,
3701
- generateDefaultCertificates,
3702
- getAdapterDir,
3703
- getInstances,
3704
- getAllInstances,
3705
- getCertificateInfo,
3706
- getConfigFileName,
3707
- getDefaultDataDir,
3708
- getDefaultNodeArgs,
3709
- getFile,
3710
- getHostInfo,
3711
- getHostName,
3712
- getInstalledInfo,
3713
- getInstanceIndicatorObjects,
3714
- getIoPack,
3715
- getJson,
3716
- getJsonAsync,
3717
- getInstancesOrderedByStartPrio,
3718
- getRepositoryFile,
3719
- getRepositoryFileAsync,
3720
- getSystemNpmVersion,
3721
- installNodeModule,
3722
- uninstallNodeModule,
3723
- rebuildNodeModules,
3724
- isObject,
3725
- isArray,
3726
- maybeCallback,
3727
- maybeCallbackWithError,
3728
- promisify,
3729
- promisifyNoError,
3730
- promiseSequence,
3731
- removeIdFromAllEnums,
3732
- resolveAdapterMainFile,
3733
- rmdirRecursiveSync,
3734
- parseDependencies,
3735
- sendDiagInfo,
3736
- upToDate,
3737
- validateGeneralObjectProperties,
3738
- checkNonEditable,
3739
- copyAttributes,
3740
- getDiskInfo,
3741
- setQualityForInstance,
3742
- appendStackTrace,
3743
- captureStackTrace,
3744
- pattern2RegEx,
3745
- encrypt,
3746
- decrypt,
3747
- measureEventLoopLag,
3748
- formatAliasValue,
3749
- pipeLinewise,
3750
- isShortGithubUrl,
3751
- parseShortGithubUrl,
3752
- setExecutableCapabilities,
3753
- isGithubPathname,
3754
- isSingleHost,
3755
- isHostRunning,
3756
- parseGithubPathname,
3757
- removePreservedProperties,
3758
- FORBIDDEN_CHARS,
3759
- getControllerDir,
3760
- getLogger,
3761
- getAllEnums,
3762
- updateLicenses,
3763
- compressFileGZip,
3764
- isDocker,
3765
- ERRORS: {
3766
- ERROR_NOT_FOUND: ERROR_NOT_FOUND,
3767
- ERROR_EMPTY_OBJECT: ERROR_EMPTY_OBJECT,
3768
- ERROR_NO_OBJECT: ERROR_NO_OBJECT,
3769
- ERROR_DB_CLOSED: ERROR_DB_CLOSED
3377
+ exports.compressFileGZip = compressFileGZip;
3378
+ /**
3379
+ * If an array is passed it will be stringified, else the parameter is returned
3380
+ * @param maybeArr parameter which will be stringified if it is an array
3381
+ */
3382
+ function maybeArrayToString(maybeArr) {
3383
+ if (Array.isArray(maybeArr)) {
3384
+ // @ts-expect-error https://github.com/microsoft/TypeScript/issues/33912
3385
+ return JSON.stringify(maybeArr);
3770
3386
  }
3771
- };
3387
+ // @ts-expect-error https://github.com/microsoft/TypeScript/issues/33912
3388
+ return maybeArr;
3389
+ }
3390
+ exports.maybeArrayToString = maybeArrayToString;
3391
+ __exportStar(require("./maybeCallback"), exports);
3392
+ //# sourceMappingURL=tools.js.map