homey-api 3.0.0-rc.9 → 3.0.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.
@@ -1,3 +1,5 @@
1
+ /* eslint-disable no-unused-vars */
2
+
1
3
  'use strict';
2
4
 
3
5
  const Item = require('../Item');
@@ -9,7 +11,100 @@ class Flow extends Item {
9
11
  * @returns Promise<Boolean>
10
12
  */
11
13
  async isBroken() {
12
- throw new Error('Not Implemented');
14
+ const managerFlow = this.homey.flow;
15
+ if (!managerFlow.isConnected()) {
16
+ throw new Error('Flow.isBroken requires ManagerFlow to be connected.');
17
+ }
18
+
19
+ const managerFlowToken = this.homey.flowtoken;
20
+ if (!managerFlowToken.isConnected()) {
21
+ throw new Error('Flow.isBroken requires ManagerFlowToken to be connected.');
22
+ }
23
+
24
+ // Array of local & global Token IDs.
25
+ // For example [ 'foo', 'homey:x:y|abc' ]
26
+ const tokenIds = [];
27
+
28
+ const checkToken = async tokenId => {
29
+ // If this is a global Token, fetch all FlowTokens
30
+ if (tokenId.includes('|')) {
31
+ const flowTokens = await managerFlowToken.getFlowTokens(); // Fill the cache
32
+ for (const flowTokenId of Object.keys(flowTokens)) {
33
+ tokenIds.push(flowTokenId);
34
+ }
35
+
36
+ tokenId = tokenId.replace('|', ':');
37
+ }
38
+
39
+ if (!tokenIds.includes(tokenId)) {
40
+ throw new Error(`Missing Token: ${tokenId}`);
41
+ }
42
+ };
43
+
44
+ const checkTokens = async card => {
45
+ // Check droptoken
46
+ if (card.droptoken) {
47
+ await checkToken(card.droptoken);
48
+ }
49
+
50
+ if (typeof card.args === 'object') {
51
+ for (const arg of Object.values(card.args)) {
52
+ if (typeof arg !== 'string') continue;
53
+ for (const [tokenMatch, tokenId] of arg.matchAll(/\[\[(.*?)\]\]/g)) {
54
+ await checkToken(tokenId);
55
+ }
56
+ }
57
+ }
58
+ };
59
+
60
+ // Check Trigger
61
+ if (this.trigger) {
62
+ try {
63
+ await managerFlow.getFlowCardTriggers(); // Fill the cache
64
+ const triggerCard = await this.manager.getFlowCardTrigger({ id: this.trigger.id });
65
+ await checkTokens(this.trigger);
66
+
67
+ // Add FlowCardTrigger.tokens to internal tokens cache
68
+ if (Array.isArray(triggerCard.tokens)) {
69
+ for (const tokenId of Object.keys(triggerCard.tokens)) {
70
+ tokenIds.push(tokenId);
71
+ }
72
+ }
73
+ } catch (err) {
74
+ this.__debug(err.message);
75
+ return true;
76
+ }
77
+ }
78
+
79
+ // Check Conditions
80
+ if (Array.isArray(this.conditions)) {
81
+ for (const condition of Object.values(this.conditions)) {
82
+ try {
83
+ await managerFlow.getFlowCardConditions(); // Fill the cache
84
+ const conditionCard = await this.manager.getFlowCardCondition({ id: condition.id });
85
+ await checkTokens(condition);
86
+ } catch (err) {
87
+ this.__debug(err.message);
88
+ return true;
89
+ }
90
+ }
91
+ }
92
+
93
+ // Check Actions
94
+ if (Array.isArray(this.actions)) {
95
+ for (const action of Object.values(this.actions)) {
96
+ try {
97
+ await managerFlow.getFlowCardActions(); // Fill the cache
98
+ const actionCard = await this.manager.getFlowCardAction({ id: action.id });
99
+ await checkTokens(action);
100
+ } catch (err) {
101
+ this.__debug(err.message);
102
+ return true;
103
+ }
104
+ }
105
+ }
106
+
107
+ return false;
13
108
  }
14
109
 
15
110
  }
@@ -4,14 +4,19 @@ const Item = require('../Item');
4
4
 
5
5
  class FlowToken extends Item {
6
6
 
7
- // TODO: Remove when back-end has removed these properties.
8
7
  static transformGet(item) {
9
8
  item = super.transformGet(item);
10
9
 
11
- delete item.uri;
12
- delete item.id;
10
+ if (item.uri) {
11
+ item.id = `${item.uri}:${item.id}`;
12
+ delete item.uri;
13
+ }
14
+
15
+ // TODO: Remove when back-end has removed these properties.
13
16
  delete item.uriObj;
14
17
  delete item.ownerName; // Prepare for back-end change
18
+
19
+ return item;
15
20
  }
16
21
 
17
22
  }
@@ -16,6 +16,7 @@ const ManagerInsights = require('./HomeyAPIV3/ManagerInsights');
16
16
  const Manager = require('./HomeyAPIV3/Manager');
17
17
 
18
18
  /**
19
+ * An authenticated Homey API. Do not construct this class manually.
19
20
  * @class
20
21
  * @hideconstructor
21
22
  * @extends HomeyAPIV2
@@ -378,32 +379,32 @@ class HomeyAPIV3 extends HomeyAPI {
378
379
  headers,
379
380
  path,
380
381
  body,
382
+ json = true,
381
383
  retryAfterRefresh = false,
382
384
  }) {
383
385
  const baseUrl = await this.baseUrl;
384
386
 
385
- method = method.toUpperCase();
387
+ method = String(method).toUpperCase();
386
388
 
387
389
  headers = {
388
390
  ...headers,
389
391
  'X-Homey-ID': this.id,
390
392
  };
391
393
 
392
- if (body) {
393
- headers['Content-Type'] = 'application/json';
394
- }
395
-
396
394
  if (this.__token) {
397
395
  headers['Authorization'] = `Bearer ${this.__token}`;
398
396
  }
399
397
 
398
+ if (body && json === true && ['PUT', 'POST'].includes(method)) {
399
+ headers['Content-Type'] = 'application/json';
400
+ body = JSON.stringify(body);
401
+ }
402
+
400
403
  this.__debug(method, `${baseUrl}${path}`);
401
404
  const res = await Util.timeout(Util.fetch(`${baseUrl}${path}`, {
402
405
  method,
403
406
  headers,
404
- body: ['PUT', 'POST'].includes(method) && typeof body !== 'undefined'
405
- ? JSON.stringify(body)
406
- : undefined,
407
+ body,
407
408
  }), $timeout);
408
409
 
409
410
  const resStatusCode = res.status;
@@ -477,16 +478,20 @@ class HomeyAPIV3 extends HomeyAPI {
477
478
 
478
479
  // Create a Session by generating a JWT token on AthomCloudAPI,
479
480
  // and then sending the JWT token to Homey.
480
- this.__debug('Retrieving token...');
481
- const jwtToken = await this.__api.createDelegationToken({ audience: 'homey' });
482
- const token = await this.users.login({
483
- $socket: false,
484
- token: jwtToken,
485
- });
486
- await this.__setStore({ token });
487
- this.__debug('Got token');
481
+ if (this.__api) {
482
+ this.__debug('Retrieving token...');
483
+ const jwtToken = await this.__api.createDelegationToken({ audience: 'homey' });
484
+ const token = await this.users.login({
485
+ $socket: false,
486
+ token: jwtToken,
487
+ });
488
+ await this.__setStore({ token });
489
+ this.__debug('Got token');
490
+
491
+ return token;
492
+ }
488
493
 
489
- return token;
494
+ throw new Error('Cannot Sign In: Missing AthomCloudAPI');
490
495
  });
491
496
 
492
497
  this.__loginPromise
@@ -33,6 +33,14 @@ class HomeyAPIV3Cloud extends HomeyAPIV3 {
33
33
  });
34
34
  }
35
35
 
36
+ get platform() {
37
+ return 'cloud';
38
+ }
39
+
40
+ get platformVersion() {
41
+ return 1;
42
+ }
43
+
36
44
  getSpecification() {
37
45
  // eslint-disable-next-line global-require
38
46
  return require('../../assets/specifications/HomeyAPIV3Cloud.json');
@@ -0,0 +1,32 @@
1
+ 'use strict';
2
+
3
+ const FormData = require('form-data');
4
+
5
+ const Manager = require('./Manager');
6
+
7
+ class ManagerDevkit extends Manager {
8
+
9
+ async runApp({
10
+ app, // Readable
11
+ env = {},
12
+ debug = false,
13
+ clean = false,
14
+ }) {
15
+ const form = new FormData();
16
+ form.append('app', app);
17
+ form.append('env', JSON.stringify(env));
18
+ form.append('debug', debug ? 'true' : 'false');
19
+ form.append('purgeSettings', clean ? 'true' : 'false');
20
+
21
+ return this.homey.call({
22
+ $timeout: 1000 * 60 * 5, // 5 minutes
23
+ method: 'POST',
24
+ path: '/api/manager/devkit/',
25
+ body: form,
26
+ json: false,
27
+ });
28
+ }
29
+
30
+ }
31
+
32
+ module.exports = ManagerDevkit;
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const HomeyAPIV3 = require('./HomeyAPIV3');
4
+ const ManagerDevkit = require('./HomeyAPIV3Local/ManagerDevkit');
4
5
 
5
6
  /**
6
7
  * This class is returned by {@link AthomCloudAPI.Homey#authenticate} for a Homey with `platform: 'local'` and `platformVersion: 1`.
@@ -11,6 +12,19 @@ const HomeyAPIV3 = require('./HomeyAPIV3');
11
12
  */
12
13
  class HomeyAPIV3Local extends HomeyAPIV3 {
13
14
 
15
+ static MANAGERS = {
16
+ ...HomeyAPIV3.MANAGERS,
17
+ ManagerDevkit,
18
+ };
19
+
20
+ get platform() {
21
+ return 'local';
22
+ }
23
+
24
+ get platformVersion() {
25
+ return 2;
26
+ }
27
+
14
28
  getSpecification() {
15
29
  // eslint-disable-next-line global-require
16
30
  return require('../../assets/specifications/HomeyAPIV3Local.json');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homey-api",
3
- "version": "3.0.0-rc.9",
3
+ "version": "3.0.1",
4
4
  "description": "Homey API",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -23,8 +23,8 @@
23
23
  "build:jsdoc": "npm run jsdoc",
24
24
  "webpack": "webpack",
25
25
  "webpack:watch": "webpack --watch",
26
- "jsdoc": "npm run jsdoc:clean; npm run generate-specs; npm run generate-jsdoc; jsdoc --configure ./jsdoc.json --recurse; jsdoc --configure ./jsdoc.json --recurse --private --destination ./jsdoc/private; rm ./jsdoc/*.js.html;",
27
- "jsdoc:clean": "rm -rf ./build/jsdoc; rm -rf ./build/jsdoc-tmp",
26
+ "jsdoc": "npm run jsdoc:clean; cp -r ./lib/ ./build/jsdoc-tmp; npm run generate-specs; npm run generate-jsdoc; jsdoc --configure ./jsdoc.json --recurse; jsdoc --configure ./jsdoc.json --recurse --private --destination ./jsdoc/private; rm ./jsdoc/*.js.html;",
27
+ "jsdoc:clean": "rm -rf ./build/jsdoc/; rm -rf ./build/jsdoc-tmp/",
28
28
  "jsdoc:watch": "watch \"npm run jsdoc:clean; npm run generate-jsdoc; npm run jsdoc;\" lib \"node_modules/@athombv/jsdoc-template\" --interval 0.5",
29
29
  "jsdoc:serve": "http-server ./jsdoc/",
30
30
  "generate-specs": "node tools/generate-specs.js",
@@ -46,6 +46,7 @@
46
46
  },
47
47
  "dependencies": {
48
48
  "core-js": "^3.19.1",
49
+ "form-data": "^4.0.0",
49
50
  "node-fetch": "^2.6.7",
50
51
  "regenerator-runtime": "^0.13.9",
51
52
  "socket.io-client": "^2.5.0"