homey-lib 2.42.1 → 2.43.0

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.
@@ -23,6 +23,10 @@ on:
23
23
  push:
24
24
  branches:
25
25
  - production
26
+
27
+ permissions:
28
+ id-token: write
29
+ contents: read
26
30
 
27
31
  jobs:
28
32
  deploy_to_npm:
@@ -48,18 +52,16 @@ jobs:
48
52
  git config --local user.name "Homey Github Actions Bot"
49
53
 
50
54
  # Configures a Node.js environment.
51
- - name: Set up node 12 environment
52
- uses: actions/setup-node@v1
55
+ - uses: actions/setup-node@v4
53
56
  with:
54
- node-version: '12'
55
- # Needed for publishing to npm
57
+ node-version: '24'
56
58
  registry-url: 'https://registry.npmjs.org'
57
59
 
58
60
  # Run `npm ci && npm run build` to re-create your local environment (make sure to commit your - package-lock.json!).
59
61
  - name: Build
60
62
  run: |
61
63
  npm ci
62
- npm run build
64
+ npm run build --if-present
63
65
 
64
66
  - name: Commit and push webpack build artefact
65
67
  run: |
@@ -97,8 +99,6 @@ jobs:
97
99
  npm publish
98
100
  VERSION="$(node -p "require('./package.json').version")"
99
101
  echo package_version=${VERSION} >> $GITHUB_ENV
100
- env:
101
- NODE_AUTH_TOKEN: ${{secrets.NPM_AUTH_TOKEN}}
102
102
 
103
103
  trigger-repository-dispatch-event:
104
104
  needs: deploy_to_npm
@@ -148,18 +148,10 @@ jobs:
148
148
  -H 'Authorization: token ${{ secrets.HOMEY_GITHUB_ACTIONS_BOT_PERSONAL_ACCESS_TOKEN }}' \
149
149
  -d '{"event_type": "update-homey-lib"}'
150
150
 
151
- - name: Trigger repository dispatch event athombv/node-homey-core
152
- run: |
153
- curl -X POST \
154
- https://api.github.com/repos/athombv/node-homey-core/dispatches \
155
- -H 'Accept: application/vnd.github.everest-preview+json' \
156
- -H 'Authorization: token ${{ secrets.HOMEY_GITHUB_ACTIONS_BOT_PERSONAL_ACCESS_TOKEN }}' \
157
- -d '{"event_type": "update-homey-lib"}'
158
-
159
- - name: Trigger repository dispatch event athombv/node-homey-pro
151
+ - name: Trigger repository dispatch event athombv/node-homey-os
160
152
  run: |
161
153
  curl -X POST \
162
- https://api.github.com/repos/athombv/node-homey-pro/dispatches \
154
+ https://api.github.com/repos/athombv/node-homey-os/dispatches \
163
155
  -H 'Accept: application/vnd.github.everest-preview+json' \
164
156
  -H 'Authorization: token ${{ secrets.HOMEY_GITHUB_ACTIONS_BOT_PERSONAL_ACCESS_TOKEN }}' \
165
157
  -d '{"event_type": "update-homey-lib"}'
@@ -1029,6 +1029,10 @@
1029
1029
  "enum": ["nfc", "speaker", "ledring", "matter", "camera-streaming"]
1030
1030
  }
1031
1031
  },
1032
+ "runtime": {
1033
+ "type": "string",
1034
+ "enum": ["nodejs", "python"]
1035
+ },
1032
1036
  "tags": {
1033
1037
  "$ref": "#/definitions/i18nArray"
1034
1038
  },
package/lib/App/index.js CHANGED
@@ -211,16 +211,29 @@ class App {
211
211
  }
212
212
  }
213
213
 
214
+ // validate that Python apps target compatibility of at least >=13.0.0
215
+ if (appJson.runtime === 'python') {
216
+ const minVersion = semver.minVersion(appJson.compatibility);
217
+ if (!semver.gte(minVersion, '13.0.0')) {
218
+ throw new Error(`Invalid compatibility (${appJson.compatibility}), Python apps must have a compatibility of at least >=13.0.0`);
219
+ }
220
+ }
221
+
222
+ // validate that Python apps use sdk v3
223
+ if (appJson.runtime === 'python' && appJson.sdk !== 3) {
224
+ throw new Error(`Invalid sdk (${appJson.sdk}), Python apps must use sdk version 3`);
225
+ }
226
+
214
227
  // validate that there are no platform local required features defined when targetting cloud
215
- if ((appJson.platforms || []).includes('cloud')
216
- && (appJson.platformLocalRequiredFeatures || []).length > 0) {
217
- throw new Error('The property `platformLocalRequiredFeatures` can not be used in combination with platform: `cloud`.');
228
+ if ((appJson.platforms || []).includes('cloud')
229
+ && (appJson.platformLocalRequiredFeatures || []).length > 0) {
230
+ throw new Error('The property `platformLocalRequiredFeatures` can not be used in combination with platform: `cloud`.');
218
231
  }
219
232
 
220
233
  // validate that platforms includes local when using platformLocalRequiredFeatures
221
234
  if ((appJson.platforms || []).includes('local') === false
222
- && (appJson.platformLocalRequiredFeatures || []).length > 0) {
223
- console.warn('Warning: using `platformLocalRequiredFeatures` requires `platforms: [local]`.');
235
+ && (appJson.platformLocalRequiredFeatures || []).length > 0) {
236
+ console.warn('Warning: using `platformLocalRequiredFeatures` requires `platforms: [local]`.');
224
237
  }
225
238
 
226
239
  // validate that platforms includes local when using platformLocalOptionalFeatures
@@ -482,7 +495,7 @@ class App {
482
495
  }
483
496
  }
484
497
 
485
- if (driver.energy.homeBattery === true && hasMeterPowerCapability) {
498
+ if (driver.energy.homeBattery === true && hasMeterPowerCapability) {
486
499
  if (typeof driver.energy.meterPowerImportedCapability !== 'string') {
487
500
  console.warn(`Warning: drivers.${driver.id} has energy.homeBattery set to true, but is missing 'meterPowerImportedCapability'.`);
488
501
  }
@@ -491,7 +504,7 @@ class App {
491
504
  }
492
505
  }
493
506
 
494
- if (driver.energy.evCharger === true && hasMeterPowerCapability) {
507
+ if (driver.energy.evCharger === true && hasMeterPowerCapability) {
495
508
  if (typeof driver.energy.meterPowerImportedCapability !== 'string') {
496
509
  console.warn(`Warning: drivers.${driver.id} has energy.evCharger set to true, but is missing 'meterPowerImportedCapability'.`);
497
510
  }
@@ -503,7 +516,7 @@ class App {
503
516
  if (typeof driver.energy.cumulativeExportedCapability === 'string' && Capability.isInstanceOfId(driver.energy.cumulativeExportedCapability, 'meter_power') === false) {
504
517
  throw new Error(`drivers.${driver.id} has 'cumulativeExportedCapability': '${driver.energy.cumulativeExportedCapability}' but only instances of 'meter_power' are allowed.`);
505
518
  }
506
-
519
+
507
520
  if (typeof driver.energy.meterPowerImportedCapability === 'string' && Capability.isInstanceOfId(driver.energy.meterPowerImportedCapability, 'meter_power') === false) {
508
521
  throw new Error(`drivers.${driver.id} has 'meterPowerImportedCapability': '${driver.energy.meterPowerImportedCapability}' but only instances of 'meter_power' are allowed.`);
509
522
  }
@@ -530,7 +543,7 @@ class App {
530
543
 
531
544
  const deviceJsExists = await this._fileExistsCaseSensitive(join('drivers', driver.id, 'device.js'));
532
545
  const deviceMjsExists = await this._fileExistsCaseSensitive(join('drivers', driver.id, 'device.mjs'));
533
-
546
+
534
547
  if (deviceJsExists || deviceMjsExists) {
535
548
  throw new Error(`drivers.${driver.id}: using a device.${deviceJsExists ? 'js' : 'mjs'} file is not supported for Matter drivers.`);
536
549
  }
@@ -651,11 +664,6 @@ class App {
651
664
  }
652
665
  }
653
666
 
654
- // validate if `/app.js` exists
655
- if (!appJson.sdk || appJson.sdk === 1) {
656
- await this._ensureFileExistsCaseSensitive('app.js');
657
- }
658
-
659
667
  // validate `/env.json`
660
668
  if (await this._fileExistsCaseSensitive('env.json')) {
661
669
  let envJson;
@@ -719,7 +727,7 @@ class App {
719
727
  }
720
728
  } else {
721
729
  for (const prefix of RESERVED_SETTING_PREFIXES) {
722
- if (typeof setting.id !== 'string') {
730
+ if (typeof setting.id !== 'string') {
723
731
  throw new Error(`drivers.${driver.id} invalid setting id: ${setting.id}, must be a string, got: ${typeof setting.id}`);
724
732
  }
725
733
  if (setting.id.startsWith(prefix)) {
@@ -796,7 +804,7 @@ class App {
796
804
  const extension = extname(imagePath);
797
805
 
798
806
  if (typeof IMAGE_MARKERS[extension] === 'undefined') {
799
- throw new Error(`Invalid image extension (${extension})${ errorPath ? ` ${errorPath}.${size}` : ''}: ${join(this._path, imagePath)}`);
807
+ throw new Error(`Invalid image extension (${extension})${errorPath ? ` ${errorPath}.${size}` : ''}: ${join(this._path, imagePath)}`);
800
808
  }
801
809
 
802
810
  await this._ensureFileExistsCaseSensitive(imagePath);
@@ -805,14 +813,14 @@ class App {
805
813
  const imageBytes = await this._readBytes(imagePath, compareBuffer.length);
806
814
 
807
815
  if (!imageBytes.equals(compareBuffer)) {
808
- throw new Error(`Invalid image${ errorPath ? ` ${errorPath}.${size}` : ''}: ${join(this._path, imagePath)}`);
816
+ throw new Error(`Invalid image${errorPath ? ` ${errorPath}.${size}` : ''}: ${join(this._path, imagePath)}`);
809
817
  }
810
818
 
811
819
  const requiredSize = IMAGE_SIZES[type][size];
812
820
  const imageSize = await imageSizeAsync(join(this._path, imagePath));
813
821
  if (imageSize.width !== requiredSize.width
814
822
  || imageSize.height !== requiredSize.height) {
815
- throw new Error(`Invalid image size (${imageSize.width}x${imageSize.height})${ errorPath ? ` ${errorPath}.${size}` : ''}: ${join(this._path, imagePath)}\nRequired: ${requiredSize.width}x${requiredSize.height}`);
823
+ throw new Error(`Invalid image size (${imageSize.width}x${imageSize.height})${errorPath ? ` ${errorPath}.${size}` : ''}: ${join(this._path, imagePath)}\nRequired: ${requiredSize.width}x${requiredSize.height}`);
816
824
  }
817
825
  }
818
826
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homey-lib",
3
- "version": "2.42.1",
3
+ "version": "2.43.0",
4
4
  "description": "Shared Library for Homey",
5
5
  "main": "index.js",
6
6
  "scripts": {