homey-api 3.4.29 → 3.4.30

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.
@@ -317,6 +317,17 @@
317
317
  }
318
318
  }
319
319
  },
320
+ "getAppIcon": {
321
+ "path": "/app/{appId}/icon",
322
+ "method": "get",
323
+ "parameters": {
324
+ "appId": {
325
+ "in": "path",
326
+ "type": "string",
327
+ "required": true
328
+ }
329
+ }
330
+ },
320
331
  "getAppInstall": {
321
332
  "path": "/app/{appId}/install",
322
333
  "method": "get",
@@ -1671,6 +1671,8 @@ export class AthomAppsAPI {
1671
1671
  userId?: string;
1672
1672
  }): Promise<any>;
1673
1673
 
1674
+ getAppIcon(opts: { appId: string }): Promise<any>;
1675
+
1674
1676
  getAppInstall(opts: {
1675
1677
  appId: string;
1676
1678
 
@@ -1959,6 +1961,8 @@ export class AthomAppsAPI {
1959
1961
  userId?: string;
1960
1962
  }): Promise<any>;
1961
1963
 
1964
+ getAppIcon(opts: { appId: string }): Promise<any>;
1965
+
1962
1966
  getAppInstall(opts: {
1963
1967
  appId: string;
1964
1968
 
@@ -4601,7 +4605,15 @@ export class HomeyCloudAPI {
4601
4605
  }
4602
4606
 
4603
4607
  export class Util {
4604
- static fetch(args: any): Promise;
4608
+ static fetch(
4609
+ args: string,
4610
+
4611
+ options?: Object,
4612
+
4613
+ timeoutDuration?: number,
4614
+
4615
+ timeoutMessage?: string,
4616
+ ): Promise<any>;
4605
4617
 
4606
4618
  static wait(ms: number): Promise<void>;
4607
4619
 
@@ -4637,7 +4649,15 @@ export class Util {
4637
4649
 
4638
4650
  static encodeUrlSearchParams(params: object): string;
4639
4651
 
4640
- static fetch(args: any): Promise;
4652
+ static fetch(
4653
+ args: string,
4654
+
4655
+ options?: Object,
4656
+
4657
+ timeoutDuration?: number,
4658
+
4659
+ timeoutMessage?: string,
4660
+ ): Promise<any>;
4641
4661
 
4642
4662
  static wait(ms: number): Promise<void>;
4643
4663
 
@@ -4847,6 +4867,8 @@ export class AthomAppsAPI {
4847
4867
  userId?: string;
4848
4868
  }): Promise<any>;
4849
4869
 
4870
+ getAppIcon(opts: { appId: string }): Promise<any>;
4871
+
4850
4872
  getAppInstall(opts: {
4851
4873
  appId: string;
4852
4874
 
@@ -5135,6 +5157,8 @@ export class AthomAppsAPI {
5135
5157
  userId?: string;
5136
5158
  }): Promise<any>;
5137
5159
 
5160
+ getAppIcon(opts: { appId: string }): Promise<any>;
5161
+
5138
5162
  getAppInstall(opts: {
5139
5163
  appId: string;
5140
5164
 
@@ -7713,7 +7737,15 @@ export class HomeyCloudAPI {
7713
7737
  }
7714
7738
 
7715
7739
  export class Util {
7716
- static fetch(args: any): Promise;
7740
+ static fetch(
7741
+ args: string,
7742
+
7743
+ options?: Object,
7744
+
7745
+ timeoutDuration?: number,
7746
+
7747
+ timeoutMessage?: string,
7748
+ ): Promise<any>;
7717
7749
 
7718
7750
  static wait(ms: number): Promise<void>;
7719
7751
 
@@ -7749,7 +7781,15 @@ export class Util {
7749
7781
 
7750
7782
  static encodeUrlSearchParams(params: object): string;
7751
7783
 
7752
- static fetch(args: any): Promise;
7784
+ static fetch(
7785
+ args: string,
7786
+
7787
+ options?: Object,
7788
+
7789
+ timeoutDuration?: number,
7790
+
7791
+ timeoutMessage?: string,
7792
+ ): Promise<any>;
7753
7793
 
7754
7794
  static wait(ms: number): Promise<void>;
7755
7795
 
package/lib/API.js CHANGED
@@ -6,7 +6,6 @@ const Util = require('./Util');
6
6
  const APIError = require('./APIError');
7
7
 
8
8
  class API {
9
-
10
9
  static SPECIFICATION = null;
11
10
  static SPECIFICATION_URL = null;
12
11
  static DEFINITION_CLASSES = {};
@@ -16,19 +15,13 @@ class API {
16
15
  static JSDOC_PRIVATE = null;
17
16
  static JSDOC_EXAMPLE = null;
18
17
 
19
- constructor({
20
- baseUrl,
21
- debug = false,
22
- secret = null,
23
- } = {}) {
18
+ constructor({ baseUrl, debug = false, secret = null } = {}) {
24
19
  // Set Debug Enabled
25
20
  const debugEnvKey = `${Util.envKey(this.constructor.name)}_DEBUG`;
26
21
  const debugEnv = Util.env(debugEnvKey);
27
22
 
28
23
  Object.defineProperty(this, '__debugEnabled', {
29
- value: debugEnv !== null
30
- ? !!debugEnv
31
- : !!debug,
24
+ value: debugEnv !== null ? !!debugEnv : !!debug,
32
25
  enumerable: false,
33
26
  writable: true,
34
27
  });
@@ -38,9 +31,7 @@ class API {
38
31
  const secretEnv = Util.env(secretEnvKey);
39
32
 
40
33
  Object.defineProperty(this, '__secret', {
41
- value: secretEnv !== null
42
- ? secretEnv
43
- : secret,
34
+ value: secretEnv !== null ? secretEnv : secret,
44
35
  enumerable: false,
45
36
  writable: false,
46
37
  });
@@ -49,11 +40,17 @@ class API {
49
40
  const baseUrlEnvKey = `${Util.envKey(this.constructor.name)}_BASEURL`;
50
41
  const baseUrlEnv = Util.env(baseUrlEnvKey);
51
42
 
52
- this.baseUrl = baseUrlEnv || baseUrl || `https://${this.constructor.SPECIFICATION.host}${this.constructor.SPECIFICATION.basePath}`;
53
- if (this.baseUrl.endsWith('/')) this.baseUrl = this.baseUrl.substring(0, this.baseUrl.length - 1);
43
+ this.baseUrl =
44
+ baseUrlEnv ||
45
+ baseUrl ||
46
+ `https://${this.constructor.SPECIFICATION.host}${this.constructor.SPECIFICATION.basePath}`;
47
+ if (this.baseUrl.endsWith('/'))
48
+ this.baseUrl = this.baseUrl.substring(0, this.baseUrl.length - 1);
54
49
 
55
50
  // Create Operations
56
- for (const [operationId, operation] of Object.entries(this.constructor.SPECIFICATION.operations || {})) {
51
+ for (const [operationId, operation] of Object.entries(
52
+ this.constructor.SPECIFICATION.operations || {}
53
+ )) {
57
54
  this.__registerOperation(operationId, operation);
58
55
  }
59
56
  }
@@ -81,7 +78,11 @@ class API {
81
78
  let value = args[parameterId];
82
79
 
83
80
  // Set secret if not provided as parameter but in constructor
84
- if (parameterId === 'secret' && typeof value === 'undefined' && typeof this.__secret === 'string') {
81
+ if (
82
+ parameterId === 'secret' &&
83
+ typeof value === 'undefined' &&
84
+ typeof this.__secret === 'string'
85
+ ) {
85
86
  value = this.__secret;
86
87
  }
87
88
 
@@ -97,16 +98,26 @@ class API {
97
98
  }
98
99
 
99
100
  if (typeof value !== 'undefined') {
100
- if (parameter.in !== 'query' && parameter.type === 'string' && typeof value !== 'string') {
101
- throw new Error(`Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: string`);
101
+ if (
102
+ parameter.in !== 'query' &&
103
+ parameter.type === 'string' &&
104
+ typeof value !== 'string'
105
+ ) {
106
+ throw new Error(
107
+ `Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: string`
108
+ );
102
109
  }
103
110
 
104
111
  if (parameter.type === 'number' && typeof value !== 'number') {
105
- throw new Error(`Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: number`);
112
+ throw new Error(
113
+ `Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: number`
114
+ );
106
115
  }
107
116
 
108
117
  if (parameter.type === 'boolean' && typeof value !== 'boolean') {
109
- throw new Error(`Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: boolean`);
118
+ throw new Error(
119
+ `Invalid Parameter Type: ${parameterId}. Got: ${typeof value}. Expected: boolean`
120
+ );
110
121
  }
111
122
  }
112
123
  }
@@ -149,7 +160,7 @@ class API {
149
160
  context: { operation },
150
161
  timeout: $timeout,
151
162
  timeoutMessage: $timeoutMessage,
152
- }).catch(err => {
163
+ }).catch((err) => {
153
164
  if (typeof this.__secret === 'string' && err.message.includes(this.__secret)) {
154
165
  err.message = err.message.replace(this.__secret, '<redacted>');
155
166
  }
@@ -189,7 +200,7 @@ class API {
189
200
  // Headers
190
201
  request.headers = {
191
202
  ...request.headers,
192
- ...await this.onCallRequestHeaders({ request }),
203
+ ...(await this.onCallRequestHeaders({ request })),
193
204
  };
194
205
 
195
206
  // Timeout
@@ -229,11 +240,18 @@ class API {
229
240
  async onCallRequestExecute({ request }) {
230
241
  this.__debug('onCallRequestExecute', request);
231
242
 
232
- return Util.timeout(Util.fetch(request.url, {
233
- method: request.method,
234
- headers: request.headers,
235
- body: request.body,
236
- }), request.timeout, request.timeoutMessage);
243
+ const result = await Util.fetch(
244
+ request.url,
245
+ {
246
+ method: request.method,
247
+ headers: request.headers,
248
+ body: request.body,
249
+ },
250
+ request.timeout,
251
+ request.timeoutMessage
252
+ );
253
+
254
+ return result;
237
255
  }
238
256
 
239
257
  async onCallResponse({ request, response }) {
@@ -313,7 +331,6 @@ class API {
313
331
  return body.message;
314
332
  }
315
333
 
316
-
317
334
  return body;
318
335
  }
319
336
 
@@ -343,7 +360,6 @@ class API {
343
360
 
344
361
  throw new APIError(message, statusCode);
345
362
  }
346
-
347
363
  }
348
364
 
349
365
  module.exports = API;
@@ -455,12 +455,13 @@ class HomeyAPIV3 extends HomeyAPI {
455
455
  }
456
456
 
457
457
  this.__debug(method, `${baseUrl}${path}`);
458
- const res = await Util.timeout(
459
- Util.fetch(`${baseUrl}${path}`, {
458
+ const res = await Util.fetch(
459
+ `${baseUrl}${path}`,
460
+ {
460
461
  method,
461
462
  headers,
462
463
  body,
463
- }),
464
+ },
464
465
  $timeout
465
466
  );
466
467
 
package/lib/Util.js CHANGED
@@ -14,25 +14,55 @@ class Util {
14
14
 
15
15
  /**
16
16
  * Makes a call using `window.fetch` or `node-fetch`.
17
- * @param {...any} args
18
- * @returns {Promise}
17
+ * @param {string} args
18
+ * @param {{}=} options
19
+ * @param {number=} timeoutDuration
20
+ * @param {string=} timeoutMessage
21
+ * @returns {Promise<any>}
19
22
  */
20
- static async fetch(...args) {
21
- if (this.isReactNative()) {
22
- return fetch(...args);
23
+ static async fetch(url, options, timeoutDuration, timeoutMessage) {
24
+ options = { ...options };
25
+ let abortTimeout = null;
26
+
27
+ if (timeoutDuration != null) {
28
+ const abortController = new AbortController();
29
+
30
+ abortTimeout = setTimeout(() => {
31
+ abortController.abort('Timeout');
32
+ }, timeoutDuration);
33
+
34
+ options.signal = abortController.signal;
23
35
  }
24
36
 
25
- if (this.isBrowser()) {
26
- return window.fetch(...args);
27
- }
37
+ let responsePromise = null;
28
38
 
29
- if (this.isNodeJS()) {
39
+ if (this.isReactNative()) {
40
+ responsePromise = fetch(url, options);
41
+ } else if (this.isBrowser()) {
42
+ responsePromise = window.fetch(url, options);
43
+ } else if (this.isNodeJS()) {
30
44
  const fetch = require('node-fetch');
31
- return fetch(...args);
45
+ responsePromise = fetch(url, options);
46
+ } else if (typeof fetch !== 'undefined') {
47
+ responsePromise = fetch(url, options);
48
+ } else {
49
+ throw new Error('No fetch implementation found');
32
50
  }
33
51
 
34
- if (typeof fetch !== 'undefined') {
35
- return fetch(...args);
52
+ try {
53
+ const result = await responsePromise;
54
+
55
+ return result;
56
+ } catch (err) {
57
+ if (err.name === 'AbortError') {
58
+ if (options.signal && options.signal.aborted && options.signal.reason === 'Timeout') {
59
+ throw new APIErrorTimeout(timeoutMessage ?? `Timeout after ${timeoutDuration}ms`);
60
+ }
61
+ }
62
+
63
+ throw err;
64
+ } finally {
65
+ clearTimeout(abortTimeout);
36
66
  }
37
67
  }
38
68
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homey-api",
3
- "version": "3.4.29",
3
+ "version": "3.4.30",
4
4
  "description": "Homey API",
5
5
  "main": "index.js",
6
6
  "files": [