@iobroker/js-controller-common 4.0.21 → 4.1.0-alpha.12-20220314-28d0dece

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