homey-api 1.5.29 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/specifications/AthomStoreAPI.json +31 -1
- package/assets/types/homey-api.d.ts +1 -1
- package/assets/types/homey-api.private.d.ts +50 -2
- package/lib/AthomCloudAPI/StorageAdapter.js +1 -1
- package/lib/AthomCloudAPI/{StorageAdapterNodeJS.js → StorageAdapterMemory.js} +3 -3
- package/lib/AthomCloudAPI.js +16 -12
- package/lib/HomeyCloudAPI.js +3 -4
- package/lib/Util.js +71 -10
- package/package.json +1 -1
|
@@ -394,7 +394,33 @@
|
|
|
394
394
|
"type": "string",
|
|
395
395
|
"required": true
|
|
396
396
|
},
|
|
397
|
-
"
|
|
397
|
+
"paymentProvider": {
|
|
398
|
+
"type": "string",
|
|
399
|
+
"in": "body"
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
"createOfferCouponApple": {
|
|
404
|
+
"path": "/offer/coupon_apple",
|
|
405
|
+
"method": "post",
|
|
406
|
+
"parameters": {
|
|
407
|
+
"coupon": {
|
|
408
|
+
"type": "string",
|
|
409
|
+
"in": "body"
|
|
410
|
+
},
|
|
411
|
+
"expiresAt": {
|
|
412
|
+
"type": "string",
|
|
413
|
+
"in": "body"
|
|
414
|
+
},
|
|
415
|
+
"subscriptionType": {
|
|
416
|
+
"type": "string",
|
|
417
|
+
"in": "body"
|
|
418
|
+
},
|
|
419
|
+
"subscriptionQuantity": {
|
|
420
|
+
"type": "number",
|
|
421
|
+
"in": "body"
|
|
422
|
+
},
|
|
423
|
+
"subscriptionDuration": {
|
|
398
424
|
"type": "string",
|
|
399
425
|
"in": "body"
|
|
400
426
|
}
|
|
@@ -417,6 +443,10 @@
|
|
|
417
443
|
"type": "string",
|
|
418
444
|
"in": "body"
|
|
419
445
|
},
|
|
446
|
+
"campaignId": {
|
|
447
|
+
"type": "string",
|
|
448
|
+
"in": "body"
|
|
449
|
+
},
|
|
420
450
|
"subscriptionType": {
|
|
421
451
|
"type": "string",
|
|
422
452
|
"in": "body"
|
|
@@ -4738,7 +4738,42 @@
|
|
|
4738
4738
|
|
|
4739
4739
|
|
|
4740
4740
|
|
|
4741
|
-
|
|
4741
|
+
paymentProvider: string,
|
|
4742
|
+
|
|
4743
|
+
|
|
4744
|
+
},
|
|
4745
|
+
|
|
4746
|
+
|
|
4747
|
+
|
|
4748
|
+
|
|
4749
|
+
):
|
|
4750
|
+
Promise<any>;
|
|
4751
|
+
|
|
4752
|
+
createOfferCouponApple(
|
|
4753
|
+
|
|
4754
|
+
|
|
4755
|
+
|
|
4756
|
+
|
|
4757
|
+
opts: {
|
|
4758
|
+
|
|
4759
|
+
|
|
4760
|
+
coupon: string,
|
|
4761
|
+
|
|
4762
|
+
|
|
4763
|
+
|
|
4764
|
+
expiresAt: string,
|
|
4765
|
+
|
|
4766
|
+
|
|
4767
|
+
|
|
4768
|
+
subscriptionType: string,
|
|
4769
|
+
|
|
4770
|
+
|
|
4771
|
+
|
|
4772
|
+
subscriptionQuantity: number,
|
|
4773
|
+
|
|
4774
|
+
|
|
4775
|
+
|
|
4776
|
+
subscriptionDuration: string,
|
|
4742
4777
|
|
|
4743
4778
|
|
|
4744
4779
|
},
|
|
@@ -4770,6 +4805,10 @@
|
|
|
4770
4805
|
|
|
4771
4806
|
|
|
4772
4807
|
|
|
4808
|
+
campaignId: string,
|
|
4809
|
+
|
|
4810
|
+
|
|
4811
|
+
|
|
4773
4812
|
subscriptionType: string,
|
|
4774
4813
|
|
|
4775
4814
|
|
|
@@ -5598,6 +5637,15 @@
|
|
|
5598
5637
|
|
|
5599
5638
|
|
|
5600
5639
|
|
|
5640
|
+
):
|
|
5641
|
+
boolean;
|
|
5642
|
+
|
|
5643
|
+
isReactNative(
|
|
5644
|
+
|
|
5645
|
+
|
|
5646
|
+
|
|
5647
|
+
|
|
5648
|
+
|
|
5601
5649
|
):
|
|
5602
5650
|
boolean;
|
|
5603
5651
|
|
|
@@ -5805,7 +5853,7 @@
|
|
|
5805
5853
|
|
|
5806
5854
|
}
|
|
5807
5855
|
|
|
5808
|
-
export class
|
|
5856
|
+
export class StorageAdapterMemory extends StorageAdapter {
|
|
5809
5857
|
|
|
5810
5858
|
|
|
5811
5859
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Abstract storage adapter. To be extended by your own, or {@link AthomCloudAPI.StorageAdapterBrowser} or {@link AthomCloudAPI.
|
|
4
|
+
* Abstract storage adapter. To be extended by your own, or {@link AthomCloudAPI.StorageAdapterBrowser} or {@link AthomCloudAPI.StorageAdapterMemory}.
|
|
5
5
|
* @class
|
|
6
6
|
* @memberof AthomCloudAPI
|
|
7
7
|
*/
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
const StorageAdapter = require('./StorageAdapter');
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* In-memory storage adapter for Node.js.
|
|
6
|
+
* In-memory storage adapter for Node.js or React Native.
|
|
7
7
|
* @class
|
|
8
8
|
* @extends StorageAdapter
|
|
9
9
|
* @memberof AthomCloudAPI
|
|
10
10
|
*/
|
|
11
|
-
class
|
|
11
|
+
class StorageAdapterMemory extends StorageAdapter {
|
|
12
12
|
|
|
13
13
|
constructor() {
|
|
14
14
|
super();
|
|
@@ -34,4 +34,4 @@ class StorageAdapterNodeJS extends StorageAdapter {
|
|
|
34
34
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
module.exports =
|
|
37
|
+
module.exports = StorageAdapterMemory;
|
package/lib/AthomCloudAPI.js
CHANGED
|
@@ -9,7 +9,7 @@ const Homey = require('./AthomCloudAPI/Homey');
|
|
|
9
9
|
const Token = require('./AthomCloudAPI/Token');
|
|
10
10
|
const StorageAdapter = require('./AthomCloudAPI/StorageAdapter');
|
|
11
11
|
const StorageAdapterBrowser = require('./AthomCloudAPI/StorageAdapterBrowser');
|
|
12
|
-
const
|
|
12
|
+
const StorageAdapterMemory = require('./AthomCloudAPI/StorageAdapterMemory');
|
|
13
13
|
|
|
14
14
|
class AthomCloudAPI extends API {
|
|
15
15
|
|
|
@@ -18,7 +18,7 @@ class AthomCloudAPI extends API {
|
|
|
18
18
|
static Token = Token;
|
|
19
19
|
static StorageAdapter = StorageAdapter;
|
|
20
20
|
static StorageAdapterBrowser = StorageAdapterBrowser;
|
|
21
|
-
static
|
|
21
|
+
static StorageAdapterMemory = StorageAdapterMemory;
|
|
22
22
|
|
|
23
23
|
static SPECIFICATION = require('../assets/specifications/AthomCloudAPI.json');
|
|
24
24
|
static SPECIFICATION_URL = 'https://api.athom.com/specification.json';
|
|
@@ -75,7 +75,7 @@ for(const device of Object.values(devices)) {
|
|
|
75
75
|
@param {string} opts.redirectUrl
|
|
76
76
|
@param {boolean} [opts.autoRefreshTokens=true]
|
|
77
77
|
@param {AthomCloudAPI.Token} [opts.token=null]
|
|
78
|
-
@param {AthomCloudAPI.StorageAdapter} [opts.store={@link AthomCloudAPI.StorageAdapterBrowser} or {@link AthomCloudAPI.
|
|
78
|
+
@param {AthomCloudAPI.StorageAdapter} [opts.store={@link AthomCloudAPI.StorageAdapterBrowser} or {@link AthomCloudAPI.StorageAdapterMemory}]`;
|
|
79
79
|
|
|
80
80
|
constructor({
|
|
81
81
|
clientId,
|
|
@@ -85,7 +85,7 @@ for(const device of Object.values(devices)) {
|
|
|
85
85
|
token = null,
|
|
86
86
|
store = Util.isBrowser()
|
|
87
87
|
? new StorageAdapterBrowser()
|
|
88
|
-
: new
|
|
88
|
+
: new StorageAdapterMemory(),
|
|
89
89
|
...args
|
|
90
90
|
} = {}) {
|
|
91
91
|
super({ ...args });
|
|
@@ -304,10 +304,11 @@ for(const device of Object.values(devices)) {
|
|
|
304
304
|
body.append('grant_type', 'client_credentials');
|
|
305
305
|
|
|
306
306
|
const response = await Util.fetch(`${this.baseUrl}/oauth2/token`, {
|
|
307
|
-
body,
|
|
307
|
+
body: body.toString(),
|
|
308
308
|
method: 'post',
|
|
309
309
|
headers: {
|
|
310
|
-
Authorization: `Basic ${Util.base64(`${this.__clientId}:${this.__clientSecret}`)}`,
|
|
310
|
+
'Authorization': `Basic ${Util.base64(`${this.__clientId}:${this.__clientSecret}`)}`,
|
|
311
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
311
312
|
},
|
|
312
313
|
});
|
|
313
314
|
|
|
@@ -358,10 +359,11 @@ for(const device of Object.values(devices)) {
|
|
|
358
359
|
body.append('code', code);
|
|
359
360
|
|
|
360
361
|
const response = await Util.fetch(`${this.baseUrl}/oauth2/token`, {
|
|
361
|
-
body,
|
|
362
|
+
body: body.toString(),
|
|
362
363
|
method: 'post',
|
|
363
364
|
headers: {
|
|
364
|
-
Authorization: `Basic ${Util.base64(`${this.__clientId}:${this.__clientSecret}`)}`,
|
|
365
|
+
'Authorization': `Basic ${Util.base64(`${this.__clientId}:${this.__clientSecret}`)}`,
|
|
366
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
365
367
|
},
|
|
366
368
|
});
|
|
367
369
|
|
|
@@ -418,10 +420,11 @@ for(const device of Object.values(devices)) {
|
|
|
418
420
|
body.append('password', password);
|
|
419
421
|
|
|
420
422
|
const response = await Util.fetch(`${this.baseUrl}/oauth2/token`, {
|
|
421
|
-
body,
|
|
423
|
+
body: body.toString(),
|
|
422
424
|
method: 'post',
|
|
423
425
|
headers: {
|
|
424
|
-
Authorization: `Basic ${Util.base64(`${this.__clientId}:${this.__clientSecret}`)}`,
|
|
426
|
+
'Authorization': `Basic ${Util.base64(`${this.__clientId}:${this.__clientSecret}`)}`,
|
|
427
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
425
428
|
},
|
|
426
429
|
});
|
|
427
430
|
|
|
@@ -462,10 +465,11 @@ for(const device of Object.values(devices)) {
|
|
|
462
465
|
body.append('refresh_token', this.__token.refresh_token);
|
|
463
466
|
|
|
464
467
|
const response = await Util.fetch(`${this.baseUrl}/oauth2/token`, {
|
|
465
|
-
body,
|
|
468
|
+
body: body.toString(),
|
|
466
469
|
method: 'post',
|
|
467
470
|
headers: {
|
|
468
|
-
Authorization: `Basic ${Util.base64(`${this.__clientId}:${this.__clientSecret}`)}`,
|
|
471
|
+
'Authorization': `Basic ${Util.base64(`${this.__clientId}:${this.__clientSecret}`)}`,
|
|
472
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
469
473
|
},
|
|
470
474
|
});
|
|
471
475
|
|
package/lib/HomeyCloudAPI.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const fetch = require('node-fetch');
|
|
4
|
-
|
|
5
3
|
const API = require('./API');
|
|
6
4
|
const APIError = require('./APIError');
|
|
5
|
+
const Util = require('./Util');
|
|
7
6
|
|
|
8
7
|
class HomeyCloudAPI extends API {
|
|
9
8
|
|
|
@@ -26,7 +25,7 @@ class HomeyCloudAPI extends API {
|
|
|
26
25
|
* @returns {string} result.region - e.g. `eu-central-1`
|
|
27
26
|
*/
|
|
28
27
|
static async getClosestRegion() {
|
|
29
|
-
const res = await fetch(`https://${HomeyCloudAPI.SPECIFICATION.host}`);
|
|
28
|
+
const res = await Util.fetch(`https://${HomeyCloudAPI.SPECIFICATION.host}`);
|
|
30
29
|
if (!res.ok) {
|
|
31
30
|
throw new Error(res.statusText || 'Unknown Error');
|
|
32
31
|
}
|
|
@@ -56,7 +55,7 @@ class HomeyCloudAPI extends API {
|
|
|
56
55
|
* @returns {Promise<object>} result
|
|
57
56
|
*/
|
|
58
57
|
async getSystemStatus({ secret }) {
|
|
59
|
-
const res = await fetch(`${this.baseUrl}/api/system/status`, {
|
|
58
|
+
const res = await Util.fetch(`${this.baseUrl}/api/system/status`, {
|
|
60
59
|
headers: {
|
|
61
60
|
'X-Homey-Secret': secret,
|
|
62
61
|
},
|
package/lib/Util.js
CHANGED
|
@@ -18,13 +18,22 @@ class Util {
|
|
|
18
18
|
* @returns {Promise}
|
|
19
19
|
*/
|
|
20
20
|
static async fetch(...args) {
|
|
21
|
-
|
|
21
|
+
if (this.isReactNative()) {
|
|
22
|
+
return fetch(...args);
|
|
23
|
+
}
|
|
24
|
+
|
|
22
25
|
if (this.isBrowser()) {
|
|
23
26
|
return window.fetch(...args);
|
|
24
27
|
}
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
if (this.isNodeJS()) {
|
|
30
|
+
const fetch = require('node-fetch');
|
|
31
|
+
return fetch(...args);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (typeof fetch !== 'undefined') {
|
|
35
|
+
return fetch(...args);
|
|
36
|
+
}
|
|
28
37
|
}
|
|
29
38
|
|
|
30
39
|
/**
|
|
@@ -81,17 +90,26 @@ class Util {
|
|
|
81
90
|
return window.location.protocol === 'http:';
|
|
82
91
|
}
|
|
83
92
|
|
|
93
|
+
/**
|
|
94
|
+
* @returns {boolean}
|
|
95
|
+
*/
|
|
96
|
+
static isReactNative() {
|
|
97
|
+
return (typeof navigator !== 'undefined' && navigator.product === 'ReactNative');
|
|
98
|
+
}
|
|
99
|
+
|
|
84
100
|
/**
|
|
85
101
|
* @returns {boolean}
|
|
86
102
|
*/
|
|
87
103
|
static isBrowser() {
|
|
88
|
-
|
|
104
|
+
if (this.isReactNative()) return false;
|
|
105
|
+
return (typeof document !== 'undefined' && typeof document.window !== 'undefined');
|
|
89
106
|
}
|
|
90
107
|
|
|
91
108
|
/**
|
|
92
109
|
* @returns {boolean}
|
|
93
110
|
*/
|
|
94
111
|
static isNodeJS() {
|
|
112
|
+
if (this.isReactNative()) return false;
|
|
95
113
|
return (typeof process !== 'undefined');
|
|
96
114
|
}
|
|
97
115
|
|
|
@@ -119,19 +137,58 @@ class Util {
|
|
|
119
137
|
}
|
|
120
138
|
|
|
121
139
|
/**
|
|
140
|
+
* This method encodes a string into a base64 string.
|
|
141
|
+
* It's provided as Util because Node.js uses `Buffer`,
|
|
142
|
+
* browsers use `btoa` and React Native doesn't provide anything.
|
|
122
143
|
* @param {string} input - Input
|
|
123
144
|
* @returns {string} - Base64 encoded output
|
|
124
145
|
*/
|
|
125
|
-
static base64(
|
|
126
|
-
|
|
127
|
-
|
|
146
|
+
static base64(s) {
|
|
147
|
+
function btoaLookup(index) {
|
|
148
|
+
if (index >= 0 && index < 64) {
|
|
149
|
+
const keystr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
150
|
+
return keystr[index];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Throw INVALID_CHARACTER_ERR exception here -- won't be hit in the tests.
|
|
154
|
+
return undefined;
|
|
128
155
|
}
|
|
129
156
|
|
|
130
|
-
if (typeof
|
|
131
|
-
|
|
157
|
+
if (typeof s !== 'string') {
|
|
158
|
+
throw new Error('Invalid Input');
|
|
132
159
|
}
|
|
133
160
|
|
|
134
|
-
|
|
161
|
+
let i;
|
|
162
|
+
|
|
163
|
+
// "The btoa() method must throw an "InvalidCharacterError" DOMException if
|
|
164
|
+
// data contains any character whose code point is greater than U+00FF."
|
|
165
|
+
for (i = 0; i < s.length; i++) {
|
|
166
|
+
if (s.charCodeAt(i) > 255) {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
let out = '';
|
|
171
|
+
for (i = 0; i < s.length; i += 3) {
|
|
172
|
+
const groupsOfSix = [undefined, undefined, undefined, undefined];
|
|
173
|
+
groupsOfSix[0] = s.charCodeAt(i) >> 2;
|
|
174
|
+
groupsOfSix[1] = (s.charCodeAt(i) & 0x03) << 4;
|
|
175
|
+
if (s.length > i + 1) {
|
|
176
|
+
groupsOfSix[1] |= s.charCodeAt(i + 1) >> 4;
|
|
177
|
+
groupsOfSix[2] = (s.charCodeAt(i + 1) & 0x0f) << 2;
|
|
178
|
+
}
|
|
179
|
+
if (s.length > i + 2) {
|
|
180
|
+
groupsOfSix[2] |= s.charCodeAt(i + 2) >> 6;
|
|
181
|
+
groupsOfSix[3] = s.charCodeAt(i + 2) & 0x3f;
|
|
182
|
+
}
|
|
183
|
+
for (let j = 0; j < groupsOfSix.length; j++) {
|
|
184
|
+
if (typeof groupsOfSix[j] === 'undefined') {
|
|
185
|
+
out += '=';
|
|
186
|
+
} else {
|
|
187
|
+
out += btoaLookup(groupsOfSix[j]);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return out;
|
|
135
192
|
}
|
|
136
193
|
|
|
137
194
|
/**
|
|
@@ -161,6 +218,10 @@ class Util {
|
|
|
161
218
|
return process.env[key] || null;
|
|
162
219
|
}
|
|
163
220
|
|
|
221
|
+
if (this.isReactNative()) {
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
|
|
164
225
|
return null;
|
|
165
226
|
}
|
|
166
227
|
|