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.
- package/assets/specifications/AthomAppsAPI.json +11 -0
- package/assets/types/homey-api.private.d.ts +44 -4
- package/lib/API.js +45 -29
- package/lib/HomeyAPI/HomeyAPIV3.js +4 -3
- package/lib/Util.js +42 -12
- package/package.json +1 -1
|
@@ -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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
53
|
-
|
|
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(
|
|
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 (
|
|
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 (
|
|
101
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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.
|
|
459
|
-
|
|
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 {
|
|
18
|
-
* @
|
|
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(
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
26
|
-
return window.fetch(...args);
|
|
27
|
-
}
|
|
37
|
+
let responsePromise = null;
|
|
28
38
|
|
|
29
|
-
if (this.
|
|
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
|
-
|
|
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
|
-
|
|
35
|
-
|
|
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
|
|